8147558: Add support for ES6 collections

Reviewed-by: attila, mhaupt
This commit is contained in:
Hannes Wallnöfer 2016-02-15 17:02:32 +01:00
parent ca3da12f5a
commit 1e80d261e3
35 changed files with 2876 additions and 61 deletions

View File

@ -48,6 +48,7 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.LIST_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.NATIVESYMBOL_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME;
@ -63,6 +64,8 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_S
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATIONKEY_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SYMBOL_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SYMBOL_PREFIX;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT;
import java.io.BufferedInputStream;
@ -277,7 +280,7 @@ public class ClassGenerator {
static void newFunction(final MethodGenerator mi, final String objName, final String className, final MemberInfo memInfo, final List<MemberInfo> specs) {
final boolean arityFound = (memInfo.getArity() != MemberInfo.DEFAULT_ARITY);
mi.loadLiteral(memInfo.getName());
loadFunctionName(mi, memInfo.getName());
mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, memInfo.getJavaName(), memInfo.getJavaDesc()));
assert specs != null;
@ -305,8 +308,8 @@ public class ClassGenerator {
// dup of Collection instance
mi.dup();
// property = AccessorProperty.create(key, flags, getter, setter);
mi.loadLiteral(propertyName);
// Load property name, converting to Symbol if it begins with "@@"
loadPropertyKey(mi, propertyName);
// setup flags
mi.push(memInfo.getAttributes());
// setup getter method handle
@ -319,6 +322,7 @@ public class ClassGenerator {
javaName = SETTER_PREFIX + memInfo.getJavaName();
mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, setterDesc(memInfo)));
}
// property = AccessorProperty.create(key, flags, getter, setter);
mi.invokeStatic(ACCESSORPROPERTY_TYPE, ACCESSORPROPERTY_CREATE, ACCESSORPROPERTY_CREATE_DESC);
// boolean Collection.add(property)
mi.invokeInterface(COLLECTION_TYPE, COLLECTION_ADD, COLLECTION_ADD_DESC);
@ -333,8 +337,8 @@ public class ClassGenerator {
// dup of Collection instance
mi.dup();
// property = AccessorProperty.create(key, flags, getter, setter);
mi.loadLiteral(propertyName);
// Load property name, converting to Symbol if it begins with "@@"
loadPropertyKey(mi, propertyName);
// setup flags
mi.push(getter.getAttributes());
// setup getter method handle
@ -347,6 +351,7 @@ public class ClassGenerator {
mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className,
setter.getJavaName(), setter.getJavaDesc()));
}
// property = AccessorProperty.create(key, flags, getter, setter);
mi.invokeStatic(ACCESSORPROPERTY_TYPE, ACCESSORPROPERTY_CREATE, ACCESSORPROPERTY_CREATE_DESC);
// boolean Collection.add(property)
mi.invokeInterface(COLLECTION_TYPE, COLLECTION_ADD, COLLECTION_ADD_DESC);
@ -365,6 +370,22 @@ public class ClassGenerator {
return getScriptClassInfo(new ClassReader(classBuf));
}
private static void loadFunctionName(final MethodGenerator mi, final String propertyName) {
if (propertyName.startsWith(SYMBOL_PREFIX)) {
mi.loadLiteral("Symbol[" + propertyName.substring(2) + "]");
} else {
mi.loadLiteral(propertyName);
}
}
private static void loadPropertyKey(final MethodGenerator mi, final String propertyName) {
if (propertyName.startsWith(SYMBOL_PREFIX)) {
mi.getStatic(NATIVESYMBOL_TYPE, propertyName.substring(2), SYMBOL_DESC);
} else {
mi.loadLiteral(propertyName);
}
}
private static ScriptClassInfo getScriptClassInfo(final ClassReader reader) {
final ScriptClassInfoCollector scic = new ScriptClassInfoCollector();
reader.accept(scic, 0);

View File

@ -28,6 +28,8 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DES
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.STRING_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_SYMBOL;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.nashorn.internal.objects.annotations.Where;
@ -466,11 +468,10 @@ public final class MemberInfo implements Cloneable {
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.INT:
case Type.LONG:
case Type.DOUBLE:
return true;
default:
return false;
return type != TYPE_SYMBOL;
}
}

View File

@ -31,12 +31,14 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import jdk.internal.org.objectweb.asm.Type;
import jdk.nashorn.internal.objects.NativeSymbol;
import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.PrototypeObject;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Specialization;
import jdk.nashorn.internal.runtime.Symbol;
/**
* String constants used for code generation/instrumentation.
@ -88,6 +90,8 @@ public interface StringConstants {
static final Type TYPE_PROTOTYPEOBJECT = Type.getType(PrototypeObject.class);
static final Type TYPE_SCRIPTFUNCTION = Type.getType(ScriptFunction.class);
static final Type TYPE_SCRIPTOBJECT = Type.getType(ScriptObject.class);
static final Type TYPE_NATIVESYMBOL = Type.getType(NativeSymbol.class);
static final Type TYPE_SYMBOL = Type.getType(Symbol.class);
static final String PROTOTYPE_SUFFIX = "$Prototype";
static final String CONSTRUCTOR_SUFFIX = "$Constructor";
@ -101,7 +105,7 @@ public interface StringConstants {
static final String ACCESSORPROPERTY_TYPE = TYPE_ACCESSORPROPERTY.getInternalName();
static final String ACCESSORPROPERTY_CREATE = "create";
static final String ACCESSORPROPERTY_CREATE_DESC =
Type.getMethodDescriptor(TYPE_ACCESSORPROPERTY, TYPE_STRING, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE);
Type.getMethodDescriptor(TYPE_ACCESSORPROPERTY, TYPE_OBJECT, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE);
// PropertyMap
static final String PROPERTYMAP_TYPE = TYPE_PROPERTYMAP.getInternalName();
@ -143,4 +147,9 @@ public interface StringConstants {
// ScriptObject.getClassName() method.
static final String GET_CLASS_NAME = "getClassName";
static final String GET_CLASS_NAME_DESC = Type.getMethodDescriptor(TYPE_STRING);
// NativeSymbol
static final String NATIVESYMBOL_TYPE = TYPE_NATIVESYMBOL.getInternalName();
static final String SYMBOL_DESC = TYPE_SYMBOL.getDescriptor();
static final String SYMBOL_PREFIX = "@@";
}

View File

@ -0,0 +1,196 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import java.lang.invoke.MethodHandle;
import java.util.function.Consumer;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
/**
* ECMA6 25.1.2 The %IteratorPrototype% Object
*/
@ScriptClass("Iterator")
public abstract class AbstractIterator extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
private final static Object ITERATOR_INVOKER_KEY = new Object();
private final static Object NEXT_INVOKER_KEY = new Object();
private final static Object DONE_INVOKER_KEY = new Object();
private final static Object VALUE_INVOKER_KEY = new Object();
/** ECMA6 iteration kinds */
enum IterationKind {
/** key iteration */
KEY,
/** value iteration */
VALUE,
/** key+value iteration */
KEY_VALUE
}
/**
* Create an abstract iterator object with the given prototype and property map.
*
* @param prototype the prototype
* @param map the property map
*/
protected AbstractIterator(final ScriptObject prototype, final PropertyMap map) {
super(prototype, map);
}
/**
* 25.1.2.1 %IteratorPrototype% [ @@iterator ] ( )
*
* @param self the self object
* @return this iterator
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
public static Object getIterator(final Object self) {
return self;
}
@Override
public String getClassName() {
return "Iterator";
}
/**
* ES6 25.1.1.2 The Iterator Interface
*
* @param arg argument
* @return next iterator result
*/
protected abstract IteratorResult next(final Object arg);
/**
* ES6 25.1.1.3 The IteratorResult Interface
*
* @param value result value
* @param done result status
* @param global the global object
* @return result object
*/
protected IteratorResult makeResult(final Object value, final Boolean done, final Global global) {
return new IteratorResult(value, done, global);
}
/**
* ES6 7.4.1 GetIterator abstract operation
*
* @param iterable an object
* @param global the global object
* @return the iterator
*/
public static Object getIterator(final Object iterable, final Global global) {
final Object object = Global.toObject(iterable);
if (object instanceof ScriptObject) {
// TODO we need to implement fast property access for Symbol keys in order to use InvokeByName here.
final Object getter = ((ScriptObject) object).get(NativeSymbol.iterator);
if (Bootstrap.isCallable(getter)) {
try {
final MethodHandle invoker = global.getDynamicInvoker(ITERATOR_INVOKER_KEY,
() -> Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class));
final Object value = invoker.invokeExact(getter, iterable);
if (JSType.isPrimitive(value)) {
throw typeError("not.an.object", ScriptRuntime.safeToString(value));
}
return value;
} catch (final Throwable t) {
throw new RuntimeException(t);
}
}
throw typeError("not.a.function", ScriptRuntime.safeToString(getter));
}
throw typeError("cannot.get.iterator", ScriptRuntime.safeToString(iterable));
}
/**
* Iterate over an iterable object, passing every value to {@code consumer}.
*
* @param iterable an iterable object
* @param global the current global
* @param consumer the value consumer
*/
public static void iterate(final Object iterable, final Global global, final Consumer<Object> consumer) {
final Object iterator = AbstractIterator.getIterator(Global.toObject(iterable), global);
final InvokeByName nextInvoker = global.getInvokeByName(AbstractIterator.NEXT_INVOKER_KEY,
() -> new InvokeByName("next", Object.class, Object.class, Object.class));
final MethodHandle doneInvoker = global.getDynamicInvoker(AbstractIterator.DONE_INVOKER_KEY,
() -> Bootstrap.createDynamicInvoker("done", NashornCallSiteDescriptor.GET_PROPERTY, Object.class, Object.class));
final MethodHandle valueInvoker = global.getDynamicInvoker(AbstractIterator.VALUE_INVOKER_KEY,
() -> Bootstrap.createDynamicInvoker("value", NashornCallSiteDescriptor.GET_PROPERTY, Object.class, Object.class));
try {
do {
final Object next = nextInvoker.getGetter().invokeExact(iterator);
if (!Bootstrap.isCallable(next)) {
break;
}
final Object result = nextInvoker.getInvoker().invokeExact(next, iterator, (Object) null);
if (!(result instanceof ScriptObject)) {
break;
}
final Object done = doneInvoker.invokeExact(result);
if (JSType.toBoolean(done)) {
break;
}
consumer.accept(valueInvoker.invokeExact(result));
} while (true);
} catch (final RuntimeException r) {
throw r;
} catch (final Throwable t) {
throw new RuntimeException(t);
}
}
}

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Undefined;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
@ScriptClass("ArrayIterator")
public class ArrayIterator extends AbstractIterator {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
private ScriptObject iteratedObject;
private long nextIndex = 0L;
private final IterationKind iterationKind;
private final Global global;
ArrayIterator(final Object iteratedObject, final IterationKind iterationKind, final Global global) {
super(global.getArrayIteratorPrototype(), $nasgenmap$);
this.iteratedObject = iteratedObject instanceof ScriptObject ? (ScriptObject) iteratedObject : null;
this.iterationKind = iterationKind;
this.global = global;
}
/**
* 22.1.5.2.1 %ArrayIteratorPrototype%.next()
*
* @param self the self reference
* @param arg the argument
* @return the next result
*/
@Function
public static Object next(final Object self, final Object arg) {
if (!(self instanceof ArrayIterator)) {
throw typeError("not.a.array.iterator", ScriptRuntime.safeToString(self));
}
return ((ArrayIterator)self).next(arg);
}
@Override
public String getClassName() {
return "Array Iterator";
}
@Override
protected IteratorResult next(final Object arg) {
final long index = nextIndex;
if (iteratedObject == null || index >= JSType.toUint32(iteratedObject.getLength())) {
// ES6 22.1.5.2.1 step 10
iteratedObject = null;
return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
}
nextIndex++;
if (iterationKind == IterationKind.KEY_VALUE) {
final NativeArray value = new NativeArray(
new Object[] {JSType.toNarrowestNumber(index), iteratedObject.get((double) index)});
return makeResult(value, Boolean.FALSE, global);
}
final Object value = iterationKind == IterationKind.KEY ?
JSType.toNarrowestNumber(index) : iteratedObject.get((double) index);
return makeResult(value, Boolean.FALSE, global);
}
}

