diff --git a/src/org/mozilla/javascript/AbstractEcmaObjectOperations.java b/src/org/mozilla/javascript/AbstractEcmaObjectOperations.java index b8529c2caf..0e787d9f4c 100644 --- a/src/org/mozilla/javascript/AbstractEcmaObjectOperations.java +++ b/src/org/mozilla/javascript/AbstractEcmaObjectOperations.java @@ -1,5 +1,11 @@ package org.mozilla.javascript; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; + /** * Abstract Object Operations as defined by EcmaScript * @@ -124,8 +130,9 @@ static boolean setIntegrityLevel(Context cx, Object o, INTEGRITY_LEVEL level) { */ ScriptableObject obj = ScriptableObject.ensureScriptableObject(o); - // TODO check .preventExtensions() return value once implemented and act accordingly to spec - obj.preventExtensions(); + if (!obj.preventExtensions()) { + return false; + } for (Object key : obj.getIds(true, true)) { ScriptableObject desc = obj.getOwnPropertyDescriptor(cx, key); @@ -232,4 +239,161 @@ static void put(Context cx, Scriptable o, int p, Object v, boolean isThrow) { base.put(p, o, v); } } + + /** + * CreateListFromArrayLike ( obj [ , elementTypes ] ) + * + *

https://262.ecma-international.org/12.0/#sec-createlistfromarraylike + */ + static List createListFromArrayLike( + Context cx, Scriptable o, Predicate elementTypesPredicate, String msg) { + ScriptableObject obj = ScriptableObject.ensureScriptableObject(o); + if (obj instanceof NativeArray) { + Object[] arr = ((NativeArray) obj).toArray(); + for (Object next : arr) { + if (!elementTypesPredicate.test(next)) { + throw ScriptRuntime.typeError(msg); + } + } + return Arrays.asList(arr); + } + + long len = lengthOfArrayLike(cx, obj); + List list = new ArrayList<>(); + long index = 0; + while (index < len) { + // String indexName = ScriptRuntime.toString(index); + Object next = ScriptableObject.getProperty(obj, (int) index); + if (!elementTypesPredicate.test(next)) { + throw ScriptRuntime.typeError(msg); + } + list.add(next); + index++; + } + return list; + } + + /** + * LengthOfArrayLike ( obj ) + * + *

https://262.ecma-international.org/12.0/#sec-lengthofarraylike + */ + static long lengthOfArrayLike(Context cx, Scriptable o) { + Object value = ScriptableObject.getProperty(o, "length"); + long len = ScriptRuntime.toLength(new Object[] {value}, 0); + return len; + } + + /** + * IsCompatiblePropertyDescriptor ( Extensible, Desc, Current ) + * + *

https://262.ecma-international.org/12.0/#sec-iscompatiblepropertydescriptor + */ + static boolean isCompatiblePropertyDescriptor( + boolean extensible, ScriptableObject desc, ScriptableObject current) { + return validateAndApplyPropertyDescriptor( + Undefined.SCRIPTABLE_UNDEFINED, + Undefined.SCRIPTABLE_UNDEFINED, + extensible, + desc, + current); + } + + /** + * ValidateAndApplyPropertyDescriptor ( O, P, extensible, Desc, current ) + * + *

