diff --git a/rhino/src/main/java/org/mozilla/javascript/AbstractEcmaObjectOperations.java b/rhino/src/main/java/org/mozilla/javascript/AbstractEcmaObjectOperations.java index 844b288511..e36ccf403b 100644 --- a/rhino/src/main/java/org/mozilla/javascript/AbstractEcmaObjectOperations.java +++ b/rhino/src/main/java/org/mozilla/javascript/AbstractEcmaObjectOperations.java @@ -417,9 +417,7 @@ static boolean validateAndApplyPropertyDescriptor( return true; } - if (!Objects.equals( - ScriptableObject.isDataDescriptor(current), - ScriptableObject.isDataDescriptor(desc))) { + if (ScriptableObject.isDataDescriptor(current) != ScriptableObject.isDataDescriptor(desc)) { if (Boolean.FALSE.equals(current.get("configurable"))) { return false; } @@ -465,4 +463,33 @@ static boolean validateAndApplyPropertyDescriptor( } return true; } + + /** + * IsConstructor ( argument ) + * + *

https://262.ecma-international.org/12.0/#sec-isconstructor + */ + static boolean isConstructor(Object argument) { + /* + The abstract operation IsConstructor takes argument argument (an ECMAScript language value). + It determines if argument is a function object with a [[Construct]] internal method. + It performs the following steps when called: + + 1. If Type(argument) is not Object, return false. + 2. If argument has a [[Construct]] internal method, return true. + 3. Return false. + */ + + // Found no good way to implement this based on the spec. + // Therefor I did this as first step - this only supports Lambda based method declarations. + // see #1376 for more + if (argument instanceof LambdaConstructor) { + return true; + } + if (argument instanceof LambdaFunction) { + return false; + } + + return argument instanceof Constructable; + } } diff --git a/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java b/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java index 5e1ad9b932..5229ac4d7e 100644 --- a/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java +++ b/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java @@ -443,8 +443,8 @@ public Scriptable construct(Context cx, Scriptable scope, Object[] args) { } /** - * Creates new script object. The default implementation of {@link #construct} uses the method - * to to get the value for thisObj argument when invoking {@link #call}. The methos + * Creates new script object. The default implementation of {@link #construct} uses this method + * to to get the value for thisObj argument when invoking {@link #call}. The method * is allowed to return null to indicate that {@link #call} will create a new * object itself. In this case {@link #construct} will set scope and prototype on the result * {@link #call} unless they are already set. diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeReflect.java b/rhino/src/main/java/org/mozilla/javascript/NativeReflect.java index e3e35d3c88..4306724b6a 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeReflect.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeReflect.java @@ -142,7 +142,7 @@ private static Scriptable construct( Integer.toString(args.length)); } - if (!isConstructor(args[0])) { + if (!AbstractEcmaObjectOperations.isConstructor(args[0])) { throw ScriptRuntime.typeErrorById("msg.not.ctor", ScriptRuntime.typeof(args[0])); } @@ -151,7 +151,7 @@ private static Scriptable construct( return ctor.construct(cx, scope, ScriptRuntime.emptyArgs); } - if (args.length > 2 && !isConstructor(args[2])) { + if (args.length > 2 && !AbstractEcmaObjectOperations.isConstructor(args[2])) { throw ScriptRuntime.typeErrorById("msg.not.ctor", ScriptRuntime.typeof(args[2])); } @@ -174,7 +174,9 @@ private static Scriptable construct( } } - // hack to set the right prototype before calling the ctor + // our Constructable interface does not support the newTarget; + // therefore we use a cloned implementation that fixes + // the prototype before executing call(..). if (ctor instanceof BaseFunction && newTargetPrototype != null) { BaseFunction ctorBaseFunction = (BaseFunction) ctor; Scriptable result = ctorBaseFunction.createObject(cx, scope); @@ -198,19 +200,6 @@ private static Scriptable construct( return newScriptable; } - private static boolean isConstructor(final Object argument) { - // Hack for the moment because all Functions are Constructable - // see #1376 for more - if (argument instanceof LambdaConstructor) { - return true; - } - if (argument instanceof LambdaFunction) { - return false; - } - - return argument instanceof Constructable; - } - private static Object defineProperty( Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (args.length < 3) {