Merge
This commit is contained in:
commit
ab1b569185
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 = "@@";
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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<>();
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
@ -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.
|
||||
*
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 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
|
||||
@ -29,6 +29,7 @@ import static jdk.nashorn.internal.runtime.JSType.isString;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Map;
|
||||
import javax.script.Bindings;
|
||||
import jdk.dynalink.CallSiteDescriptor;
|
||||
@ -135,12 +136,15 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
|
||||
}
|
||||
|
||||
private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) {
|
||||
// TODO: if call site is already a vararg, don't do asCollector
|
||||
MethodHandle mh = JSOBJECT_CALL;
|
||||
if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
|
||||
mh = MH.insertArguments(JSOBJECT_CALL_TO_APPLY, 0, JSOBJECT_CALL);
|
||||
}
|
||||
return new GuardedInvocation(MH.asCollector(mh, Object[].class, desc.getMethodType().parameterCount() - 2), IS_JSOBJECT_GUARD);
|
||||
final MethodType type = desc.getMethodType();
|
||||
mh = type.parameterType(type.parameterCount() - 1) == Object[].class ?
|
||||
mh :
|
||||
MH.asCollector(mh, Object[].class, type.parameterCount() - 2);
|
||||
return new GuardedInvocation(mh, IS_JSOBJECT_GUARD);
|
||||
}
|
||||
|
||||
private static GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
87
nashorn/test/script/basic/es6/iterator.js
Normal file
87
nashorn/test/script/basic/es6/iterator.js
Normal 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);
|
||||
|
195
nashorn/test/script/basic/es6/map.js
Normal file
195
nashorn/test/script/basic/es6/map.js
Normal 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]);
|
||||
|
||||
|
||||
|
||||
|
173
nashorn/test/script/basic/es6/set.js
Normal file
173
nashorn/test/script/basic/es6/set.js
Normal 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]);
|
||||
|
||||
|
100
nashorn/test/script/basic/es6/weakmap.js
Normal file
100
nashorn/test/script/basic/es6/weakmap.js
Normal 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);
|
100
nashorn/test/script/basic/es6/weakset.js
Normal file
100
nashorn/test/script/basic/es6/weakset.js
Normal 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);
|
||||
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.runtime.test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import jdk.nashorn.api.scripting.AbstractJSObject;
|
||||
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* @bug 8148140
|
||||
* @summary arguments are handled differently in apply for JS functions and AbstractJSObjects
|
||||
*/
|
||||
public class JDK_8148140_Test {
|
||||
|
||||
ScriptEngine engine;
|
||||
|
||||
static final String RESULT = "[1, 2, 3]";
|
||||
|
||||
@BeforeClass
|
||||
public void setupTest() {
|
||||
engine = new ScriptEngineManager().getEngineByName("js");
|
||||
engine.put("f", new AbstractJSObject() {
|
||||
@Override
|
||||
public boolean isFunction() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public Object call(Object thiz, Object... args) {
|
||||
return Arrays.deepToString(args);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCallF() throws ScriptException {
|
||||
assertEquals(RESULT, engine.eval("f(1,2,3)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyF() throws ScriptException {
|
||||
assertEquals(RESULT, engine.eval("Function.prototype.apply.call(f, null, [1,2,3])"));
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.runtime.test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
Loading…
Reference in New Issue
Block a user