https://262.ecma-international.org/12.0/#sec-validateandapplypropertydescriptor + */ + static boolean validateAndApplyPropertyDescriptor( + Scriptable o, + Scriptable p, + boolean extensible, + ScriptableObject desc, + ScriptableObject current) { + if (Undefined.isUndefined(current)) { + if (!extensible) { + return false; + } + + if (ScriptableObject.isGenericDescriptor(desc) + || ScriptableObject.isDataDescriptor(desc)) { + /* + i. i. If O is not undefined, create an own data property named P of object O whose [[Value]], [[Writable]], [[Enumerable]], and [[Configurable]] attribute values are described by Desc. + If the value of an attribute field of Desc is absent, the attribute of the newly created property is set to its default value. + */ + } else { + /* + ii. ii. If O is not undefined, create an own accessor property named P of object O whose [[Get]], [[Set]], [[Enumerable]], and [[Configurable]] attribute values are described by Desc. If the value of an attribute field of Desc is absent, the attribute of the newly created property is set to its default value. + */ + } + return true; + } + + if (desc.getIds().length == 0) { + return true; + } + + if (Boolean.FALSE.equals(current.get("configurable"))) { + if (Boolean.TRUE.equals(ScriptableObject.hasProperty(desc, "configurable")) + && Boolean.TRUE.equals(desc.get("configurable"))) { + return false; + } + + if (Boolean.TRUE.equals(ScriptableObject.hasProperty(desc, "enumerable")) + && !Objects.equals(desc.get("enumerable"), current.get("enumerable"))) { + return false; + } + } + + // if (!ScriptableObject.isGenericDescriptor(desc)) { + if (ScriptableObject.isGenericDescriptor(desc)) { + return true; + } else if (!Objects.equals( + ScriptableObject.isGenericDescriptor(current), + ScriptableObject.isGenericDescriptor(desc))) { + if (Boolean.FALSE.equals(current.get("configurable"))) { + return false; + } + if (ScriptableObject.isDataDescriptor(current)) { + if (Boolean.FALSE.equals(current.get("configurable"))) { + // i. i. If O is not undefined, convert the property named P of object O from a + // data property to an accessor property. Preserve the existing values of the + // converted property's [[Configurable]] and [[Enumerable]] attributes and set + // the rest of the property's attributes to their default values. + } else { + // i. i. If O is not undefined, convert the property named P of object O from an + // accessor property to a data property. Preserve the existing values of the + // converted property's [[Configurable]] and [[Enumerable]] attributes and set + // the rest of the property's attributes to their default values. + } + } + } else if (ScriptableObject.isDataDescriptor(current) + && ScriptableObject.isDataDescriptor(desc)) { + if (Boolean.FALSE.equals(current.get("configurable")) + && Boolean.FALSE.equals(current.get("writable"))) { + if (Boolean.TRUE.equals(ScriptableObject.hasProperty(desc, "writable")) + && Boolean.TRUE.equals(desc.get("writable"))) { + return false; + } + if (Boolean.TRUE.equals(ScriptableObject.hasProperty(desc, "value")) + && !Objects.equals(desc.get("value"), current.get("value"))) { + return false; + } + return true; + } + } else { + if (Boolean.FALSE.equals(current.get("configurable"))) { + if (Boolean.TRUE.equals(ScriptableObject.hasProperty(desc, "set")) + && !Objects.equals(desc.get("set"), current.get("set"))) { + return false; + } + if (Boolean.TRUE.equals(ScriptableObject.hasProperty(desc, "get")) + && !Objects.equals(desc.get("get"), current.get("get"))) { + return false; + } + return true; + } + } + return true; + } } diff --git a/src/org/mozilla/javascript/Arguments.java b/src/org/mozilla/javascript/Arguments.java index b0300b22e6..e1e79e0dba 100644 --- a/src/org/mozilla/javascript/Arguments.java +++ b/src/org/mozilla/javascript/Arguments.java @@ -350,33 +350,34 @@ protected ScriptableObject getOwnPropertyDescriptor(Context cx, Object id) { } @Override - protected void defineOwnProperty( + protected boolean defineOwnProperty( Context cx, Object id, ScriptableObject desc, boolean checkValid) { super.defineOwnProperty(cx, id, desc, checkValid); if (ScriptRuntime.isSymbol(id)) { - return; + return true; } double d = ScriptRuntime.toNumber(id); int index = (int) d; - if (d != index) return; + if (d != index) return true; Object value = arg(index); - if (value == NOT_FOUND) return; + if (value == NOT_FOUND) return true; if (isAccessorDescriptor(desc)) { removeArg(index); - return; + return true; } Object newValue = getProperty(desc, "value"); - if (newValue == NOT_FOUND) return; + if (newValue == NOT_FOUND) return true; replaceArg(index, newValue); if (isFalse(getProperty(desc, "writable"))) { removeArg(index); } + return true; } // ECMAScript2015 diff --git a/src/org/mozilla/javascript/IdScriptableObject.java b/src/org/mozilla/javascript/IdScriptableObject.java index 650dd7f6ba..ad05ed75ec 100644 --- a/src/org/mozilla/javascript/IdScriptableObject.java +++ b/src/org/mozilla/javascript/IdScriptableObject.java @@ -852,7 +852,7 @@ private IdFunctionObject newIdFunction( } @Override - protected void defineOwnProperty( + protected boolean defineOwnProperty( Context cx, Object key, ScriptableObject desc, boolean checkValid) { if (key instanceof String) { String name = (String) key; @@ -875,7 +875,7 @@ protected void defineOwnProperty( } attr = applyDescriptorToAttributeBitset(attr, desc); setAttributes(name, attr); - return; + return true; } } if (prototypeValues != null) { @@ -905,12 +905,12 @@ protected void defineOwnProperty( super.delete(name); } - return; + return true; } } } } - super.defineOwnProperty(cx, key, desc, checkValid); + return super.defineOwnProperty(cx, key, desc, checkValid); } @Override diff --git a/src/org/mozilla/javascript/Interpreter.java b/src/org/mozilla/javascript/Interpreter.java index af904e2686..4b2a374516 100644 --- a/src/org/mozilla/javascript/Interpreter.java +++ b/src/org/mozilla/javascript/Interpreter.java @@ -1909,12 +1909,12 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl continue StateLoop; } } - if (!(lhs instanceof Function)) { + if (!(lhs instanceof Constructable)) { if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]); throw ScriptRuntime.notFunctionError(lhs); } - Function fun = (Function) lhs; + Constructable fun = (Constructable) lhs; if (fun instanceof IdFunctionObject) { IdFunctionObject ifun = (IdFunctionObject) fun; diff --git a/src/org/mozilla/javascript/LambdaConstructor.java b/src/org/mozilla/javascript/LambdaConstructor.java index 4c9ef8f4f4..910a42faed 100644 --- a/src/org/mozilla/javascript/LambdaConstructor.java +++ b/src/org/mozilla/javascript/LambdaConstructor.java @@ -61,6 +61,10 @@ public LambdaConstructor( this.flags = flags; } + protected Constructable getTargetConstructor() { + return targetConstructor; + } + @Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if ((flags & CONSTRUCTOR_FUNCTION) == 0) { diff --git a/src/org/mozilla/javascript/NativeArray.java b/src/org/mozilla/javascript/NativeArray.java index 9096dec92e..0213bed11b 100644 --- a/src/org/mozilla/javascript/NativeArray.java +++ b/src/org/mozilla/javascript/NativeArray.java @@ -701,7 +701,7 @@ protected ScriptableObject getOwnPropertyDescriptor(Context cx, Object id) { } @Override - protected void defineOwnProperty( + protected boolean defineOwnProperty( Context cx, Object id, ScriptableObject desc, boolean checkValid) { long index = toArrayIndex(id); if (index >= length) { @@ -732,6 +732,7 @@ protected void defineOwnProperty( lengthAttr = getAttributes("length"); // Update cached attributes value for length property } + return true; } /** See ECMA 15.4.1,2 */ @@ -2249,6 +2250,9 @@ private static boolean js_isArray(Object o) { if (!(o instanceof Scriptable)) { return false; } + if (o instanceof NativeProxy) { + return js_isArray(((NativeProxy) o).getTargetThrowIfRevoked()); + } return "Array".equals(((Scriptable) o).getClassName()); } diff --git a/src/org/mozilla/javascript/NativeObject.java b/src/org/mozilla/javascript/NativeObject.java index 6408e53a55..a896dc99d4 100644 --- a/src/org/mozilla/javascript/NativeObject.java +++ b/src/org/mozilla/javascript/NativeObject.java @@ -564,7 +564,10 @@ public Object execIdCall( } ScriptableObject obj = ensureScriptableObject(arg); - obj.preventExtensions(); + boolean status = obj.preventExtensions(); + if (!status) { + throw ScriptRuntime.typeError("Object.preventExtensions is not allowed"); + } return obj; } case ConstructorId_defineProperties: @@ -622,8 +625,12 @@ public Object execIdCall( return arg; } - AbstractEcmaObjectOperations.setIntegrityLevel( - cx, arg, AbstractEcmaObjectOperations.INTEGRITY_LEVEL.SEALED); + boolean status = + AbstractEcmaObjectOperations.setIntegrityLevel( + cx, arg, AbstractEcmaObjectOperations.INTEGRITY_LEVEL.SEALED); + if (!status) { + throw ScriptRuntime.typeError("Object is not sealable"); + } return arg; } @@ -635,8 +642,12 @@ public Object execIdCall( return arg; } - AbstractEcmaObjectOperations.setIntegrityLevel( - cx, arg, AbstractEcmaObjectOperations.INTEGRITY_LEVEL.FROZEN); + boolean status = + AbstractEcmaObjectOperations.setIntegrityLevel( + cx, arg, AbstractEcmaObjectOperations.INTEGRITY_LEVEL.FROZEN); + if (!status) { + throw ScriptRuntime.typeError("Object is not freezable"); + } return arg; } diff --git a/src/org/mozilla/javascript/NativeProxy.java b/src/org/mozilla/javascript/NativeProxy.java new file mode 100644 index 0000000000..df636cd647 --- /dev/null +++ b/src/org/mozilla/javascript/NativeProxy.java @@ -0,0 +1,1322 @@ +/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.javascript; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; + +/** + * This class implements the Proxy object. + * + * @author Ronald Brill + */ +final class NativeProxy extends ScriptableObject implements Callable, Constructable { + private static final long serialVersionUID = 6676871870513494844L; + + private static final String PROXY_TAG = "Proxy"; + + private static final String TRAP_GET_PROTOTYPE_OF = "getPrototypeOf"; + private static final String TRAP_SET_PROTOTYPE_OF = "setPrototypeOf"; + private static final String TRAP_IS_EXTENSIBLE = "isExtensible"; + private static final String TRAP_PREVENT_EXTENSIONS = "preventExtensions"; + private static final String TRAP_GET_OWN_PROPERTY_DESCRIPTOR = "getOwnPropertyDescriptor"; + private static final String TRAP_DEFINE_PROPERTY = "defineProperty"; + private static final String TRAP_HAS = "has"; + private static final String TRAP_GET = "get"; + private static final String TRAP_SET = "set"; + private static final String TRAP_DELETE_PROPERTY = "deleteProperty"; + private static final String TRAP_OWN_KEYS = "ownKeys"; + private static final String TRAP_APPLY = "apply"; + private static final String TRAP_CONSTRUCT = "construct"; + + private ScriptableObject targetObj; + private Scriptable handlerObj; + private final String typeOf; + + private static final class Revoker implements Callable { + private NativeProxy revocableProxy = null; + + public Revoker(NativeProxy proxy) { + revocableProxy = proxy; + } + + @Override + public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + if (revocableProxy != null) { + revocableProxy.handlerObj = null; + revocableProxy.targetObj = null; + revocableProxy = null; + } + return Undefined.instance; + } + } + + public static void init(Context cx, Scriptable scope, boolean sealed) { + LambdaConstructor constructor = + new LambdaConstructor( + scope, + PROXY_TAG, + 2, + LambdaConstructor.CONSTRUCTOR_NEW, + NativeProxy::constructor) { + + @Override + public Scriptable construct(Context cx, Scriptable scope, Object[] args) { + NativeProxy obj = + (NativeProxy) getTargetConstructor().construct(cx, scope, args); + // avoid getting trapped + obj.setPrototypeDirect(getClassPrototype()); + obj.setParentScope(scope); + return obj; + } + }; + constructor.setPrototypeProperty(null); + + constructor.defineConstructorMethod( + scope, "revocable", 2, NativeProxy::revocable, DONTENUM, DONTENUM | READONLY); + + ScriptableObject.defineProperty(scope, PROXY_TAG, constructor, DONTENUM); + if (sealed) { + constructor.sealObject(); + } + } + + private NativeProxy(ScriptableObject target, Scriptable handler) { + this.targetObj = target; + this.handlerObj = handler; + + if (target == null || !(target instanceof Callable)) { + typeOf = super.getTypeOf(); + } else { + typeOf = target.getTypeOf(); + } + } + + @Override + public String getClassName() { + ScriptableObject target = getTargetThrowIfRevoked(); + return target.getClassName(); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-construct-argumentslist-newtarget + */ + @Override + public Scriptable construct(Context cx, Scriptable scope, Object[] args) { + /* + * 1. Let handler be O.[[ProxyHandler]]. + * 2. If handler is null, throw a TypeError exception. + * 3. Assert: Type(handler) is Object. + * 4. Let target be O.[[ProxyTarget]]. + * 5. Assert: IsConstructor(target) is true. + * 6. Let trap be ? GetMethod(handler, "construct"). + * 7. If trap is undefined, then + * a. Return ? Construct(target, argumentsList, newTarget). + * 8. Let argArray be ! CreateArrayFromList(argumentsList). + * 9. Let newObj be ? Call(trap, handler, « target, argArray, newTarget »). + * 10. If Type(newObj) is not Object, throw a TypeError exception. + * 11. Return newObj. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_CONSTRUCT); + if (trap != null) { + Object result = callTrap(trap, new Object[] {target, args, this}); + if (!(result instanceof Scriptable) || ScriptRuntime.isSymbol(result)) { + throw ScriptRuntime.typeError("Constructor trap has to return a scriptable."); + } + return (ScriptableObject) result; + } + + return ((Constructable) target).construct(cx, scope, args); + } + + /** + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p + */ + @Override + public boolean has(String name, Scriptable start) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "has"). + * 7. If trap is undefined, then + * a. Return ? target.[[HasProperty]](P). + * 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P »)). + * 9. If booleanTrapResult is false, then + * a. Let targetDesc be ? target.[[GetOwnProperty]](P). + * b. If targetDesc is not undefined, then + * i. If targetDesc.[[Configurable]] is false, throw a TypeError exception. + * ii. Let extensibleTarget be ? IsExtensible(target). + * iii. If extensibleTarget is false, throw a TypeError exception. + * 10. Return booleanTrapResult. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_HAS); + if (trap != null) { + + boolean booleanTrapResult = + ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target, name})); + if (!booleanTrapResult) { + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), name); + if (targetDesc != null) { + if (Boolean.FALSE.equals(targetDesc.get("configurable")) + || !target.isExtensible()) { + throw ScriptRuntime.typeError( + "proxy can't report an existing own property '" + + name + + "' as non-existent on a non-extensible object"); + } + } + } + return booleanTrapResult; + } + + return ScriptableObject.hasProperty(target, name); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p + */ + @Override + public boolean has(int index, Scriptable start) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "has"). + * 7. If trap is undefined, then + * a. Return ? target.[[HasProperty]](P). + * 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P »)). + * 9. If booleanTrapResult is false, then + * a. Let targetDesc be ? target.[[GetOwnProperty]](P). + * b. If targetDesc is not undefined, then + * i. If targetDesc.[[Configurable]] is false, throw a TypeError exception. + * ii. Let extensibleTarget be ? IsExtensible(target). + * iii. If extensibleTarget is false, throw a TypeError exception. + * 10. Return booleanTrapResult. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_HAS); + if (trap != null) { + boolean booleanTrapResult = + ScriptRuntime.toBoolean( + callTrap(trap, new Object[] {target, ScriptRuntime.toString(index)})); + if (!booleanTrapResult) { + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), index); + if (targetDesc != null) { + if (Boolean.FALSE.equals(targetDesc.get("configurable")) + || !target.isExtensible()) { + throw ScriptRuntime.typeError( + "proxy can't check an existing property ' + name + ' existance on an not configurable or not extensible object"); + } + } + } + + return booleanTrapResult; + } + + return ScriptableObject.hasProperty(target, index); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p + */ + @Override + public boolean has(Symbol key, Scriptable start) { + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_HAS); + if (trap != null) { + boolean booleanTrapResult = + ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target, key})); + if (!booleanTrapResult) { + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), key); + if (targetDesc != null) { + if (Boolean.FALSE.equals(targetDesc.get("configurable")) + || !target.isExtensible()) { + throw ScriptRuntime.typeError( + "proxy can't check an existing property ' + name + ' existance on an not configurable or not extensible object"); + } + } + } + + return booleanTrapResult; + } + + return ScriptableObject.hasProperty(target, key); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys + */ + @Override + Object[] getIds(boolean getNonEnumerable, boolean getSymbols) { + /* + * 1. Let handler be O.[[ProxyHandler]]. + * 2. If handler is null, throw a TypeError exception. + * 3. Assert: Type(handler) is Object. + * 4. Let target be O.[[ProxyTarget]]. + * 5. Let trap be ? GetMethod(handler, "ownKeys"). + * 6. If trap is undefined, then + * a. Return ? target.[[OwnPropertyKeys]](). + * 7. Let trapResultArray be ? Call(trap, handler, « target »). + * 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, « String, Symbol »). + * 9. If trapResult contains any duplicate entries, throw a TypeError exception. + * 10. Let extensibleTarget be ? IsExtensible(target). + * 11. Let targetKeys be ? target.[[OwnPropertyKeys]](). + * 12. Assert: targetKeys is a List whose elements are only String and Symbol values. + * 13. Assert: targetKeys contains no duplicate entries. + * 14. Let targetConfigurableKeys be a new empty List. + * 15. Let targetNonconfigurableKeys be a new empty List. + * 16. For each element key of targetKeys, do + * a. Let desc be ? target.[[GetOwnProperty]](key). + * b. If desc is not undefined and desc.[[Configurable]] is false, then + * i. i. Append key as an element of targetNonconfigurableKeys. + * c. Else, + i. i. Append key as an element of targetConfigurableKeys. + * 17. If extensibleTarget is true and targetNonconfigurableKeys is empty, then + * a. Return trapResult. + * 18. Let uncheckedResultKeys be a List whose elements are the elements of trapResult. + * 19. For each element key of targetNonconfigurableKeys, do + * a. a. If key is not an element of uncheckedResultKeys, throw a TypeError exception. + * b. Remove key from uncheckedResultKeys. + * 20. If extensibleTarget is true, return trapResult. + * 21. For each element key of targetConfigurableKeys, do + * a. a. If key is not an element of uncheckedResultKeys, throw a TypeError exception. + * b. Remove key from uncheckedResultKeys. + * 22. If uncheckedResultKeys is not empty, throw a TypeError exception. + * 23. Return trapResult. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_OWN_KEYS); + if (trap != null) { + Object res = callTrap(trap, new Object[] {target}); + if (!(res instanceof Scriptable)) { + throw ScriptRuntime.typeError("ownKeys trap must be an object"); + } + if (!ScriptRuntime.isArrayLike((Scriptable) res)) { + throw ScriptRuntime.typeError("ownKeys trap must be an array like object"); + } + + Context cx = Context.getContext(); + + List trapResult = + AbstractEcmaObjectOperations.createListFromArrayLike( + cx, + (Scriptable) res, + (o) -> + o instanceof CharSequence + || o instanceof NativeString + || ScriptRuntime.isSymbol(o), + "proxy [[OwnPropertyKeys]] must return an array with only string and symbol elements"); + + boolean extensibleTarget = target.isExtensible(); + Object[] targetKeys = target.getIds(getNonEnumerable, getSymbols); + + HashSet uncheckedResultKeys = new HashSet(trapResult); + if (uncheckedResultKeys.size() != trapResult.size()) { + throw ScriptRuntime.typeError("ownKeys trap result must not contain duplicates"); + } + + ArrayList targetConfigurableKeys = new ArrayList<>(); + ArrayList targetNonconfigurableKeys = new ArrayList<>(); + for (Object targetKey : targetKeys) { + ScriptableObject desc = target.getOwnPropertyDescriptor(cx, targetKey); + if (desc != null && Boolean.FALSE.equals(desc.get("configurable"))) { + targetNonconfigurableKeys.add(targetKey); + } else { + targetConfigurableKeys.add(targetKey); + } + } + + if (extensibleTarget && targetNonconfigurableKeys.size() == 0) { + return trapResult.toArray(); + } + + for (Object key : targetNonconfigurableKeys) { + if (!uncheckedResultKeys.contains(key)) { + throw ScriptRuntime.typeError( + "proxy can't skip a non-configurable property " + key); + } + uncheckedResultKeys.remove(key); + } + if (extensibleTarget) { + return trapResult.toArray(); + } + + for (Object key : targetConfigurableKeys) { + if (!uncheckedResultKeys.contains(key)) { + throw ScriptRuntime.typeError( + "proxy can't skip a configurable property " + key); + } + uncheckedResultKeys.remove(key); + } + + if (uncheckedResultKeys.size() > 0) { + throw ScriptRuntime.typeError("proxy can't skip properties"); + } + + return trapResult.toArray(); + } + + return target.getIds(getNonEnumerable, getSymbols); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver + */ + @Override + public Object get(String name, Scriptable start) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "get"). + * 7. If trap is undefined, then + * a. Return ? target.[[Get]](P, Receiver). + * 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »). + * 9. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 10. If targetDesc is not undefined and targetDesc.[[Configurable]] is false, then + * a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] is false, then + * i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a TypeError exception. + * b. If IsAccessorDescriptor(targetDesc) is true and targetDesc.[[Get]] is undefined, then + * i. If trapResult is not undefined, throw a TypeError exception. + * 11. Return trapResult. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_GET); + if (trap != null) { + Object trapResult = callTrap(trap, new Object[] {target, name, this}); + + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), name); + if (targetDesc != null + && !Undefined.isUndefined(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("configurable"))) { + if (ScriptableObject.isDataDescriptor(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("writable"))) { + if (!Objects.equals(trapResult, targetDesc.get("value"))) { + throw ScriptRuntime.typeError( + "proxy get has to return the same value as the plain call"); + } + } + if (ScriptableObject.isAccessorDescriptor(targetDesc) + && Undefined.isUndefined(targetDesc.get("get"))) { + if (!Undefined.isUndefined(trapResult)) { + throw ScriptRuntime.typeError( + "proxy get has to return the same value as the plain call"); + } + } + } + return trapResult; + } + + return ScriptRuntime.getObjectProp(target, name, Context.getContext()); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver + */ + @Override + public Object get(int index, Scriptable start) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "get"). + * 7. If trap is undefined, then + * a. Return ? target.[[Get]](P, Receiver). + * 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »). + * 9. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 10. If targetDesc is not undefined and targetDesc.[[Configurable]] is false, then + * a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] is false, then + * i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a TypeError exception. + * b. If IsAccessorDescriptor(targetDesc) is true and targetDesc.[[Get]] is undefined, then + * i. If trapResult is not undefined, throw a TypeError exception. + * 11. Return trapResult. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_GET); + if (trap != null) { + Object trapResult = + callTrap(trap, new Object[] {target, ScriptRuntime.toString(index), this}); + + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), index); + if (targetDesc != null + && !Undefined.isUndefined(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("configurable"))) { + if (ScriptableObject.isDataDescriptor(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("writable"))) { + if (!Objects.equals(trapResult, targetDesc.get("value"))) { + throw ScriptRuntime.typeError( + "proxy get has to return the same value as the plain call"); + } + } + if (ScriptableObject.isAccessorDescriptor(targetDesc) + && Undefined.isUndefined(targetDesc.get("get"))) { + if (!Undefined.isUndefined(trapResult)) { + throw ScriptRuntime.typeError( + "proxy get has to return the same value as the plain call"); + } + } + } + return trapResult; + } + + return ScriptRuntime.getObjectIndex(target, index, Context.getContext()); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver + */ + @Override + public Object get(Symbol key, Scriptable start) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "get"). + * 7. If trap is undefined, then + * a. Return ? target.[[Get]](P, Receiver). + * 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »). + * 9. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 10. If targetDesc is not undefined and targetDesc.[[Configurable]] is false, then + * a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] is false, then + * i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a TypeError exception. + * b. If IsAccessorDescriptor(targetDesc) is true and targetDesc.[[Get]] is undefined, then + * i. If trapResult is not undefined, throw a TypeError exception. + * 11. Return trapResult. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_GET); + if (trap != null) { + Object trapResult = callTrap(trap, new Object[] {target, key, this}); + + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), key); + if (targetDesc != null + && !Undefined.isUndefined(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("configurable"))) { + if (ScriptableObject.isDataDescriptor(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("writable"))) { + if (!Objects.equals(trapResult, targetDesc.get("value"))) { + throw ScriptRuntime.typeError( + "proxy get has to return the same value as the plain call"); + } + } + if (ScriptableObject.isAccessorDescriptor(targetDesc) + && Undefined.isUndefined(targetDesc.get("get"))) { + if (!Undefined.isUndefined(trapResult)) { + throw ScriptRuntime.typeError( + "proxy get has to return the same value as the plain call"); + } + } + } + return trapResult; + } + + if (start == this) { + start = target; + } + SymbolScriptable symbolScriptableTarget = ensureSymbolScriptable(target); + return symbolScriptableTarget.get(key, start); + } + + /** + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver + */ + @Override + public void put(String name, Scriptable start, Object value) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "set"). + * 7. If trap is undefined, then + * a. Return ? target.[[Set]](P, V, Receiver). + * 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P, V, Receiver »)). + * 9. If booleanTrapResult is false, return false. + * 10. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 11. If targetDesc is not undefined and targetDesc.[[Configurable]] is false, then + * a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] is false, then + * i. If SameValue(V, targetDesc.[[Value]]) is false, throw a TypeError exception. + * b. If IsAccessorDescriptor(targetDesc) is true, then + * i. If targetDesc.[[Set]] is undefined, throw a TypeError exception. + * 12. Return true. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_SET); + if (trap != null) { + boolean booleanTrapResult = + ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target, name, value})); + if (!booleanTrapResult) { + return; // false + } + + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), name); + if (targetDesc != null + && !Undefined.isUndefined(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("configurable"))) { + if (ScriptableObject.isDataDescriptor(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("writable"))) { + if (!Objects.equals(value, targetDesc.get("value"))) { + throw ScriptRuntime.typeError( + "proxy set has to use the same value as the plain call"); + } + } + if (ScriptableObject.isAccessorDescriptor(targetDesc) + && Undefined.isUndefined(targetDesc.get("set"))) { + throw ScriptRuntime.typeError("proxy set has to be available"); + } + } + return; // true + } + + ScriptableObject.putProperty(target, name, value); + } + + /** + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver + */ + @Override + public void put(int index, Scriptable start, Object value) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "set"). + * 7. If trap is undefined, then + * a. Return ? target.[[Set]](P, V, Receiver). + * 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P, V, Receiver »)). + * 9. If booleanTrapResult is false, return false. + * 10. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 11. If targetDesc is not undefined and targetDesc.[[Configurable]] is false, then + * a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] is false, then + * i. If SameValue(V, targetDesc.[[Value]]) is false, throw a TypeError exception. + * b. If IsAccessorDescriptor(targetDesc) is true, then + * i. If targetDesc.[[Set]] is undefined, throw a TypeError exception. + * 12. Return true. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_SET); + if (trap != null) { + boolean booleanTrapResult = + ScriptRuntime.toBoolean( + callTrap( + trap, + new Object[] {target, ScriptRuntime.toString(index), value})); + if (!booleanTrapResult) { + return; // false + } + + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), index); + if (targetDesc != null + && !Undefined.isUndefined(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("configurable"))) { + if (ScriptableObject.isDataDescriptor(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("writable"))) { + if (!Objects.equals(value, targetDesc.get("value"))) { + throw ScriptRuntime.typeError( + "proxy set has to use the same value as the plain call"); + } + } + if (ScriptableObject.isAccessorDescriptor(targetDesc) + && Undefined.isUndefined(targetDesc.get("set"))) { + throw ScriptRuntime.typeError("proxy set has to be available"); + } + } + return; // true + } + + ScriptableObject.putProperty(target, index, value); + } + + /** + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver + */ + @Override + public void put(Symbol key, Scriptable start, Object value) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "set"). + * 7. If trap is undefined, then + * a. Return ? target.[[Set]](P, V, Receiver). + * 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P, V, Receiver »)). + * 9. If booleanTrapResult is false, return false. + * 10. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 11. If targetDesc is not undefined and targetDesc.[[Configurable]] is false, then + * a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] is false, then + * i. If SameValue(V, targetDesc.[[Value]]) is false, throw a TypeError exception. + * b. If IsAccessorDescriptor(targetDesc) is true, then + * i. If targetDesc.[[Set]] is undefined, throw a TypeError exception. + * 12. Return true. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_SET); + if (trap != null) { + boolean booleanTrapResult = + ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target, key, value})); + if (!booleanTrapResult) { + return; // false + } + + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), key); + if (targetDesc != null + && !Undefined.isUndefined(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("configurable"))) { + if (ScriptableObject.isDataDescriptor(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("writable"))) { + if (!Objects.equals(value, targetDesc.get("value"))) { + throw ScriptRuntime.typeError( + "proxy set has to use the same value as the plain call"); + } + } + if (ScriptableObject.isAccessorDescriptor(targetDesc) + && Undefined.isUndefined(targetDesc.get("set"))) { + throw ScriptRuntime.typeError("proxy set has to be available"); + } + } + return; // true + } + + if (start == this) { + start = target; + } + SymbolScriptable symbolScriptableTarget = ensureSymbolScriptable(target); + symbolScriptableTarget.put(key, start, value); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-delete-p + */ + @Override + public void delete(String name) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "deleteProperty"). + * 7. If trap is undefined, then + * a. Return ? target.[[Delete]](P). + * 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P »)). + * 9. If booleanTrapResult is false, return false. + * 10. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 11. If targetDesc is undefined, return true. + * 12. If targetDesc.[[Configurable]] is false, throw a TypeError exception. + * 13. Let extensibleTarget be ? IsExtensible(target). + * 14. If extensibleTarget is false, throw a TypeError exception. + * 15. Return true. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_DELETE_PROPERTY); + if (trap != null) { + boolean booleanTrapResult = + ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target, name})); + if (!booleanTrapResult) { + return; // false + } + + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), name); + if (targetDesc == null) { + return; // true + } + if (Boolean.FALSE.equals(targetDesc.get("configurable")) || !target.isExtensible()) { + throw ScriptRuntime.typeError( + "proxy can't delete an existing own property ' + name + ' on an not configurable or not extensible object"); + } + + return; // true + } + + target.delete(name); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-delete-p + */ + @Override + public void delete(int index) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "deleteProperty"). + * 7. If trap is undefined, then + * a. Return ? target.[[Delete]](P). + * 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P »)). + * 9. If booleanTrapResult is false, return false. + * 10. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 11. If targetDesc is undefined, return true. + * 12. If targetDesc.[[Configurable]] is false, throw a TypeError exception. + * 13. Let extensibleTarget be ? IsExtensible(target). + * 14. If extensibleTarget is false, throw a TypeError exception. + * 15. Return true. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_DELETE_PROPERTY); + if (trap != null) { + boolean booleanTrapResult = + ScriptRuntime.toBoolean( + callTrap(trap, new Object[] {target, ScriptRuntime.toString(index)})); + if (!booleanTrapResult) { + return; // false + } + + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), index); + if (targetDesc == null) { + return; // true + } + if (Boolean.FALSE.equals(targetDesc.get("configurable")) || !target.isExtensible()) { + throw ScriptRuntime.typeError( + "proxy can't delete an existing own property ' + name + ' on an not configurable or not extensible object"); + } + + return; // true + } + + target.delete(index); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-delete-p + */ + @Override + public void delete(Symbol key) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "deleteProperty"). + * 7. If trap is undefined, then + * a. Return ? target.[[Delete]](P). + * 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P »)). + * 9. If booleanTrapResult is false, return false. + * 10. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 11. If targetDesc is undefined, return true. + * 12. If targetDesc.[[Configurable]] is false, throw a TypeError exception. + * 13. Let extensibleTarget be ? IsExtensible(target). + * 14. If extensibleTarget is false, throw a TypeError exception. + * 15. Return true. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_DELETE_PROPERTY); + if (trap != null) { + boolean booleanTrapResult = + ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target, key})); + if (!booleanTrapResult) { + return; // false + } + + ScriptableObject targetDesc = + target.getOwnPropertyDescriptor(Context.getContext(), key); + if (targetDesc == null) { + return; // true + } + if (Boolean.FALSE.equals(targetDesc.get("configurable")) || !target.isExtensible()) { + throw ScriptRuntime.typeError( + "proxy can't delete an existing own property ' + name + ' on an not configurable or not extensible object"); + } + + return; // true + } + + SymbolScriptable symbolScriptableTarget = ensureSymbolScriptable(target); + symbolScriptableTarget.delete(key); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-getownproperty-p + */ + @Override + protected ScriptableObject getOwnPropertyDescriptor(Context cx, Object id) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor"). + * 7. If trap is undefined, then + * a. Return ? target.[[GetOwnProperty]](P). + * 8. Let trapResultObj be ? Call(trap, handler, « target, P »). + * 9. If Type(trapResultObj) is neither Object nor Undefined, throw a TypeError exception. + * 10. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 11. If trapResultObj is undefined, then + * a. If targetDesc is undefined, return undefined. + * b. If targetDesc.[[Configurable]] is false, throw a TypeError exception. + * c. Let extensibleTarget be ? IsExtensible(target). + * d. If extensibleTarget is false, throw a TypeError exception. + * e. Return undefined. + * 12. Let extensibleTarget be ? IsExtensible(target). + * 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj). + * 14. Call CompletePropertyDescriptor(resultDesc). + * 15. Let valid be IsCompatiblePropertyDescriptor(extensibleTarget, resultDesc, targetDesc). + * 16. If valid is false, throw a TypeError exception. + * 17. If resultDesc.[[Configurable]] is false, then + * a. If targetDesc is undefined or targetDesc.[[Configurable]] is true, then + * i. Throw a TypeError exception. + * b. If resultDesc has a [[Writable]] field and resultDesc.[[Writable]] is false, then + * i. If targetDesc.[[Writable]] is true, throw a TypeError exception. + * 18. Return resultDesc. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_GET_OWN_PROPERTY_DESCRIPTOR); + if (trap != null) { + Object trapResultObj = callTrap(trap, new Object[] {target, id}); + if (!Undefined.isUndefined(trapResultObj) + && !(trapResultObj instanceof Scriptable + && !ScriptRuntime.isSymbol(trapResultObj))) { + throw ScriptRuntime.typeError( + "getOwnPropertyDescriptor trap has to return undefined or an object"); + } + + ScriptableObject targetDesc; + if (ScriptRuntime.isSymbol(id)) { + targetDesc = target.getOwnPropertyDescriptor(cx, id); + } else { + targetDesc = target.getOwnPropertyDescriptor(cx, ScriptRuntime.toString(id)); + } + + if (Undefined.isUndefined(trapResultObj)) { + if (Undefined.isUndefined(targetDesc)) { + return null; + } + + if (Boolean.FALSE.equals(targetDesc.get("configurable")) + || !target.isExtensible()) { + throw ScriptRuntime.typeError( + "proxy can't report an existing own property '" + + id + + "' as non-existent on a non-extensible object"); + } + return null; + } + + Scriptable trapResult = (Scriptable) trapResultObj; + if (trapResultObj != null) { + Object value = ScriptableObject.getProperty(trapResult, "value"); + int attributes = + applyDescriptorToAttributeBitset( + DONTENUM | READONLY | PERMANENT, trapResult); + + ScriptableObject desc = + ScriptableObject.buildDataDescriptor(target, value, attributes); + return desc; + } + return null; + } + + if (ScriptRuntime.isSymbol(id)) { + return target.getOwnPropertyDescriptor(cx, id); + } + + return target.getOwnPropertyDescriptor(cx, ScriptRuntime.toString(id)); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-defineownproperty-p-desc + */ + @Override + public boolean defineOwnProperty(Context cx, Object id, ScriptableObject desc) { + /* + * 1. Assert: IsPropertyKey(P) is true. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "defineProperty"). + * 7. If trap is undefined, then + * a. Return ? target.[[DefineOwnProperty]](P, Desc). + * 8. Let descObj be FromPropertyDescriptor(Desc). + * 9. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P, descObj »)). + * 10. If booleanTrapResult is false, return false. + * 11. Let targetDesc be ? target.[[GetOwnProperty]](P). + * 12. Let extensibleTarget be ? IsExtensible(target). + * 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] is false, then + * a. Let settingConfigFalse be true. + * 14. Else, let settingConfigFalse be false. + * 15. If targetDesc is undefined, then + * a. If extensibleTarget is false, throw a TypeError exception. + * b. If settingConfigFalse is true, throw a TypeError exception. + * 16. Else, + * a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, targetDesc) is false, throw a TypeError exception. + * b. If settingConfigFalse is true and targetDesc.[[Configurable]] is true, throw a TypeError exception. + * c. If IsDataDescriptor(targetDesc) is true, targetDesc.[[Configurable]] is false, and targetDesc.[[Writable]] is true, then + * i. If Desc has a [[Writable]] field and Desc.[[Writable]] is false, throw a TypeError exception. + * 17. Return true. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_DEFINE_PROPERTY); + if (trap != null) { + boolean booleanTrapResult = + ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target, id, desc})); + if (!booleanTrapResult) { + return false; + } + + ScriptableObject targetDesc = target.getOwnPropertyDescriptor(Context.getContext(), id); + boolean extensibleTarget = target.isExtensible(); + + boolean settingConfigFalse = + Boolean.TRUE.equals(ScriptableObject.hasProperty(desc, "configurable")) + && Boolean.FALSE.equals(desc.get("configurable")); + + if (targetDesc == null) { + if (!extensibleTarget || settingConfigFalse) { + throw ScriptRuntime.typeError( + "proxy can't define an incompatible property descriptor"); + } + } else { + if (!AbstractEcmaObjectOperations.isCompatiblePropertyDescriptor( + extensibleTarget, desc, targetDesc)) { + throw ScriptRuntime.typeError( + "proxy can't define an incompatible property descriptor"); + } + + if (settingConfigFalse && Boolean.TRUE.equals(targetDesc.get("configurable"))) { + throw ScriptRuntime.typeError( + "proxy can't define an incompatible property descriptor"); + } + + if (ScriptableObject.isDataDescriptor(targetDesc) + && Boolean.FALSE.equals(targetDesc.get("configurable")) + && Boolean.TRUE.equals(targetDesc.get("writable"))) { + if (Boolean.TRUE.equals(ScriptableObject.hasProperty(desc, "writable")) + && Boolean.FALSE.equals(desc.get("writable"))) { + throw ScriptRuntime.typeError( + "proxy can't define an incompatible property descriptor"); + } + } + } + return true; + } + + return target.defineOwnProperty(cx, id, desc); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-isextensible + */ + @Override + public boolean isExtensible() { + /* + * 1. Let handler be O.[[ProxyHandler]]. + * 2. If handler is null, throw a TypeError exception. + * 3. Assert: Type(handler) is Object. + * 4. Let target be O.[[ProxyTarget]]. + * 5. Let trap be ? GetMethod(handler, "isExtensible"). + * 6. If trap is undefined, then + * a. a. Return ? IsExtensible(target). + * 7. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target »)). + * 8. Let targetResult be ? IsExtensible(target). + * 9. If SameValue(booleanTrapResult, targetResult) is false, throw a TypeError exception. + * 10. Return booleanTrapResult. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_IS_EXTENSIBLE); + if (trap == null) { + return target.isExtensible(); + } + + boolean booleanTrapResult = ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target})); + if (booleanTrapResult != target.isExtensible()) { + throw ScriptRuntime.typeError( + "IsExtensible trap has to return the same value as the target"); + } + return booleanTrapResult; + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-preventextensions + */ + @Override + public boolean preventExtensions() { + /* + * 1. Let handler be O.[[ProxyHandler]]. + * 2. If handler is null, throw a TypeError exception. + * 3. Assert: Type(handler) is Object. + * 4. Let target be O.[[ProxyTarget]]. + * 5. Let trap be ? GetMethod(handler, "preventExtensions"). + * 6. If trap is undefined, then + * a. Return ? target.[[PreventExtensions]](). + * 7. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target »)). + * 8. If booleanTrapResult is true, then + * a. Let extensibleTarget be ? IsExtensible(target). + * b. If extensibleTarget is true, throw a TypeError exception. + * 9. Return booleanTrapResult. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_PREVENT_EXTENSIONS); + if (trap == null) { + return target.preventExtensions(); + } + boolean booleanTrapResult = ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target})); + if (booleanTrapResult && target.isExtensible()) { + throw ScriptRuntime.typeError("target is extensible but trap returned true"); + } + + return booleanTrapResult; + } + + @Override + public String getTypeOf() { + return typeOf; + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-getprototypeof + */ + @Override + public Scriptable getPrototype() { + /* + * 1. Let handler be O.[[ProxyHandler]]. + * 2. If handler is null, throw a TypeError exception. + * 3. Assert: Type(handler) is Object. + * 4. Let target be O.[[ProxyTarget]]. + * 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). + * 6. If trap is undefined, then + * a. Return ? target.[[GetPrototypeOf]](). + * 7. Let handlerProto be ? Call(trap, handler, « target »). + * 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError exception. + * 9. Let extensibleTarget be ? IsExtensible(target). + * 10. If extensibleTarget is true, return handlerProto. + * 11. Let targetProto be ? target.[[GetPrototypeOf]](). + * 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError exception. + * 13. Return handlerProto. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_GET_PROTOTYPE_OF); + if (trap != null) { + Object handlerProto = callTrap(trap, new Object[] {target}); + + Scriptable handlerProtoScriptable = Undefined.SCRIPTABLE_UNDEFINED; + if (handlerProtoScriptable == null + || Undefined.isUndefined(handlerProto) + || ScriptRuntime.isSymbol(handlerProto)) { + throw ScriptRuntime.typeErrorById( + "msg.arg.not.object", ScriptRuntime.typeof(handlerProto)); + } + + handlerProtoScriptable = ensureScriptable(handlerProto); + + if (target.isExtensible()) { + return handlerProtoScriptable; + } + if (handlerProto != target.getPrototype()) { + throw ScriptRuntime.typeError( + "getPrototypeOf trap has to return the original prototype"); + } + return handlerProtoScriptable; + } + + return target.getPrototype(); + } + + private void setPrototypeDirect(Scriptable prototype) { + super.setPrototype(prototype); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v + */ + @Override + public void setPrototype(Scriptable prototype) { + /* + * 1. Assert: Either Type(V) is Object or Type(V) is Null. + * 2. Let handler be O.[[ProxyHandler]]. + * 3. If handler is null, throw a TypeError exception. + * 4. Assert: Type(handler) is Object. + * 5. Let target be O.[[ProxyTarget]]. + * 6. Let trap be ? GetMethod(handler, "setPrototypeOf"). + * 7. If trap is undefined, then + * a. Return ? target.[[SetPrototypeOf]](V). + * 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, V »)). + * 9. If booleanTrapResult is false, return false. + * 10. Let extensibleTarget be ? IsExtensible(target). + * 11. If extensibleTarget is true, return true. + * 12. Let targetProto be ? target.[[SetPrototypeOf]](). + * 13. If SameValue(V, targetProto) is false, throw a TypeError exception. + * 14. Return true. + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Callable trap = getTrap(TRAP_SET_PROTOTYPE_OF); + if (trap != null) { + boolean booleanTrapResult = + ScriptRuntime.toBoolean(callTrap(trap, new Object[] {target, prototype})); + if (!booleanTrapResult) { + return; // false + } + if (target.isExtensible()) { + return; // true + } + + return; + } + + target.setPrototype(prototype); + } + + /** + * see + * https://262.ecma-international.org/12.0/#sec-proxy-object-internal-methods-and-internal-slots-call-thisargument-argumentslist + */ + @Override + public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + /* + * 1. Let handler be O.[[ProxyHandler]]. + * 2. If handler is null, throw a TypeError exception. + * 3. Assert: Type(handler) is Object. + * 4. Let target be O.[[ProxyTarget]]. + * 5. Let trap be ? GetMethod(handler, "apply"). + * 6. If trap is undefined, then + * a. Return ? Call(target, thisArgument, argumentsList). + * 7. Let argArray be ! CreateArrayFromList(argumentsList). + * 8. Return ? Call(trap, handler, « target, thisArgument, argArray »). + */ + ScriptableObject target = getTargetThrowIfRevoked(); + + Scriptable argumentsList = cx.newArray(scope, args); + + Callable trap = getTrap(TRAP_APPLY); + if (trap != null) { + return callTrap(trap, new Object[] {target, thisObj, argumentsList}); + } + + return ScriptRuntime.applyOrCall( + true, cx, scope, target, new Object[] {thisObj, argumentsList}); + } + + private static NativeProxy constructor(Context cx, Scriptable scope, Object[] args) { + if (args.length < 2) { + throw ScriptRuntime.typeErrorById( + "msg.method.missing.parameter", + "Proxy.ctor", + "2", + Integer.toString(args.length)); + } + ScriptableObject trgt = ensureScriptableObject(args[0]); + + ScriptableObject hndlr = ensureScriptableObject(args[1]); + + NativeProxy proxy = new NativeProxy(trgt, hndlr); + proxy.setPrototypeDirect(ScriptableObject.getClassPrototype(scope, PROXY_TAG)); + proxy.setParentScope(scope); + return proxy; + } + + // Proxy.revocable + private static Object revocable( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + if (!ScriptRuntime.isObject(thisObj)) { + throw ScriptRuntime.typeErrorById("msg.arg.not.object", ScriptRuntime.typeof(thisObj)); + } + NativeProxy proxy = constructor(cx, scope, args); + + NativeObject revocable = (NativeObject) cx.newObject(scope); + + revocable.put("proxy", revocable, proxy); + revocable.put("revoke", revocable, new LambdaFunction(scope, "", 0, new Revoker(proxy))); + return revocable; + } + + private Callable getTrap(String trapName) { + Object handlerProp = ScriptableObject.getProperty(handlerObj, trapName); + if (Scriptable.NOT_FOUND == handlerProp) { + return null; + } + if (handlerProp == null || Undefined.isUndefined(handlerProp)) { + return null; + } + if (!(handlerProp instanceof Callable)) { + throw ScriptRuntime.notFunctionError(handlerProp, trapName); + } + + return (Callable) handlerProp; + } + + private Object callTrap(Callable trap, Object[] args) { + return trap.call(Context.getContext(), handlerObj, handlerObj, args); + } + + ScriptableObject getTargetThrowIfRevoked() { + if (targetObj == null) { + throw ScriptRuntime.typeError("Illegal operation attempted on a revoked proxy"); + } + return targetObj; + } +} diff --git a/src/org/mozilla/javascript/NativeReflect.java b/src/org/mozilla/javascript/NativeReflect.java new file mode 100644 index 0000000000..7ae6a13e7b --- /dev/null +++ b/src/org/mozilla/javascript/NativeReflect.java @@ -0,0 +1,419 @@ +/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.javascript; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class implements the Reflect object. + * + * @author Ronald Brill + */ +final class NativeReflect extends ScriptableObject { + private static final long serialVersionUID = 2920773905356325445L; + + private static final String REFLECT_TAG = "Reflect"; + + public static void init(Context cx, Scriptable scope, boolean sealed) { + NativeReflect reflect = new NativeReflect(); + reflect.setPrototype(getObjectPrototype(scope)); + reflect.setParentScope(scope); + + reflect.defineProperty( + scope, "apply", 3, NativeReflect::apply, DONTENUM, DONTENUM | READONLY); + reflect.defineProperty( + scope, "construct", 2, NativeReflect::construct, DONTENUM, DONTENUM | READONLY); + reflect.defineProperty( + scope, + "defineProperty", + 3, + NativeReflect::defineProperty, + DONTENUM, + DONTENUM | READONLY); + reflect.defineProperty( + scope, + "deleteProperty", + 2, + NativeReflect::deleteProperty, + DONTENUM, + DONTENUM | READONLY); + reflect.defineProperty(scope, "get", 2, NativeReflect::get, DONTENUM, DONTENUM | READONLY); + reflect.defineProperty( + scope, + "getOwnPropertyDescriptor", + 2, + NativeReflect::getOwnPropertyDescriptor, + DONTENUM, + DONTENUM | READONLY); + reflect.defineProperty( + scope, + "getPrototypeOf", + 1, + NativeReflect::getPrototypeOf, + DONTENUM, + DONTENUM | READONLY); + reflect.defineProperty(scope, "has", 2, NativeReflect::has, DONTENUM, DONTENUM | READONLY); + reflect.defineProperty( + scope, + "isExtensible", + 1, + NativeReflect::isExtensible, + DONTENUM, + DONTENUM | READONLY); + reflect.defineProperty( + scope, "ownKeys", 1, NativeReflect::ownKeys, DONTENUM, DONTENUM | READONLY); + reflect.defineProperty( + scope, + "preventExtensions", + 1, + NativeReflect::preventExtensions, + DONTENUM, + DONTENUM | READONLY); + reflect.defineProperty(scope, "set", 3, NativeReflect::set, DONTENUM, DONTENUM | READONLY); + reflect.defineProperty( + scope, + "setPrototypeOf", + 2, + NativeReflect::setPrototypeOf, + DONTENUM, + DONTENUM | READONLY); + + reflect.defineProperty(SymbolKey.TO_STRING_TAG, REFLECT_TAG, DONTENUM | READONLY); + + ScriptableObject.defineProperty(scope, REFLECT_TAG, reflect, DONTENUM); + if (sealed) { + reflect.sealObject(); + } + } + + private NativeReflect() {} + + @Override + public String getClassName() { + return "Reflect"; + } + + private static Object apply(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + if (args.length < 3) { + throw ScriptRuntime.typeErrorById( + "msg.method.missing.parameter", + "Reflect.apply", + "3", + Integer.toString(args.length)); + } + + Scriptable callable = ScriptableObject.ensureScriptable(args[0]); + + if (args[1] instanceof Scriptable) { + thisObj = (Scriptable) args[1]; + } else if (ScriptRuntime.isPrimitive(args[1])) { + thisObj = cx.newObject(scope, "Object", new Object[] {args[1]}); + } + + if (ScriptRuntime.isSymbol(args[2])) { + throw ScriptRuntime.typeErrorById("msg.arg.not.object", ScriptRuntime.typeof(args[2])); + } + ScriptableObject argumentsList = ScriptableObject.ensureScriptableObject(args[2]); + + return ScriptRuntime.applyOrCall( + true, cx, scope, callable, new Object[] {thisObj, argumentsList}); + } + + /** see https://262.ecma-international.org/12.0/#sec-reflect.construct */ + private static Scriptable construct( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + /* + * 1. If IsConstructor(target) is false, throw a TypeError exception. + * 2. If newTarget is not present, set newTarget to target. + * 3. Else if IsConstructor(newTarget) is false, throw a TypeError exception. + * 4. Let args be ? CreateListFromArrayLike(argumentsList). + * 5. Return ? Construct(target, args, newTarget). + */ + if (args.length < 1) { + throw ScriptRuntime.typeErrorById( + "msg.method.missing.parameter", + "Reflect.construct", + "3", + Integer.toString(args.length)); + } + + if (!(args[0] instanceof Constructable)) { + throw ScriptRuntime.typeErrorById("msg.not.ctor", ScriptRuntime.typeof(args[0])); + } + + Constructable ctor = (Constructable) args[0]; + if (args.length < 2) { + return ctor.construct(cx, scope, ScriptRuntime.emptyArgs); + } + + if (args.length > 2 && !(args[2] instanceof Constructable)) { + throw ScriptRuntime.typeErrorById("msg.not.ctor", ScriptRuntime.typeof(args[2])); + } + + Object[] callArgs = ScriptRuntime.getApplyArguments(cx, args[1]); + + Object newTargetPrototype = null; + if (args.length > 2) { + Scriptable newTarget = ScriptableObject.ensureScriptable(args[2]); + + if (newTarget instanceof BaseFunction) { + newTargetPrototype = ((BaseFunction) newTarget).getPrototypeProperty(); + } else { + newTargetPrototype = newTarget.get("prototype", newTarget); + } + + if (!(newTargetPrototype instanceof Scriptable) + || ScriptRuntime.isSymbol(newTargetPrototype) + || Undefined.isUndefined(newTargetPrototype)) { + newTargetPrototype = null; + } + } + + // hack to set the right prototype before calling the ctor + if (ctor instanceof BaseFunction && newTargetPrototype != null) { + BaseFunction ctorBaseFunction = (BaseFunction) ctor; + Scriptable result = ctorBaseFunction.createObject(cx, scope); + if (result != null) { + result.setPrototype((Scriptable) newTargetPrototype); + + Object val = ctorBaseFunction.call(cx, scope, result, callArgs); + if (val instanceof Scriptable) { + return (Scriptable) val; + } + + return result; + } + } + + Scriptable newScriptable = ctor.construct(cx, scope, callArgs); + if (newTargetPrototype != null) { + newScriptable.setPrototype((Scriptable) newTargetPrototype); + } + + return newScriptable; + } + + private static Object defineProperty( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + if (args.length < 3) { + throw ScriptRuntime.typeErrorById( + "msg.method.missing.parameter", + "Reflect.defineProperty", + "3", + Integer.toString(args.length)); + } + + ScriptableObject target = checkTarget(args); + ScriptableObject desc = ScriptableObject.ensureScriptableObject(args[2]); + + try { + return target.defineOwnProperty(cx, args[1], desc); + } catch (EcmaError e) { + return false; + } + } + + private static Object deleteProperty( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + ScriptableObject target = checkTarget(args); + + if (args.length > 1) { + if (ScriptRuntime.isSymbol(args[1])) { + return ScriptableObject.deleteProperty(target, (Symbol) args[1]); + } + return ScriptableObject.deleteProperty(target, ScriptRuntime.toString(args[1])); + } + + return false; + } + + private static Object get(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + ScriptableObject target = checkTarget(args); + + if (args.length > 1) { + if (ScriptRuntime.isSymbol(args[1])) { + Object prop = ScriptableObject.getProperty(target, (Symbol) args[1]); + return prop == Scriptable.NOT_FOUND ? Undefined.SCRIPTABLE_UNDEFINED : prop; + } + if (args[1] instanceof Double) { + Object prop = ScriptableObject.getProperty(target, ScriptRuntime.toIndex(args[1])); + return prop == Scriptable.NOT_FOUND ? Undefined.SCRIPTABLE_UNDEFINED : prop; + } + + Object prop = ScriptableObject.getProperty(target, ScriptRuntime.toString(args[1])); + return prop == Scriptable.NOT_FOUND ? Undefined.SCRIPTABLE_UNDEFINED : prop; + } + return Undefined.SCRIPTABLE_UNDEFINED; + } + + private static Scriptable getOwnPropertyDescriptor( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + ScriptableObject target = checkTarget(args); + + if (args.length > 1) { + if (ScriptRuntime.isSymbol(args[1])) { + ScriptableObject desc = target.getOwnPropertyDescriptor(cx, args[1]); + return desc == null ? Undefined.SCRIPTABLE_UNDEFINED : desc; + } + + ScriptableObject desc = + target.getOwnPropertyDescriptor(cx, ScriptRuntime.toString(args[1])); + return desc == null ? Undefined.SCRIPTABLE_UNDEFINED : desc; + } + return Undefined.SCRIPTABLE_UNDEFINED; + } + + private static Scriptable getPrototypeOf( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + ScriptableObject target = checkTarget(args); + + return target.getPrototype(); + } + + private static Object has(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + ScriptableObject target = checkTarget(args); + + if (args.length > 1) { + if (ScriptRuntime.isSymbol(args[1])) { + return ScriptableObject.hasProperty(target, (Symbol) args[1]); + } + + return ScriptableObject.hasProperty(target, ScriptRuntime.toString(args[1])); + } + return false; + } + + private static Object isExtensible( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + ScriptableObject target = checkTarget(args); + return target.isExtensible(); + } + + private static Scriptable ownKeys( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + ScriptableObject target = checkTarget(args); + + final List strings = new ArrayList<>(); + final List symbols = new ArrayList<>(); + + for (Object o : target.getIds(true, true)) { + if (o instanceof Symbol) { + symbols.add(o); + } else { + strings.add(ScriptRuntime.toString(o)); + } + } + + Object[] keys = new Object[strings.size() + symbols.size()]; + System.arraycopy(strings.toArray(), 0, keys, 0, strings.size()); + System.arraycopy(symbols.toArray(), 0, keys, strings.size(), symbols.size()); + + return cx.newArray(scope, keys); + } + + private static Object preventExtensions( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + ScriptableObject target = checkTarget(args); + + return target.preventExtensions(); + } + + private static Object set(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + ScriptableObject target = checkTarget(args); + if (args.length < 2) { + return true; + } + + ScriptableObject receiver = + args.length > 3 ? ScriptableObject.ensureScriptableObject(args[3]) : target; + if (receiver != target) { + ScriptableObject descriptor = target.getOwnPropertyDescriptor(cx, args[1]); + if (descriptor != null) { + Object setter = descriptor.get("set"); + if (setter != null && setter != NOT_FOUND) { + ((Function) setter).call(cx, scope, receiver, new Object[] {args[2]}); + return true; + } + + if (Boolean.FALSE.equals(descriptor.get("configurable"))) { + return false; + } + } + } + + if (ScriptRuntime.isSymbol(args[1])) { + receiver.put((Symbol) args[1], receiver, args[2]); + } else if (args[1] instanceof Double) { + receiver.put(ScriptRuntime.toIndex(args[1]), receiver, args[2]); + } else { + receiver.put(ScriptRuntime.toString(args[1]), receiver, args[2]); + } + + return true; + } + + private static Object setPrototypeOf( + Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + if (args.length < 2) { + throw ScriptRuntime.typeErrorById( + "msg.method.missing.parameter", + "Reflect.js_setPrototypeOf", + "2", + Integer.toString(args.length)); + } + + ScriptableObject target = checkTarget(args); + + if (target.getPrototype() == args[1]) { + return true; + } + + if (!target.isExtensible()) { + return false; + } + + if (args[1] == null) { + target.setPrototype(null); + return true; + } + + if (ScriptRuntime.isSymbol(args[1])) { + throw ScriptRuntime.typeErrorById("msg.arg.not.object", ScriptRuntime.typeof(args[0])); + } + + ScriptableObject proto = ScriptableObject.ensureScriptableObject(args[1]); + if (target.getPrototype() == proto) { + return true; + } + + // avoid cycles + Scriptable p = proto; + while (p != null) { + if (target == p) { + return false; + } + p = p.getPrototype(); + } + + target.setPrototype(proto); + return true; + } + + private static ScriptableObject checkTarget(Object[] args) { + if (args.length == 0 || args[0] == null || args[0] == Undefined.instance) { + Object argument = args.length == 0 ? Undefined.instance : args[0]; + throw ScriptRuntime.typeErrorById( + "msg.no.properties", ScriptRuntime.toString(argument)); + } + + if (ScriptRuntime.isSymbol(args[0])) { + throw ScriptRuntime.typeErrorById("msg.arg.not.object", ScriptRuntime.typeof(args[0])); + } + return ScriptableObject.ensureScriptableObject(args[0]); + } +} diff --git a/src/org/mozilla/javascript/ScriptRuntime.java b/src/org/mozilla/javascript/ScriptRuntime.java index 2a02469156..21137f2967 100644 --- a/src/org/mozilla/javascript/ScriptRuntime.java +++ b/src/org/mozilla/javascript/ScriptRuntime.java @@ -287,6 +287,9 @@ public static ScriptableObject initSafeStandardObjects( NativeWeakMap.init(scope, sealed); NativeWeakSet.init(scope, sealed); NativeBigInt.init(scope, sealed); + + NativeProxy.init(cx, scope, sealed); + NativeReflect.init(cx, scope, sealed); } if (scope instanceof TopLevel) { @@ -2717,10 +2720,10 @@ public static Ref callRef(Callable function, Scriptable thisObj, Object[] args, *