View File

@ -95,6 +95,8 @@ public final class Global extends Scope {
// (__FILE__, __DIR__, __LINE__)
private static final Object LAZY_SENTINEL = new Object();
private static final String PACKAGE_PREFIX = "jdk.nashorn.internal.objects.";
private InvokeByName TO_STRING;
private InvokeByName VALUE_OF;
@ -222,9 +224,6 @@ public final class Global extends Scope {
@Property(name = "Number", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object number;
/** ECMA 2016 19.4.1 - Symbol constructor */
@Property(name = "Symbol", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object symbol;
/**
* Getter for ECMA 15.1.4.7 Date property
@ -748,6 +747,147 @@ public final class Global extends Scope {
private volatile Object float64Array;
/**
* Getter for the Symbol property.
*
* @param self self reference
* @return the value of the Symbol property
*/
@Getter(name = "Symbol", attributes = Attribute.NOT_ENUMERABLE)
public static Object getSymbol(final Object self) {
final Global global = Global.instanceFrom(self);
if (global.symbol == LAZY_SENTINEL) {
global.symbol = global.getBuiltinSymbol();
}
return global.symbol;
}
/**
* Setter for the Symbol property.
*
* @param self self reference
* @param value value of the Symbol property
*/
@Setter(name = "Symbol", attributes = Attribute.NOT_ENUMERABLE)
public static void setSymbol(final Object self, final Object value) {
Global.instanceFrom(self).symbol = value;
}
private volatile Object symbol;
/**
* Getter for the Map property.
*
* @param self self reference
* @return the value of the Map property
*/
@Getter(name = "Map", attributes = Attribute.NOT_ENUMERABLE)
public static Object getMap(final Object self) {
final Global global = Global.instanceFrom(self);
if (global.map == LAZY_SENTINEL) {
global.map = global.getBuiltinMap();
}
return global.map;
}
/**
* Setter for the Map property.
*
* @param self self reference
* @param value value of the Map property
*/
@Setter(name = "Map", attributes = Attribute.NOT_ENUMERABLE)
public static void setMap(final Object self, final Object value) {
Global.instanceFrom(self).map = value;
}
private volatile Object map;
/**
* Getter for the WeakMap property.
*
* @param self self reference
* @return the value of the WeakMap property
*/
@Getter(name = "WeakMap", attributes = Attribute.NOT_ENUMERABLE)
public static Object getWeakMap(final Object self) {
final Global global = Global.instanceFrom(self);
if (global.weakMap == LAZY_SENTINEL) {
global.weakMap = global.getBuiltinWeakMap();
}
return global.weakMap;
}
/**
* Setter for the WeakMap property.
*
* @param self self reference
* @param value value of the WeakMap property
*/
@Setter(name = "WeakMap", attributes = Attribute.NOT_ENUMERABLE)
public static void setWeakMap(final Object self, final Object value) {
Global.instanceFrom(self).weakMap = value;
}
private volatile Object weakMap;
/**
* Getter for the Set property.
*
* @param self self reference
* @return the value of the Set property
*/
@Getter(name = "Set", attributes = Attribute.NOT_ENUMERABLE)
public static Object getSet(final Object self) {
final Global global = Global.instanceFrom(self);
if (global.set == LAZY_SENTINEL) {
global.set = global.getBuiltinSet();
}
return global.set;
}
/**
* Setter for the Set property.
*
* @param self self reference
* @param value value of the Set property
*/
@Setter(name = "Set", attributes = Attribute.NOT_ENUMERABLE)
public static void setSet(final Object self, final Object value) {
Global.instanceFrom(self).set = value;
}
private volatile Object set;
/**
* Getter for the WeakSet property.
*
* @param self self reference
* @return the value of the WeakSet property
*/
@Getter(name = "WeakSet", attributes = Attribute.NOT_ENUMERABLE)
public static Object getWeakSet(final Object self) {
final Global global = Global.instanceFrom(self);
if (global.weakSet == LAZY_SENTINEL) {
global.weakSet = global.getBuiltinWeakSet();
}
return global.weakSet;
}
/**
* Setter for the WeakSet property.
*
* @param self self reference
* @param value value of the WeakSet property
*/
@Setter(name = "WeakSet", attributes = Attribute.NOT_ENUMERABLE)
public static void setWeakSet(final Object self, final Object value) {
Global.instanceFrom(self).weakSet = value;
}
private volatile Object weakSet;
/** Nashorn extension: Java access - global.Packages */
@Property(name = "Packages", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object packages;
@ -907,6 +1047,15 @@ public final class Global extends Scope {
private ScriptFunction builtinFloat32Array;
private ScriptFunction builtinFloat64Array;
private ScriptFunction builtinSymbol;
private ScriptFunction builtinMap;
private ScriptFunction builtinWeakMap;
private ScriptFunction builtinSet;
private ScriptFunction builtinWeakSet;
private ScriptObject builtinIteratorPrototype;
private ScriptObject builtinMapIteratorPrototype;
private ScriptObject builtinSetIteratorPrototype;
private ScriptObject builtinArrayIteratorPrototype;
private ScriptObject builtinStringIteratorPrototype;
/*
* ECMA section 13.2.3 The [[ThrowTypeError]] Function Object
@ -1673,7 +1822,58 @@ public final class Global extends Scope {
}
ScriptObject getSymbolPrototype() {
return ScriptFunction.getPrototype(builtinSymbol);
return ScriptFunction.getPrototype(getBuiltinSymbol());
}
ScriptObject getMapPrototype() {
return ScriptFunction.getPrototype(getBuiltinMap());
}
ScriptObject getWeakMapPrototype() {
return ScriptFunction.getPrototype(getBuiltinWeakMap());
}
ScriptObject getSetPrototype() {
return ScriptFunction.getPrototype(getBuiltinSet());
}
ScriptObject getWeakSetPrototype() {
return ScriptFunction.getPrototype(getBuiltinWeakSet());
}
ScriptObject getIteratorPrototype() {
if (builtinIteratorPrototype == null) {
builtinIteratorPrototype = initPrototype("AbstractIterator", getObjectPrototype());
}
return builtinIteratorPrototype;
}
ScriptObject getMapIteratorPrototype() {
if (builtinMapIteratorPrototype == null) {
builtinMapIteratorPrototype = initPrototype("MapIterator", getIteratorPrototype());
}
return builtinMapIteratorPrototype;
}
ScriptObject getSetIteratorPrototype() {
if (builtinSetIteratorPrototype == null) {
builtinSetIteratorPrototype = initPrototype("SetIterator", getIteratorPrototype());
}
return builtinSetIteratorPrototype;
}
ScriptObject getArrayIteratorPrototype() {
if (builtinArrayIteratorPrototype == null) {
builtinArrayIteratorPrototype = initPrototype("ArrayIterator", getIteratorPrototype());
}
return builtinArrayIteratorPrototype;
}
ScriptObject getStringIteratorPrototype() {
if (builtinStringIteratorPrototype == null) {
builtinStringIteratorPrototype = initPrototype("StringIterator", getIteratorPrototype());
}
return builtinStringIteratorPrototype;
}
private synchronized ScriptFunction getBuiltinArrayBuffer() {
@ -1916,6 +2116,41 @@ public final class Global extends Scope {
return this.builtinURIError;
}
private synchronized ScriptFunction getBuiltinSymbol() {
if (this.builtinSymbol == null) {
this.builtinSymbol = initConstructorAndSwitchPoint("Symbol", ScriptFunction.class);
}
return this.builtinSymbol;
}
private synchronized ScriptFunction getBuiltinMap() {
if (this.builtinMap == null) {
this.builtinMap = initConstructorAndSwitchPoint("Map", ScriptFunction.class);
}
return this.builtinMap;
}
private synchronized ScriptFunction getBuiltinWeakMap() {
if (this.builtinWeakMap == null) {
this.builtinWeakMap = initConstructorAndSwitchPoint("WeakMap", ScriptFunction.class);
}
return this.builtinWeakMap;
}
private synchronized ScriptFunction getBuiltinSet() {
if (this.builtinSet == null) {
this.builtinSet = initConstructorAndSwitchPoint("Set", ScriptFunction.class);
}
return this.builtinSet;
}
private synchronized ScriptFunction getBuiltinWeakSet() {
if (this.builtinWeakSet == null) {
this.builtinWeakSet = initConstructorAndSwitchPoint("WeakSet", ScriptFunction.class);
}
return this.builtinWeakSet;
}
@Override
public String getClassName() {
return "global";
@ -2311,14 +2546,6 @@ public final class Global extends Scope {
this.builtinString = initConstructorAndSwitchPoint("String", ScriptFunction.class);
this.builtinMath = initConstructorAndSwitchPoint("Math", ScriptObject.class);
if (env._es6) {
this.builtinSymbol = initConstructorAndSwitchPoint("Symbol", ScriptFunction.class);
} else {
// We need to manually delete nasgen-generated properties we don't want
this.delete("Symbol", false);
this.builtinObject.delete("getOwnPropertySymbols", false);
}
// initialize String.prototype.length to 0
// add String.prototype.length
final ScriptObject stringPrototype = getStringPrototype();
@ -2328,6 +2555,25 @@ public final class Global extends Scope {
final ScriptObject arrayPrototype = getArrayPrototype();
arrayPrototype.setIsArray();
if (env._es6) {
this.symbol = LAZY_SENTINEL;
this.map = LAZY_SENTINEL;
this.weakMap = LAZY_SENTINEL;
this.set = LAZY_SENTINEL;
this.weakSet = LAZY_SENTINEL;
} else {
// We need to manually delete nasgen-generated properties we don't want
this.delete("Symbol", false);
this.delete("Map", false);
this.delete("WeakMap", false);
this.delete("Set", false);
this.delete("WeakSet", false);
builtinObject.delete("getOwnPropertySymbols", false);
arrayPrototype.delete("entries", false);
arrayPrototype.delete("keys", false);
arrayPrototype.delete("values", false);
}
// Error stuff
initErrorObjects();
@ -2522,7 +2768,6 @@ public final class Global extends Scope {
this.string = this.builtinString;
this.syntaxError = this.builtinSyntaxError;
this.typeError = this.builtinTypeError;
this.symbol = this.builtinSymbol;
}
private void initDebug() {
@ -2558,7 +2803,7 @@ public final class Global extends Scope {
private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) {
try {
// Assuming class name pattern for built-in JS constructors.
final StringBuilder sb = new StringBuilder("jdk.nashorn.internal.objects.");
final StringBuilder sb = new StringBuilder(PACKAGE_PREFIX);
sb.append("Native");
sb.append(name);
@ -2586,6 +2831,22 @@ public final class Global extends Scope {
}
}
private ScriptObject initPrototype(final String name, final ScriptObject prototype) {
try {
// Assuming class name pattern for JS prototypes
final String className = PACKAGE_PREFIX + name + "$Prototype";
final Class<?> funcClass = Class.forName(className);
final ScriptObject res = (ScriptObject) funcClass.newInstance();
res.setIsBuiltin();
res.setInitialProto(prototype);
return res;
} catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) {
final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>();

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
@ScriptClass("IteratorResult")
public class IteratorResult extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
IteratorResult(final Object value, final Boolean done, final Global global) {
super(global.getObjectPrototype(), $nasgenmap$);
this.value = value;
this.done = done;
}
/**
* The result value property.
*/
@Property
public Object value;
/**
* The result status property.
*/
@Property
public Object done;
}

View File

@ -0,0 +1,239 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.runtime.Undefined;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* <p>A linked hash map used by the ES6 Map and Set objects. As required by the ECMA specification for these objects,
* this class allows arbitrary modifications to the base collection while being iterated over. However, note that
* such modifications are only safe from the same thread performing the iteration; the class is not thread-safe.</p>
*
* <p>Deletions and additions that occur during iteration are reflected in the elements visited by the iterator
* (except for deletion of elements that have already been visited). In non-concurrent Java collections such as
* {@code java.util.LinkedHashMap} this would result in a {@link java.util.ConcurrentModificationException}
* being thrown.</p>
*
* <p>This class is implemented using a {@link java.util.HashMap} as backing storage with doubly-linked
* list nodes as values.</p>
*
* @see <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-map.prototype.foreach">Map.prototype.forEach</a>
* @see <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-set.prototype.foreach">Set.prototype.forEach</a>
*/
public class LinkedMap {
// We use a plain hash map as our hash storage.
private final Map<Object, Node> data = new HashMap<>();
// The head and tail of our doubly-linked list. We use the same node to represent both the head and the
// tail of the list, so the list is circular. This node is never unlinked and thus always remain alive.
private final Node head = new Node();
/**
* A node of a linked list that is used as value in our map. The linked list uses insertion order
* and allows fast iteration over its element even while the map is modified.
*/
static class Node {
private final Object key;
private final Object value;
private volatile boolean alive = true;
private volatile Node prev;
private volatile Node next;
/**
* Constructor for the list head. This creates an empty circular list.
*/
private Node() {
this(null, null);
this.next = this;
this.prev = this;
}
/**
* Constructor for value nodes.
*
* @param key the key
* @param value the value
*/
private Node(final Object key, final Object value) {
this.key = key;
this.value = value;
}
/**
* Get the node's key.
* @return the hash key
*/
public Object getKey() {
return key;
}
/**
* Get the node's value.
* @return the value
*/
public Object getValue() {
return value;
}
}
/**
* An iterator over the elements in the map.
*/
class LinkedMapIterator {
private Node cursor;
private LinkedMapIterator() {
this.cursor = head;
}
/**
* Get the next node in this iteration. Changes in the underlying map are reflected in the iteration
* as required by the ES6 specification. Note that this method could return a deleted node if deletion
* occurred concurrently on another thread.
*
* @return the next node
*/
public Node next() {
if (cursor != null) {
// If last node is not alive anymore (i.e. has been deleted) go back to the last live node
// and continue from there. This may be the list head, which always remains alive.
while (!cursor.alive) {
assert cursor != head;
cursor = cursor.prev;
}
cursor = cursor.next;
if (cursor == head) {
cursor = null; // We've come full circle to the end
}
}
return cursor;
}
}
/**
* Add a key-value pair to the map.
* @param key the key
* @param value the value
*/
public void set(final Object key, final Object value) {
final Node newNode = new Node(key, value);
final Node oldNode = data.put(key, newNode);
if (oldNode != null) {
unlink(oldNode);
}
link(newNode);
}
/**
* Get the value associated with {@code key}.
* @param key the key
* @return the associated value, or {@code null} if {@code key} is not contained in the map
*/
public Object get(final Object key) {
final Node node = data.get(key);
return node == null ? Undefined.getUndefined() : node.getValue();
}
/**
* Returns {@code true} if {@code key} is contained in the map.
* @param key the key
* @return {@code true} if {@code key} is contained
*/
public boolean has(final Object key) {
return data.containsKey(key);
}
/**
* Delete the node associated with {@code key} from the map.
* @param key the key
* @return {@code true} if {@code key} was contained in the map
*/
public boolean delete (final Object key) {
final Node node = data.remove(key);
if (node != null) {
unlink(node);
return true;
}
return false;
}
/**
* Remove all key-value pairs from the map.
*/
public void clear() {
data.clear();
for (Node node = head.next; node != head; node = node.next) {
node.alive = false;
}
head.next = head;
head.prev = head;
}
/**
* Return the current number of key-value pairs in the map.
* @return the map size
*/
public int size() {
return data.size();
}
/**
* Get an iterator over the key-value pairs in the map.
* @return an iterator
*/
public LinkedMapIterator getIterator() {
return new LinkedMapIterator();
}
private void link(final Node newNode) {
// We always insert at the end (head == tail)
newNode.next = head;
newNode.prev = head.prev;
newNode.prev.next = newNode;
head.prev = newNode;
}
private void unlink(final Node oldNode) {
// Note that we unlink references to the node being deleted, but keep the references from the deleted node.
// This is necessary to allow iterators to go back to the last live node in case the current node has been
// deleted. Also, the forward link of a deleted node may still be followed by an iterator and must not be null.
oldNode.prev.next = oldNode.next;
oldNode.next.prev = oldNode.prev;
oldNode.alive = false;
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Undefined;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
/**
* ECMA6 23.1.5 Map Iterator Objects
*/
@ScriptClass("MapIterator")
public class MapIterator extends AbstractIterator {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
private LinkedMap.LinkedMapIterator iterator;
private final IterationKind iterationKind;
// Cached global needed for each iteration result
private final Global global;
/**
* Constructor for Map iterators.
* @param map the map to iterate over
* @param iterationKind the iteration kind
* @param global the current global object
*/
MapIterator(final NativeMap map, final IterationKind iterationKind, final Global global) {
super(global.getMapIteratorPrototype(), $nasgenmap$);
this.iterator = map.getJavaMap().getIterator();
this.iterationKind = iterationKind;
this.global = global;
}
/**
* ES6 23.1.5.2.1 %MapIteratorPrototype%.next()
*
* @param self the self reference
* @param arg the argument
* @return the next result
*/
@Function
public static Object next(final Object self, final Object arg) {
if (!(self instanceof MapIterator)) {
throw typeError("not.a.map.iterator", ScriptRuntime.safeToString(self));
}
return ((MapIterator)self).next(arg);
}
@Override
public String getClassName() {
return "Map Iterator";
}
@Override
protected IteratorResult next(final Object arg) {
if (iterator == null) {
return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
}
final LinkedMap.Node node = iterator.next();
if (node == null) {
iterator = null;
return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
}
if (iterationKind == IterationKind.KEY_VALUE) {
final NativeArray array = new NativeArray(new Object[] {node.getKey(), node.getValue()});
return makeResult(array, Boolean.FALSE, global);
}
return makeResult(iterationKind == IterationKind.KEY ? node.getKey() : node.getValue(), Boolean.FALSE, global);
}
}

View File

@ -1717,6 +1717,50 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
return reduceInner(reverseArrayLikeIterator(self), self, args);
}
/**
* ECMA6 22.1.3.4 Array.prototype.entries ( )
*
* @param self the self reference
* @return an iterator over the array's entries
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object entries(final Object self) {
return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance());
}
/**
* ECMA6 22.1.3.13 Array.prototype.keys ( )
*
* @param self the self reference
* @return an iterator over the array's keys
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object keys(final Object self) {
return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.KEY, Global.instance());
}
/**
* ECMA6 22.1.3.29 Array.prototype.values ( )
*
* @param self the self reference
* @return an iterator over the array's values
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object values(final Object self) {
return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.VALUE, Global.instance());
}
/**
* 22.1.3.30 Array.prototype [ @@iterator ] ( )
*
* @param self the self reference
* @return an iterator over the array's values
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
public static Object getIterator(final Object self) {
return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.VALUE, Global.instance());
}
/**
* Determine if Java bulk array operations may be used on the underlying
* storage. This is possible only if the object's prototype chain is empty

View File

@ -0,0 +1,287 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import java.lang.invoke.MethodHandle;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Undefined;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
/**
* This implements the ECMA6 Map object.
*/
@ScriptClass("Map")
public class NativeMap extends ScriptObject {
// our underlying map
private final LinkedMap map = new LinkedMap();
// key for the forEach invoker callback
private final static Object FOREACH_INVOKER_KEY = new Object();
// initialized by nasgen
private static PropertyMap $nasgenmap$;
private NativeMap(final ScriptObject proto, final PropertyMap map) {
super(proto, map);
}
/**
* ECMA6 23.1.1 The Map Constructor
*
* @param isNew is this called with the new operator?
* @param self self reference
* @param arg optional iterable argument
* @return a new Map instance
*/
@Constructor(arity = 0)
public static Object construct(final boolean isNew, final Object self, final Object arg) {
if (!isNew) {
throw typeError("constructor.requires.new", "Map");
}
final Global global = Global.instance();
final NativeMap map = new NativeMap(global.getMapPrototype(), $nasgenmap$);
populateMap(map.getJavaMap(), arg, global);
return map;
}
/**
* ECMA6 23.1.3.1 Map.prototype.clear ( )
*
* @param self the self reference
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static void clear(final Object self) {
getNativeMap(self).map.clear();
}
/**
* ECMA6 23.1.3.3 Map.prototype.delete ( key )
*
* @param self the self reference
* @param key the key to delete
* @return true if the key was deleted
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static boolean delete(final Object self, final Object key) {
return getNativeMap(self).map.delete(convertKey(key));
}
/**
* ECMA6 23.1.3.7 Map.prototype.has ( key )
*
* @param self the self reference
* @param key the key
* @return true if key is contained
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static boolean has(final Object self, final Object key) {
return getNativeMap(self).map.has(convertKey(key));
}
/**
* ECMA6 23.1.3.9 Map.prototype.set ( key , value )
*
* @param self the self reference
* @param key the key
* @param value the value
* @return this Map object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object set(final Object self, final Object key, final Object value) {
getNativeMap(self).map.set(convertKey(key), value);
return self;
}
/**
* ECMA6 23.1.3.6 Map.prototype.get ( key )
*
* @param self the self reference
* @param key the key
* @return the associated value or undefined
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object get(final Object self, final Object key) {
return getNativeMap(self).map.get(convertKey(key));
}
/**
* ECMA6 23.1.3.10 get Map.prototype.size
*
* @param self the self reference
* @return the size of the map
*/
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.IS_ACCESSOR, where = Where.PROTOTYPE)
public static int size(final Object self) {
return getNativeMap(self).map.size();
}
/**
* ECMA6 23.1.3.4 Map.prototype.entries ( )
*
* @param self the self reference
* @return an iterator over the Map's entries
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object entries(final Object self) {
return new MapIterator(getNativeMap(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance());
}
/**
* ECMA6 23.1.3.8 Map.prototype.keys ( )
*
* @param self the self reference
* @return an iterator over the Map's keys
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object keys(final Object self) {
return new MapIterator(getNativeMap(self), AbstractIterator.IterationKind.KEY, Global.instance());
}
/**
* ECMA6 23.1.3.11 Map.prototype.values ( )
*
* @param self the self reference
* @return an iterator over the Map's values
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object values(final Object self) {
return new MapIterator(getNativeMap(self), AbstractIterator.IterationKind.VALUE, Global.instance());
}
/**
* ECMA6 23.1.3.12 Map.prototype [ @@iterator ]( )
*
* @param self the self reference
* @return An iterator over the Map's entries
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
public static Object getIterator(final Object self) {
return new MapIterator(getNativeMap(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance());
}
/**
*
* @param self the self reference
* @param callbackFn the callback function
* @param thisArg optional this-object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static void forEach(final Object self, final Object callbackFn, final Object thisArg) {
final NativeMap map = getNativeMap(self);
if (!Bootstrap.isCallable(callbackFn)) {
throw typeError("not.a.function", ScriptRuntime.safeToString(callbackFn));
}
final MethodHandle invoker = Global.instance().getDynamicInvoker(FOREACH_INVOKER_KEY,
() -> Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class, Object.class, Object.class, Object.class));
final LinkedMap.LinkedMapIterator iterator = map.getJavaMap().getIterator();
for (;;) {
final LinkedMap.Node node = iterator.next();
if (node == null) {
break;
}
try {
final Object result = invoker.invokeExact(callbackFn, thisArg, node.getValue(), node.getKey(), self);
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
throw new RuntimeException(t);
}
}
}
@Override
public String getClassName() {
return "Map";
}
static void populateMap(final LinkedMap map, final Object arg, final Global global) {
if (arg != null && arg != Undefined.getUndefined()) {
AbstractIterator.iterate(arg, global, value -> {
if (JSType.isPrimitive(value)) {
throw typeError(global, "not.an.object", ScriptRuntime.safeToString(value));
}
if (value instanceof ScriptObject) {
final ScriptObject sobj = (ScriptObject) value;
map.set(convertKey(sobj.get(0)), sobj.get(1));
}
});
}
}
/**
* Returns a canonicalized key object by converting numbers to their narrowest representation and
* ConsStrings to strings. Conversion of Double to Integer also takes care of converting -0 to 0
* as required by step 6 of ECMA6 23.1.3.9.
*
* @param key a key
* @return the canonical key
*/
static Object convertKey(final Object key) {
if (key instanceof ConsString) {
return key.toString();
}
if (key instanceof Double) {
final Double d = (Double) key;
if (JSType.isRepresentableAsInt(d.doubleValue())) {
return d.intValue();
}
}
return key;
}
/**
* Get the underlying Java map.
* @return the Java map
*/
LinkedMap getJavaMap() {
return map;
}
private static NativeMap getNativeMap(final Object self) {
if (self instanceof NativeMap) {
return (NativeMap)self;
} else {
throw typeError("not.a.map", ScriptRuntime.safeToString(self));
}
}
}

View File

@ -0,0 +1,239 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import java.lang.invoke.MethodHandle;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Undefined;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import static jdk.nashorn.internal.objects.NativeMap.convertKey;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
/**
* This implements the ECMA6 Set object.
*/
@ScriptClass("Set")
public class NativeSet extends ScriptObject {
// our set/map implementation
private final LinkedMap map = new LinkedMap();
// Invoker for the forEach callback
private final static Object FOREACH_INVOKER_KEY = new Object();
// initialized by nasgen
private static PropertyMap $nasgenmap$;
private NativeSet(final ScriptObject proto, final PropertyMap map) {
super(proto, map);
}
/**
* ECMA6 23.1 Set constructor
*
* @param isNew whether the new operator used
* @param self self reference
* @param arg optional iterable argument
* @return a new Set object
*/
@Constructor(arity = 0)
public static Object construct(final boolean isNew, final Object self, final Object arg){
if (!isNew) {
throw typeError("constructor.requires.new", "Set");
}
final Global global = Global.instance();
final NativeSet set = new NativeSet(global.getSetPrototype(), $nasgenmap$);
populateSet(set.getJavaMap(), arg, global);
return set;
}
/**
* ECMA6 23.2.3.1 Set.prototype.add ( value )
*
* @param self the self reference
* @param value the value to add
* @return this Set object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object add(final Object self, final Object value) {
getNativeSet(self).map.set(convertKey(value), null);
return self;
}
/**
* ECMA6 23.2.3.7 Set.prototype.has ( value )
*
* @param self the self reference
* @param value the value
* @return true if value is contained
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static boolean has(final Object self, final Object value) {
return getNativeSet(self).map.has(convertKey(value));
}
/**
* ECMA6 23.2.3.2 Set.prototype.clear ( )
*
* @param self the self reference
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static void clear(final Object self) {
getNativeSet(self).map.clear();
}
/**
* ECMA6 23.2.3.4 Set.prototype.delete ( value )
*
* @param self the self reference
* @param value the value
* @return true if value was deleted
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static boolean delete(final Object self, final Object value) {
return getNativeSet(self).map.delete(convertKey(value));
}
/**
* ECMA6 23.2.3.9 get Set.prototype.size
*
* @param self the self reference
* @return the number of contained values
*/
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.IS_ACCESSOR, where = Where.PROTOTYPE)
public static int size(final Object self) {
return getNativeSet(self).map.size();
}
/**
* ECMA6 23.2.3.5 Set.prototype.entries ( )
*
* @param self the self reference
* @return an iterator over the Set object's entries
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object entries(final Object self) {
return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance());
}
/**
* ECMA6 23.2.3.8 Set.prototype.keys ( )
*
* @param self the self reference
* @return an iterator over the Set object's values
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object keys(final Object self) {
return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.KEY, Global.instance());
}
/**
* ECMA6 23.2.3.10 Set.prototype.values ( )
*
* @param self the self reference
* @return an iterator over the Set object's values
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object values(final Object self) {
return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.VALUE, Global.instance());
}
/**
* ECMA6 23.2.3.11 Set.prototype [ @@iterator ] ( )
*
* @param self the self reference
* @return an iterator over the Set object's values
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
public static Object getIterator(final Object self) {
return new SetIterator(getNativeSet(self), AbstractIterator.IterationKind.VALUE, Global.instance());
}
/**
* ECMA6 23.2.3.6 Set.prototype.forEach ( callbackfn [ , thisArg ] )
*
* @param self the self reference
* @param callbackFn the callback function
* @param thisArg optional this object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static void forEach(final Object self, final Object callbackFn, final Object thisArg) {
final NativeSet set = getNativeSet(self);
if (!Bootstrap.isCallable(callbackFn)) {
throw typeError("not.a.function", ScriptRuntime.safeToString(callbackFn));
}
final MethodHandle invoker = Global.instance().getDynamicInvoker(FOREACH_INVOKER_KEY,
() -> Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class, Object.class, Object.class, Object.class));
final LinkedMap.LinkedMapIterator iterator = set.getJavaMap().getIterator();
for (;;) {
final LinkedMap.Node node = iterator.next();
if (node == null) {
break;
}
try {
final Object result = invoker.invokeExact(callbackFn, thisArg, node.getKey(), node.getKey(), self);
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
throw new RuntimeException(t);
}
}
}
@Override
public String getClassName() {
return "Set";
}
static void populateSet(final LinkedMap map, final Object arg, final Global global) {
if (arg != null && arg != Undefined.getUndefined()) {
AbstractIterator.iterate(arg, global, value -> map.set(convertKey(value), null));
}
}
LinkedMap getJavaMap() {
return map;
}
private static NativeSet getNativeSet(final Object self) {
if (self instanceof NativeSet) {
return (NativeSet) self;
} else {
throw typeError("not.a.set", ScriptRuntime.safeToString(self));
}
}
}

View File

@ -1227,6 +1227,17 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti
return newObj ? newObj(str) : str;
}
/**
* ECMA 6 21.1.3.27 String.prototype [ @@iterator ]( )
*
* @param self self reference
* @return a string iterator
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
public static Object getIterator(final Object self) {
return new StringIterator(checkObjectToString(self), Global.instance());
}
/**
* Lookup the appropriate method for an invoke dynamic call.
*

View File

@ -37,6 +37,8 @@ import jdk.nashorn.internal.WeakValueCache;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.JSType;
@ -66,6 +68,12 @@ public final class NativeSymbol extends ScriptObject {
/** See ES6 19.4.2.1 */
private static WeakValueCache<String, Symbol> globalSymbolRegistry = new WeakValueCache<>();
/**
* ECMA 6 19.4.2.4 Symbol.iterator
*/
@Property(where = Where.CONSTRUCTOR, attributes = Attribute.NON_ENUMERABLE_CONSTANT, name = "iterator")
public static final Symbol iterator = new Symbol("Symbol.iterator");
NativeSymbol(final Symbol symbol) {
this(symbol, Global.instance());
}

View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import java.util.Map;
import java.util.WeakHashMap;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Undefined;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.isPrimitive;
/**
* This implements the ECMA6 WeakMap object.
*/
@ScriptClass("WeakMap")
public class NativeWeakMap extends ScriptObject {
private final Map<Object, Object> jmap = new WeakHashMap<>();
// initialized by nasgen
private static PropertyMap $nasgenmap$;
private NativeWeakMap(final ScriptObject proto, final PropertyMap map) {
super(proto, map);
}
/**
* ECMA6 23.3.1 The WeakMap Constructor
*
* @param isNew whether the new operator used
* @param self self reference
* @param arg optional iterable argument
* @return a new WeakMap object
*/
@Constructor(arity = 0)
public static Object construct(final boolean isNew, final Object self, final Object arg) {
if (!isNew) {
throw typeError("constructor.requires.new", "WeakMap");
}
final Global global = Global.instance();
final NativeWeakMap weakMap = new NativeWeakMap(global.getWeakMapPrototype(), $nasgenmap$);
populateMap(weakMap.jmap, arg, global);
return weakMap;
}
/**
* ECMA6 23.3.3.5 WeakMap.prototype.set ( key , value )
*
* @param self the self reference
* @param key the key
* @param value the value
* @return this WeakMap object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object set(final Object self, final Object key, final Object value) {
final NativeWeakMap map = getMap(self);
map.jmap.put(checkKey(key), value);
return self;
}
/**
* ECMA6 23.3.3.3 WeakMap.prototype.get ( key )
*
* @param self the self reference
* @param key the key
* @return the associated value or undefined
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object get(final Object self, final Object key) {
final NativeWeakMap map = getMap(self);
if (isPrimitive(key)) {
return Undefined.getUndefined();
}
return map.jmap.get(key);
}
/**
* ECMA6 23.3.3.2 WeakMap.prototype.delete ( key )
*
* @param self the self reference
* @param key the key to delete
* @return true if the key was deleted
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static boolean delete(final Object self, final Object key) {
final Map<Object, Object> map = getMap(self).jmap;
if (isPrimitive(key)) {
return false;
}
final boolean returnValue = map.containsKey(key);
map.remove(key);
return returnValue;
}
/**
* ECMA6 23.3.3.4 WeakMap.prototype.has ( key )
*
* @param self the self reference
* @param key the key
* @return true if key is contained
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static boolean has(final Object self, final Object key) {
final NativeWeakMap map = getMap(self);
return !isPrimitive(key) && map.jmap.containsKey(key);
}
@Override
public String getClassName() {
return "WeakMap";
}
/**
* Make sure {@code key} is not a JavaScript primitive value.
*
* @param key a key object
* @return the valid key
*/
static Object checkKey(final Object key) {
if (isPrimitive(key)) {
throw typeError("invalid.weak.key", ScriptRuntime.safeToString(key));
}
return key;
}
static void populateMap(final Map<Object, Object> map, final Object arg, final Global global) {
// This method is similar to NativeMap.populateMap, but it uses a different
// map implementation and the checking/conversion of keys differs as well.
if (arg != null && arg != Undefined.getUndefined()) {
AbstractIterator.iterate(arg, global, value -> {
if (isPrimitive(value)) {
throw typeError(global, "not.an.object", ScriptRuntime.safeToString(value));
}
if (value instanceof ScriptObject) {
final ScriptObject sobj = (ScriptObject) value;
map.put(checkKey(sobj.get(0)), sobj.get(1));
}
});
}
}
private static NativeWeakMap getMap(final Object self) {
if (self instanceof NativeWeakMap) {
return (NativeWeakMap)self;
} else {
throw typeError("not.a.weak.map", ScriptRuntime.safeToString(self));
}
}
}

View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import java.util.Map;
import java.util.WeakHashMap;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Undefined;
import static jdk.nashorn.internal.objects.NativeWeakMap.checkKey;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.isPrimitive;
/**
* This implements the ECMA6 WeakSet object.
*/
@ScriptClass("WeakSet")
public class NativeWeakSet extends ScriptObject {
private final Map<Object, Boolean> map = new WeakHashMap<>();
// initialized by nasgen
private static PropertyMap $nasgenmap$;
private NativeWeakSet(final ScriptObject proto, final PropertyMap map) {
super(proto, map);
}
/**
* ECMA6 23.3.1 The WeakSet Constructor
*
* @param isNew whether the new operator used
* @param self self reference
* @param arg optional iterable argument
* @return a new WeakSet object
*/
@Constructor(arity = 0)
public static Object construct(final boolean isNew, final Object self, final Object arg) {
if (!isNew) {
throw typeError("constructor.requires.new", "WeakSet");
}
final Global global = Global.instance();
final NativeWeakSet weakSet = new NativeWeakSet(global.getWeakSetPrototype(), $nasgenmap$);
populateWeakSet(weakSet.map, arg, global);
return weakSet;
}
/**
* ECMA6 23.4.3.1 WeakSet.prototype.add ( value )
*
* @param self the self reference
* @param value the value to add
* @return this Set object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object add(final Object self, final Object value) {
final NativeWeakSet set = getSet(self);
set.map.put(checkKey(value), Boolean.TRUE);
return self;
}
/**
* ECMA6 23.4.3.4 WeakSet.prototype.has ( value )
*
* @param self the self reference
* @param value the value
* @return true if value is contained
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static boolean has(final Object self, final Object value) {
final NativeWeakSet set = getSet(self);
return !isPrimitive(value) && set.map.containsKey(value);
}
/**
* ECMA6 23.4.3.3 WeakSet.prototype.delete ( value )
*
* @param self the self reference
* @param value the value
* @return true if value was deleted
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static boolean delete(final Object self, final Object value) {
final Map<Object, Boolean> map = getSet(self).map;
if (isPrimitive(value)) {
return false;
}
final boolean returnValue = map.containsKey(value);
map.remove(value);
return returnValue;
}
@Override
public String getClassName() {
return "WeakSet";
}
static void populateWeakSet(final Map<Object, Boolean> set, final Object arg, final Global global) {
if (arg != null && arg != Undefined.getUndefined()) {
AbstractIterator.iterate(arg, global, value -> {
set.put(checkKey(value), Boolean.TRUE);
});
}
}
private static NativeWeakSet getSet(final Object self) {
if (self instanceof NativeWeakSet) {
return (NativeWeakSet) self;
} else {
throw typeError("not.a.weak.set", ScriptRuntime.safeToString(self));
}
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Undefined;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
/**
* ECMA6 23.2.5 Set Iterator Objects
*/
@ScriptClass("SetIterator")
public class SetIterator extends AbstractIterator {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
private LinkedMap.LinkedMapIterator iterator;
private final IterationKind iterationKind;
// Cached global needed for every iteration result
private final Global global;
SetIterator(final NativeSet set, final IterationKind iterationKind, final Global global) {
super(global.getSetIteratorPrototype(), $nasgenmap$);
this.iterator = set.getJavaMap().getIterator();
this.iterationKind = iterationKind;
this.global = global;
}
/**
* ES6 23.2.5.2.1 %SetIteratorPrototype%.next()
*
* @param self the self reference
* @param arg the argument
* @return the next result
*/
@Function
public static Object next(final Object self, final Object arg) {
if (!(self instanceof SetIterator)) {
throw typeError("not.a.set.iterator", ScriptRuntime.safeToString(self));
}
return ((SetIterator)self).next(arg);
}
@Override
public String getClassName() {
return "Set Iterator";
}
@Override
protected IteratorResult next(final Object arg) {
if (iterator == null) {
return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
}
final LinkedMap.Node node = iterator.next();
if (node == null) {
iterator = null;
return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
}
if (iterationKind == IterationKind.KEY_VALUE) {
final NativeArray array = new NativeArray(new Object[] {node.getKey(), node.getKey()});
return makeResult(array, Boolean.FALSE, global);
}
return makeResult(node.getKey(), Boolean.FALSE, global);
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Undefined;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
/**
* ECMA6 21.1.5 String Iterator Objects
*/
@ScriptClass("StringIterator")
public class StringIterator extends AbstractIterator {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
private String iteratedString;
private int nextIndex = 0;
private final Global global;
StringIterator(final String iteratedString, final Global global) {
super(global.getStringIteratorPrototype(), $nasgenmap$);
this.iteratedString = iteratedString;
this.global = global;
}
/**
* ES6 21.1.5.2.1 %StringIteratorPrototype%.next()
*
* @param self the self reference
* @param arg the argument
* @return the next result
*/
@Function
public static Object next(final Object self, final Object arg) {
if (!(self instanceof StringIterator)) {
throw typeError("not.a.string.iterator", ScriptRuntime.safeToString(self));
}
return ((StringIterator)self).next(arg);
}
@Override
public String getClassName() {
return "String Iterator";
}
@Override
protected IteratorResult next(final Object arg) {
final int index = nextIndex;
final String string = iteratedString;
if (string == null || index >= string.length()) {
// ES6 21.1.5.2.1 step 8
iteratedString = null;
return makeResult(Undefined.getUndefined(), Boolean.TRUE, global);
}
final char first = string.charAt(index);
if (first >= 0xd800 && first <= 0xdbff && index < string.length() - 1) {
final char second = string.charAt(index + 1);
if (second >= 0xdc00 && second <= 0xdfff) {
nextIndex += 2;
return makeResult(String.valueOf(new char[] {first, second}), Boolean.FALSE, global);
}
}
nextIndex++;
return makeResult(String.valueOf(first), Boolean.FALSE, global);
}
}

View File

@ -31,21 +31,31 @@ package jdk.nashorn.internal.objects.annotations;
*/
public interface Attribute {
/** flag for non writable objects */
/** Flag for non-writable properties */
public static final int NOT_WRITABLE = jdk.nashorn.internal.runtime.Property.NOT_WRITABLE;
/** flag for non enumerable objects */
/** Flag for non-enumerable properties */
public static final int NOT_ENUMERABLE = jdk.nashorn.internal.runtime.Property.NOT_ENUMERABLE;
/** flag for non configurable objects */
/** Flag for non-configurable properties */
public static final int NOT_CONFIGURABLE = jdk.nashorn.internal.runtime.Property.NOT_CONFIGURABLE;
/** read-only, non-configurable property */
/**
* Flag for accessor (getter/setter) properties as opposed to data properties.
*
* <p>This allows nasgen-created properties to behave like user-accessors. it should only be used for
* properties that are explicitly specified as accessor properties in the ECMAScript specification
* such as Map.prototype.size in ES6, not value properties that happen to be implemented by getter/setter
* such as the "length" properties of String or Array objects.</p>
*/
public static final int IS_ACCESSOR = jdk.nashorn.internal.runtime.Property.IS_ACCESSOR_PROPERTY;
/** Read-only, non-configurable property */
public static final int CONSTANT = NOT_WRITABLE | NOT_CONFIGURABLE;
/** non-enumerable, read-only, non-configurable property */
/** Non-enumerable, read-only, non-configurable property */
public static final int NON_ENUMERABLE_CONSTANT = NOT_ENUMERABLE | CONSTANT;
/** by default properties are writable, enumerable and configurable */
/** By default properties are writable, enumerable and configurable */
public static final int DEFAULT_ATTRIBUTES = 0;
}

View File

@ -127,7 +127,7 @@ public class AccessorProperty extends Property {
*
* @return New {@link AccessorProperty} created.
*/
public static AccessorProperty create(final String key, final int propertyFlags, final MethodHandle getter, final MethodHandle setter) {
public static AccessorProperty create(final Object key, final int propertyFlags, final MethodHandle getter, final MethodHandle setter) {
return new AccessorProperty(key, propertyFlags, -1, getter, setter);
}
@ -601,6 +601,11 @@ public class AccessorProperty extends Property {
return getLocalType() == null;
}
@Override
public boolean hasNativeSetter() {
return objectSetter != null;
}
@Override
public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
checkUndeclared();

View File

@ -163,7 +163,7 @@ public final class FindProperty {
* @return appropriate receiver
*/
public ScriptObject getGetterReceiver() {
return property != null && property instanceof UserAccessorProperty ? self : prototype;
return property != null && property.isAccessorProperty() ? self : prototype;
}
/**

View File

@ -99,6 +99,9 @@ public abstract class Property implements Serializable {
/** Does this property support dual field representation? */
public static final int DUAL_FIELDS = 1 << 11;
/** Is this an accessor property as as defined in ES5 8.6.1? */
public static final int IS_ACCESSOR_PROPERTY = 1 << 12;
/** Property key. */
private final Object key;
@ -495,6 +498,16 @@ public abstract class Property implements Serializable {
*/
public abstract void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict);
/**
* Returns true if this property has a low-level setter handle. This can be used to determine whether a
* nasgen-generated accessor property should be treated as non-writable. For user-created accessor properties
* {@link #hasSetterFunction(ScriptObject)} should be used to find whether a setter function exists in
* a given object.
*
* @return true if a native setter handle exists
*/
public abstract boolean hasNativeSetter();
/**
* Abstract method for retrieving the setter for the property. We do not know
* anything about the internal representation when we request the setter, we only
@ -693,4 +706,12 @@ public abstract class Property implements Serializable {
public boolean hasDualFields() {
return (flags & DUAL_FIELDS) != 0;
}
/**
* Is this an accessor property as defined in ES5 8.6.1?
* @return true if this is an accessor property
*/
public boolean isAccessorProperty() {
return (flags & IS_ACCESSOR_PROPERTY) != 0;
}
}

View File

@ -702,10 +702,8 @@ public class PropertyMap implements Iterable<Object>, Serializable {
private boolean allFrozen() {
for (final Property property : properties.getProperties()) {
// check if it is a data descriptor
if (!(property instanceof UserAccessorProperty)) {
if (property.isWritable()) {
return false;
}
if (!property.isAccessorProperty() && property.isWritable()) {
return false;
}
if (property.isConfigurable()) {
return false;

View File

@ -612,7 +612,7 @@ public class ScriptFunction extends ScriptObject {
*
* @param newPrototype new prototype object
*/
public synchronized final void setPrototype(final Object newPrototype) {
public final void setPrototype(final Object newPrototype) {
if (newPrototype instanceof ScriptObject && newPrototype != this.prototype && allocatorMap != null) {
// Unset allocator map to be replaced with one matching the new prototype.
allocatorMap = null;

View File

@ -468,7 +468,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
final boolean enumerable = property.isEnumerable();
final boolean writable = property.isWritable();
if (property instanceof UserAccessorProperty) {
if (property.isAccessorProperty()) {
return global.newAccessorDescriptor(
get != null ?
get :
@ -910,10 +910,9 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
}
private void erasePropertyValue(final Property property) {
// Erase the property field value with undefined. If the property is defined
// by user-defined accessors, we don't want to call the setter!!
if (!(property instanceof UserAccessorProperty)) {
assert property != null;
// Erase the property field value with undefined. If the property is an accessor property
// we don't want to call the setter!!
if (property != null && !property.isAccessorProperty()) {
property.setValue(this, this, UNDEFINED, false);
}
}
@ -996,7 +995,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
assert gs != null;
//reuse existing getter setter for speed
gs.set(getter, setter);
if (uc.getFlags() == propertyFlags) {
if (uc.getFlags() == (propertyFlags | Property.IS_ACCESSOR_PROPERTY)) {
return oldProperty;
}
newProperty = new UserAccessorProperty(uc.getKey(), propertyFlags, slot);
@ -2022,7 +2021,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
} else if (!find.isSelf()) {
assert mh.type().returnType().equals(returnType) :
"return type mismatch for getter " + mh.type().returnType() + " != " + returnType;
if (!(property instanceof UserAccessorProperty)) {
if (!property.isAccessorProperty()) {
// Add a filter that replaces the self object with the prototype owning the property.
mh = addProtoFilter(mh, find.getProtoChainLength());
}
@ -2185,7 +2184,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
FindProperty find = findProperty(name, true, this);
// If it's not a scope search, then we don't want any inherited properties except those with user defined accessors.
if (find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
if (find != null && find.isInherited() && !find.getProperty().isAccessorProperty()) {
// We should still check if inherited data property is not writable
if (isExtensible() && !find.getProperty().isWritable()) {
return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
@ -2201,9 +2200,13 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
if (NashornCallSiteDescriptor.isScope(desc) && find.getProperty().isLexicalBinding()) {
throw typeError("assign.constant", name); // Overwriting ES6 const should throw also in non-strict mode.
}
// Existing, non-writable property
// Existing, non-writable data property
return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
}
if (!find.getProperty().hasNativeSetter()) {
// Existing accessor property without setter
return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.has.no.setter", true);
}
} else {
if (!isExtensible()) {
return createEmptySetMethod(desc, explicitInstanceOfCheck, "object.non.extensible", false);
@ -3040,7 +3043,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
invalidateGlobalConstant(key);
if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) {
if (f != null && f.isInherited() && !f.getProperty().isAccessorProperty()) {
final boolean isScope = isScopeFlag(callSiteFlags);
// If the start object of the find is not this object it means the property was found inside a
// 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set'
@ -3061,12 +3064,14 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
}
if (f != null) {
if (!f.getProperty().isWritable()) {
if (!f.getProperty().isWritable() || !f.getProperty().hasNativeSetter()) {
if (isScopeFlag(callSiteFlags) && f.getProperty().isLexicalBinding()) {
throw typeError("assign.constant", key.toString()); // Overwriting ES6 const should throw also in non-strict mode.
}
if (isStrictFlag(callSiteFlags)) {
throw typeError("property.not.writable", key.toString(), ScriptRuntime.safeToString(this));
throw typeError(
f.getProperty().isAccessorProperty() ? "property.has.no.setter" : "property.not.writable",
key.toString(), ScriptRuntime.safeToString(this));
}
return;
}

View File

@ -54,7 +54,7 @@ final class SetMethodCreator {
/**
* Creates a new property setter method creator.
* @param sobj the object for which we're creating the property setter
* @param find a result of a {@link ScriptObject#findProperty(String, boolean)} on the object for the property we
* @param find a result of a {@link ScriptObject#findProperty(Object, boolean)} on the object for the property we
* want to create a setter for. Can be null if the property does not yet exist on the object.
* @param desc the descriptor of the call site that triggered the property setter lookup
* @param request the link request
@ -66,7 +66,6 @@ final class SetMethodCreator {
this.desc = desc;
this.type = desc.getMethodType().parameterType(1);
this.request = request;
}
private String getName() {
@ -172,7 +171,7 @@ final class SetMethodCreator {
assert property != null;
final MethodHandle boundHandle;
if (!(property instanceof UserAccessorProperty) && find.isInherited()) {
if (!property.isAccessorProperty() && find.isInherited()) {
boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength());
} else {
boundHandle = methodHandle;

View File

@ -119,7 +119,8 @@ public final class UserAccessorProperty extends SpillProperty {
* @param slot spill slot
*/
UserAccessorProperty(final Object key, final int flags, final int slot) {
super(key, flags, slot);
// Always set accessor property flag for this class
super(key, flags | IS_ACCESSOR_PROPERTY, slot);
}
private UserAccessorProperty(final UserAccessorProperty property) {

View File

@ -42,7 +42,6 @@ import jdk.nashorn.internal.runtime.GlobalConstants;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UserAccessorProperty;
/**
* Implements lookup of methods to link for dynamic operations on JavaScript primitive values (booleans, strings, and
@ -118,7 +117,7 @@ public final class PrimitiveLookup {
return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
}
if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
if (find.isInherited() && !(find.getProperty().isAccessorProperty())) {
// If property is found in the prototype object bind the method handle directly to
// the proto filter instead of going through wrapper instantiation below.
final ScriptObject proto = wrappedReceiver.getProto();
@ -180,9 +179,13 @@ public final class PrimitiveLookup {
// See ES5.1 8.7.2 PutValue (V, W)
final String name = JSType.toString(key);
final FindProperty find = wrappedSelf.findProperty(name, true);
if (find == null || !(find.getProperty() instanceof UserAccessorProperty) || !find.getProperty().isWritable()) {
if (find == null || !find.getProperty().isAccessorProperty() || !find.getProperty().hasNativeSetter()) {
if (strict) {
throw typeError("property.not.writable", name, ScriptRuntime.safeToString(self));
if (find == null || !find.getProperty().isAccessorProperty()) {
throw typeError("property.not.writable", name, ScriptRuntime.safeToString(self));
} else {
throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
}
}
return;
}

View File

@ -82,6 +82,14 @@ type.error.not.a.string={0} is not a String
type.error.not.a.function={0} is not a function
type.error.not.a.function.value={0}, which has value {1}, is not a function
type.error.not.a.constructor={0} is not a constructor function
type.error.not.a.map={0} is not a Map object
type.error.not.a.set={0} is not a Set object
type.error.not.a.weak.map={0} is not a WeakMap object
type.error.not.a.weak.set={0} is not a WeakSet object
type.error.not.a.map.iterator={0} is not a Map iterator
type.error.not.a.set.iterator={0} is not a Set iterator
type.error.not.a.array.iterator={0} is not an Array iterator
type.error.not.a.string.iterator={0} is not a String iterator
type.error.not.a.file={0} is not a File
type.error.not.a.numeric.array={0} is not a numeric array
type.error.not.a.bytebuffer={0} is not a java.nio.ByteBuffer
@ -122,6 +130,7 @@ type.error.array.reduceright.invalid.init=invalid initialValue for Array.prototy
type.error.assign.constant=Assignment to constant "{0}"
type.error.cannot.get.default.string=Cannot get default string value
type.error.cannot.get.default.number=Cannot get default number value
type.error.cannot.get.iterator=Cannot get iterator from {1}
type.error.cant.apply.with.to.null=Cannot apply "with" to null
type.error.cant.apply.with.to.undefined=Cannot apply "with" to undefined
type.error.cant.apply.with.to.non.scriptobject=Cannot apply "with" to non script object. Consider using "with(Object.bindProperties('{'}, nonScriptObject))".
@ -154,7 +163,7 @@ type.error.unsupported.java.to.type=Unsupported Java.to target type {0}.
type.error.java.array.conversion.failed=Java.to conversion to array type {0} failed
type.error.constructor.requires.new=Constructor {0} requires "new".
type.error.new.on.nonpublic.javatype=new cannot be used with non-public java type {0}.
type.error.invalid.weak.key=invalid value {0} used as weak key.
type.error.invalid.weak.key=primitive value {0} used as weak key.
type.error.symbol.to.string=Can not convert Symbol value to string.
type.error.symbol.to.number=Can not convert Symbol value to number.
type.error.not.a.symbol={0} is not a symbol.

View File

@ -28,13 +28,21 @@
* @run
*/
if (typeof Symbol !== 'undefined' || 'Symbol' in this) {
Assert.fail('Symbol is defined in global scope');
function checkUndefined(name, object) {
if (typeof object[name] !== 'undefined' || name in object) {
Assert.fail(name + ' is defined in ' + object);
}
}
if (typeof Object.getOwnPropertySymbols !== 'undefined' || 'getOwnPropertySymbols' in Object) {
Assert.fail('getOwnPropertySymbols is defined in global Object');
}
checkUndefined('Symbol', this);
checkUndefined('Map', this);
checkUndefined('Set', this);
checkUndefined('WeakMap', this);
checkUndefined('WeakSet', this);
checkUndefined('getOwnPropertySymbols', Object);
checkUndefined('entries', Array.prototype);
checkUndefined('values', Array.prototype);
checkUndefined('keys', Array.prototype);
function expectError(src, msg, error) {
try {

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8147558: Add support for ES6 collections
*
* @test
* @run
* @option --language=es6
*/
function testIterator(iter, expectedValues) {
let next;
for (var i = 0; i < expectedValues.length; i++) {
next = iter.next();
Assert.assertTrue(next.done === false);
if (Array.isArray(expectedValues[i])) {
Assert.assertTrue(Array.isArray(next.value));
Assert.assertTrue(next.value.length === expectedValues[i].length);
Assert.assertTrue(next.value.every(function(v, j) {
return v === expectedValues[i][j];
}));
} else {
Assert.assertTrue(next.value === expectedValues[i]);
}
}
next = iter.next();
Assert.assertTrue(next.done === true);
Assert.assertTrue(next.value === undefined);
}
const str = "abcdefg";
const array = ["a", "b", "c", "d", "e", "f", "g"];
const arrayKeys = [0, 1, 2, 3, 4, 5, 6];
const setEntries = [["a", "a"], ["b", "b"], ["c", "c"], ["d", "d"], ["e", "e"], ["f", "f"], ["g", "g"]];
const mapEntries = [["a", "A"], ["b", "B"], ["c", "C"], ["d", "D"], ["e", "E"], ["f", "F"], ["g", "G"]];
const mapValues = ["A", "B", "C", "D", "E", "F", "G"];
const arrayEntries = [[0, "a"], [1, "b"], [2, "c"], [3, "d"], [4, "e"], [5, "f"], [6, "g"]];
// Set iterator tests
const set = new Set(str);
testIterator(set[Symbol.iterator](), str);
testIterator(set.values(), str);
testIterator(set.keys(), str);
testIterator(set.entries(), setEntries);
// Map iterator tests
const map = new Map(mapEntries);
testIterator(map[Symbol.iterator](), mapEntries);
testIterator(map.values(), mapValues);
testIterator(map.keys(), array);
testIterator(map.entries(), mapEntries);
// String iterator tests
testIterator(str[Symbol.iterator](), str);
// Array iterator tests
testIterator(array[Symbol.iterator](), array);
testIterator(array.values(), array);
testIterator(array.keys(), arrayKeys);
testIterator(array.entries(), arrayEntries);

View File

@ -0,0 +1,195 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8147558: Add support for ES6 collections
*
* @test
* @run
* @option --language=es6
*/
function assertThrows(src, error) {
try {
eval(src);
Assert.fail("No error, expected " + error);
} catch (e) {
if (!(e instanceof error)) {
Assert.fail("Wrong error, expected " + error + " but got " + e);
}
}
}
// Map constructor and prototype
var desc = Object.getOwnPropertyDescriptor(this, "Map");
Assert.assertEquals(desc.writable, true);
Assert.assertEquals(desc.configurable, true);
Assert.assertEquals(desc.enumerable, false);
Assert.assertTrue(Object.getPrototypeOf(new Map()) === Map.prototype);
Assert.assertTrue(Object.getPrototypeOf(Map.prototype) === Object.prototype);
Assert.assertTrue(new Map().size === 0);
Assert.assertTrue(Object.getPrototypeOf(new Map([["a", 1], ["b", 2]])) === Map.prototype);
Assert.assertTrue(new Map([["a", 1], ["b", 2]]).size === 2);
Assert.assertTrue(Object.getPrototypeOf(new Map("")) === Map.prototype);
Assert.assertTrue(new Map("").size === 0);
Assert.assertTrue(Object.getPrototypeOf(new Map([])) === Map.prototype);
Assert.assertTrue(new Map([]).size === 0);
assertThrows("Map()", TypeError);
assertThrows("new Map(3)", TypeError);
assertThrows("new Map('abc')", TypeError);
assertThrows("new Map({})", TypeError);
assertThrows("new Map([1, 2, 3])", TypeError);
assertThrows("Map.prototype.set.apply({}, ['', ''])", TypeError);
assertThrows("Map.prototype.get.apply([], [''])", TypeError);
assertThrows("Map.prototype.has.apply(3, [''])", TypeError);
assertThrows("Map.prototype.clear.apply('', [])", TypeError);
// Map methods
var m = new Map([["a", 1], ["b", 2]]);
Assert.assertTrue(m.size, 2);
Assert.assertTrue(m.get("a") === 1);
Assert.assertTrue(m.get("b") === 2);
Assert.assertTrue(m.get("c") === undefined);
Assert.assertTrue(m.has("a") === true);
Assert.assertTrue(m.has("b") === true);
Assert.assertTrue(m.has("c") === false);
m.clear();
Assert.assertTrue(m.size === 0);
Assert.assertTrue(m.get("a") === undefined);
Assert.assertTrue(m.get("b") === undefined);
Assert.assertTrue(m.get("c") === undefined);
Assert.assertTrue(m.has("a") === false);
Assert.assertTrue(m.has("b") === false);
Assert.assertTrue(m.has("c") === false);
var a = "a", x = "x"; // for ConsString keys
Assert.assertTrue(m.set("ab", false) === m);
Assert.assertTrue(m.set(x + "y", m) === m);
Assert.assertTrue(m.get(a + "b") === false);
Assert.assertTrue(m.get("xy") === m);
Assert.assertTrue(m.has(a + "b") === true);
Assert.assertTrue(m.has("xy") === true);
// Special keys
m = new Map();
Assert.assertTrue(m.set(NaN, NaN) === m); // NaN should work as key
Assert.assertTrue(m.size === 1);
Assert.assertTrue(isNaN(m.get(NaN)));
Assert.assertTrue(isNaN(m.keys().next().value));
Assert.assertTrue(isNaN(m.values().next().value));
Assert.assertTrue(m.has(NaN) === true);
Assert.assertTrue(m.delete(NaN));
Assert.assertTrue(m.size === 0);
Assert.assertTrue(m.get(NaN) === undefined);
Assert.assertTrue(m.keys().next().done);
Assert.assertTrue(m.values().next().done);
Assert.assertTrue(m.has(NaN) === false);
m.clear();
m.set(-0, -0); // -0 key should be converted to +0
Assert.assertTrue(m.size === 1);
Assert.assertTrue(m.get(-0) === 0);
Assert.assertTrue(1 / m.keys().next().value === Infinity);
Assert.assertTrue(1 / m.values().next().value === -Infinity);
Assert.assertTrue(m.has(-0) === true);
Assert.assertTrue(m.has(0) === true);
Assert.assertTrue(m.delete(-0));
Assert.assertTrue(m.size === 0);
Assert.assertTrue(m.get(-0) === undefined);
Assert.assertTrue(m.get(0) === undefined);
Assert.assertTrue(m.has(-0) === false);
Assert.assertTrue(m.has(0) === false);
Assert.assertFalse(m.delete("foo"));
Assert.assertFalse(m.delete(0));
Assert.assertFalse(m.delete(NaN));
// foreach
m = new Map([[1, "one"], [2, "two"], [3, "three"]]);
m.forEach(function(value, key, map) {
Assert.assertTrue(this === m);
Assert.assertTrue(map === m);
}, m);
function assertEqualArrays(a, b) {
Assert.assertTrue(Array.isArray(a));
Assert.assertTrue(Array.isArray(b));
Assert.assertTrue(a.length === b.length);
Assert.assertTrue(a.every(function(v, j) {
return v === b[j];
}));
}
let array = [];
m = new Map([[1, "one"], [2, "two"], [3, "three"]]);
m.forEach(function(value, key, map) {
array.push(value);
});
assertEqualArrays(array, ["one", "two", "three"]);
array = [];
m = new Map([[1, "one"], [2, "two"], [3, "three"]]);
m.forEach(function(value, key, map) {
array.push(value);
if (key == 3) {
map.clear();
map.set(4, "four");
}
});
assertEqualArrays(array, ["one", "two", "three", "four"]);
array = [];
m = new Map([[1, "one"], [2, "two"], [3, "three"]]);
m.forEach(function(value, key, map) {
array.push(value);
if (key == 1) {
map.delete(1);
}
if (key == 2) {
map.delete(3);
}
});
assertEqualArrays(array, ["one", "two"]);
array = [];
m = new Map([[1, "one"], [2, "two"], [3, "three"]]);
m.forEach(function(value, key, map) {
array.push(value);
if (array.length < 4) {
map.delete(key);
map.set(key, key + 3)
}
});
assertEqualArrays(array, ["one", "two", "three", 4, 5, 6]);

View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8147558: Add support for ES6 collections
*
* @test
* @run
* @option --language=es6
*/
function assertThrows(src, error) {
try {
eval(src);
Assert.fail("No error, expected " + error);
} catch (e) {
if (!(e instanceof error)) {
Assert.fail("Wrong error, expected " + error + " but got " + e);
}
}
}
// Set constructor and prototype
var desc = Object.getOwnPropertyDescriptor(this, "Set");
Assert.assertEquals(desc.writable, true);
Assert.assertEquals(desc.configurable, true);
Assert.assertEquals(desc.enumerable, false);
Assert.assertTrue(Object.getPrototypeOf(new Set()) === Set.prototype);
Assert.assertTrue(Object.getPrototypeOf(Set.prototype) === Object.prototype);
Assert.assertTrue(new Set().size === 0);
Assert.assertTrue(Object.getPrototypeOf(new Set(["a", 3, false])) === Set.prototype);
Assert.assertTrue(new Set(["a", 3, false]).size === 3);
Assert.assertTrue(new Set("abc").size === 3);
Assert.assertTrue(new Set("").size === 0);
Assert.assertTrue(new Set([]).size === 0);
assertThrows("Set()", TypeError);
assertThrows("new Set(3)", TypeError);
assertThrows("new Set({})", TypeError);
assertThrows("Set.prototype.add.apply({}, [''])", TypeError);
assertThrows("Set.prototype.has.apply(3, [''])", TypeError);
assertThrows("Set.prototype.delete.apply('', [3])", TypeError);
// Set methods
var s = new Set(["a", 3, false]);
Assert.assertTrue(s.size, 2);
Assert.assertTrue(s.has("a") === true);
Assert.assertTrue(s.has(3) === true);
Assert.assertTrue(s.has(false) === true);
Assert.assertTrue(s.clear() === undefined);
Assert.assertTrue(s.size === 0);
Assert.assertTrue(s.has("a") === false);
Assert.assertTrue(s.has(3) === false);
Assert.assertTrue(s.has(false) === false);
var a = "a", x = "x"; // for ConsString keys
Assert.assertTrue(s.add("ab", false) === s);
Assert.assertTrue(s.add(x + "y", s) === s);
Assert.assertTrue(s.has(a + "b") === true);
Assert.assertTrue(s.has("xy") === true);
// Special keys
s.clear()
Assert.assertTrue(s.add(NaN) === s); // NaN should work as key
Assert.assertTrue(s.size === 1);
Assert.assertTrue(isNaN(s.keys().next().value));
Assert.assertTrue(isNaN(s.values().next().value));
Assert.assertTrue(s.has(NaN) === true);
Assert.assertTrue(s.delete(NaN) === true);
Assert.assertTrue(s.size === 0);
Assert.assertTrue(s.keys().next().done);
Assert.assertTrue(s.values().next().done);
Assert.assertTrue(s.has(NaN) === false);
s.clear()
s.add(-0); // -0 key should be converted to +0
Assert.assertTrue(s.size === 1);
Assert.assertTrue(1 / s.keys().next().value === Infinity);
Assert.assertTrue(1 / s.values().next().value === Infinity);
Assert.assertTrue(s.has(-0) === true);
Assert.assertTrue(s.has(0) === true);
Assert.assertTrue(s.delete(-0) === true);
Assert.assertTrue(s.size === 0);
Assert.assertTrue(s.has(-0) === false);
Assert.assertTrue(s.has(0) === false);
// foreach
s = new Set([1, 2, 3]);
s.forEach(function(value, key, set) {
Assert.assertTrue(this === s);
Assert.assertTrue(set === s);
}, s);
function assertEqualArrays(a, b) {
Assert.assertTrue(Array.isArray(a));
Assert.assertTrue(Array.isArray(b));
Assert.assertTrue(a.length === b.length);
Assert.assertTrue(a.every(function(v, j) {
return v === b[j];
}));
}
let array = [];
s = new Set([1, 2, 3]);
s.forEach(function(value, key, set) {
array.push(value);
});
assertEqualArrays(array, [1, 2, 3]);
array = [];
s = new Set([1, 2, 3]);
s.forEach(function(value, key, set) {
array.push(value);
if (key == 3) {
set.clear();
set.add("four");
}
});
assertEqualArrays(array, [1, 2, 3, "four"]);
array = [];
s = new Set([1, 2, 3]);
s.forEach(function(value, key, set) {
array.push(value);
if (key == 1) {
set.delete(1);
}
if (key == 2) {
set.delete(3);
}
});
assertEqualArrays(array, [1, 2]);
array = [];
s = new Set([1, 2, 3]);
s.forEach(function(value, key, set) {
array.push(value);
if (key < 4) {
set.delete(key);
set.add(key + 3)
}
});
assertEqualArrays(array, [1, 2, 3, 4, 5, 6]);

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8147558: Add support for ES6 collections
*
* @test
* @run
* @option --language=es6
*/
function assertThrows(src, error) {
try {
eval(src);
Assert.fail("No error, expected " + error);
} catch (e) {
if (!(e instanceof error)) {
Assert.fail("Wrong error, expected " + error + " but got " + e);
}
}
}
// WeakMap constructor and prototype
var desc = Object.getOwnPropertyDescriptor(this, "WeakMap");
Assert.assertEquals(desc.writable, true);
Assert.assertEquals(desc.configurable, true);
Assert.assertEquals(desc.enumerable, false);
Assert.assertTrue(Object.getPrototypeOf(new WeakMap()) === WeakMap.prototype);
Assert.assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype);
Assert.assertTrue(Object.getPrototypeOf(new WeakMap("")) === WeakMap.prototype);
Assert.assertTrue(Object.getPrototypeOf(new WeakMap([])) === WeakMap.prototype);
assertThrows("WeakMap()", TypeError);
assertThrows("new WeakMap(3)", TypeError);
assertThrows("new WeakMap({})", TypeError);
assertThrows("new WeakMap([['a', {}]])", TypeError);
assertThrows("new WeakMap([[3, {}]])", TypeError);
assertThrows("new WeakMap([[true, {}]])", TypeError);
assertThrows("new WeakMap([[Symbol.iterator, {}]])", TypeError);
assertThrows("WeakMap.prototype.set.apply({}, [{}, {}])", TypeError);
assertThrows("WeakMap.prototype.has.apply(3, [{}])", TypeError);
assertThrows("WeakMap.prototype.delete.apply('', [3])", TypeError);
// WeakMap methods
let values = [[{}, 1], [{}, 2], [{}, 3]];
let m = new WeakMap(values);
for (let i = 0; i < values.length; i++) {
Assert.assertTrue(m.has(values[i][0]) === true);
Assert.assertTrue(m.get(values[i][0]) === values[i][1]);
Assert.assertTrue(m.delete(values[i][0]) === true);
Assert.assertTrue(m.has(values[i][0]) === false);
}
values.forEach(function(v) {
Assert.assertTrue(m.set(v[0], v[1]) === m);
});
for (let i = 0; i < values.length; i++) {
Assert.assertTrue(m.has(values[i][0]) === true);
Assert.assertTrue(m.get(values[i][0]) === values[i][1]);
Assert.assertTrue(m.delete(values[i][0]) === true);
Assert.assertTrue(m.has(values[i][0]) === false);
}
// Primitive keys
assertThrows("m.set('a', {})", TypeError);
assertThrows("m.set(3, {})", TypeError);
assertThrows("m.set(false, {})", TypeError);
assertThrows("m.set(Symbol.iterator, {})", TypeError);
Assert.assertTrue(m.has('a') === false);
Assert.assertTrue(m.delete(3) === false);
Assert.assertTrue(m.get(Symbol.iterator) === undefined);
Assert.assertTrue(m.get(true) === undefined);

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8147558: Add support for ES6 collections
*
* @test
* @run
* @option --language=es6
*/
function assertThrows(src, error) {
try {
eval(src);
Assert.fail("No error, expected " + error);
} catch (e) {
if (!(e instanceof error)) {
Assert.fail("Wrong error, expected " + error + " but got " + e);
}
}
}
// WeakSet constructor and prototype
var desc = Object.getOwnPropertyDescriptor(this, "WeakSet");
Assert.assertEquals(desc.writable, true);
Assert.assertEquals(desc.configurable, true);
Assert.assertEquals(desc.enumerable, false);
Assert.assertTrue(Object.getPrototypeOf(new WeakSet()) === WeakSet.prototype);
Assert.assertTrue(Object.getPrototypeOf(WeakSet.prototype) === Object.prototype);
Assert.assertTrue(Object.getPrototypeOf(new WeakSet("")) === WeakSet.prototype);
Assert.assertTrue(Object.getPrototypeOf(new WeakSet([])) === WeakSet.prototype);
assertThrows("WeakSet()", TypeError);
assertThrows("new WeakSet(3)", TypeError);
assertThrows("new WeakSet({})", TypeError);
assertThrows("new WeakSet(['a'])", TypeError);
assertThrows("new WeakSet([3])", TypeError);
assertThrows("new WeakSet([true])", TypeError);
assertThrows("new WeakSet([Symbol.iterator])", TypeError);
assertThrows("WeakSet.prototype.add.apply({}, [''])", TypeError);
assertThrows("WeakSet.prototype.has.apply(3, [''])", TypeError);
assertThrows("WeakSet.prototype.delete.apply('', [3])", TypeError);
// WeakSet methods
let values = [{}, {}, {}];
let s = new WeakSet(values);
for (let i = 0; i < values.length; i++) {
Assert.assertTrue(s.has(values[i]) === true);
Assert.assertTrue(s.delete(values[i]) === true);
Assert.assertTrue(s.has(values[i]) === false);
}
values.forEach(function(v) {
Assert.assertTrue(s.add(v) === s);
});
for (let i = 0; i < values.length; i++) {
Assert.assertTrue(s.has(values[i]) === true);
Assert.assertTrue(s.delete(values[i]) === true);
Assert.assertTrue(s.has(values[i]) === false);
}
// Primitive keys
assertThrows("s.add('a')", TypeError);
assertThrows("s.add(3)", TypeError);
assertThrows("s.add(false)", TypeError);
assertThrows("s.add(Symbol.iterator)", TypeError);
Assert.assertTrue(s.has('a') === false);
Assert.assertTrue(s.delete(3) === false);
Assert.assertTrue(s.has(Symbol.iterator) === false);
Assert.assertTrue(s.delete(true) === false);