diff --git a/src/org/mozilla/javascript/ArrowFunction.java b/src/org/mozilla/javascript/ArrowFunction.java index 9d958bf00a..399d1daeed 100644 --- a/src/org/mozilla/javascript/ArrowFunction.java +++ b/src/org/mozilla/javascript/ArrowFunction.java @@ -19,7 +19,7 @@ public ArrowFunction( this.targetFunction = targetFunction; this.boundThis = boundThis; - ScriptRuntime.setFunctionProtoAndParent(this, scope); + ScriptRuntime.setFunctionProtoAndParent(this, cx, scope, false); Function thrower = ScriptRuntime.typeErrorThrower(cx); NativeObject throwing = new NativeObject(); diff --git a/src/org/mozilla/javascript/BaseFunction.java b/src/org/mozilla/javascript/BaseFunction.java index 6cfce5fbaa..0acfa10ff4 100644 --- a/src/org/mozilla/javascript/BaseFunction.java +++ b/src/org/mozilla/javascript/BaseFunction.java @@ -22,13 +22,22 @@ public class BaseFunction extends IdScriptableObject implements Function { private static final String FUNCTION_CLASS = "Function"; static final String GENERATOR_FUNCTION_CLASS = "__GeneratorFunction"; - static void init(Scriptable scope, boolean sealed) { + static void init(Context cx, Scriptable scope, boolean sealed) { BaseFunction obj = new BaseFunction(); // Function.prototype attributes: see ECMA 15.3.3.1 obj.prototypePropertyAttributes = DONTENUM | READONLY | PERMANENT; + if (cx.getLanguageVersion() >= Context.VERSION_ES6) { + obj.setStandardPropertyAttributes(READONLY | DONTENUM); + } obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } + /** @deprecated Use {@link #init(Context, Scriptable, boolean)} instead */ + @Deprecated + static void init(Scriptable scope, boolean sealed) { + init(Context.getContext(), scope, sealed); + } + static Object initAsGeneratorFunction(Scriptable scope, boolean sealed) { BaseFunction obj = new BaseFunction(true); // Function.prototype attributes: see ECMA 15.3.3.1 diff --git a/src/org/mozilla/javascript/BoundFunction.java b/src/org/mozilla/javascript/BoundFunction.java index 74210f05bb..65dd912e85 100644 --- a/src/org/mozilla/javascript/BoundFunction.java +++ b/src/org/mozilla/javascript/BoundFunction.java @@ -35,7 +35,7 @@ public BoundFunction( length = 0; } - ScriptRuntime.setFunctionProtoAndParent(this, scope); + ScriptRuntime.setFunctionProtoAndParent(this, cx, scope, false); Function thrower = ScriptRuntime.typeErrorThrower(cx); NativeObject throwing = new NativeObject(); diff --git a/src/org/mozilla/javascript/FunctionObject.java b/src/org/mozilla/javascript/FunctionObject.java index 72ca22629a..0773ca2442 100644 --- a/src/org/mozilla/javascript/FunctionObject.java +++ b/src/org/mozilla/javascript/FunctionObject.java @@ -142,7 +142,7 @@ public FunctionObject(String name, Member methodOrConstructor, Scriptable scope) } } - ScriptRuntime.setFunctionProtoAndParent(this, scope); + ScriptRuntime.setFunctionProtoAndParent(this, Context.getCurrentContext(), scope, false); } /** diff --git a/src/org/mozilla/javascript/JavaMembers.java b/src/org/mozilla/javascript/JavaMembers.java index b582b17013..2ec20d98c1 100644 --- a/src/org/mozilla/javascript/JavaMembers.java +++ b/src/org/mozilla/javascript/JavaMembers.java @@ -53,7 +53,7 @@ class JavaMembers { this.staticMembers = new HashMap(); this.cl = cl; boolean includePrivate = cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS); - reflect(scope, includeProtected, includePrivate); + reflect(cx, scope, includeProtected, includePrivate); } finally { Context.exit(); } @@ -412,7 +412,8 @@ public int hashCode() { } } - private void reflect(Scriptable scope, boolean includeProtected, boolean includePrivate) { + private void reflect( + Context cx, Scriptable scope, boolean includeProtected, boolean includePrivate) { // We reflect methods first, because we want overloaded field/method // names to be allocated to the NativeJavaMethod before the field // gets in the way. @@ -465,7 +466,7 @@ private void reflect(Scriptable scope, boolean includeProtected, boolean include } NativeJavaMethod fun = new NativeJavaMethod(methodBoxes); if (scope != null) { - ScriptRuntime.setFunctionProtoAndParent(fun, scope); + ScriptRuntime.setFunctionProtoAndParent(fun, cx, scope, false); } ht.put(entry.getKey(), fun); } diff --git a/src/org/mozilla/javascript/NativeFunction.java b/src/org/mozilla/javascript/NativeFunction.java index 4a3899442a..a85c07a925 100644 --- a/src/org/mozilla/javascript/NativeFunction.java +++ b/src/org/mozilla/javascript/NativeFunction.java @@ -23,7 +23,7 @@ public final void initScriptFunction(Context cx, Scriptable scope) { public final void initScriptFunction( Context cx, Scriptable scope, boolean es6GeneratorFunction) { - ScriptRuntime.setFunctionProtoAndParent(this, scope, es6GeneratorFunction); + ScriptRuntime.setFunctionProtoAndParent(this, cx, scope, es6GeneratorFunction); } /** diff --git a/src/org/mozilla/javascript/NativeScript.java b/src/org/mozilla/javascript/NativeScript.java index 1582134914..d095143145 100644 --- a/src/org/mozilla/javascript/NativeScript.java +++ b/src/org/mozilla/javascript/NativeScript.java @@ -23,11 +23,17 @@ class NativeScript extends BaseFunction { private static final Object SCRIPT_TAG = "Script"; - static void init(Scriptable scope, boolean sealed) { + static void init(Context cx, Scriptable scope, boolean sealed) { NativeScript obj = new NativeScript(null); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } + /** @deprecated Use {@link #init(Context, Scriptable, boolean)} instead */ + @Deprecated + static void init(Scriptable scope, boolean sealed) { + init(Context.getContext(), scope, sealed); + } + private NativeScript(Script script) { this.script = script; } diff --git a/src/org/mozilla/javascript/ScriptRuntime.java b/src/org/mozilla/javascript/ScriptRuntime.java index 423b2a9c89..c34e22a4c5 100644 --- a/src/org/mozilla/javascript/ScriptRuntime.java +++ b/src/org/mozilla/javascript/ScriptRuntime.java @@ -60,7 +60,7 @@ public int getLength() { return 0; } }; - ScriptRuntime.setFunctionProtoAndParent(thrower, cx.topCallScope); + ScriptRuntime.setFunctionProtoAndParent(thrower, cx, cx.topCallScope, false); thrower.preventExtensions(); cx.typeErrorThrower = thrower; } @@ -146,7 +146,7 @@ public static ScriptableObject initSafeStandardObjects( scope.associateValue(LIBRARY_SCOPE_KEY, scope); (new ClassCache()).associate(scope); - BaseFunction.init(scope, sealed); + BaseFunction.init(cx, scope, sealed); NativeObject.init(scope, sealed); Scriptable objectProto = ScriptableObject.getObjectPrototype(scope); @@ -178,7 +178,7 @@ public static ScriptableObject initSafeStandardObjects( NativeWith.init(scope, sealed); NativeCall.init(scope, sealed); - NativeScript.init(scope, sealed); + NativeScript.init(cx, scope, sealed); NativeIterator.init(cx, scope, sealed); // Also initializes NativeGenerator & ES6Generator @@ -4263,6 +4263,15 @@ public static void setFunctionProtoAndParent( } } + public static void setFunctionProtoAndParent( + BaseFunction fn, Context cx, Scriptable scope, boolean es6GeneratorFunction) { + setFunctionProtoAndParent(fn, scope, es6GeneratorFunction); + + if (cx != null && cx.getLanguageVersion() >= Context.VERSION_ES6) { + fn.setStandardPropertyAttributes(ScriptableObject.READONLY | ScriptableObject.DONTENUM); + } + } + public static void setObjectProtoAndParent(ScriptableObject object, Scriptable scope) { // Compared with function it always sets the scope to top scope scope = ScriptableObject.getTopLevelScope(scope); diff --git a/testsrc/org/mozilla/javascript/tests/es6/NativeFunctionTest.java b/testsrc/org/mozilla/javascript/tests/es6/NativeFunctionTest.java new file mode 100644 index 0000000000..1cf71a4eb8 --- /dev/null +++ b/testsrc/org/mozilla/javascript/tests/es6/NativeFunctionTest.java @@ -0,0 +1,127 @@ +package org.mozilla.javascript.tests.es6; + +import static org.junit.Assert.assertEquals; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.annotations.JSConstructor; +import org.mozilla.javascript.annotations.JSFunction; + +public class NativeFunctionTest { + private Context cx; + private ScriptableObject scope; + + @Before + public void setUp() throws Exception { + cx = Context.enter(); + cx.setLanguageVersion(Context.VERSION_ES6); + scope = cx.initStandardObjects(); + ScriptableObject.defineClass(scope, HelperObject.class); + } + + @After + public void tearDown() { + Context.exit(); + } + + @Test + public void testFunctionPrototypeLength() { + Object result = + cx.evaluateString( + scope, + "var desc=Object.getOwnPropertyDescriptor(Function.prototype, 'length');\n" + + "var res = 'configurable: ' + desc.configurable;\n" + + "res += ' enumerable: ' + desc.enumerable;\n" + + "res += ' writable: ' + desc.writable;", + "test", + 1, + null); + assertEquals("configurable: true enumerable: false writable: false", result); + } + + @Test + public void testFunctionPrototypeName() { + Object result = + cx.evaluateString( + scope, + "var desc=Object.getOwnPropertyDescriptor(Function.prototype, 'name');\n" + + "var res = 'configurable: ' + desc.configurable;\n" + + "res += ' enumerable: ' + desc.enumerable;\n" + + "res += ' writable: ' + desc.writable;", + "test", + 1, + null); + assertEquals("configurable: true enumerable: false writable: false", result); + } + + @Test + public void testFunctionLength() { + Object result = + cx.evaluateString( + scope, + "var f=function(){};\n" + + "var desc=Object.getOwnPropertyDescriptor(f, 'length');\n" + + "var res = 'configurable: ' + desc.configurable;\n" + + "res += ' enumerable: ' + desc.enumerable;\n" + + "res += ' writable: ' + desc.writable;", + "test", + 1, + null); + assertEquals("configurable: true enumerable: false writable: false", result); + } + + @Test + public void testFunctionName() { + Object result = + cx.evaluateString( + scope, + "var f=function(){};\n" + + "var desc=Object.getOwnPropertyDescriptor(f, 'name');\n" + + "var res = 'configurable: ' + desc.configurable;\n" + + "res += ' enumerable: ' + desc.enumerable;\n" + + "res += ' writable: ' + desc.writable;", + "test", + 1, + null); + assertEquals("configurable: true enumerable: false writable: false", result); + } + + @Test + public void testFunctionNameJavaObject() { + Object result = + cx.evaluateString( + scope, + "var f=new HelperObject().foo;\n" + + "var desc=Object.getOwnPropertyDescriptor(f, 'name');\n" + + "var res = 'configurable: ' + desc.configurable;\n" + + "res += ' enumerable: ' + desc.enumerable;\n" + + "res += ' writable: ' + desc.writable;", + "test", + 1, + null); + assertEquals("configurable: true enumerable: false writable: false", result); + } + + public static class HelperObject extends ScriptableObject { + + public HelperObject() {} + + @Override + public String getClassName() { + return "HelperObject"; + } + + @JSConstructor + public void jsConstructorMethod() { + put("initialized", this, Boolean.TRUE); + } + + @JSFunction("foo") + public Object foo() { + return "foo()"; + } + } +} diff --git a/testsrc/test262.properties b/testsrc/test262.properties index cb085c3d62..96b97e3ea7 100644 --- a/testsrc/test262.properties +++ b/testsrc/test262.properties @@ -494,13 +494,11 @@ built-ins/eval 3/9 (33.33%) name.js private-identifiers-not-empty.js {unsupported: [class-fields-private]} -built-ins/Function 194/505 (38.42%) +built-ins/Function 187/505 (37.03%) internals/Call 2/2 (100.0%) internals/Construct 6/6 (100.0%) length/S15.3.5.1_A1_T3.js strict - length/S15.3.5.1_A2_T1.js - length/S15.3.5.1_A2_T2.js - length/S15.3.5.1_A2_T3.js + length/S15.3.5.1_A2_T3.js strict length/S15.3.5.1_A3_T3.js strict length/S15.3.5.1_A4_T3.js strict prototype/apply/15.3.4.3-1-s.js strict @@ -529,9 +527,7 @@ built-ins/Function 194/505 (38.42%) prototype/bind/instance-construct-newtarget-boundtarget-bound.js {unsupported: [Reflect, 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-length-default-value.js prototype/bind/instance-length-exceeds-int32.js - prototype/bind/instance-length-prop-desc.js prototype/bind/instance-length-tointeger.js prototype/bind/instance-name.js prototype/bind/instance-name-chained.js @@ -633,8 +629,6 @@ built-ins/Function 194/505 (38.42%) prototype/toString/setter-object.js prototype/toString/symbol-named-builtins.js prototype/toString/unicode.js - prototype/length.js - prototype/name.js prototype/restricted-property-arguments.js prototype/restricted-property-caller.js prototype/S15.3.4_A5.js @@ -678,7 +672,6 @@ built-ins/Function 194/505 (38.42%) 15.3.5.4_2-9gs.js strict call-bind-this-realm-undef.js call-bind-this-realm-value.js - instance-name.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]} @@ -808,7 +801,7 @@ built-ins/Number 9/283 (3.18%) S9.3.1_A3_T1_U180E.js {unsupported: [u180e]} S9.3.1_A3_T2_U180E.js {unsupported: [u180e]} -built-ins/Object 141/3150 (4.48%) +built-ins/Object 140/3150 (4.44%) 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]} @@ -876,7 +869,6 @@ built-ins/Object 141/3150 (4.48%) 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]} - getOwnPropertyDescriptor/15.2.3.3-4-187.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 @@ -961,7 +953,7 @@ built-ins/parseInt 3/60 (5.0%) S15.1.2.2_A2_T10_U180E.js {unsupported: [u180e]} S15.1.2.2_A9.2.js -built-ins/Promise 406/599 (67.78%) +built-ins/Promise 405/599 (67.61%) allSettled/capability-resolve-throws-reject.js {unsupported: [async]} allSettled/ctx-ctor.js {unsupported: [class]} allSettled/does-not-invoke-array-setters.js {unsupported: [async]} @@ -1285,7 +1277,6 @@ built-ins/Promise 406/599 (67.78%) race/reject-ignored-deferred.js {unsupported: [async]} race/reject-ignored-immed.js {unsupported: [async]} race/reject-immed.js {unsupported: [async]} - race/resolve-element-function-name.js race/resolve-ignores-late-rejection.js {unsupported: [async]} race/resolve-ignores-late-rejection-deferred.js {unsupported: [async]} race/resolve-non-callable.js {unsupported: [async]} @@ -1716,7 +1707,7 @@ built-ins/ThrowTypeError 7/13 (53.85%) unique-per-realm-non-simple.js unique-per-realm-unmapped-args.js -built-ins/TypedArray 1006/1070 (94.02%) +built-ins/TypedArray 1005/1070 (93.93%) from/arylk-get-length-error.js from/arylk-to-length-error.js from/iter-access-error.js @@ -2286,7 +2277,6 @@ built-ins/TypedArray 1006/1070 (94.02%) prototype 3/3 (100.0%) Symbol.species 4/4 (100.0%) invoked.js - length.js name.js prototype.js @@ -3104,7 +3094,7 @@ language/expressions/addition 9/48 (18.75%) get-symbol-to-prim-err.js order-of-evaluation.js -language/expressions/arrow-function 254/333 (76.28%) +language/expressions/arrow-function 253/333 (75.98%) dstr/ary-init-iter-close.js dstr/ary-init-iter-get-err.js dstr/ary-init-iter-get-err-array-prototype.js @@ -3343,7 +3333,6 @@ language/expressions/arrow-function 254/333 (76.28%) lexical-super-property.js lexical-super-property-from-within-constructor.js lexical-supercall-from-immediately-invoked-arrow.js - name.js object-destructuring-param-strict-body.js {unsupported: [rest-parameters]} param-dflt-yield-expr.js {unsupported: [default-parameters]} param-dflt-yield-id-non-strict.js {unsupported: [default-parameters]} @@ -3581,7 +3570,7 @@ language/expressions/exponentiation 4/44 (9.09%) bigint-wrapped-values.js {unsupported: [computed-property-names]} order-of-evaluation.js -language/expressions/function 206/248 (83.06%) +language/expressions/function 205/248 (82.66%) dstr/ary-init-iter-close.js dstr/ary-init-iter-get-err.js dstr/ary-init-iter-get-err-array-prototype.js @@ -3761,7 +3750,6 @@ language/expressions/function 206/248 (83.06%) dflt-params-trailing-comma.js eval-var-scope-syntax-err.js {unsupported: [default-parameters]} length-dflt.js {unsupported: [default-parameters]} - name.js name-arguments-strict-body.js non-strict name-eval-strict-body.js non-strict object-destructuring-param-strict-body.js {unsupported: [rest-parameters]} @@ -3786,7 +3774,7 @@ language/expressions/function 206/248 (83.06%) scope-paramsbody-var-close.js scope-paramsbody-var-open.js -language/expressions/generators 235/275 (85.45%) +language/expressions/generators 233/275 (84.73%) dstr/ary-init-iter-close.js dstr/ary-init-iter-get-err.js dstr/ary-init-iter-get-err-array-prototype.js @@ -3980,8 +3968,6 @@ language/expressions/generators 235/275 (85.45%) implicit-name.js invoke-as-constructor.js length-dflt.js {unsupported: [default-parameters]} - length-property-descriptor.js - name.js named-yield-as-binding-identifier-escaped.js named-yield-as-identifier-reference-escaped.js named-yield-as-label-identifier-escaped.js @@ -4077,7 +4063,7 @@ language/expressions/multiplication 4/40 (10.0%) bigint-wrapped-values.js {unsupported: [computed-property-names]} order-of-evaluation.js -language/expressions/object 971/1081 (89.82%) +language/expressions/object 970/1081 (89.73%) dstr/async-gen-meth-ary-init-iter-close.js {unsupported: [async-iteration, async]} dstr/async-gen-meth-ary-init-iter-get-err.js {unsupported: [async-iteration]} dstr/async-gen-meth-ary-init-iter-get-err-array-prototype.js {unsupported: [async-iteration]} @@ -4798,7 +4784,6 @@ language/expressions/object 971/1081 (89.82%) method-definition/meth-rest-param-strict-body.js {unsupported: [rest-parameters]} method-definition/name-invoke-ctor.js method-definition/name-invoke-fn-strict.js non-strict - method-definition/name-length.js method-definition/name-length-dflt.js {unsupported: [default-parameters]} method-definition/name-name-prop-string.js method-definition/name-name-prop-symbol.js @@ -6287,7 +6272,7 @@ language/statements/for-of 471/725 (64.97%) scope-head-lex-open.js scope-head-var-none.js non-strict -language/statements/generators 225/259 (86.87%) +language/statements/generators 223/259 (86.1%) dstr/ary-init-iter-close.js dstr/ary-init-iter-get-err.js dstr/ary-init-iter-get-err-array-prototype.js @@ -6480,8 +6465,6 @@ language/statements/generators 225/259 (86.87%) has-instance.js invoke-as-constructor.js length-dflt.js {unsupported: [default-parameters]} - length-property-descriptor.js - name.js object-destructuring-param-strict-body.js {unsupported: [rest-parameters]} param-dflt-yield.js {unsupported: [default-parameters]} params-dflt-args-unmapped.js {unsupported: [default-parameters]}