See ECMA 11.2.2 */ public static Scriptable newObject(Object fun, Context cx, Scriptable scope, Object[] args) { - if (!(fun instanceof Function)) { + if (!(fun instanceof Constructable)) { throw notFunctionError(fun); } - Function function = (Function) fun; + Constructable function = (Constructable) fun; return function.construct(cx, scope, args); } @@ -2811,7 +2814,7 @@ public static Object applyOrCall( } /** @return true if the passed in Scriptable looks like an array */ - private static boolean isArrayLike(Scriptable obj) { + public static boolean isArrayLike(Scriptable obj) { return obj != null && (obj instanceof NativeArray || obj instanceof Arguments @@ -3679,6 +3682,10 @@ public static boolean shallowEq(Object x, Object y) { if (y instanceof Boolean) { return x.equals(y); } + } else if (x instanceof SymbolKey) { + return x.equals(y); + } else if (y instanceof SymbolKey) { + return y.equals(x); } else if (x instanceof Scriptable) { if (x instanceof Wrapper && y instanceof Wrapper) { return ((Wrapper) x).unwrap() == ((Wrapper) y).unwrap(); diff --git a/src/org/mozilla/javascript/ScriptableObject.java b/src/org/mozilla/javascript/ScriptableObject.java index 6ff475eaab..d9ac07ee3b 100644 --- a/src/org/mozilla/javascript/ScriptableObject.java +++ b/src/org/mozilla/javascript/ScriptableObject.java @@ -1566,9 +1566,9 @@ public void defineOwnProperties(Context cx, ScriptableObject props) { * @param id the name/index of the property * @param desc the new property descriptor, as described in 8.6.1 */ - public void defineOwnProperty(Context cx, Object id, ScriptableObject desc) { + public boolean defineOwnProperty(Context cx, Object id, ScriptableObject desc) { checkPropertyDefinition(desc); - defineOwnProperty(cx, id, desc, true); + return defineOwnProperty(cx, id, desc, true); } /** @@ -1581,7 +1581,7 @@ public void defineOwnProperty(Context cx, Object id, ScriptableObject desc) { * @param desc the new property descriptor, as described in 8.6.1 * @param checkValid whether to perform validity checks */ - protected void defineOwnProperty( + protected boolean defineOwnProperty( Context cx, Object id, ScriptableObject desc, boolean checkValid) { Object key = null; @@ -1650,6 +1650,8 @@ protected void defineOwnProperty( } slot.setAttributes(attributes); } + + return true; } /** @@ -1779,7 +1781,7 @@ protected boolean sameValue(Object newValue, Object currentValue) { return ScriptRuntime.shallowEq(currentValue, newValue); } - protected int applyDescriptorToAttributeBitset(int attributes, ScriptableObject desc) { + protected int applyDescriptorToAttributeBitset(int attributes, Scriptable desc) { Object enumerable = getProperty(desc, "enumerable"); if (enumerable != NOT_FOUND) { attributes = @@ -1833,7 +1835,7 @@ protected static boolean isAccessorDescriptor(ScriptableObject desc) { * @param desc a property descriptor * @return true if this is a generic descriptor. */ - protected boolean isGenericDescriptor(ScriptableObject desc) { + protected static boolean isGenericDescriptor(ScriptableObject desc) { return !isDataDescriptor(desc) && !isAccessorDescriptor(desc); } @@ -1964,8 +1966,9 @@ public boolean isExtensible() { return isExtensible; } - public void preventExtensions() { + public boolean preventExtensions() { isExtensible = false; + return true; } /** @@ -2293,6 +2296,15 @@ public static boolean deleteProperty(Scriptable obj, int index) { return !base.has(index, obj); } + /** A version of deleteProperty for properties with Symbol keys. */ + public static boolean deleteProperty(Scriptable obj, Symbol key) { + Scriptable base = getBase(obj, key); + if (base == null) return true; + SymbolScriptable scriptable = ensureSymbolScriptable(base); + scriptable.delete(key); + return !scriptable.has(key, obj); + } + /** * Returns an array of all ids from an object and its prototypes. * diff --git a/testsrc/org/mozilla/javascript/tests/Test262SuiteTest.java b/testsrc/org/mozilla/javascript/tests/Test262SuiteTest.java index 70ee634479..61c2e6c8eb 100644 --- a/testsrc/org/mozilla/javascript/tests/Test262SuiteTest.java +++ b/testsrc/org/mozilla/javascript/tests/Test262SuiteTest.java @@ -90,11 +90,6 @@ public class Test262SuiteTest { Arrays.asList( "Atomics", "IsHTMLDDA", - "Proxy", - "Reflect", - "Reflect.construct", - "Reflect.set", - "Reflect.setPrototypeOf", "SharedArrayBuffer", "Symbol.species", "async-functions", diff --git a/testsrc/org/mozilla/javascript/tests/es6/NativeProxyTest.java b/testsrc/org/mozilla/javascript/tests/es6/NativeProxyTest.java new file mode 100644 index 0000000000..962e4336d7 --- /dev/null +++ b/testsrc/org/mozilla/javascript/tests/es6/NativeProxyTest.java @@ -0,0 +1,918 @@ +package org.mozilla.javascript.tests.es6; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.tests.Utils; + +public class NativeProxyTest { + + @Test + public void testToString() { + testString("function Proxy() {\n\t[native code, arity=2]\n}\n", "Proxy.toString()"); + + testString("[object Object]", "Object.prototype.toString.call(new Proxy({}, {}))"); + testString("[object Array]", "Object.prototype.toString.call(new Proxy([], {}))"); + testString( + "[object Array]", + "Object.prototype.toString.call(new Proxy(new Proxy([], {}), {}))"); + } + + @Test + public void testToStringRevoke() { + String js = + "var rev = Proxy.revocable(%s, {});\n" + + "rev.revoke();\n" + + "try {" + + " Object.prototype.toString.call(%s);\n" + + "} catch(e) {\n" + + " '' + e;\n" + + "}"; + + testString( + "TypeError: Illegal operation attempted on a revoked proxy", + String.format(js, "{}", "rev.proxy")); + testString( + "TypeError: Illegal operation attempted on a revoked proxy", + String.format(js, "[]", "rev.proxy")); + } + + @Test + public void prototype() { + testString("false", "'' + Object.hasOwnProperty.call(Proxy, 'prototype')"); + + testString("2", "'' + Proxy.length"); + } + + @Test + public void ctorMissingArgs() { + testString( + "TypeError: Proxy.ctor: At least 2 arguments required, but only 0 passed", + "try { new Proxy() } catch(e) { '' + e }"); + testString( + "TypeError: Proxy.ctor: At least 2 arguments required, but only 1 passed", + "try { new Proxy({}) } catch(e) { '' + e }"); + + testString( + "TypeError: Expected argument of type object, but instead had type undefined", + "try { new Proxy(undefined, {}) } catch(e) { '' + e }"); + testString( + "TypeError: Expected argument of type object, but instead had type object", + "try { new Proxy(null, {}) } catch(e) { '' + e }"); + } + + @Test + public void ctorAsFunction() { + testString( + "TypeError: The constructor for Proxy may not be invoked as a function", + "try { Proxy() } catch(e) { '' + e }"); + } + + @Test + public void construct() { + String js = + "var _target, _handler, _args, _P;\n" + + "function Target() {}\n" + + "var handler = {\n" + + " construct: function(t, args, newTarget) {\n" + + " _handler = this;\n" + + " _target = t;\n" + + " _args = args;\n" + + " _P = newTarget;\n" + + " return new t(args[0], args[1]);\n" + + " }\n" + + "};\n" + + "var P = new Proxy(Target, handler);\n" + + "new P(1, 4);\n" + + "'' + (_handler === handler)\n" + + "+ ' ' + (_target === Target)" + + "+ ' ' + (_P === P)" + + "+ ' ' + _args.length + ' ' + _args[0] + ' ' + _args[1]"; + + testString("true true true 2 1 4", js); + } + + @Test + public void apply() { + String js = + "function sum(a, b) {\n" + + " return a + b;\n" + + "}\n" + + "var res = '';\n" + + "var handler = {\n" + + " apply: function (target, thisArg, argumentsList) {\n" + + " res += ' ' + `Calculate sum: ${argumentsList}`;\n" + + " return target(argumentsList[0], argumentsList[1]) * 7;\n" + + " },\n" + + "};\n" + + "var proxy1 = new Proxy(sum, handler);\n" + + "var x = ' ' + proxy1(1, 2);\n" + + "res + x"; + + testString(" Calculate sum: 1,2 21", js); + } + + @Test + public void applyParameters() { + String js = + "var _target, _args, _handler, _context;\n" + + "var target = function() {\n" + + " throw new Error('target should not be called');\n" + + "};\n" + + "var handler = {\n" + + " apply: function(t, c, args) {\n" + + " _handler = this;\n" + + " _target = t;\n" + + " _context = c;\n" + + " _args = args;\n" + + " }\n" + + "};\n" + + "var p = new Proxy(target, handler);\n" + + "var context = {};\n" + + "p.call(context, 1, 4);\n" + + "'' + (_handler === handler)\n" + + "+ ' ' + (_target === target)" + + "+ ' ' + (_context === context)" + + "+ ' ' + _args.length + ' ' + _args[0] + ' ' + _args[1]"; + + testString("true true true 2 1 4", js); + } + + @Test + public void applyTrapIsNull() { + String js = + "var calls = 0;\n" + + "var _context;\n" + + "var target = new Proxy(function() {}, {\n" + + " apply: function(_target, context, args) {\n" + + " calls++;\n" + + " _context = context;\n" + + " return args[0] + args[1];\n" + + " }\n" + + "})\n" + + "var p = new Proxy(target, {\n" + + " apply: null\n" + + "});\n" + + "var context = {};\n" + + "var res = p.call(context, 1, 2);\n" + + "'' + calls\n" + + "+ ' ' + (_context === context)" + + "+ ' ' + res"; + + testString("1 true 3", js); + } + + @Test + public void applyWithoutHandler() { + String js = + "function sum(a, b) {\n" + + " return a + b;\n" + + "}\n" + + "var proxy1 = new Proxy(sum, {});\n" + + "proxy1(1, 2);"; + + testDouble(3.0, js); + } + + @Test + public void defineProperty() { + String js = + "var o = {};\n" + + "var res = '';\n" + + "var handler = {\n" + + " defineProperty(target, key, desc) {\n" + + " res = res + target + ' ' + key + ' '\n" + + " + desc.writable + ' ' + desc.configurable + ' ' + desc.enumerable;\n" + + " return true;\n" + + " }\n" + + " };\n" + + "var proxy1 = new Proxy(o, handler);\n" + + "Object.defineProperty(proxy1, 'p', { value: 42, writable: false });\n" + + "res;"; + testString("[object Object] p false undefined undefined", js); + } + + @Test + public void definePropertyTrapReturnsFalse() { + String js = + "var target = {};\n" + + "var p = new Proxy(target, {\n" + + " defineProperty: function(t, prop, desc) {\n" + + " return 0;\n" + + " }\n" + + "});\n" + + "'' + Reflect.defineProperty(p, 'attr', {})" + + "+ ' ' + Object.getOwnPropertyDescriptor(target, 'attr')"; + testString("false undefined", js); + } + + @Test + public void + definePropertyDescNotConfigurableAndTargetPropertyDescriptorConfigurableAndTrapResultIsTrue() { + String js = + "var target = {};\n" + + "var p = new Proxy(target, {\n" + + " defineProperty: function(t, prop, desc) {\n" + + " return true;\n" + + " }\n" + + "});\n" + + "Object.defineProperty(target, \"foo\", {\n" + + " value: 1,\n" + + " configurable: true\n" + + "});\n" + + "try {\n" + + " Object.defineProperty(p, \"foo\", {\n" + + " value: 1,\n" + + " configurable: false\n" + + " });\n" + + "} catch(e) {\n" + + " '' + e;\n" + + "}\n"; + testString("TypeError: proxy can't define an incompatible property descriptor", js); + } + + @Test + public void definePropertyDescAndTargetPropertyDescriptorNotCompatibleAndTrapResultIsTrue() { + String js = + "var target = {};\n" + + "var p = new Proxy(target, {\n" + + " defineProperty: function(t, prop, desc) {\n" + + " return true;\n" + + " }\n" + + "});\n" + + "Object.defineProperty(target, \"foo\", {\n" + + " value: 1\n" + + "});\n" + + "try {\n" + + " Object.defineProperty(p, \"foo\", {\n" + + " value: 2\n" + + " });\n" + + "} catch(e) {\n" + + " '' + e;\n" + + "}\n"; + testString("TypeError: proxy can't define an incompatible property descriptor", js); + } + + @Test + public void definePropertyDescAndTargetPropertyDescriptorNotCompatibleAndTrapResultIsTrue2() { + String js = + "var target = Object.create(null);\n" + + "var p = new Proxy(target, {\n" + + " defineProperty: function() {\r\n" + + " return true;\r\n" + + " }\n" + + "});\n" + + "Object.defineProperty(target, 'prop', {\n" + + " value: 1,\n" + + " configurable: false\n" + + "});\n" + + "try {\n" + + " Object.defineProperty(p, 'prop', {\n" + + " value: 1,\n" + + " configurable: true\n" + + " });\n" + + "} catch(e) {\n" + + " '' + e;\n" + + "}\n"; + testString("TypeError: proxy can't define an incompatible property descriptor", js); + } + + @Test + public void definePropertyWithoutHandler() { + String js = + "var o = {};\n" + + "var proxy1 = new Proxy(o, {});\n" + + "proxy1.p = 42;\n" + + "'' + o.p;"; + testString("42", js); + } + + @Test + public void definePropertyFreezedWithoutHandler() { + String js = + "var o = {};\n" + + "Object.freeze(o);\n" + + "var proxy1 = new Proxy(o, {});\n" + + "try {\n" + + " Object.defineProperty(proxy1, 'p', { value: 42, writable: false });\n" + + " '' + o.p;\n" + + "} catch(e) {\n" + + " '' + e;" + + "}\n"; + testString( + "TypeError: Cannot add properties to this object because extensible is false.", js); + } + + @Test + public void definePropertyHandlerNotFunction() { + String js = + "var o = {};\n" + + "var proxy1 = new Proxy(o, { defineProperty: 7 });\n" + + "try {\n" + + " Object.defineProperty(proxy1, 'p', { value: 42, writable: false });\n" + + " '' + o.p;\n" + + "} catch(e) {\n" + + " '' + e;" + + "}\n"; + testString("TypeError: defineProperty is not a function, it is number.", js); + } + + @Test + public void definePropertyHandlerNull() { + String js = + "var o = {};\n" + + "var proxy1 = new Proxy(o, { defineProperty: null });\n" + + "try {\n" + + " Object.defineProperty(proxy1, 'p', { value: 42, writable: false });\n" + + " '' + o.p;\n" + + "} catch(e) {\n" + + " '' + e;" + + "}\n"; + testString("42", js); + } + + @Test + public void definePropertyHandlerUndefined() { + String js = + "var o = {};\n" + + "var proxy1 = new Proxy(o, { defineProperty: undefined });\n" + + "try {\n" + + " Object.defineProperty(proxy1, 'p', { value: 42, writable: false });\n" + + " '' + o.p;\n" + + "} catch(e) {\n" + + " '' + e;" + + "}\n"; + testString("42", js); + } + + @Test + public void deletePropertyWithoutHandler() { + String js = + "var o = { p: 42 };\n" + + "var proxy1 = new Proxy(o, {});\n" + + "delete proxy1.p;\n" + + "'' + o.p;"; + testString("undefined", js); + } + + @Test + public void getOwnPropertyDescriptor() { + String js = + "var o1 = {};\n" + + "var fn = function() {};\n" + + "Object.defineProperty(o1, 'p', {\n" + + " get: fn,\n" + + " configurable: true\n" + + "});\n" + + "var proxy1 = new Proxy(o1, {\n" + + " getOwnPropertyDescriptor(target, prop) {\n" + + " return { configurable: true, enumerable: true, value: 7 };\n" + + " }});\n" + + "var result = Object.getOwnPropertyDescriptor(proxy1, 'p');\n" + + "'' + o1.p + ' ' + result.value \n" + + "+ ' [' + Object.getOwnPropertyNames(result) + ']' " + + "+ ' ' + result.enumerable " + + "+ ' ' + result.configurable " + + "+ ' ' + result.writable " + + "+ ' ' + (result.get === fn) " + + "+ ' ' + (result.set === undefined)"; + testString( + "undefined 7 [value,writable,enumerable,configurable] true true false false true", + js); + } + + @Test + public void getOwnPropertyDescriptorResultUndefined() { + String js = + "var target = {attr: 1};\n" + + "var p = new Proxy(target, {\n" + + " getOwnPropertyDescriptor: function(t, prop) {\n" + + " return;\n" + + " }\n" + + " });\n" + + "'' + Object.getOwnPropertyDescriptor(p, 'attr');"; + testString("undefined", js); + } + + @Test + public void getOwnPropertyDescriptorWithoutHandler() { + String js = + "var o1 = {};\n" + + "var fn = function() {};\n" + + "Object.defineProperty(o1, 'p', {\n" + + " get: fn,\n" + + " configurable: true\n" + + "});\n" + + "var proxy1 = new Proxy(o1, {});\n" + + "var result = Object.getOwnPropertyDescriptor(proxy1, 'p');\n" + + "'[' + Object.getOwnPropertyNames(result) + ']'" + + "+ ' ' + result.enumerable" + + "+ ' ' + result.configurable" + + "+ ' ' + (result.get === fn)" + + "+ ' ' + (result.set === undefined)"; + testString("[get,set,enumerable,configurable] false true true true", js); + } + + @Test + public void isExtensible() { + String js = + "var o = {};\n" + + "var res = '';\n" + + "var handler = {\n" + + " isExtensible(target) {\n" + + " res += ' a ' + (target == o);\n" + + " return Reflect.isExtensible(target);" + + " },\n" + + " preventExtensions(target) {\n" + + " res += ' o ' + (target == o);\n" + + " }\n" + + " };\n" + + "var proxy1 = new Proxy(o, handler);\n" + + "var x = Object.isExtensible(proxy1);\n" + + "res += ' ' + x;\n" + + "res += ' ' + x;\n"; + testString(" a true true true", js); + } + + @Test + public void isExtensibleWithoutHandler() { + String js = + "var o1 = {};\n" + + "var proxy1 = new Proxy(o1, {});\n" + + "var result = '' + Object.isExtensible(o1) + '-' + Object.isExtensible(proxy1);\n" + + "Object.preventExtensions(proxy1);\n" + + "result += ' ' + Object.isExtensible(o1) + '-' + Object.isExtensible(proxy1);\n" + + "var o2 = Object.seal({});\n" + + "var proxy2 = new Proxy(o2, {});\n" + + "result += ' ' + Object.isExtensible(o2) + '-' + Object.isExtensible(proxy2);\n"; + + testString("true-true false-false false-false", js); + } + + @Test + public void preventExtensionsTrapReturnsNoBoolean() { + String js = + "var target = {};\n" + + "var p = new Proxy({}, {\n" + + " preventExtensions: function(t) {\n" + + " return 0;\n" + + " }\n" + + "});\n" + + "var res = '' + Reflect.preventExtensions(p);\n" + + "Object.preventExtensions(target);\n" + + "res += ' ' + Reflect.preventExtensions(p);\n"; + testString("false false", js); + } + + @Test + public void preventExtensionsTrapIsUndefined() { + String js = + "var target = {};\n" + + "var p = new Proxy(target, {});\n" + + "'' + Reflect.preventExtensions(p);"; + testString("true", js); + } + + @Test + public void ownKeys() { + String js = + "var o = { d: 42 };\n" + + "var res = '';\n" + + "var handler = {\n" + + " ownKeys(target) {\n" + + " res += (target == o);\n" + + " return Reflect.ownKeys(target);" + + " }\n" + + " };\n" + + "var proxy1 = new Proxy(o, handler);\n" + + "var x = Object.keys(proxy1);\n" + + "res += ' ' + x;\n"; + testString("true d", js); + } + + @Test + public void ownKeysTrapUndefined() { + String js = + "var target = {\n" + + " foo: 1,\n" + + " bar: 2\n" + + "};\n" + + "var p = new Proxy(target, {});\n" + + "var keys = Object.getOwnPropertyNames(p);\n" + + "'' + keys[0] + ' ' + keys[1] + ' ' + keys.length"; + testString("foo bar 2", js); + } + + @Test + public void ownKeysArrayInTrapResult() { + String js = + "var p = new Proxy({}, {\n" + + " ownKeys: function() {\n" + + " return [ [] ];\n" + + " }\n" + + "});\n" + + "try { Object.keys(p); } catch(e) { '' + e }\n"; + testString( + "TypeError: proxy [[OwnPropertyKeys]] must return an array with only string and symbol elements", + js); + } + + @Test + public void ownKeysWithoutHandler() { + String js = + "var o1 = {\n" + + " p1: 42,\n" + + " p2: 'one'\n" + + "};\n" + + "var a1 = [];\n" + + "var proxy1 = new Proxy(o1, {});\n" + + "var proxy2 = new Proxy(a1, {});\n" + + "'' + Object.keys(proxy1)" + + "+ ' ' + Object.keys(proxy2)"; + testString("p1,p2 ", js); + } + + @Test + public void ownKeysWithoutHandler2() { + String js = + "let s1 = Symbol.for('foo');\n" + + "let s2 = Symbol.for('bar');\n" + + "var o1 = {\n" + + " s1: 0,\n" + + " 'str': 0,\n" + + " 773: 0,\n" + + " '55': 0,\n" + + " 0: 0,\n" + + " '-1': 0,\n" + + " 8: 0,\n" + + " '6': 8,\n" + + " s2: 0,\n" + + " 'str2': 0\n" + + "};\n" + + "var a1 = [];\n" + + "var proxy1 = new Proxy(o1, {});\n" + + "'' + Object.keys(proxy1)"; + testString("0,6,8,55,773,s1,str,-1,s2,str2", js); + } + + @Test + public void ownKeysWithoutHandlerEmptyObj() { + String js = "var proxy1 = new Proxy({}, {});\n" + "'' + Object.keys(proxy1).length"; + testString("0", js); + } + + @Test + public void ownKeysWithoutHandlerDeleteObj() { + String js = + "var o = { d: 42 };\n" + + "delete o.d;\n" + + "var proxy1 = new Proxy(o, {});\n" + + "'' + Object.keys(proxy1).length"; + testString("0", js); + } + + @Test + public void ownKeysWithoutHandlerEmptyArray() { + String js = "var proxy1 = new Proxy([], {});\n" + "'' + Object.keys(proxy1)"; + testString("", js); + } + + @Test + public void ownKeysWithoutHandlerArray() { + String js = "var proxy1 = new Proxy([, , 2], {});\n" + "'' + Object.keys(proxy1)"; + testString("2", js); + } + + @Test + public void ownKeysWithoutHandlerNotEnumerable() { + String js = + "var o = {};\n" + + "Object.defineProperty(o, 'p1', { value: 42, enumerable: false });\n" + + "Object.defineProperty(o, 'p2', { get: function() {}, enumerable: false });\n" + + "var proxy1 = new Proxy(o, {});\n" + + "'' + Object.keys(proxy1)"; + testString("", js); + } + + @Test + public void hasTargetNotExtensible() { + String js = + "var target = {};\n" + + "var handler = {\n" + + " has: function(t, prop) {\n" + + " return 0;\n" + + " }\n" + + "};\n" + + "var p = new Proxy(target, handler);\n" + + "Object.defineProperty(target, 'attr', {\n" + + " configurable: true,\n" + + " extensible: false,\n" + + " value: 1\n" + + "});\n" + + "Object.preventExtensions(target);\n" + + "try { 'attr' in p; } catch(e) { '' + e }\n"; + + testString( + "TypeError: proxy can't report an existing own property 'attr' as non-existent on a non-extensible object", + js); + } + + @Test + public void hasHandlerCallsIn() { + String js = + "var _handler, _target, _prop;\n" + + "var target = {};\n" + + "var handler = {\n" + + " has: function(t, prop) {\n" + + " _handler = this;\n" + + " _target = t;\n" + + " _prop = prop;\n" + + " return prop in t;\n" + + " }\n" + + "};\n" + + "var p = new Proxy(target, handler);\n" + + "'' + (_handler === handler)\n" + + "+ ' ' + (_target === target)" + + "+ ' ' + ('attr' === _prop)" + + "+ ' ' + ('attr' in p)"; + + testString("false false false false", js); + } + + @Test + public void hasWithoutHandler() { + String js = + "var o1 = { p: 42 }\n" + + "var proxy1 = new Proxy(o1, {});\n" + + "'' + ('p' in proxy1)" + + "+ ' ' + ('p2' in proxy1)" + + "+ ' ' + ('toString' in proxy1)"; + testString("true false true", js); + } + + @Test + public void hasSymbolWithoutHandler() { + String js = + "var s1 = Symbol('1');\n" + + "var s2 = Symbol('1');\n" + + "var o = {};\n" + + "o[s1] = 42;\n" + + "var proxy1 = new Proxy(o, {});\n" + + "'' + (s1 in proxy1)" + + "+ ' ' + (2 in proxy1)"; + testString("true false", js); + } + + @Test + public void getTrapIsNullTargetIsProxy() { + String js = + "var stringTarget = new Proxy(new String('str'), {});\n" + + "var stringProxy = new Proxy(stringTarget, {\n" + + " get: null,\n" + + "});\n" + + "'' + stringProxy.length" + + " + ' ' + stringProxy[0]" + + " + ' ' + stringProxy[4];"; + testString("3 s undefined", js); + } + + @Test + public void getTrapIsNullTargetIsProxy2() { + String js = + "var sym = Symbol();\n" + + "var target = new Proxy({}, {\n" + + " get: function(_target, key) {\n" + + " switch (key) {\n" + + " case sym: return 1;\n" + + " case \"10\": return 2;\n" + + " case \"foo\": return 3;\n" + + " }\n" + + " },\n" + + "});\n" + + "var proxy = new Proxy(target, {\n" + + " get: null,\n" + + "});\n" + + "'' + proxy[sym]" + + " + ' ' + proxy[10]" + + " + ' ' + Object.create(proxy).foo" + + " + ' ' + proxy.bar;"; + testString("1 2 3 undefined", js); + } + + @Test + public void setTrap() { + String js = + "var res = '';\n" + + "var proxy = new Proxy({}, {\n" + + " set(obj, prop, value) {\n" + + " res += value + ' ' + (value instanceof Array);\n" + + " obj[prop] = value;\n" + + " return true;\n" + + " },\n" + + "});\n" + + "proxy.foo = [1, 2, 3];\n" + + "res"; + + testString("1,2,3 true", js); + } + + @Test + public void getPropertyByIntWithoutHandler() { + String js = "var a = ['zero', 'one'];" + "var proxy1 = new Proxy(a, {});\n" + "proxy1[1];"; + testString("one", js); + } + + @Test + public void getProperty() { + String js = + "var o = {};\n" + + "o.p1 = 'value 1';\n" + + "var proxy1 = new Proxy(o, { get: function(t, prop) {\n" + + " return t[prop] + '!';\n" + + " }});\n" + + "var result = ''\n;" + + "result += proxy1.p1;\n" + + "Object.defineProperty(o, 'p3', { get: function() { return 'foo'; } });\n" + + "result += ', ' + proxy1.p3;\n" + + "var o2 = Object.create({ p: 42 });\n" + + "var proxy2 = new Proxy(o2, {});\n" + + "result += ', ' + proxy2.p;\n" + + "result += ', ' + proxy2.u;\n"; + + testString("value 1!, foo!, 42, undefined", js); + } + + @Test + public void getPropertyParameters() { + String js = + "var _target, _handler, _prop, _receiver;\n" + + "var target = {\n" + + " attr: 1\n" + + "};\n" + + "var handler = {\n" + + " get: function(t, prop, receiver) {\n" + + " _handler = this;\n" + + " _target = t;\n" + + " _prop = prop;\n" + + " _receiver = receiver;\n" + + " }\n" + + "};\n" + + "var p = new Proxy(target, handler);\r\n" + + "p.attr;\n" + + "var res = '' + (_handler === handler)\n" + + "+ ' ' + (_target === target)" + + "+ ' ' + (_prop == 'attr')" + + "+ ' ' + (_receiver === p);" + + "_prop = null;\n" + + "p['attr'];\n" + + "res + ' ' + (_prop == 'attr')"; + + testString("true true true true true", js); + } + + @Test + public void getPropertyWithoutHandler() { + String js = + "var o = {};\n" + + "o.p1 = 'value 1';\n" + + "var proxy1 = new Proxy(o, {});\n" + + "var result = ''\n;" + + "result += proxy1.p1;\n" + + "Object.defineProperty(o, 'p2', { get: undefined });\n" + + "result += ', ' + proxy1.p2;\n" + + "Object.defineProperty(o, 'p3', { get: function() { return 'foo'; } });\n" + + "result += ', ' + proxy1.p3;\n" + + "var o2 = Object.create({ p: 42 });\n" + + "var proxy2 = new Proxy(o2, {});\n" + + "result += ', ' + proxy2.p;\n" + + "result += ', ' + proxy2.u;\n"; + + testString("value 1, undefined, foo, 42, undefined", js); + } + + @Test + public void getPrototypeOfNull() { + String js = + "var plainObjectTarget = new Proxy(Object.create(null), {});\n" + + "var plainObjectProxy = new Proxy(plainObjectTarget, {\n" + + " getPrototypeOf: null,\n" + + "});\n" + + "'' + Object.getPrototypeOf(plainObjectProxy);\n"; + testString("null", js); + } + + @Test + public void setPrototypeOfWithoutHandler() { + String js = + "var o1 = {};\n" + + "var result = '';\n" + + "result += Reflect.setPrototypeOf(o1, Object.prototype);\n" + + "result += ' ' + Reflect.setPrototypeOf(o1, null);\n" + + "var o2 = {};\n" + + "result += ' ' + Reflect.setPrototypeOf(Object.freeze(o2), null);\n"; + testString("true true false", js); + } + + @Test + public void setPrototypeOfCycleWithoutHandler() { + String js = "var o1 = {};\n" + "'' + Reflect.setPrototypeOf(o1, o1);\n"; + testString("false", js); + } + + @Test + public void setPrototypeOfCycleComplexWithoutHandler() { + String js = + "var o1 = {};\n" + + "var o2 = {};\n" + + "var o3 = {};\n" + + "'' + Reflect.setPrototypeOf(o1, o2)" + + "+ ' ' + Reflect.setPrototypeOf(o2, o3)" + + "+ ' ' + Reflect.setPrototypeOf(o3, o1)"; + testString("true true false", js); + } + + @Test + public void setPrototypeOfSameWithoutHandler() { + String js = + "var o1 = {};\n" + + "Object.preventExtensions(o1);\n" + + "var o2 = Object.create(null);\n" + + "Object.preventExtensions(o2);\n" + + "var proto = {};\n" + + "var o3 = Object.create(proto);\n" + + "Object.preventExtensions(o3);\n" + + "'' + Reflect.setPrototypeOf(o1, Object.prototype)" + + "+ ' ' + Reflect.setPrototypeOf(o2, null)" + + "+ ' ' + Reflect.setPrototypeOf(o3, proto)"; + testString("true true true", js); + } + + @Test + public void typeof() { + testString("object", "typeof new Proxy({}, {})"); + testString("function", "typeof new Proxy(function() {}, {})"); + } + + @Test + public void typeofRevocable() { + testString("object", "var rev = Proxy.revocable({}, {}); rev.revoke(); typeof rev.proxy"); + testString( + "function", + "var rev = Proxy.revocable(function() {}, {}); rev.revoke(); typeof rev.proxy"); + + String js = + "var revocableTarget = Proxy.revocable(function() {}, {});\n" + + "revocableTarget.revoke();\n" + + "var revocable = Proxy.revocable(revocableTarget.proxy, {});\n" + + "'' + typeof revocable.proxy;\n"; + testString("function", js); + } + + @Test + public void revocableFunctionIsAnonymous() { + String js = + "var rev = Proxy.revocable({}, {}).revoke;\n" + + "var desc = Object.getOwnPropertyDescriptor(rev, 'name');\n" + + "'' + desc.name + ' ' + desc.value " + + "+ ' ' + desc.writable " + + "+ ' ' + desc.enumerable " + + "+ ' ' + desc.configurable"; + testString("undefined false false true", js); + } + + @Test + public void revocableGetPrototypeOf() { + testString( + "TypeError: Illegal operation attempted on a revoked proxy", + "var rev = Proxy.revocable({}, {}); rev.revoke(); " + + "try { Object.getPrototypeOf(rev.proxy); } catch(e) { '' + e }"); + } + + private static void testString(String expected, String js) { + Utils.runWithAllOptimizationLevels( + cx -> { + cx.setLanguageVersion(Context.VERSION_ES6); + final Scriptable scope = cx.initStandardObjects(); + + Object result = cx.evaluateString(scope, js, "test", 1, null); + assertEquals(expected, result); + + return null; + }); + } + + private static void testDouble(double expected, String js) { + Utils.runWithAllOptimizationLevels( + cx -> { + cx.setLanguageVersion(Context.VERSION_ES6); + final Scriptable scope = cx.initStandardObjects(); + + Object result = cx.evaluateString(scope, js, "test", 1, null); + assertEquals(expected, ((Double) result).doubleValue(), 0.00001); + + return null; + }); + } +} diff --git a/testsrc/org/mozilla/javascript/tests/es6/NativeReflectTest.java b/testsrc/org/mozilla/javascript/tests/es6/NativeReflectTest.java new file mode 100644 index 0000000000..619cd4186b --- /dev/null +++ b/testsrc/org/mozilla/javascript/tests/es6/NativeReflectTest.java @@ -0,0 +1,501 @@ +package org.mozilla.javascript.tests.es6; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.tests.Utils; + +public class NativeReflectTest { + + @Test + public void testToString() { + testString("[object Reflect]", "Reflect.toString()"); + } + + @Test + public void apply() { + testDouble(1.0, "Reflect.apply(Math.floor, undefined, [1.75])"); + testString( + "hello", + "Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111])"); + testInt(4, "Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index"); + testString("i", "Reflect.apply(''.charAt, 'ponies', [3])"); + } + + @Test + public void applyString() { + testString("foo", "Reflect.apply(String.prototype.toString, 'foo', [])"); + testString("oo", "Reflect.apply(String.prototype.substring, 'foo', [1])"); + } + + @Test + public void applyNumber() { + testString("1.234567e+3", "Reflect.apply(Number.prototype.toExponential, 1234.567, [])"); + testString("1.23e+3", "Reflect.apply(Number.prototype.toExponential, 1234.567, [2])"); + } + + @Test + public void applyBoolean() { + testString("true", "Reflect.apply(Boolean.prototype.toString, true, [])"); + testString("false", "Reflect.apply(Boolean.prototype.toString, false, [])"); + } + + @Test + public void applyDetails() { + String js = + "var o = {};\n" + + "var count = 0;\n" + + "var results, args;\n" + + "function fn() {\n" + + " count++;\n" + + " results = {\n" + + " thisArg: this,\n" + + " args: arguments\n" + + " };\n" + + "}\n" + + "Reflect.apply(fn, o, ['arg1', 2, , null]);\n" + + "'' + count " + + "+ ' ' + (results.thisArg === o)" + + "+ ' ' + results.args.length" + + "+ ' ' + results.args[0]" + + "+ ' ' + results.args[1]" + + "+ ' ' + results.args[2]" + + "+ ' ' + results.args[3]"; + testString("1 true 4 arg1 2 undefined null", js); + } + + @Test + public void applyMissingArgs() { + String js = "try {\n" + " Reflect.apply();\n" + "} catch(e) {\n" + " '' + e;\n" + "}"; + testString( + "TypeError: Reflect.apply: At least 3 arguments required, but only 0 passed", js); + } + + @Test + public void applyTargetNotFunction() { + String js = + "try {\n" + + " Reflect.apply({}, undefined, [1.75]);\n" + + "} catch(e) {\n" + + " '' + e;\n" + + "}"; + testString("TypeError: [object Object] is not a function, it is object.", js); + } + + @Test + public void applyArgumentsListNotFunction() { + String js = + "var s1 = Symbol('1');" + + "try {\n" + + " Reflect.apply(Math.floor, undefined, s1);\n" + + "} catch(e) {\n" + + " '' + e;\n" + + "}"; + testString("TypeError: Expected argument of type object, but instead had type symbol", js); + } + + @Test + public void construct() { + String js = + "var d = Reflect.construct(Date, [1776, 6, 4]);\n" + + "'' + (d instanceof Date) + ' ' + d.getFullYear();"; + testString("true 1776", js); + } + + @Test + public void constructNewTarget() { + String js = + "var o = {};\n" + + "var internPrototype;\n" + + "function fn() {\n" + + " this.o = o;\n" + + " internPrototype = Object.getPrototypeOf(this);\n" + + "}\n" + + "var result = Reflect.construct(fn, [], Array);\n" + + "'' + (Object.getPrototypeOf(result) === Array.prototype)" + + " + ' ' + (internPrototype === Array.prototype)" + + " + ' ' + (result.o === o)"; + testString("true true true", js); + } + + @Test + public void constructNoConstructorNumber() { + String js = + "try {\n" + + " Reflect.construct(function() {}, [], 1);\n" + + "} catch(e) {\n" + + " '' + e;\n" + + "}"; + testString("TypeError: \"number\" is not a constructor.", js); + } + + @Test + public void constructNoConstructorNull() { + String js = + "try {\n" + + " Reflect.construct(function() {}, [], null);\n" + + "} catch(e) {\n" + + " '' + e;\n" + + "}"; + testString("TypeError: \"object\" is not a constructor.", js); + } + + @Test + public void constructNoConstructorObject() { + String js = + "try {\n" + + " Reflect.construct(function() {}, [], {});\n" + + "} catch(e) {\n" + + " '' + e;\n" + + "}"; + testString("TypeError: \"object\" is not a constructor.", js); + } + + @Test + public void constructNoConstructorFunction() { + String js = + "try {\n" + + " Reflect.construct(function() {}, [], Date.now);\n" + + "} catch(e) {\n" + + " '' + e;\n" + + "}"; + // testString("TypeError: \"object\" is not a constructor.", js); + // found no way to check a function for constructor + } + + @Test + public void constructorArgs() { + final String script = + " var res = '';\n" + + "function foo(a, b) {\n" + + " res += 'foo - ';\n" + + " for (let i = 0; i < arguments.length; i++) {\n" + + " res += arguments[i] + ' ';\n" + + " }\n" + + "}\n" + + "Reflect.construct(foo, [1, 2]);\n" + + "res;"; + + testString("foo - 1 2 ", script); + } + + @Test + public void constructorArgsWithTarget() { + final String script = + " var res = '';\n" + + "function foo(a, b) {\n" + + " res += 'foo - ';\n" + + " for (let i = 0; i < arguments.length; i++) {\n" + + " res += arguments[i] + ' ';\n" + + " }\n" + + "}\n" + + "function bar(a, b) {\n" + + " res += 'bar - ';\n" + + " for (let i = 0; i < arguments.length; i++) {\n" + + " res += arguments[i] + ' ';\n" + + " }\n" + + "}\n" + + "Reflect.construct(foo, [6, 7, 8], bar);\n" + + "res;"; + + testString("foo - 6 7 8 ", script); + } + + @Test + public void defineProperty() { + String js = + "var o = {};\n" + "'' + Reflect.defineProperty(o, 'p', { value: 42 }) + ' ' + o.p;"; + testString("true 42", js); + } + + @Test + public void definePropertyWithoutValue() { + String js = + "var o = {};\n" + + "'' + Reflect.defineProperty(o, 'p', {})" + + "+ ' ' + Reflect.has(o, 'p')" + + "+ ' ' + o.p;"; + testString("true true undefined", js); + } + + @Test + public void definePropertyFreezed() { + String js = + "var o = {};\n" + + "Object.freeze(o);\n" + + "'' + Reflect.defineProperty(o, 'p', { value: 42 }) + ' ' + o.p;"; + testString("false undefined", js); + } + + @Test + public void deleteProperty() { + String js = + "var o = { p: 42 };\n" + + "'' + Reflect.deleteProperty(o, 'p')" + + "+ ' ' + Reflect.has(o, 'p')" + + "+ ' ' + o.p;"; + testString("true false undefined", js); + } + + @Test + public void getOwnPropertyDescriptor() { + String js = + "var o1 = {};\n" + + "var fn = function() {};\n" + + "Object.defineProperty(o1, 'p', {\n" + + " get: fn,\n" + + " configurable: true\n" + + "});\n" + + "var result = Reflect.getOwnPropertyDescriptor(o1, 'p');\n" + + "'[' + Object.getOwnPropertyNames(result) + ']'" + + "+ ' ' + result.enumerable" + + "+ ' ' + result.configurable" + + "+ ' ' + (result.get === fn)" + + "+ ' ' + (result.set === undefined)"; + testString("[get,set,enumerable,configurable] false true true true", js); + } + + @Test + public void isExtensible() { + String js = + "var o1 = {};\n" + + "var result = '' + Reflect.isExtensible(o1);\n" + + "Reflect.preventExtensions(o1);\n" + + "result += ' ' + Reflect.isExtensible(o1);\n" + + "var o2 = Object.seal({});\n" + + "result += ' ' + Reflect.isExtensible(o2);\n"; + + testString("true false false", js); + } + + @Test + public void ownKeys() { + String js = + "var o1 = {\n" + + " p1: 42,\n" + + " p2: 'one'\n" + + "};\n" + + "var a1 = [];\n" + + "'' + Reflect.ownKeys(o1)" + + "+ ' ' + Reflect.ownKeys(a1)"; + testString("p1,p2 length", js); + } + + @Test + public void ownKeys2() { + String js = + "let s1 = Symbol.for('foo');\n" + + "let s2 = Symbol.for('bar');\n" + + "var o1 = {\n" + + " s1: 0,\n" + + " 'str': 0,\n" + + " 773: 0,\n" + + " '55': 0,\n" + + " 0: 0,\n" + + " '-1': 0,\n" + + " 8: 0,\n" + + " '6': 8,\n" + + " s2: 0,\n" + + " 'str2': 0\n" + + "};\n" + + "var a1 = [];\n" + + "'' + Reflect.ownKeys(o1)"; + testString("0,6,8,55,773,s1,str,-1,s2,str2", js); + } + + @Test + public void ownKeysEmptyObj() { + String js = "'' + Reflect.ownKeys({}).length"; + testString("0", js); + } + + @Test + public void ownKeysDeleteObj() { + String js = "var o = { d: 42 };\n" + "delete o.d;\n" + "'' + Reflect.ownKeys(o).length"; + testString("0", js); + } + + @Test + public void ownKeysEmptyArray() { + String js = "'' + Reflect.ownKeys([])"; + testString("length", js); + } + + @Test + public void ownKeysArray() { + String js = "'' + Reflect.ownKeys([, , 2])"; + testString("2,length", js); + } + + @Test + public void ownKeysNotEnumerable() { + String js = + "var o = {};\n" + + "Object.defineProperty(o, 'p1', { value: 42, enumerable: false });\n" + + "Object.defineProperty(o, 'p2', { get: function() {}, enumerable: false });\n" + + "'' + Reflect.ownKeys(o)"; + testString("p1,p2", js); + } + + @Test + public void has() { + String js = + "var o1 = { p: 42 }\n" + + "'' + Reflect.has(o1, 'p')" + + "+ ' ' + Reflect.has(o1, 'p2')" + + "+ ' ' + Reflect.has(o1, 'toString')"; + testString("true false true", js); + } + + @Test + public void hasSymbol() { + String js = + "var s1 = Symbol('1');\n" + + "var s2 = Symbol('1');\n" + + "var o = {};\n" + + "o[s1] = 42;\n" + + "'' + Reflect.has(o, s1)" + + "+ ' ' + Reflect.has(o, 2)"; + testString("true false", js); + } + + @Test + public void hasProto() { + String js = "var o1 = { p: 42 }\n" + "'' + typeof Reflect.has.__proto__"; + testString("function", js); + } + + @Test + public void getOwnPropertyDescriptorSymbol() { + String js = + "var s = Symbol('sym');\n" + + "var o = {};\n" + + "o[s] = 42;\n" + + "var result = Reflect.getOwnPropertyDescriptor(o, s);\n" + + "'' + result.value" + + "+ ' ' + result.enumerable" + + "+ ' ' + result.configurable" + + "+ ' ' + result.writable"; + testString("42 true true true", js); + } + + @Test + public void getOwnPropertyDescriptorUndefinedProperty() { + String js = + "var o = Object.create({p: 1});\n" + + "var result = Reflect.getOwnPropertyDescriptor(o, 'p');\n" + + "'' + (result === undefined)"; + testString("true", js); + } + + @Test + public void getPropertyByInt() { + String js = "var a = ['zero', 'one']\n" + "Reflect.get(a, 1);"; + testString("one", js); + } + + @Test + public void getProperty() { + String js = + "var o = {};\n" + + "o.p1 = 'value 1';\n" + + "var result = '';" + + "result += Reflect.get(o, 'p1');\n" + + "Object.defineProperty(o, 'p2', { get: undefined });\n" + + "result += ', ' + Reflect.get(o, 'p2');\n" + + "Object.defineProperty(o, 'p3', { get: function() { return 'foo'; } });\n" + + "result += ', ' + Reflect.get(o, 'p3');\n" + + "var o2 = Object.create({ p: 42 });\n" + + "result += ', ' + Reflect.get(o2, 'p');\n" + + "result += ', ' + Reflect.get(o2, 'u');\n"; + + testString("value 1, undefined, foo, 42, undefined", js); + } + + @Test + public void setPrototypeOf() { + String js = + "var o1 = {};\n" + + "var result = '';\n" + + "result += Reflect.setPrototypeOf(o1, Object.prototype);\n" + + "result += ' ' + Reflect.setPrototypeOf(o1, null);\n" + + "var o2 = {};\n" + + "result += ' ' + Reflect.setPrototypeOf(Object.freeze(o2), null);\n"; + testString("true true false", js); + } + + @Test + public void setPrototypeOfCycle() { + String js = "var o1 = {};\n" + "'' + Reflect.setPrototypeOf(o1, o1);\n"; + testString("false", js); + } + + @Test + public void setPrototypeOfCycleComplex() { + String js = + "var o1 = {};\n" + + "var o2 = {};\n" + + "var o3 = {};\n" + + "'' + Reflect.setPrototypeOf(o1, o2)" + + "+ ' ' + Reflect.setPrototypeOf(o2, o3)" + + "+ ' ' + Reflect.setPrototypeOf(o3, o1)"; + testString("true true false", js); + } + + @Test + public void setPrototypeOfSame() { + String js = + "var o1 = {};\n" + + "Object.preventExtensions(o1);\n" + + "var o2 = Object.create(null);\n" + + "Object.preventExtensions(o2);\n" + + "var proto = {};\n" + + "var o3 = Object.create(proto);\n" + + "Object.preventExtensions(o3);\n" + + "'' + Reflect.setPrototypeOf(o1, Object.prototype)" + + "+ ' ' + Reflect.setPrototypeOf(o2, null)" + + "+ ' ' + Reflect.setPrototypeOf(o3, proto)"; + testString("true true true", js); + } + + private static void testString(String expected, String js) { + Utils.runWithAllOptimizationLevels( + cx -> { + cx.setLanguageVersion(Context.VERSION_ES6); + final Scriptable scope = cx.initStandardObjects(); + + Object result = cx.evaluateString(scope, js, "test", 1, null); + assertEquals(expected, result); + + return null; + }); + } + + private static void testDouble(double expected, String js) { + Utils.runWithAllOptimizationLevels( + cx -> { + cx.setLanguageVersion(Context.VERSION_ES6); + final Scriptable scope = cx.initStandardObjects(); + + Object result = cx.evaluateString(scope, js, "test", 1, null); + assertEquals(expected, ((Double) result).doubleValue(), 0.00001); + + return null; + }); + } + + private static void testInt(int expected, String js) { + Utils.runWithAllOptimizationLevels( + cx -> { + cx.setLanguageVersion(Context.VERSION_ES6); + final Scriptable scope = cx.initStandardObjects(); + + Object result = cx.evaluateString(scope, js, "test", 1, null); + assertEquals(expected, ((Integer) result).intValue()); + + return null; + }); + } +} diff --git a/testsrc/test262.properties b/testsrc/test262.properties index 30b5b4c2af..673a57abf8 100644 --- a/testsrc/test262.properties +++ b/testsrc/test262.properties @@ -1,6 +1,6 @@ # This is a configuration file for Test262SuiteTest.java. See ./README.md for more info about this file -built-ins/Array 177/2670 (6.63%) +built-ins/Array 159/2670 (5.96%) from/calling-from-valid-1-noStrict.js non-strict Spec pretty clearly says this should be undefined from/elements-deleted-after.js Checking to see if length changed, but spec says it should not from/iter-map-fn-this-non-strict.js non-strict Error propagation needs work in general @@ -12,15 +12,11 @@ built-ins/Array 177/2670 (6.63%) from/source-object-iterator-2.js Uses "get" syntax that's not implemented from/source-object-length-set-elem-prop-err.js from/source-object-length-set-elem-prop-non-writable.js - isArray/proxy.js {unsupported: [Proxy]} - isArray/proxy-revoked.js {unsupported: [Proxy]} - length/define-own-prop-length-coercion-order.js {unsupported: [Reflect]} - length/define-own-prop-length-coercion-order-set.js {unsupported: [Reflect, Reflect.set]} - length/define-own-prop-length-no-value-order.js {unsupported: [Reflect]} + length/define-own-prop-length-coercion-order.js + length/define-own-prop-length-coercion-order-set.js + length/define-own-prop-length-no-value-order.js length/define-own-prop-length-overflow-order.js of/proto-from-ctor-realm.js - of/return-abrupt-from-data-property-using-proxy.js {unsupported: [Proxy]} - prototype/concat/arg-length-exceeding-integer-limit.js {unsupported: [Proxy]} prototype/concat/Array.prototype.concat_large-typed-array.js new prototype/concat/Array.prototype.concat_non-array.js prototype/concat/Array.prototype.concat_small-typed-array.js @@ -28,8 +24,7 @@ built-ins/Array 177/2670 (6.63%) prototype/concat/create-ctor-poisoned.js prototype/concat/create-proto-from-ctor-realm-array.js {unsupported: [Symbol.species]} prototype/concat/create-proto-from-ctor-realm-non-array.js {unsupported: [Symbol.species]} - prototype/concat/create-proxy.js {unsupported: [Proxy, Symbol.species]} - prototype/concat/create-revoked-proxy.js {unsupported: [Proxy]} + prototype/concat/create-proxy.js {unsupported: [Symbol.species]} prototype/concat/create-species.js {unsupported: [Symbol.species]} prototype/concat/create-species-abrupt.js {unsupported: [Symbol.species]} prototype/concat/create-species-non-ctor.js {unsupported: [Symbol.species]} @@ -43,22 +38,16 @@ built-ins/Array 177/2670 (6.63%) prototype/concat/create-species-with-non-writable-property.js {unsupported: [Symbol.species]} prototype/concat/create-species-with-non-writable-property-spreadable.js {unsupported: [Symbol.species]} prototype/concat/is-concat-spreadable-get-order.js - prototype/concat/is-concat-spreadable-is-array-proxy-revoked.js {unsupported: [Proxy]} - prototype/concat/is-concat-spreadable-proxy.js {unsupported: [Proxy]} - prototype/concat/is-concat-spreadable-proxy-revoked.js {unsupported: [Proxy]} prototype/copyWithin/coerced-values-start-change-start.js prototype/copyWithin/coerced-values-start-change-target.js - prototype/copyWithin/return-abrupt-from-delete-proxy-target.js {unsupported: [Proxy]} prototype/copyWithin/return-abrupt-from-delete-target.js non-strict Not throwing properly on unwritable - prototype/copyWithin/return-abrupt-from-has-start.js {unsupported: [Proxy]} prototype/every/15.4.4.16-5-1-s.js non-strict prototype/filter/15.4.4.20-5-1-s.js non-strict prototype/filter/create-ctor-non-object.js prototype/filter/create-ctor-poisoned.js prototype/filter/create-proto-from-ctor-realm-array.js {unsupported: [Symbol.species]} prototype/filter/create-proto-from-ctor-realm-non-array.js {unsupported: [Symbol.species]} - prototype/filter/create-proxy.js {unsupported: [Proxy, Symbol.species]} - prototype/filter/create-revoked-proxy.js {unsupported: [Proxy]} + prototype/filter/create-proxy.js {unsupported: [Symbol.species]} prototype/filter/create-species.js {unsupported: [Symbol.species]} prototype/filter/create-species-abrupt.js {unsupported: [Symbol.species]} prototype/filter/create-species-non-ctor.js {unsupported: [Symbol.species]} @@ -88,25 +77,22 @@ built-ins/Array 177/2670 (6.63%) prototype/flat/target-array-with-non-configurable-property.js {unsupported: [Symbol.species]} prototype/flat/target-array-with-non-writable-property.js {unsupported: [Symbol.species]} prototype/forEach/15.4.4.18-5-1-s.js non-strict - prototype/includes/get-prop.js {unsupported: [Proxy]} - prototype/indexOf/calls-only-has-on-prototype-after-length-zeroed.js {unsupported: [Proxy]} + prototype/indexOf/calls-only-has-on-prototype-after-length-zeroed.js prototype/indexOf/length-zero-returns-minus-one.js - prototype/lastIndexOf/calls-only-has-on-prototype-after-length-zeroed.js {unsupported: [Proxy]} + prototype/lastIndexOf/calls-only-has-on-prototype-after-length-zeroed.js prototype/lastIndexOf/length-zero-returns-minus-one.js prototype/map/15.4.4.19-5-1-s.js non-strict prototype/map/create-ctor-non-object.js prototype/map/create-ctor-poisoned.js prototype/map/create-proto-from-ctor-realm-array.js {unsupported: [Symbol.species]} prototype/map/create-proto-from-ctor-realm-non-array.js {unsupported: [Symbol.species]} - prototype/map/create-proxy.js {unsupported: [Proxy, Symbol.species]} - prototype/map/create-revoked-proxy.js {unsupported: [Proxy]} + prototype/map/create-proxy.js {unsupported: [Symbol.species]} prototype/map/create-species.js {unsupported: [Symbol.species]} prototype/map/create-species-abrupt.js {unsupported: [Symbol.species]} prototype/map/create-species-non-ctor.js {unsupported: [Symbol.species]} prototype/map/create-species-null.js {unsupported: [Symbol.species]} prototype/map/create-species-poisoned.js {unsupported: [Symbol.species]} prototype/map/create-species-undef.js {unsupported: [Symbol.species]} - prototype/map/create-species-undef-invalid-len.js {unsupported: [Proxy]} prototype/map/target-array-non-extensible.js {unsupported: [Symbol.species]} prototype/map/target-array-with-non-configurable-property.js {unsupported: [Symbol.species]} prototype/map/target-array-with-non-writable-property.js {unsupported: [Symbol.species]} @@ -123,9 +109,7 @@ built-ins/Array 177/2670 (6.63%) prototype/slice/create-ctor-poisoned.js prototype/slice/create-proto-from-ctor-realm-array.js {unsupported: [Symbol.species]} prototype/slice/create-proto-from-ctor-realm-non-array.js {unsupported: [Symbol.species]} - prototype/slice/create-proxied-array-invalid-len.js {unsupported: [Proxy]} - prototype/slice/create-proxy.js {unsupported: [Proxy, Symbol.species]} - prototype/slice/create-revoked-proxy.js {unsupported: [Proxy]} + prototype/slice/create-proxy.js {unsupported: [Symbol.species]} prototype/slice/create-species.js {unsupported: [Symbol.species]} prototype/slice/create-species-abrupt.js {unsupported: [Symbol.species]} prototype/slice/create-species-neg-zero.js {unsupported: [Symbol.species]} @@ -133,7 +117,6 @@ built-ins/Array 177/2670 (6.63%) prototype/slice/create-species-null.js {unsupported: [Symbol.species]} prototype/slice/create-species-poisoned.js {unsupported: [Symbol.species]} prototype/slice/create-species-undef.js {unsupported: [Symbol.species]} - prototype/slice/length-exceeding-integer-limit-proxied-array.js prototype/slice/target-array-non-extensible.js {unsupported: [Symbol.species]} prototype/slice/target-array-with-non-configurable-property.js {unsupported: [Symbol.species]} prototype/slice/target-array-with-non-writable-property.js {unsupported: [Symbol.species]} @@ -146,8 +129,8 @@ built-ins/Array 177/2670 (6.63%) prototype/splice/create-ctor-poisoned.js prototype/splice/create-proto-from-ctor-realm-array.js {unsupported: [Symbol.species]} prototype/splice/create-proto-from-ctor-realm-non-array.js {unsupported: [Symbol.species]} - prototype/splice/create-proxy.js {unsupported: [Proxy, Symbol.species]} - prototype/splice/create-revoked-proxy.js {unsupported: [Proxy]} + prototype/splice/create-proxy.js {unsupported: [Symbol.species]} + prototype/splice/create-revoked-proxy.js prototype/splice/create-species.js {unsupported: [Symbol.species]} prototype/splice/create-species-abrupt.js {unsupported: [Symbol.species]} prototype/splice/create-species-length-exceeding-integer-limit.js {unsupported: [Symbol.species]} @@ -156,8 +139,7 @@ built-ins/Array 177/2670 (6.63%) prototype/splice/create-species-null.js {unsupported: [Symbol.species]} prototype/splice/create-species-poisoned.js {unsupported: [Symbol.species]} prototype/splice/create-species-undef.js {unsupported: [Symbol.species]} - prototype/splice/create-species-undef-invalid-len.js {unsupported: [Proxy]} - prototype/splice/property-traps-order-with-species.js {unsupported: [Proxy, Symbol.species]} + prototype/splice/property-traps-order-with-species.js {unsupported: [Symbol.species]} prototype/splice/S15.4.4.12_A6.1_T2.js incorrect length handling prototype/splice/S15.4.4.12_A6.1_T3.js non-strict prototype/splice/set_length_no_args.js @@ -171,11 +153,11 @@ built-ins/Array 177/2670 (6.63%) prototype/methods-called-as-functions.js {unsupported: [Symbol.species]} prototype/Symbol.iterator.js Expects a particular string value Symbol.species 4/4 (100.0%) - proto-from-ctor-realm-one.js {unsupported: [Reflect]} - proto-from-ctor-realm-two.js {unsupported: [Reflect]} - proto-from-ctor-realm-zero.js {unsupported: [Reflect]} + proto-from-ctor-realm-one.js + proto-from-ctor-realm-two.js + proto-from-ctor-realm-zero.js -built-ins/ArrayBuffer 30/80 (37.5%) +built-ins/ArrayBuffer 29/80 (36.25%) isView/arg-is-dataview-subclass-instance.js {unsupported: [class]} isView/arg-is-typedarray-subclass-instance.js {unsupported: [class]} prototype/byteLength/detached-buffer.js @@ -198,10 +180,9 @@ built-ins/ArrayBuffer 30/80 (37.5%) prototype/slice/this-is-sharedarraybuffer.js {unsupported: [SharedArrayBuffer]} prototype/Symbol.toStringTag.js Symbol.species 4/4 (100.0%) - data-allocation-after-object-creation.js {unsupported: [Reflect.construct]} - newtarget-prototype-is-not-object.js {unsupported: [Reflect.construct]} - proto-from-ctor-realm.js {unsupported: [Reflect]} - prototype-from-newtarget.js {unsupported: [Reflect.construct]} + data-allocation-after-object-creation.js + proto-from-ctor-realm.js + prototype-from-newtarget.js undefined-newtarget-throws.js built-ins/ArrayIteratorPrototype 1/27 (3.7%) @@ -228,9 +209,9 @@ built-ins/BigInt 14/68 (20.59%) prototype/toString/thisbigintvalue-not-valid-throws.js Computed property is not support built-ins/Boolean 1/49 (2.04%) - proto-from-ctor-realm.js {unsupported: [Reflect]} + proto-from-ctor-realm.js -built-ins/DataView 166/455 (36.48%) +built-ins/DataView 164/455 (36.04%) prototype/buffer/detached-buffer.js prototype/buffer/invoked-as-accessor.js prototype/buffer/length.js @@ -370,13 +351,11 @@ built-ins/DataView 166/455 (36.48%) buffer-does-not-have-arraybuffer-data-throws-sab.js {unsupported: [SharedArrayBuffer]} buffer-reference-sab.js {unsupported: [SharedArrayBuffer]} byteoffset-is-negative-throws-sab.js {unsupported: [SharedArrayBuffer]} - custom-proto-access-detaches-buffer.js {unsupported: [Reflect.construct]} - custom-proto-access-throws.js {unsupported: [Reflect.construct]} - custom-proto-access-throws-sab.js {unsupported: [Reflect.construct, SharedArrayBuffer]} - custom-proto-if-not-object-fallbacks-to-default-prototype.js {unsupported: [Reflect.construct]} - custom-proto-if-not-object-fallbacks-to-default-prototype-sab.js {unsupported: [Reflect.construct, SharedArrayBuffer]} - custom-proto-if-object-is-used.js {unsupported: [Reflect.construct]} - custom-proto-if-object-is-used-sab.js {unsupported: [Reflect.construct, SharedArrayBuffer]} + custom-proto-access-detaches-buffer.js + custom-proto-access-throws.js + custom-proto-access-throws-sab.js {unsupported: [SharedArrayBuffer]} + custom-proto-if-not-object-fallbacks-to-default-prototype-sab.js {unsupported: [SharedArrayBuffer]} + custom-proto-if-object-is-used-sab.js {unsupported: [SharedArrayBuffer]} defined-bytelength-and-byteoffset-sab.js {unsupported: [SharedArrayBuffer]} defined-byteoffset-sab.js {unsupported: [SharedArrayBuffer]} defined-byteoffset-undefined-bytelength-sab.js {unsupported: [SharedArrayBuffer]} @@ -388,8 +367,8 @@ built-ins/DataView 166/455 (36.48%) negative-byteoffset-throws-sab.js {unsupported: [SharedArrayBuffer]} newtarget-undefined-throws.js newtarget-undefined-throws-sab.js {unsupported: [SharedArrayBuffer]} - proto-from-ctor-realm.js {unsupported: [Reflect]} - proto-from-ctor-realm-sab.js {unsupported: [SharedArrayBuffer, Reflect]} + proto-from-ctor-realm.js + proto-from-ctor-realm-sab.js {unsupported: [SharedArrayBuffer]} return-abrupt-tonumber-bytelength-sab.js {unsupported: [SharedArrayBuffer]} return-abrupt-tonumber-bytelength-symbol-sab.js {unsupported: [SharedArrayBuffer]} return-abrupt-tonumber-byteoffset-sab.js {unsupported: [SharedArrayBuffer]} @@ -398,7 +377,7 @@ built-ins/DataView 166/455 (36.48%) toindex-bytelength-sab.js {unsupported: [SharedArrayBuffer]} toindex-byteoffset-sab.js {unsupported: [SharedArrayBuffer]} -built-ins/Date 39/707 (5.52%) +built-ins/Date 38/707 (5.37%) prototype/setFullYear/15.9.5.40_1.js prototype/Symbol.toPrimitive/hint-default-first-invalid.js prototype/Symbol.toPrimitive/hint-default-first-non-callable.js @@ -414,7 +393,7 @@ built-ins/Date 39/707 (5.52%) prototype/Symbol.toPrimitive/name.js prototype/Symbol.toPrimitive/prop-desc.js prototype/Symbol.toPrimitive/this-val-non-obj.js - prototype/toJSON/builtin.js {unsupported: [Reflect.construct]} + prototype/toJSON/builtin.js prototype/toJSON/called-as-function.js prototype/toJSON/invoke-result.js prototype/toJSON/to-primitive-symbol.js @@ -423,10 +402,9 @@ built-ins/Date 39/707 (5.52%) prototype/no-date-value.js UTC/coercion-order.js coercion-order.js - proto-from-ctor-realm-one.js {unsupported: [Reflect]} - proto-from-ctor-realm-two.js {unsupported: [Reflect]} - proto-from-ctor-realm-zero.js {unsupported: [Reflect]} - subclassing.js {unsupported: [Reflect]} + proto-from-ctor-realm-one.js + proto-from-ctor-realm-two.js + proto-from-ctor-realm-zero.js value-get-symbol-to-prim-err.js value-symbol-to-prim-err.js value-symbol-to-prim-invocation.js @@ -460,13 +438,13 @@ built-ins/Error 5/42 (11.9%) prototype/toString/invalid-receiver.js prototype/no-error-data.js prototype/S15.11.4_A2.js - proto-from-ctor-realm.js {unsupported: [Reflect]} + proto-from-ctor-realm.js built-ins/eval 2/9 (22.22%) length-non-configurable.js private-identifiers-not-empty.js {unsupported: [class-fields-private]} -built-ins/Function 186/505 (36.83%) +built-ins/Function 185/505 (36.63%) internals/Call 2/2 (100.0%) internals/Construct 6/6 (100.0%) length/S15.3.5.1_A1_T3.js strict @@ -493,18 +471,18 @@ built-ins/Function 186/505 (36.83%) prototype/apply/S15.3.4.3_A7_T7.js non-interpreted prototype/apply/this-not-callable-realm.js prototype/bind/BoundFunction_restricted-properties.js - prototype/bind/get-fn-realm.js {unsupported: [Reflect]} - prototype/bind/get-fn-realm-recursive.js {unsupported: [Reflect]} - prototype/bind/instance-construct-newtarget-boundtarget.js {unsupported: [Reflect, new.target]} - prototype/bind/instance-construct-newtarget-boundtarget-bound.js {unsupported: [Reflect, new.target]} + prototype/bind/get-fn-realm.js + prototype/bind/get-fn-realm-recursive.js + prototype/bind/instance-construct-newtarget-boundtarget.js {unsupported: [new.target]} + prototype/bind/instance-construct-newtarget-boundtarget-bound.js {unsupported: [new.target]} prototype/bind/instance-construct-newtarget-self-new.js {unsupported: [new.target]} - prototype/bind/instance-construct-newtarget-self-reflect.js {unsupported: [Reflect, new.target]} + prototype/bind/instance-construct-newtarget-self-reflect.js {unsupported: [new.target]} prototype/bind/instance-length-exceeds-int32.js prototype/bind/instance-length-tointeger.js prototype/bind/instance-name.js prototype/bind/instance-name-chained.js prototype/bind/instance-name-error.js - prototype/bind/proto-from-ctor-realm.js {unsupported: [Reflect]} + prototype/bind/proto-from-ctor-realm.js prototype/call/15.3.4.4-1-s.js strict prototype/call/15.3.4.4-2-s.js strict prototype/call/15.3.4.4-3-s.js strict @@ -527,7 +505,7 @@ built-ins/Function 186/505 (36.83%) prototype/Symbol.hasInstance/this-val-bound-target.js prototype/Symbol.hasInstance/this-val-not-callable.js prototype/Symbol.hasInstance/this-val-poisoned-prototype.js - prototype/Symbol.hasInstance/value-get-prototype-of-err.js {unsupported: [Proxy]} + prototype/Symbol.hasInstance/value-get-prototype-of-err.js prototype/Symbol.hasInstance/value-negative.js prototype/Symbol.hasInstance/value-non-obj.js prototype/Symbol.hasInstance/value-positive.js @@ -550,7 +528,7 @@ built-ins/Function 186/505 (36.83%) prototype/toString/AsyncFunction.js {unsupported: [async-functions]} prototype/toString/AsyncGenerator.js {unsupported: [async-iteration]} prototype/toString/bound-function.js - prototype/toString/built-in-function-object.js {unsupported: [Reflect]} + prototype/toString/built-in-function-object.js prototype/toString/class-declaration-complex-heritage.js prototype/toString/class-declaration-explicit-ctor.js prototype/toString/class-declaration-implicit-ctor.js @@ -582,17 +560,16 @@ built-ins/Function 186/505 (36.83%) prototype/toString/private-method-class-statement.js prototype/toString/private-static-method-class-expression.js prototype/toString/private-static-method-class-statement.js - prototype/toString/proxy-arrow-function.js {unsupported: [Proxy]} - prototype/toString/proxy-async-function.js {unsupported: [Proxy, async-functions]} - prototype/toString/proxy-async-generator-function.js {unsupported: [Proxy, async-iteration]} - prototype/toString/proxy-async-generator-method-definition.js {unsupported: [Proxy, async-iteration]} - prototype/toString/proxy-async-method-definition.js {unsupported: [Proxy, async-functions]} - prototype/toString/proxy-bound-function.js {unsupported: [Proxy]} - prototype/toString/proxy-class.js {unsupported: [Proxy, class]} - prototype/toString/proxy-function-expression.js {unsupported: [Proxy]} - prototype/toString/proxy-generator-function.js {unsupported: [Proxy]} - prototype/toString/proxy-method-definition.js {unsupported: [Proxy]} - prototype/toString/proxy-non-callable-throws.js {unsupported: [Proxy]} + prototype/toString/proxy-arrow-function.js + prototype/toString/proxy-async-function.js {unsupported: [async-functions]} + prototype/toString/proxy-async-generator-function.js {unsupported: [async-iteration]} + prototype/toString/proxy-async-generator-method-definition.js {unsupported: [async-iteration]} + prototype/toString/proxy-async-method-definition.js {unsupported: [async-functions]} + prototype/toString/proxy-bound-function.js + prototype/toString/proxy-class.js {unsupported: [class]} + prototype/toString/proxy-function-expression.js + prototype/toString/proxy-generator-function.js + prototype/toString/proxy-method-definition.js prototype/toString/setter-class-expression.js prototype/toString/setter-class-expression-static.js prototype/toString/setter-class-statement.js @@ -644,8 +621,8 @@ built-ins/Function 186/505 (36.83%) call-bind-this-realm-undef.js call-bind-this-realm-value.js private-identifiers-not-empty.js {unsupported: [class-fields-private]} - proto-from-ctor-realm.js {unsupported: [Reflect]} - proto-from-ctor-realm-prototype.js {unsupported: [Reflect]} + proto-from-ctor-realm.js + proto-from-ctor-realm-prototype.js StrictFunction_restricted-properties.js strict ~built-ins/GeneratorFunction @@ -691,46 +668,38 @@ built-ins/isNaN 7/16 (43.75%) ~built-ins/IteratorPrototype -built-ins/JSON 34/140 (24.29%) - parse/builtin.js {unsupported: [Reflect.construct]} - parse/revived-proxy.js {unsupported: [Proxy]} - parse/revived-proxy-revoked.js {unsupported: [Proxy]} - parse/reviver-array-define-prop-err.js {unsupported: [Proxy]} - parse/reviver-array-delete-err.js {unsupported: [Proxy]} +built-ins/JSON 26/140 (18.57%) + parse/builtin.js + parse/revived-proxy.js + parse/reviver-array-define-prop-err.js parse/reviver-array-get-prop-from-prototype.js - parse/reviver-array-length-coerce-err.js {unsupported: [Proxy]} - parse/reviver-array-length-get-err.js {unsupported: [Proxy]} + parse/reviver-array-length-coerce-err.js + parse/reviver-array-length-get-err.js parse/reviver-call-order.js - parse/reviver-object-define-prop-err.js {unsupported: [Proxy]} - parse/reviver-object-delete-err.js {unsupported: [Proxy]} + parse/reviver-object-define-prop-err.js parse/reviver-object-get-prop-from-prototype.js parse/reviver-object-non-configurable-prop-create.js parse/reviver-object-non-configurable-prop-delete.js strict - parse/reviver-object-own-keys-err.js {unsupported: [Proxy]} parse/text-negative-zero.js - stringify/builtin.js {unsupported: [Reflect.construct]} - stringify/replacer-array-abrupt.js {unsupported: [Proxy]} - stringify/replacer-array-proxy.js {unsupported: [Proxy]} - stringify/replacer-array-proxy-revoked.js {unsupported: [Proxy]} - stringify/replacer-array-proxy-revoked-realm.js {unsupported: [Proxy]} - stringify/replacer-array-wrong-type.js {unsupported: [Proxy]} + stringify/builtin.js + stringify/replacer-array-abrupt.js + stringify/replacer-array-proxy.js + stringify/replacer-array-wrong-type.js stringify/replacer-function-arguments.js stringify/replacer-function-object-deleted-property.js stringify/replacer-function-result.js - stringify/value-array-abrupt.js {unsupported: [Proxy]} - stringify/value-array-proxy.js {unsupported: [Proxy]} - stringify/value-array-proxy-revoked.js {unsupported: [Proxy]} + stringify/value-array-abrupt.js + stringify/value-array-proxy.js stringify/value-bigint-cross-realm.js stringify/value-bigint-tojson-receiver.js - stringify/value-object-proxy.js {unsupported: [Proxy]} - stringify/value-object-proxy-revoked.js {unsupported: [Proxy]} + stringify/value-object-proxy.js stringify/value-string-escape-ascii.js stringify/value-string-escape-unicode.js built-ins/Map 6/145 (4.14%) Symbol.species 4/4 (100.0%) iterator-is-undefined-throws.js - proto-from-ctor-realm.js {unsupported: [Reflect]} + proto-from-ctor-realm.js built-ins/MapIteratorPrototype 0/11 (0.0%) @@ -743,17 +712,17 @@ built-ins/NativeErrors 35/108 (32.41%) AggregateError/prototype 6/6 (100.0%) AggregateError 17/17 (100.0%) EvalError/prototype/not-error-object.js - EvalError/proto-from-ctor-realm.js {unsupported: [Reflect]} + EvalError/proto-from-ctor-realm.js RangeError/prototype/not-error-object.js - RangeError/proto-from-ctor-realm.js {unsupported: [Reflect]} + RangeError/proto-from-ctor-realm.js ReferenceError/prototype/not-error-object.js - ReferenceError/proto-from-ctor-realm.js {unsupported: [Reflect]} + ReferenceError/proto-from-ctor-realm.js SyntaxError/prototype/not-error-object.js - SyntaxError/proto-from-ctor-realm.js {unsupported: [Reflect]} + SyntaxError/proto-from-ctor-realm.js TypeError/prototype/not-error-object.js - TypeError/proto-from-ctor-realm.js {unsupported: [Reflect]} + TypeError/proto-from-ctor-realm.js URIError/prototype/not-error-object.js - URIError/proto-from-ctor-realm.js {unsupported: [Reflect]} + URIError/proto-from-ctor-realm.js built-ins/Number 9/283 (3.18%) prototype/toExponential/return-abrupt-tointeger-fractiondigits.js @@ -761,17 +730,15 @@ built-ins/Number 9/283 (3.18%) prototype/toExponential/undefined-fractiondigits.js prototype/toLocaleString/length.js prototype/toPrecision/nan.js - proto-from-ctor-realm.js {unsupported: [Reflect]} + proto-from-ctor-realm.js S9.3.1_A2_U180E.js {unsupported: [u180e]} S9.3.1_A3_T1_U180E.js {unsupported: [u180e]} S9.3.1_A3_T2_U180E.js {unsupported: [u180e]} -built-ins/Object 127/3150 (4.03%) - assign/source-own-prop-desc-missing.js {unsupported: [Proxy]} - assign/source-own-prop-error.js {unsupported: [Proxy]} - assign/source-own-prop-keys-error.js {unsupported: [Proxy]} +built-ins/Object 102/3150 (3.24%) + assign/source-own-prop-error.js assign/strings-and-symbol-order.js - assign/strings-and-symbol-order-proxy.js {unsupported: [Proxy]} + assign/strings-and-symbol-order-proxy.js defineProperties/15.2.3.7-6-a-112.js non-strict defineProperties/15.2.3.7-6-a-113.js non-strict defineProperties/15.2.3.7-6-a-118.js @@ -788,7 +755,7 @@ built-ins/Object 127/3150 (4.03%) defineProperties/15.2.3.7-6-a-184.js defineProperties/15.2.3.7-6-a-185.js defineProperties/15.2.3.7-6-a-282.js - defineProperties/proxy-no-ownkeys-returned-keys-order.js {unsupported: [Proxy]} + defineProperties/proxy-no-ownkeys-returned-keys-order.js defineProperty/15.2.3.6-4-116.js non-strict defineProperty/15.2.3.6-4-117.js non-strict defineProperty/15.2.3.6-4-122.js @@ -807,11 +774,9 @@ built-ins/Object 127/3150 (4.03%) defineProperty/15.2.3.6-4-293-3.js non-strict defineProperty/15.2.3.6-4-293-4.js strict defineProperty/15.2.3.6-4-336.js - entries/observable-operations.js {unsupported: [Proxy]} + entries/observable-operations.js entries/order-after-define-property.js - freeze/abrupt-completion.js {unsupported: [Proxy]} - freeze/proxy-no-ownkeys-returned-keys-order.js {unsupported: [Proxy, Reflect]} - freeze/throws-when-false.js + freeze/proxy-no-ownkeys-returned-keys-order.js fromEntries/evaluation-order.js fromEntries/iterator-closed-for-null-entry.js fromEntries/iterator-closed-for-string-entry.js @@ -824,44 +789,31 @@ built-ins/Object 127/3150 (4.03%) fromEntries/iterator-not-closed-for-uncallable-next.js fromEntries/to-property-key.js fromEntries/uses-keys-not-iterator.js - getOwnPropertyDescriptors/observable-operations.js {unsupported: [Proxy]} - getOwnPropertyDescriptors/order-after-define-property.js {unsupported: [Reflect]} - getOwnPropertyDescriptors/proxy-no-ownkeys-returned-keys-order.js {unsupported: [Proxy]} - getOwnPropertyDescriptors/proxy-undefined-descriptor.js {unsupported: [Proxy]} + getOwnPropertyDescriptors/order-after-define-property.js + getOwnPropertyDescriptors/proxy-no-ownkeys-returned-keys-order.js + getOwnPropertyDescriptors/proxy-undefined-descriptor.js getOwnPropertyDescriptor/15.2.3.3-4-212.js getOwnPropertyDescriptor/15.2.3.3-4-213.js getOwnPropertyDescriptor/15.2.3.3-4-214.js getOwnPropertyDescriptor/15.2.3.3-4-215.js getOwnPropertyDescriptor/15.2.3.3-4-250.js getOwnPropertyNames/order-after-define-property.js - getOwnPropertyNames/proxy-invariant-absent-not-configurable-symbol-key.js {unsupported: [Proxy]} - getOwnPropertyNames/proxy-invariant-duplicate-symbol-entry.js {unsupported: [Proxy]} - getOwnPropertyNames/proxy-invariant-not-extensible-absent-symbol-key.js {unsupported: [Proxy]} - getOwnPropertyNames/proxy-invariant-not-extensible-extra-symbol-key.js {unsupported: [Proxy]} - getOwnPropertySymbols/proxy-invariant-absent-not-configurable-string-key.js {unsupported: [Proxy]} - getOwnPropertySymbols/proxy-invariant-duplicate-string-entry.js {unsupported: [Proxy]} - getOwnPropertySymbols/proxy-invariant-not-extensible-absent-string-key.js {unsupported: [Proxy]} - getOwnPropertySymbols/proxy-invariant-not-extensible-extra-string-key.js {unsupported: [Proxy]} - internals/DefineOwnProperty/consistent-value-function-arguments.js - internals/DefineOwnProperty/consistent-value-function-caller.js + getOwnPropertyNames/proxy-invariant-absent-not-configurable-symbol-key.js + getOwnPropertyNames/proxy-invariant-not-extensible-absent-symbol-key.js internals/DefineOwnProperty/consistent-value-regexp-dollar1.js - internals/DefineOwnProperty/consistent-writable-regexp-dollar1.js - isFrozen/proxy-no-ownkeys-returned-keys-order.js {unsupported: [Proxy, Reflect]} - isSealed/proxy-no-ownkeys-returned-keys-order.js {unsupported: [Proxy, Reflect]} - keys/order-after-define-property.js {unsupported: [Proxy]} - keys/property-traps-order-with-proxied-array.js {unsupported: [Proxy]} + isFrozen/proxy-no-ownkeys-returned-keys-order.js + isSealed/proxy-no-ownkeys-returned-keys-order.js + keys/order-after-define-property.js + keys/property-traps-order-with-proxied-array.js keys/proxy-keys.js - keys/proxy-non-enumerable-prop-invariant-1.js {unsupported: [Proxy]} - keys/proxy-non-enumerable-prop-invariant-2.js {unsupported: [Proxy]} - keys/proxy-non-enumerable-prop-invariant-3.js {unsupported: [Proxy]} - preventExtensions/abrupt-completion.js {unsupported: [Proxy]} - preventExtensions/throws-when-false.js + keys/proxy-non-enumerable-prop-invariant-1.js + keys/proxy-non-enumerable-prop-invariant-2.js + keys/proxy-non-enumerable-prop-invariant-3.js prototype/hasOwnProperty/symbol_property_toPrimitive.js prototype/hasOwnProperty/symbol_property_toString.js prototype/hasOwnProperty/symbol_property_valueOf.js prototype/hasOwnProperty/topropertykey_before_toobject.js - prototype/isPrototypeOf/arg-is-proxy.js {unsupported: [Proxy]} - prototype/isPrototypeOf/builtin.js {unsupported: [Reflect.construct]} + prototype/isPrototypeOf/builtin.js prototype/isPrototypeOf/null-this-and-primitive-arg-returns-false.js prototype/isPrototypeOf/undefined-this-and-primitive-arg-returns-false.js prototype/propertyIsEnumerable/symbol_property_toPrimitive.js @@ -870,30 +822,22 @@ built-ins/Object 127/3150 (4.03%) prototype/toLocaleString/primitive_this_value.js strict prototype/toLocaleString/primitive_this_value_getter.js strict prototype/toString/get-symbol-tag-err.js - prototype/toString/proxy-array.js {unsupported: [Proxy]} - prototype/toString/proxy-function.js {unsupported: [Proxy, async-functions]} - prototype/toString/proxy-function-async.js {unsupported: [Proxy, async-functions]} - prototype/toString/proxy-revoked.js {unsupported: [Proxy]} - prototype/toString/proxy-revoked-during-get-call.js {unsupported: [Proxy]} + prototype/toString/proxy-function.js {unsupported: [async-functions]} + prototype/toString/proxy-function-async.js {unsupported: [async-functions]} prototype/toString/symbol-tag-non-str-bigint.js prototype/toString/symbol-tag-non-str-builtin.js - prototype/toString/symbol-tag-non-str-proxy-function.js {unsupported: [Proxy, async-functions]} + prototype/toString/symbol-tag-non-str-proxy-function.js {unsupported: [async-functions]} prototype/toString/symbol-tag-override-bigint.js prototype/toString/symbol-tag-override-instances.js prototype/toString/symbol-tag-override-primitives.js prototype/toString/symbol-tag-str.js prototype/valueOf/S15.2.4.4_A14.js prototype/valueOf/S15.2.4.4_A15.js - prototype/setPrototypeOf-with-different-values.js {unsupported: [Reflect.setPrototypeOf]} - prototype/setPrototypeOf-with-same-value.js {unsupported: [Reflect.setPrototypeOf]} - seal/abrupt-completion.js {unsupported: [Proxy]} - seal/proxy-no-ownkeys-returned-keys-order.js {unsupported: [Proxy, Reflect]} - seal/throws-when-false.js - setPrototypeOf/set-error.js {unsupported: [Proxy]} - values/observable-operations.js {unsupported: [Proxy]} + seal/proxy-no-ownkeys-returned-keys-order.js + values/observable-operations.js values/order-after-define-property.js - proto-from-ctor-realm.js {unsupported: [Reflect]} - subclass-object-arg.js {unsupported: [Reflect.construct, Reflect, class]} + proto-from-ctor-realm.js + subclass-object-arg.js {unsupported: [class]} built-ins/parseFloat 2/58 (3.45%) S15.1.2.3_A2_T10_U180E.js {unsupported: [u180e]} @@ -903,7 +847,7 @@ built-ins/parseInt 2/60 (3.33%) S15.1.2.2_A2_T10_U180E.js {unsupported: [u180e]} S15.1.2.2_A9.2.js -built-ins/Promise 405/599 (67.61%) +built-ins/Promise 403/599 (67.28%) allSettled/capability-resolve-throws-reject.js {unsupported: [async]} allSettled/ctx-ctor.js {unsupported: [class]} allSettled/does-not-invoke-array-setters.js {unsupported: [async]} @@ -1113,22 +1057,21 @@ built-ins/Promise 405/599 (67.61%) any/species-get-error.js {unsupported: [Symbol.species]} prototype/catch/S25.4.5.1_A3.1_T1.js {unsupported: [async]} prototype/catch/S25.4.5.1_A3.1_T2.js {unsupported: [async]} - prototype/finally/invokes-then-with-function.js {unsupported: [Reflect.construct]} + prototype/finally/invokes-then-with-function.js prototype/finally/rejected-observable-then-calls.js {unsupported: [async]} - prototype/finally/rejected-observable-then-calls-argument.js {unsupported: [Reflect.construct, async]} + prototype/finally/rejected-observable-then-calls-argument.js {unsupported: [async]} prototype/finally/rejected-observable-then-calls-PromiseResolve.js {unsupported: [async]} prototype/finally/rejection-reason-no-fulfill.js {unsupported: [async]} prototype/finally/rejection-reason-override-with-throw.js {unsupported: [async]} prototype/finally/resolution-value-no-override.js {unsupported: [async]} prototype/finally/resolved-observable-then-calls.js {unsupported: [async]} - prototype/finally/resolved-observable-then-calls-argument.js {unsupported: [Reflect.construct, async]} + prototype/finally/resolved-observable-then-calls-argument.js {unsupported: [async]} prototype/finally/resolved-observable-then-calls-PromiseResolve.js {unsupported: [async]} prototype/finally/species-constructor.js {unsupported: [async]} prototype/finally/subclass-reject-count.js {unsupported: [async]} prototype/finally/subclass-resolve-count.js {unsupported: [async]} prototype/finally/subclass-species-constructor-reject-count.js prototype/finally/subclass-species-constructor-resolve-count.js - prototype/finally/this-value-proxy.js prototype/then/capability-executor-called-twice.js {unsupported: [class]} prototype/then/capability-executor-not-callable.js {unsupported: [class]} prototype/then/ctor-access-count.js {unsupported: [async]} @@ -1275,14 +1218,13 @@ built-ins/Promise 405/599 (67.61%) resolve/S25.Promise_resolve_foreign_thenable_1.js {unsupported: [async]} resolve/S25.Promise_resolve_foreign_thenable_2.js {unsupported: [async]} Symbol.species 5/5 (100.0%) - create-resolving-functions-reject.js {unsupported: [Reflect.construct, async]} - create-resolving-functions-resolve.js {unsupported: [Reflect.construct, async]} + create-resolving-functions-reject.js {unsupported: [async]} + create-resolving-functions-resolve.js {unsupported: [async]} exception-after-resolve-in-executor.js {unsupported: [async]} exception-after-resolve-in-thenable-job.js {unsupported: [async]} - executor-function-nonconstructor.js {unsupported: [Reflect.construct]} - get-prototype-abrupt.js {unsupported: [Reflect.construct, Reflect]} - get-prototype-abrupt-executor-not-callable.js {unsupported: [Reflect.construct, Reflect]} - proto-from-ctor-realm.js {unsupported: [Reflect]} + executor-function-nonconstructor.js + get-prototype-abrupt.js + proto-from-ctor-realm.js reject-ignored-via-abrupt.js {unsupported: [async]} reject-ignored-via-fn-deferred.js {unsupported: [async]} reject-ignored-via-fn-immed.js {unsupported: [async]} @@ -1306,9 +1248,96 @@ built-ins/Promise 405/599 (67.61%) resolve-thenable-deferred.js {unsupported: [async]} resolve-thenable-immed.js {unsupported: [async]} -~built-ins/Proxy - -~built-ins/Reflect +built-ins/Proxy 74/306 (24.18%) + construct/arguments-realm.js + construct/call-parameters.js + construct/call-parameters-new-target.js + construct/trap-is-missing-target-is-proxy.js {unsupported: [class]} + construct/trap-is-null.js + construct/trap-is-null-target-is-proxy.js {unsupported: [class]} + construct/trap-is-undefined.js + construct/trap-is-undefined-no-property.js + construct/trap-is-undefined-proto-from-newtarget-realm.js + construct/trap-is-undefined-target-is-proxy.js {unsupported: [class]} + defineProperty/desc-realm.js + defineProperty/targetdesc-not-configurable-writable-desc-not-writable.js + defineProperty/targetdesc-undefined-target-is-not-extensible-realm.js non-strict + defineProperty/trap-is-missing-target-is-proxy.js + defineProperty/trap-is-undefined-target-is-proxy.js + deleteProperty/boolean-trap-result-boolean-false.js + deleteProperty/return-false-not-strict.js non-strict + deleteProperty/return-false-strict.js strict + deleteProperty/targetdesc-is-configurable-target-is-not-extensible.js + deleteProperty/trap-is-missing-target-is-proxy.js + deleteProperty/trap-is-null-target-is-proxy.js + deleteProperty/trap-is-undefined-strict.js strict + deleteProperty/trap-is-undefined-target-is-proxy.js + getOwnPropertyDescriptor/result-is-undefined-targetdesc-is-undefined.js + getOwnPropertyDescriptor/resultdesc-is-invalid-descriptor.js + getOwnPropertyDescriptor/resultdesc-is-not-configurable-not-writable-targetdesc-is-writable.js + getOwnPropertyDescriptor/resultdesc-is-not-configurable-targetdesc-is-configurable.js + getOwnPropertyDescriptor/resultdesc-is-not-configurable-targetdesc-is-undefined.js + getOwnPropertyDescriptor/trap-is-missing-target-is-proxy.js + getOwnPropertyDescriptor/trap-is-null-target-is-proxy.js + getOwnPropertyDescriptor/trap-is-undefined.js + getOwnPropertyDescriptor/trap-is-undefined-target-is-proxy.js + get/accessor-get-is-undefined-throws.js + get/trap-is-undefined-receiver.js + has/call-in-prototype.js + has/call-in-prototype-index.js + has/call-with.js non-strict + has/return-false-target-not-extensible-using-with.js non-strict + has/return-false-target-prop-exists-using-with.js non-strict + has/return-false-targetdesc-not-configurable-using-with.js non-strict + has/return-is-abrupt-with.js non-strict + has/return-true-target-prop-exists-using-with.js non-strict + has/trap-is-missing-target-is-proxy.js + has/trap-is-not-callable-using-with.js non-strict + ownKeys/trap-is-undefined-target-is-proxy.js + preventExtensions/trap-is-undefined-target-is-proxy.js {unsupported: [module]} + revocable/builtin.js + revocable/revocation-function-nonconstructor.js + setPrototypeOf/internals-call-order.js + setPrototypeOf/not-extensible-target-not-same-target-prototype.js + setPrototypeOf/return-abrupt-from-target-getprototypeof.js + setPrototypeOf/toboolean-trap-result-false.js + setPrototypeOf/toboolean-trap-result-true-target-is-extensible.js + setPrototypeOf/trap-is-missing-target-is-proxy.js + setPrototypeOf/trap-is-null-target-is-proxy.js + set/boolean-trap-result-is-false-boolean-return-false.js + set/boolean-trap-result-is-false-null-return-false.js + set/boolean-trap-result-is-false-number-return-false.js + set/boolean-trap-result-is-false-string-return-false.js + set/boolean-trap-result-is-false-undefined-return-false.js + set/call-parameters.js + set/call-parameters-prototype.js + set/call-parameters-prototype-index.js + set/target-property-is-accessor-not-configurable-set-is-undefined.js + set/trap-is-missing-receiver-multiple-calls.js + set/trap-is-missing-receiver-multiple-calls-index.js + set/trap-is-missing-target-is-proxy.js + set/trap-is-null-receiver.js + set/trap-is-null-target-is-proxy.js + set/trap-is-undefined-target-is-proxy.js + create-handler-not-object-throw-symbol.js + create-target-not-object-throw-symbol.js + get-fn-realm.js + get-fn-realm-recursive.js + +built-ins/Reflect 13/139 (9.35%) + construct/newtarget-is-not-constructor-throws.js + defineProperty/return-abrupt-from-property-key.js + deleteProperty/return-abrupt-from-result.js + deleteProperty/return-boolean.js strict + get/return-value-from-receiver.js + ownKeys/order-after-define-property.js + ownKeys/return-on-corresponding-order-large-index.js {unsupported: [computed-property-names]} + set/call-prototype-property-set.js + set/different-property-descriptors.js + set/receiver-is-not-object.js + set/return-abrupt-from-result.js + set/return-false-if-receiver-is-not-writable.js + set/return-false-if-target-is-not-writable.js built-ins/RegExp 897/1464 (61.27%) CharacterClassEscapes 24/24 (100.0%) @@ -1530,7 +1559,7 @@ built-ins/RegExp 897/1464 (61.27%) from-regexp-like-get-flags-err.js from-regexp-like-get-source-err.js from-regexp-like-short-circuit.js - proto-from-ctor-realm.js {unsupported: [Reflect]} + proto-from-ctor-realm.js quantifier-integer-limit.js S15.10.1_A1_T13.js S15.10.1_A1_T14.js @@ -1547,7 +1576,7 @@ built-ins/RegExp 897/1464 (61.27%) built-ins/Set 5/188 (2.66%) Symbol.species 4/4 (100.0%) - proto-from-ctor-realm.js {unsupported: [Reflect]} + proto-from-ctor-realm.js built-ins/SetIteratorPrototype 0/11 (0.0%) @@ -1616,11 +1645,11 @@ built-ins/String 120/1114 (10.77%) prototype/trimStart/this-value-object-valueof-returns-object-err.js prototype/trim/u180e.js {unsupported: [u180e]} prototype/valueOf/non-generic-realm.js - proto-from-ctor-realm.js {unsupported: [Reflect]} + proto-from-ctor-realm.js built-ins/StringIteratorPrototype 0/7 (0.0%) -built-ins/Symbol 29/85 (34.12%) +built-ins/Symbol 28/85 (32.94%) asyncIterator/prop-desc.js for/cross-realm.js hasInstance/cross-realm.js @@ -1645,7 +1674,6 @@ built-ins/Symbol 29/85 (34.12%) toPrimitive/cross-realm.js toStringTag/cross-realm.js unscopables/cross-realm.js - is-constructor.js {unsupported: [Reflect.construct]} built-ins/ThrowTypeError 7/13 (53.85%) extensible.js @@ -1733,7 +1761,7 @@ built-ins/TypedArray 992/1070 (92.71%) prototype/every/callbackfn-not-called-on-empty.js prototype/every/callbackfn-return-does-not-change-instance.js prototype/every/callbackfn-returns-abrupt.js - prototype/every/callbackfn-set-value-during-interaction.js {unsupported: [Reflect.set]} + prototype/every/callbackfn-set-value-during-interaction.js prototype/every/callbackfn-this.js prototype/every/detached-buffer.js prototype/every/get-length-uses-internal-arraylength.js @@ -1781,7 +1809,7 @@ built-ins/TypedArray 992/1070 (92.71%) prototype/filter/callbackfn-not-called-on-empty.js prototype/filter/callbackfn-return-does-not-change-instance.js prototype/filter/callbackfn-returns-abrupt.js - prototype/filter/callbackfn-set-value-during-iteration.js {unsupported: [Reflect.set]} + prototype/filter/callbackfn-set-value-during-iteration.js prototype/filter/callbackfn-this.js prototype/filter/detached-buffer.js prototype/filter/invoked-as-func.js @@ -1856,7 +1884,7 @@ built-ins/TypedArray 992/1070 (92.71%) prototype/forEach/callbackfn-not-called-on-empty.js prototype/forEach/callbackfn-return-does-not-change-instance.js prototype/forEach/callbackfn-returns-abrupt.js - prototype/forEach/callbackfn-set-value-during-interaction.js {unsupported: [Reflect.set]} + prototype/forEach/callbackfn-set-value-during-interaction.js prototype/forEach/callbackfn-this.js prototype/forEach/detached-buffer.js prototype/forEach/invoked-as-func.js @@ -1964,7 +1992,7 @@ built-ins/TypedArray 992/1070 (92.71%) prototype/map/callbackfn-return-does-not-change-instance.js prototype/map/callbackfn-return-does-not-copy-non-integer-properties.js prototype/map/callbackfn-returns-abrupt.js - prototype/map/callbackfn-set-value-during-interaction.js {unsupported: [Reflect.set]} + prototype/map/callbackfn-set-value-during-interaction.js prototype/map/callbackfn-this.js prototype/map/detached-buffer.js prototype/map/invoked-as-func.js @@ -2001,7 +2029,7 @@ built-ins/TypedArray 992/1070 (92.71%) prototype/reduceRight/callbackfn-not-called-on-empty.js prototype/reduceRight/callbackfn-return-does-not-change-instance.js prototype/reduceRight/callbackfn-returns-abrupt.js - prototype/reduceRight/callbackfn-set-value-during-iteration.js {unsupported: [Reflect.set]} + prototype/reduceRight/callbackfn-set-value-during-iteration.js prototype/reduceRight/callbackfn-this.js prototype/reduceRight/detached-buffer.js prototype/reduceRight/empty-instance-return-initialvalue.js @@ -2024,7 +2052,7 @@ built-ins/TypedArray 992/1070 (92.71%) prototype/reduce/callbackfn-not-called-on-empty.js prototype/reduce/callbackfn-return-does-not-change-instance.js prototype/reduce/callbackfn-returns-abrupt.js - prototype/reduce/callbackfn-set-value-during-iteration.js {unsupported: [Reflect.set]} + prototype/reduce/callbackfn-set-value-during-iteration.js prototype/reduce/callbackfn-this.js prototype/reduce/detached-buffer.js prototype/reduce/empty-instance-return-initialvalue.js @@ -2129,7 +2157,7 @@ built-ins/TypedArray 992/1070 (92.71%) prototype/some/callbackfn-not-called-on-empty.js prototype/some/callbackfn-return-does-not-change-instance.js prototype/some/callbackfn-returns-abrupt.js - prototype/some/callbackfn-set-value-during-interaction.js {unsupported: [Reflect.set]} + prototype/some/callbackfn-set-value-during-interaction.js prototype/some/callbackfn-this.js prototype/some/detached-buffer.js prototype/some/get-length-uses-internal-arraylength.js @@ -2216,7 +2244,7 @@ built-ins/TypedArray 992/1070 (92.71%) name.js prototype.js -built-ins/TypedArrayConstructors 529/684 (77.34%) +built-ins/TypedArrayConstructors 512/684 (74.85%) BigInt64Array/prototype 4/4 (100.0%) BigInt64Array 7/7 (100.0%) BigUint64Array/prototype 4/4 (100.0%) @@ -2234,8 +2262,8 @@ built-ins/TypedArrayConstructors 529/684 (77.34%) ctors/buffer-arg/byteoffset-throws-from-modulo-element-size-sab.js {unsupported: [SharedArrayBuffer]} ctors/buffer-arg/byteoffset-to-number-detachbuffer.js ctors/buffer-arg/byteoffset-to-number-throws-sab.js {unsupported: [SharedArrayBuffer]} - ctors/buffer-arg/custom-proto-access-throws.js {unsupported: [Reflect]} - ctors/buffer-arg/custom-proto-access-throws-sab.js {unsupported: [SharedArrayBuffer, Reflect]} + ctors/buffer-arg/custom-proto-access-throws.js + ctors/buffer-arg/custom-proto-access-throws-sab.js {unsupported: [SharedArrayBuffer]} ctors/buffer-arg/defined-length-and-offset-sab.js {unsupported: [SharedArrayBuffer]} ctors/buffer-arg/defined-length-sab.js {unsupported: [SharedArrayBuffer]} ctors/buffer-arg/defined-negative-length.js @@ -2250,30 +2278,24 @@ built-ins/TypedArrayConstructors 529/684 (77.34%) ctors/buffer-arg/length-is-symbol-throws-sab.js {unsupported: [SharedArrayBuffer]} ctors/buffer-arg/length-to-number-detachbuffer.js ctors/buffer-arg/new-instance-extensibility-sab.js {unsupported: [SharedArrayBuffer]} - ctors/buffer-arg/proto-from-ctor-realm.js {unsupported: [Reflect]} - ctors/buffer-arg/proto-from-ctor-realm-sab.js {unsupported: [SharedArrayBuffer, Reflect]} + ctors/buffer-arg/proto-from-ctor-realm.js + ctors/buffer-arg/proto-from-ctor-realm-sab.js {unsupported: [SharedArrayBuffer]} ctors/buffer-arg/returns-new-instance-sab.js {unsupported: [SharedArrayBuffer]} ctors/buffer-arg/toindex-bytelength-sab.js {unsupported: [SharedArrayBuffer]} ctors/buffer-arg/toindex-byteoffset-sab.js {unsupported: [SharedArrayBuffer]} ctors/buffer-arg/typedarray-backed-by-sharedarraybuffer.js {unsupported: [SharedArrayBuffer]} - ctors/buffer-arg/use-custom-proto-if-object.js {unsupported: [Reflect]} - ctors/buffer-arg/use-custom-proto-if-object-sab.js {unsupported: [SharedArrayBuffer, Reflect]} - ctors/buffer-arg/use-default-proto-if-custom-proto-is-not-object.js + ctors/buffer-arg/use-custom-proto-if-object-sab.js {unsupported: [SharedArrayBuffer]} ctors/buffer-arg/use-default-proto-if-custom-proto-is-not-object-sab.js {unsupported: [SharedArrayBuffer]} - ctors/length-arg/custom-proto-access-throws.js {unsupported: [Reflect]} + ctors/length-arg/custom-proto-access-throws.js ctors/length-arg/is-infinity-throws-rangeerror.js ctors/length-arg/is-negative-integer-throws-rangeerror.js ctors/length-arg/is-symbol-throws.js - ctors/length-arg/proto-from-ctor-realm.js {unsupported: [Reflect]} + ctors/length-arg/proto-from-ctor-realm.js ctors/length-arg/toindex-length.js - ctors/length-arg/use-custom-proto-if-object.js {unsupported: [Reflect]} - ctors/length-arg/use-default-proto-if-custom-proto-is-not-object.js - ctors/no-args/custom-proto-access-throws.js {unsupported: [Reflect]} - ctors/no-args/proto-from-ctor-realm.js {unsupported: [Reflect]} - ctors/no-args/use-custom-proto-if-object.js {unsupported: [Reflect]} - ctors/no-args/use-default-proto-if-custom-proto-is-not-object.js + ctors/no-args/custom-proto-access-throws.js + ctors/no-args/proto-from-ctor-realm.js ctors/object-arg/as-generator-iterable-returns.js - ctors/object-arg/custom-proto-access-throws.js {unsupported: [Reflect]} + ctors/object-arg/custom-proto-access-throws.js ctors/object-arg/iterating-throws.js ctors/object-arg/iterator-is-null-as-array-like.js ctors/object-arg/iterator-not-callable-throws.js @@ -2282,16 +2304,14 @@ built-ins/TypedArrayConstructors 529/684 (77.34%) ctors/object-arg/length-is-symbol-throws.js ctors/object-arg/length-throws.js ctors/object-arg/new-instance-extensibility.js - ctors/object-arg/proto-from-ctor-realm.js {unsupported: [Reflect]} + ctors/object-arg/proto-from-ctor-realm.js ctors/object-arg/returns.js ctors/object-arg/throws-from-property.js ctors/object-arg/throws-setting-obj-to-primitive.js ctors/object-arg/throws-setting-obj-to-primitive-typeerror.js ctors/object-arg/throws-setting-property.js ctors/object-arg/throws-setting-symbol-property.js - ctors/object-arg/use-custom-proto-if-object.js {unsupported: [Reflect]} - ctors/object-arg/use-default-proto-if-custom-proto-is-not-object.js - ctors/typedarray-arg/custom-proto-access-throws.js {unsupported: [Reflect]} + ctors/typedarray-arg/custom-proto-access-throws.js ctors/typedarray-arg/detached-when-species-retrieved-different-type.js {unsupported: [Symbol.species]} ctors/typedarray-arg/detached-when-species-retrieved-same-type.js {unsupported: [Symbol.species]} ctors/typedarray-arg/other-ctor-buffer-ctor-access-throws.js @@ -2303,7 +2323,7 @@ built-ins/TypedArrayConstructors 529/684 (77.34%) ctors/typedarray-arg/other-ctor-buffer-ctor-species-null.js {unsupported: [Symbol.species]} ctors/typedarray-arg/other-ctor-buffer-ctor-species-prototype-throws.js {unsupported: [Symbol.species]} ctors/typedarray-arg/other-ctor-buffer-ctor-species-undefined.js {unsupported: [Symbol.species]} - ctors/typedarray-arg/proto-from-ctor-realm.js {unsupported: [Reflect]} + ctors/typedarray-arg/proto-from-ctor-realm.js ctors/typedarray-arg/same-ctor-buffer-ctor-access-throws.js ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom.js {unsupported: [Symbol.species]} ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js {unsupported: [Symbol.species]} @@ -2314,8 +2334,6 @@ built-ins/TypedArrayConstructors 529/684 (77.34%) ctors/typedarray-arg/same-ctor-buffer-ctor-species-undefined.js {unsupported: [Symbol.species]} ctors/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js ctors/typedarray-arg/src-typedarray-big-throws.js - ctors/typedarray-arg/use-custom-proto-if-object.js {unsupported: [Reflect]} - ctors/typedarray-arg/use-default-proto-if-custom-proto-is-not-object.js Float32Array/prototype/not-typedarray-object.js Float32Array/prototype/proto.js Float64Array/prototype/not-typedarray-object.js @@ -2351,7 +2369,24 @@ built-ins/TypedArrayConstructors 529/684 (77.34%) Int8Array/prototype/not-typedarray-object.js Int8Array/prototype/proto.js internals/DefineOwnProperty/BigInt 20/20 (100.0%) - internals/DefineOwnProperty 22/22 (100.0%) + internals/DefineOwnProperty/conversion-operation.js + internals/DefineOwnProperty/conversion-operation-consistent-nan.js + internals/DefineOwnProperty/desc-value-throws.js + internals/DefineOwnProperty/detached-buffer.js + internals/DefineOwnProperty/detached-buffer-realm.js + internals/DefineOwnProperty/key-is-greater-than-last-index.js + internals/DefineOwnProperty/key-is-lower-than-zero.js + internals/DefineOwnProperty/key-is-minus-zero.js + internals/DefineOwnProperty/key-is-not-canonical-index.js + internals/DefineOwnProperty/key-is-not-integer.js + internals/DefineOwnProperty/key-is-numericindex.js + internals/DefineOwnProperty/key-is-numericindex-accessor-desc.js + internals/DefineOwnProperty/key-is-numericindex-desc-configurable.js + internals/DefineOwnProperty/key-is-numericindex-desc-not-enumerable.js + internals/DefineOwnProperty/key-is-numericindex-desc-not-writable.js + internals/DefineOwnProperty/non-extensible-redefine-key.js + internals/DefineOwnProperty/set-value.js + internals/DefineOwnProperty/tonumber-value-detached-buffer.js internals/Get/BigInt 14/14 (100.0%) internals/GetOwnProperty/BigInt 12/12 (100.0%) internals/GetOwnProperty/detached-buffer.js @@ -2374,22 +2409,33 @@ built-ins/TypedArrayConstructors 529/684 (77.34%) internals/Get/key-is-out-of-bounds.js internals/Get/key-is-symbol.js internals/HasProperty/BigInt 15/15 (100.0%) - internals/HasProperty 15/15 (100.0%) + internals/HasProperty/abrupt-from-ordinary-has-parent-hasproperty.js + internals/HasProperty/detached-buffer.js + internals/HasProperty/detached-buffer-key-is-not-number.js + internals/HasProperty/detached-buffer-key-is-symbol.js + internals/HasProperty/detached-buffer-realm.js + internals/HasProperty/infinity-with-detached-buffer.js non-strict + internals/HasProperty/inherited-property.js + internals/HasProperty/key-is-greater-than-last-index.js + internals/HasProperty/key-is-lower-than-zero.js + internals/HasProperty/key-is-minus-zero.js + internals/HasProperty/key-is-not-canonical-index.js + internals/HasProperty/key-is-not-integer.js internals/OwnPropertyKeys/BigInt 4/4 (100.0%) internals/OwnPropertyKeys 4/4 (100.0%) internals/Set/BigInt 23/23 (100.0%) internals/Set/detached-buffer.js - internals/Set/detached-buffer-key-is-not-numeric-index.js {unsupported: [Reflect]} - internals/Set/detached-buffer-key-is-symbol.js {unsupported: [Reflect]} + internals/Set/detached-buffer-key-is-not-numeric-index.js + internals/Set/detached-buffer-key-is-symbol.js internals/Set/detached-buffer-realm.js - internals/Set/indexed-value.js {unsupported: [Reflect]} - internals/Set/key-is-minus-zero.js {unsupported: [Reflect]} - internals/Set/key-is-not-canonical-index.js {unsupported: [Reflect]} - internals/Set/key-is-not-integer.js {unsupported: [Reflect]} - internals/Set/key-is-not-numeric-index.js {unsupported: [Reflect]} - internals/Set/key-is-out-of-bounds.js {unsupported: [Reflect]} - internals/Set/key-is-symbol.js {unsupported: [Reflect]} - internals/Set/tonumber-value-detached-buffer.js {unsupported: [Reflect]} + internals/Set/indexed-value.js + internals/Set/key-is-minus-zero.js + internals/Set/key-is-not-canonical-index.js + internals/Set/key-is-not-integer.js + internals/Set/key-is-not-numeric-index.js + internals/Set/key-is-out-of-bounds.js + internals/Set/key-is-symbol.js + internals/Set/tonumber-value-detached-buffer.js internals/Set/tonumber-value-throws.js of/BigInt 12/12 (100.0%) of/argument-number-value-throws.js @@ -2442,10 +2488,10 @@ built-ins/TypedArrayConstructors 529/684 (77.34%) built-ins/undefined 0/8 (0.0%) built-ins/WeakMap 1/88 (1.14%) - proto-from-ctor-realm.js {unsupported: [Reflect]} + proto-from-ctor-realm.js built-ins/WeakSet 1/75 (1.33%) - proto-from-ctor-realm.js {unsupported: [Reflect]} + proto-from-ctor-realm.js language/arguments-object 191/260 (73.46%) mapped/mapped-arguments-nonconfigurable-3.js non-strict @@ -4482,7 +4528,7 @@ language/expressions/object 841/1081 (77.8%) dstr/meth-obj-ptrn-rest-getter.js {unsupported: [object-rest]} dstr/meth-obj-ptrn-rest-skip-non-enumerable.js {unsupported: [object-rest]} dstr/meth-obj-ptrn-rest-val-obj.js {unsupported: [object-rest]} - dstr/object-rest-proxy-ownkeys-returned-keys-order.js {unsupported: [Proxy, object-rest]} + dstr/object-rest-proxy-ownkeys-returned-keys-order.js {unsupported: [object-rest]} method-definition/async-await-as-binding-identifier.js {unsupported: [async-functions]} method-definition/async-await-as-binding-identifier-escaped.js {unsupported: [async-functions]} method-definition/async-await-as-identifier-reference.js {unsupported: [async-functions]} @@ -4756,9 +4802,9 @@ language/expressions/object 841/1081 (77.8%) let-non-strict-syntax.js non-strict literal-property-name-bigint.js {unsupported: [class]} method.js - object-spread-proxy-ownkeys-returned-keys-order.js {unsupported: [Proxy]} + object-spread-proxy-ownkeys-returned-keys-order.js prop-def-id-eval-error.js non-strict - prop-def-id-eval-error-2.js {unsupported: [Proxy]} + prop-def-id-eval-error-2.js non-strict prop-dup-data-data.js strict prop-dup-data-set.js strict prop-dup-get-data.js strict @@ -4874,9 +4920,7 @@ language/expressions/template-literal 2/57 (3.51%) language/expressions/this 0/6 (0.0%) -language/expressions/typeof 2/16 (12.5%) - built-in-ordinary-objects-no-call.js - proxy.js {unsupported: [Proxy]} +language/expressions/typeof 0/16 (0.0%) language/expressions/unary-minus 1/14 (7.14%) bigint-non-primitive.js @@ -5482,7 +5526,7 @@ language/statements/for-in 39/114 (34.21%) scope-head-lex-open.js scope-head-var-none.js non-strict -language/statements/for-of 471/725 (64.97%) +language/statements/for-of 470/725 (64.83%) dstr/array-elem-init-assignment.js dstr/array-elem-init-evaluation.js dstr/array-elem-init-fn-name-arrow.js @@ -5930,7 +5974,6 @@ language/statements/for-of 471/725 (64.97%) head-var-bound-names-let.js non-strict head-var-init.js head-var-no-expr.js - iterator-as-proxy.js {unsupported: [Proxy]} iterator-close-non-object.js iterator-close-non-throw-get-method-abrupt.js iterator-close-non-throw-get-method-is-null.js @@ -6295,8 +6338,8 @@ language/types 9/113 (7.96%) number/S8.5_A4_T1.js number/S8.5_A4_T2.js non-strict reference/get-value-prop-base-primitive-realm.js - reference/put-value-prop-base-primitive.js {unsupported: [Proxy]} - reference/put-value-prop-base-primitive-realm.js {unsupported: [Proxy]} + reference/put-value-prop-base-primitive.js + reference/put-value-prop-base-primitive-realm.js undefined/S8.1_A3_T1.js undefined/S8.1_A3_T2.js non-strict