diff --git a/benchmarks/src/jmh/java/org/mozilla/javascript/benchmarks/BuiltinBenchmark.java b/benchmarks/src/jmh/java/org/mozilla/javascript/benchmarks/BuiltinBenchmark.java
index 27478b3352e..7a664df5df9 100644
--- a/benchmarks/src/jmh/java/org/mozilla/javascript/benchmarks/BuiltinBenchmark.java
+++ b/benchmarks/src/jmh/java/org/mozilla/javascript/benchmarks/BuiltinBenchmark.java
@@ -334,12 +334,11 @@ public Object dumbLambdaClassMethods(DumbLambdaState state) {
private static class DumbLambdaClass extends ScriptableObject {
- private static Object noop(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ private static Object noop(Context cx, VarScope scope, Object thisObj, Object[] args) {
return Undefined.instance;
}
- private static Object setValue(
- Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ private static Object setValue(Context cx, VarScope scope, Object thisObj, Object[] args) {
if (args.length < 1) {
throw ScriptRuntime.throwError(cx, scope, "Not enough args");
}
@@ -349,8 +348,7 @@ private static Object setValue(
return Undefined.instance;
}
- private static Object getValue(
- Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ private static Object getValue(Context cx, VarScope scope, Object thisObj, Object[] args) {
DumbLambdaClass self =
LambdaConstructor.convertThisObject(thisObj, DumbLambdaClass.class);
return self.value;
diff --git a/rhino-engine/src/main/java/org/mozilla/javascript/engine/Builtins.java b/rhino-engine/src/main/java/org/mozilla/javascript/engine/Builtins.java
index 6d779758c47..cf1b6994d27 100644
--- a/rhino-engine/src/main/java/org/mozilla/javascript/engine/Builtins.java
+++ b/rhino-engine/src/main/java/org/mozilla/javascript/engine/Builtins.java
@@ -11,7 +11,6 @@
import javax.script.ScriptContext;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ScriptRuntime;
-import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.TopLevel;
import org.mozilla.javascript.Undefined;
@@ -48,7 +47,7 @@ void register(Context cx, TopLevel scope, ScriptContext sc) {
ScriptableObject.DONTENUM | ScriptableObject.READONLY);
}
- private static Object print(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ private static Object print(Context cx, VarScope scope, Object thisObj, Object[] args) {
try {
Builtins self = getSelf(scope);
for (Object arg : args) {
diff --git a/rhino-tools/src/main/java/org/mozilla/javascript/tools/debugger/Dim.java b/rhino-tools/src/main/java/org/mozilla/javascript/tools/debugger/Dim.java
index 617b3049a67..9d42b0156e8 100644
--- a/rhino-tools/src/main/java/org/mozilla/javascript/tools/debugger/Dim.java
+++ b/rhino-tools/src/main/java/org/mozilla/javascript/tools/debugger/Dim.java
@@ -980,7 +980,7 @@ public static class StackFrame implements DebugFrame {
private VarScope scope;
/** The 'this' object. */
- private Scriptable thisObj;
+ private Object thisObj;
/** Whether this frame represents a function (vs a top-level script). */
private boolean isFunction;
@@ -1006,7 +1006,7 @@ private StackFrame(Context cx, Dim dim, FunctionSource fsource, boolean isFuncti
/** Called when the stack frame is entered. */
@Override
- public void onEnter(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public void onEnter(Context cx, VarScope scope, Object thisObj, Object[] args) {
contextData.pushFrame(this);
this.scope = scope;
this.thisObj = thisObj;
diff --git a/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Global.java b/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Global.java
index 6e4ea8ba6d7..9827ae10047 100644
--- a/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Global.java
+++ b/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Global.java
@@ -155,6 +155,10 @@ public void init(Context cx) {
history = (NativeArray) cx.newArray(this, 0);
defineProperty("history", history, ScriptableObject.DONTENUM);
+ // Initialize Test262 support
+ Test262 proto262 = Test262.init(cx, this, Test262.RealmMode.STANDARD);
+ Test262.install(this, proto262, Test262.RealmMode.STANDARD);
+
initialized = true;
}
diff --git a/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java b/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java
index 720563501bc..e536ff69784 100644
--- a/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java
+++ b/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java
@@ -23,7 +23,6 @@
import org.mozilla.javascript.Context;
import org.mozilla.javascript.GeneratedClassLoader;
import org.mozilla.javascript.Script;
-import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.VarScope;
public class JavaPolicySecurity extends SecurityProxy {
@@ -205,7 +204,7 @@ public Object callWithDomain(
Context cx,
Callable callable,
VarScope scope,
- Scriptable thisObj,
+ Object thisObj,
Object[] args) {
return doAction(securityDomain, () -> callable.call(cx, scope, thisObj, args));
}
@@ -216,7 +215,7 @@ public Object callWithDomain(
Context cx,
Script script,
VarScope scope,
- Scriptable thisObj,
+ Object thisObj,
Object[] args) {
return doAction(securityDomain, () -> script.exec(cx, scope, thisObj));
}
diff --git a/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Test262.java b/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Test262.java
new file mode 100644
index 00000000000..76b4d8c5009
--- /dev/null
+++ b/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Test262.java
@@ -0,0 +1,144 @@
+/* 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.tools.shell;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.ScopeObject;
+import org.mozilla.javascript.ScriptRuntime;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.SymbolKey;
+import org.mozilla.javascript.TopLevel;
+import org.mozilla.javascript.Undefined;
+import org.mozilla.javascript.VarScope;
+import org.mozilla.javascript.typedarrays.NativeArrayBuffer;
+
+/**
+ * Implements the $262 object required by the Test262 ECMAScript conformance test suite.
+ *
+ *
This class provides the host-defined functions specified by Test262 for testing ECMAScript
+ * implementations. It supports creating new realms, evaluating scripts, and accessing global
+ * objects.
+ *
+ * @see
+ * Test262 Host-Defined Functions
+ */
+public class Test262 extends ScriptableObject {
+
+ /** Enum to control how realms are initialized. */
+ public enum RealmMode {
+ /** Uses initSafeStandardObjects - restricts Java access for sandboxing (used in tests) */
+ SAFE,
+ /** Uses initStandardObjects - full access to Java integration (used in shell) */
+ STANDARD
+ }
+
+ private RealmMode realmMode;
+
+ public Test262() {
+ super();
+ }
+
+ Test262(VarScope scope, Scriptable prototype, RealmMode mode) {
+ super(scope, prototype);
+ this.realmMode = mode;
+ }
+
+ /**
+ * Initialize the $262 prototype object with all Test262 host-defined functions.
+ *
+ * @param cx the current Context
+ * @param scope the scope to install the prototype in
+ * @param mode the realm mode (SAFE for tests, STANDARD for shell)
+ * @return the initialized $262 prototype
+ */
+ public static Test262 init(Context cx, VarScope scope, RealmMode mode) {
+ Test262 proto = new Test262();
+ proto.realmMode = mode;
+ proto.setPrototype(getObjectPrototype(scope));
+ proto.setParentScope(scope);
+
+ proto.defineProperty(scope, "gc", 0, Test262::gc);
+ proto.defineProperty(scope, "createRealm", 0, Test262::createRealm);
+ proto.defineProperty(scope, "evalScript", 1, Test262::evalScript);
+ proto.defineProperty(scope, "detachArrayBuffer", 0, Test262::detachArrayBuffer);
+
+ proto.defineProperty(cx, scope, "global", Test262::getGlobal, null, DONTENUM | READONLY);
+ proto.defineProperty(cx, scope, "agent", Test262::getAgent, null, DONTENUM | READONLY);
+
+ proto.defineProperty(SymbolKey.TO_STRING_TAG, "__262__", DONTENUM | READONLY);
+
+ ScriptableObject.defineProperty(scope, "__262__", proto, DONTENUM);
+ return proto;
+ }
+
+ /**
+ * Install a $262 instance into a scope.
+ *
+ * @param scope the scope to install into
+ * @param parentScope the parent scope for the $262 instance
+ * @param mode the realm mode
+ * @return the installed $262 instance
+ */
+ public static Test262 install(ScopeObject scope, Scriptable parentScope, RealmMode mode) {
+ Test262 instance = new Test262(scope, parentScope, mode);
+
+ scope.put("$262", scope, instance);
+ scope.setAttributes("$262", ScriptableObject.DONTENUM);
+
+ return instance;
+ }
+
+ private static Object gc(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ System.gc();
+ return Undefined.instance;
+ }
+
+ public static Object evalScript(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ if (args.length == 0) {
+ throw ScriptRuntime.throwError(cx, scope, "not enough args");
+ }
+ String source = Context.toString(args[0]);
+ return cx.evaluateString(scope, source, "", 1, null);
+ }
+
+ public static Object getGlobal(Scriptable scriptable) {
+ return ((TopLevel) scriptable.getParentScope()).getGlobalThis();
+ }
+
+ public static Test262 createRealm(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ // Get the realm mode from the parent $262 instance
+ Test262 parent = (Test262) ScriptRuntime.toObject(scope, thisObj);
+ RealmMode mode = parent.realmMode;
+
+ // Create realm based on mode
+ TopLevel realm;
+ if (mode == RealmMode.SAFE) {
+ realm = cx.initSafeStandardObjects(new TopLevel());
+ } else {
+ realm = cx.initStandardObjects(new TopLevel());
+ }
+
+ return install(realm, ScriptRuntime.toObject(realm, thisObj).getPrototype(), mode);
+ }
+
+ public static Object detachArrayBuffer(
+ Context cx, VarScope scope, Object thisObj, Object[] args) {
+ Scriptable buf = ScriptRuntime.toObject(scope, args[0]);
+ if (buf instanceof NativeArrayBuffer) {
+ ((NativeArrayBuffer) buf).detach();
+ }
+ return Undefined.instance;
+ }
+
+ public static Object getAgent(Scriptable scriptable) {
+ throw new UnsupportedOperationException("$262.agent property not yet implemented");
+ }
+
+ @Override
+ public String getClassName() {
+ return "__262__";
+ }
+}
diff --git a/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Timers.java b/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Timers.java
index e91bb9f5864..7f7e477e765 100644
--- a/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Timers.java
+++ b/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Timers.java
@@ -6,7 +6,6 @@
import org.mozilla.javascript.Function;
import org.mozilla.javascript.LambdaFunction;
import org.mozilla.javascript.ScriptRuntime;
-import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.VarScope;
@@ -29,19 +28,14 @@ public class Timers {
public void install(VarScope scope) {
LambdaFunction setTimeout =
new LambdaFunction(
- scope,
- "setTimeout",
- 1,
- (Context lcx, VarScope lscope, Scriptable thisObj, Object[] args) ->
- setTimeout(args));
+ scope, "setTimeout", 1, (lcx, lscope, thisObj, args) -> setTimeout(args));
ScriptableObject.defineProperty(scope, "setTimeout", setTimeout, ScriptableObject.DONTENUM);
LambdaFunction clearTimeout =
new LambdaFunction(
scope,
"clearTimeout",
1,
- (Context lcx, VarScope lscope, Scriptable thisObj, Object[] args) ->
- clearTimeout(args));
+ (lcx, lscope, thisObj, args) -> clearTimeout(args));
ScriptableObject.defineProperty(
scope, "clearTimeout", clearTimeout, ScriptableObject.DONTENUM);
}
diff --git a/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLLibImpl.java b/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
index ff0df5ef5c3..2332f213670 100644
--- a/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
+++ b/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLLibImpl.java
@@ -25,7 +25,7 @@ public final class XMLLibImpl extends XMLLib implements Serializable {
// EXPERIMENTAL Java interface
//
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = -6301237868232033480L;
/** This experimental interface is undocumented. */
public static org.w3c.dom.Node toDomNode(Object xmlObject) {
diff --git a/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLList.java b/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLList.java
index dd0e20f04a1..2acb4c3a099 100644
--- a/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLList.java
+++ b/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XMLList.java
@@ -765,7 +765,7 @@ private XMLList getPropertyList(XMLName name) {
}
private Object applyOrCall(
- boolean isApply, Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ boolean isApply, Context cx, VarScope scope, Object thisObj, Object[] args) {
String methodName = isApply ? "apply" : "call";
if (!(thisObj instanceof XMLList) || ((XMLList) thisObj).targetProperty == null)
throw ScriptRuntime.typeErrorById("msg.isnt.function", methodName);
@@ -797,7 +797,7 @@ public Scriptable getExtraMethodSource(Context cx) {
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
// This XMLList is being called as a Function.
// Let's find the real Function object.
if (targetProperty == null) throw ScriptRuntime.notFunctionError(this);
@@ -812,7 +812,7 @@ public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args
throw ScriptRuntime.typeErrorById("msg.incompat.call", methodName);
}
Object func = null;
- Scriptable sobj = thisObj;
+ Scriptable sobj = ScriptRuntime.toObject(getDeclarationScope(), thisObj);
while (sobj instanceof XMLObject) {
XMLObject xmlObject = (XMLObject) sobj;
@@ -839,4 +839,9 @@ public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args
public Scriptable construct(Context cx, VarScope scope, Object[] args) {
throw ScriptRuntime.typeErrorById("msg.not.ctor", "XMLList");
}
+
+ @Override
+ public Scriptable construct(Context cx, Object nt, VarScope s, Object thisObj, Object[] args) {
+ throw ScriptRuntime.typeErrorById("msg.not.ctor", "XMLList");
+ }
}
diff --git a/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XmlNode.java b/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XmlNode.java
index f54eaf668ad..7c8a1681d3e 100644
--- a/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XmlNode.java
+++ b/rhino-xml/src/main/java/org/mozilla/javascript/xmlimpl/XmlNode.java
@@ -20,7 +20,7 @@
import org.w3c.dom.UserDataHandler;
class XmlNode implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 7498300745525888082L;
private static final String XML_NAMESPACES_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
diff --git a/rhino/src/main/java/org/mozilla/javascript/ArrayLikeAbstractOperations.java b/rhino/src/main/java/org/mozilla/javascript/ArrayLikeAbstractOperations.java
index 304b2b81c24..045de788053 100644
--- a/rhino/src/main/java/org/mozilla/javascript/ArrayLikeAbstractOperations.java
+++ b/rhino/src/main/java/org/mozilla/javascript/ArrayLikeAbstractOperations.java
@@ -31,59 +31,6 @@ public interface LengthAccessor {
public long getLength(Context cx, Scriptable o);
}
- /**
- * Implements the methods "every", "filter", "forEach", "map", and "some" without using an
- * IdFunctionObject.
- */
- public static Object iterativeMethod(
- Context cx,
- IterativeOperation operation,
- VarScope scope,
- Object thisObj,
- Object[] args,
- LengthAccessor lengthAccessor) {
- return iterativeMethod(cx, null, operation, scope, thisObj, args, lengthAccessor, true);
- }
-
- /**
- * Implements the methods "every", "filter", "forEach", "map", and "some" using an
- * IdFunctionObject.
- */
- public static Object iterativeMethod(
- Context cx,
- IdFunctionObject fun,
- IterativeOperation operation,
- VarScope scope,
- Object thisObj,
- Object[] args,
- LengthAccessor lengthAccessor) {
- return iterativeMethod(cx, fun, operation, scope, thisObj, args, lengthAccessor, false);
- }
-
- private static Object iterativeMethod(
- Context cx,
- IdFunctionObject fun,
- IterativeOperation operation,
- VarScope scope,
- Object thisObj,
- Object[] args,
- LengthAccessor lengthAccessor,
- boolean skipCoercibleCheck) {
- Scriptable o = ScriptRuntime.toObject(cx, scope, thisObj);
-
- if (!skipCoercibleCheck) {
- if (IterativeOperation.FIND == operation
- || IterativeOperation.FIND_INDEX == operation
- || IterativeOperation.FIND_LAST == operation
- || IterativeOperation.FIND_LAST_INDEX == operation) {
- requireObjectCoercible(cx, o, fun);
- }
- }
-
- long length = lengthAccessor.getLength(cx, o);
- return coercibleIterativeMethod(cx, operation, scope, o, args, length);
- }
-
public static Object iterativeMethod(
Context cx,
Object tag,
diff --git a/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java b/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java
index d5386cd7419..eec59e7957b 100644
--- a/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java
+++ b/rhino/src/main/java/org/mozilla/javascript/BaseFunction.java
@@ -6,6 +6,10 @@
package org.mozilla.javascript;
+import static org.mozilla.javascript.ClassDescriptor.Builder.value;
+import static org.mozilla.javascript.ClassDescriptor.Destination.PROTO;
+import static org.mozilla.javascript.Symbol.Kind.REGULAR;
+
import java.util.EnumSet;
import org.mozilla.javascript.xml.XMLObject;
@@ -23,100 +27,108 @@ public class BaseFunction extends ScriptableObject implements Function {
private static final Object FUNCTION_TAG = "Function";
private static final String FUNCTION_CLASS = "Function";
- static final String GENERATOR_FUNCTION_CLASS = "__GeneratorFunction";
+ static final SymbolKey GENERATOR_FUNCTION_CLASS =
+ new SymbolKey("GeneratorFunctionPrototype", REGULAR);
+ static final SymbolKey ASYNC_FUNCTION_CLASS = new SymbolKey("AsyncFunctionPrototype", REGULAR);
+ static final SymbolKey ASYNC_GENERATOR_FUNCTION_CLASS =
+ new SymbolKey("AsyncGeneratorFunctionPrototype", REGULAR);
private static final String APPLY_TAG = "APPLY_TAG";
private static final String CALL_TAG = "CALL_TAG";
private static final String PROTOTYPE_PROPERTY_NAME = "prototype";
- static LambdaConstructor init(Context cx, VarScope scope, boolean sealed) {
- LambdaConstructor ctor =
- new LambdaConstructor(
- scope,
- FUNCTION_CLASS,
- 1,
- BaseFunction::js_constructorCall,
- BaseFunction::js_constructor);
-
+ private static final ClassDescriptor DESCRIPTOR;
+ private static final ClassDescriptor ES6_DESCRIPTOR;
+ private static final ClassDescriptor GENERATOR_DESCRIPTOR;
+ // private static final ClassDescriptor GENERATOR_DESCRIPTOR;
+ private static final ClassDescriptor ASYNC_DESCRIPTOR;
+ private static final ClassDescriptor ASYNC_GENERATOR_DESCRIPTOR;
+ private static final JSDescriptor APPLY_DESCRIPTOR;
+ private static final JSDescriptor CALL_DESCRIPTOR;
+
+ static {
+ var builder =
+ new ClassDescriptor.Builder(
+ FUNCTION_CLASS,
+ 1,
+ BaseFunction::js_constructor,
+ BaseFunction::js_constructor)
+ .withMethod(PROTO, "call", 1, BaseFunction::js_call)
+ .withMethod(PROTO, "apply", 2, BaseFunction::js_apply)
+ .withMethod(PROTO, "bind", 1, BaseFunction::js_bind)
+ .withMethod(PROTO, "toSource", 1, BaseFunction::js_toSource)
+ .withMethod(PROTO, "toString", 0, BaseFunction::js_toString)
+ .withMethod(
+ PROTO,
+ SymbolKey.HAS_INSTANCE,
+ 1,
+ BaseFunction::js_hasInstance,
+ DONTENUM | READONLY | PERMANENT,
+ DONTENUM | READONLY);
+
+ DESCRIPTOR = builder.build();
+ ES6_DESCRIPTOR =
+ builder.withProp(
+ PROTO,
+ "arguments",
+ BaseFunction::js_protoArgumentsGetter,
+ BaseFunction::js_protoArgumentsSetter,
+ DONTENUM | READONLY)
+ .build();
+
+ APPLY_DESCRIPTOR = DESCRIPTOR.findProtoDesc("apply");
+ CALL_DESCRIPTOR = DESCRIPTOR.findProtoDesc("call");
+
+ GENERATOR_DESCRIPTOR =
+ new ClassDescriptor.Builder(
+ GENERATOR_FUNCTION_CLASS,
+ "GeneratorFunction",
+ 1,
+ BaseFunction::js_gen_constructor,
+ BaseFunction::js_gen_constructor)
+ .withProp(
+ PROTO,
+ SymbolKey.TO_STRING_TAG,
+ value("GeneratorFunction", READONLY | DONTENUM))
+ .build();
+
+ ASYNC_DESCRIPTOR =
+ new ClassDescriptor.Builder(
+ ASYNC_FUNCTION_CLASS,
+ "AsyncFunction",
+ 1,
+ BaseFunction::js_async_constructor,
+ BaseFunction::js_async_constructor)
+ .withProp(
+ PROTO,
+ SymbolKey.TO_STRING_TAG,
+ value("AsyncFunction", READONLY | DONTENUM))
+ .build();
+
+ ASYNC_GENERATOR_DESCRIPTOR =
+ new ClassDescriptor.Builder(
+ ASYNC_GENERATOR_FUNCTION_CLASS,
+ "AsyncGeneratorFunction",
+ 1,
+ BaseFunction::js_async_gen_constructor,
+ BaseFunction::js_async_gen_constructor)
+ .withProp(
+ PROTO,
+ SymbolKey.TO_STRING_TAG,
+ value("AsyncGeneratorFunction", READONLY | DONTENUM))
+ .build();
+ }
+
+ static JSFunction init(Context cx, VarScope scope, boolean sealed) {
var proto =
new LambdaFunction(
scope, "", 0, null, (lcx, lscope, lthisObj, largs) -> Undefined.instance);
- proto.defineProperty("constructor", ctor, DONTENUM);
- // Set the constructor correctly here. i.e. ctor.prototype.constructor == ctor
- // Redo the stuff about setupDefaultPrototype.
-
- ctor.setPrototypeProperty(proto);
- // Do this early, so that the functions on the prototype get
- // the right prototype...
- ScriptableObject.defineProperty(scope, FUNCTION_CLASS, ctor, DONTENUM);
- ctor.setPrototype((Scriptable) ctor.getPrototypeProperty());
-
- defKnownBuiltInOnProto(ctor, APPLY_TAG, scope, "apply", 2, BaseFunction::js_apply);
- defOnProto(ctor, scope, "bind", 1, BaseFunction::js_bind);
- defKnownBuiltInOnProto(ctor, CALL_TAG, scope, "call", 1, BaseFunction::js_call);
- defOnProto(ctor, scope, "toSource", 1, BaseFunction::js_toSource);
- defOnProto(ctor, scope, "toString", 0, BaseFunction::js_toString);
- defOnProto(
- ctor,
- scope,
- SymbolKey.HAS_INSTANCE,
- 1,
- BaseFunction::js_hasInstance,
- DONTENUM | READONLY | PERMANENT);
-
- // Function.prototype attributes: see ECMA 15.3.3.1
- ctor.setPrototypePropertyAttributes(DONTENUM | READONLY | PERMANENT);
- if (cx.getLanguageVersion() >= Context.VERSION_ES6) {
- ctor.setStandardPropertyAttributes(READONLY | DONTENUM);
- }
-
- if (!cx.isStrictMode() && cx.getLanguageVersion() >= Context.VERSION_ES6) {
- ctor.definePrototypeProperty(
- cx,
- "arguments",
- BaseFunction::js_protoArgumentsGetter,
- BaseFunction::js_protoArgumentsSetter,
- DONTENUM | READONLY);
- }
-
- ScriptableObject.defineProperty(scope, FUNCTION_CLASS, ctor, DONTENUM);
- if (sealed) {
- ctor.sealObject();
- ((ScriptableObject) ctor.getPrototypeProperty()).sealObject();
+ if (cx.getLanguageVersion() < Context.VERSION_ES6) {
+ return DESCRIPTOR.buildConstructor(cx, scope, proto, sealed);
+ } else {
+ return ES6_DESCRIPTOR.buildConstructor(cx, scope, proto, sealed);
}
- return ctor;
- }
-
- private static void defOnProto(
- LambdaConstructor constructor,
- VarScope scope,
- String name,
- int length,
- SerializableCallable target) {
- constructor.definePrototypeMethod(scope, name, length, target);
- }
-
- private static void defKnownBuiltInOnProto(
- LambdaConstructor constructor,
- Object tag,
- VarScope scope,
- String name,
- int length,
- SerializableCallable target) {
- constructor.defineKnownBuiltInPrototypeMethod(
- tag, scope, name, length, null, target, DONTENUM, DONTENUM | READONLY);
- }
-
- private static void defOnProto(
- LambdaConstructor constructor,
- VarScope scope,
- SymbolKey name,
- int length,
- SerializableCallable target,
- int attributes) {
- constructor.definePrototypeMethod(
- scope, name, length, null, target, attributes, DONTENUM | READONLY);
}
/**
@@ -127,54 +139,75 @@ static void init(VarScope scope, boolean sealed) {
init(Context.getContext(), scope, sealed);
}
- static Object initAsGeneratorFunction(VarScope scope, boolean sealed) {
+ static Object initAsGeneratorFunction(Context cx, VarScope scope, boolean sealed) {
var proto = new NativeObject();
- VarScope top = ScriptableObject.getTopLevelScope(scope);
-
- var function = (Scriptable) ScriptableObject.getProperty(scope, FUNCTION_CLASS);
- var functionProto =
- (Scriptable) ScriptableObject.getProperty(function, PROTOTYPE_PROPERTY_NAME);
- proto.setPrototype(functionProto);
- var iterator = (Scriptable) ScriptableObject.getProperty(scope, "Iterator");
- ScriptableObject.putProperty(
+ return GENERATOR_DESCRIPTOR.buildConstructor(
+ cx,
+ scope,
proto,
- PROTOTYPE_PROPERTY_NAME,
- ScriptableObject.getTopScopeValue(top, ES6Generator.GENERATOR_TAG));
+ sealed,
+ (c, ctor) -> {
+ VarScope top = ScriptableObject.getTopLevelScope(scope);
+
+ var function = (Scriptable) ScriptableObject.getProperty(scope, FUNCTION_CLASS);
+ var functionProto =
+ (Scriptable)
+ ScriptableObject.getProperty(function, PROTOTYPE_PROPERTY_NAME);
+ proto.setPrototype(functionProto);
- LambdaConstructor ctor =
- new LambdaConstructor(
- scope,
- GENERATOR_FUNCTION_CLASS,
- 1,
- proto,
- BaseFunction::js_gen_constructorCall,
- BaseFunction::js_gen_constructor);
+ var generatorProto =
+ ScriptableObject.getTopScopeValue(top, ES6Generator.GENERATOR_TAG);
- proto.defineProperty("constructor", ctor, READONLY | DONTENUM);
+ proto.setAttributes("constructor", DONTENUM | READONLY);
+ proto.defineProperty("prototype", generatorProto, READONLY | DONTENUM);
+ });
+ }
- // Function.prototype attributes: see ECMA 15.3.3.1
- ctor.setPrototypePropertyAttributes(DONTENUM | READONLY | PERMANENT);
+ static Object initAsAsyncFunction(Context cx, VarScope scope, boolean sealed) {
+ var proto = new NativeObject();
- proto.defineProperty(SymbolKey.TO_STRING_TAG, "GeneratorFunction", READONLY | DONTENUM);
- ScriptableObject.putProperty(scope, GENERATOR_FUNCTION_CLASS, ctor);
- // Function.prototype attributes: see ECMA 15.3.3.1
- // The "GeneratorFunction" name actually never appears in the global scope.
- // Return it here so it can be cached as a "builtin"
- return ctor;
+ return ASYNC_DESCRIPTOR.buildConstructor(
+ cx,
+ scope,
+ proto,
+ sealed,
+ (c, ctor) -> {
+ var function = (Scriptable) ScriptableObject.getProperty(scope, FUNCTION_CLASS);
+ var functionProto =
+ (Scriptable)
+ ScriptableObject.getProperty(function, PROTOTYPE_PROPERTY_NAME);
+ proto.setPrototype(functionProto);
+ proto.setAttributes("constructor", DONTENUM | READONLY);
+ });
}
- public BaseFunction() {
- createProperties();
+ static Object initAsAsyncGeneratorFunction(Context cx, VarScope scope, boolean sealed) {
+ var proto = new NativeObject();
+
+ return ASYNC_GENERATOR_DESCRIPTOR.buildConstructor(
+ cx,
+ scope,
+ proto,
+ sealed,
+ (c, ctor) -> {
+ var function = (Scriptable) ScriptableObject.getProperty(scope, FUNCTION_CLASS);
+ var functionProto =
+ (Scriptable)
+ ScriptableObject.getProperty(function, PROTOTYPE_PROPERTY_NAME);
+ proto.setPrototype(functionProto);
+ proto.setAttributes("constructor", DONTENUM | READONLY);
+ });
}
- public BaseFunction(boolean isGenerator) {
+ public BaseFunction(VarScope scope) {
+ declarationScope = scope;
createProperties();
- this.isGeneratorFunction = isGenerator;
}
public BaseFunction(VarScope scope, Scriptable prototype) {
super(scope, prototype);
+ declarationScope = scope;
createProperties();
ScriptRuntime.setBuiltinProtoAndParent(this, scope, TopLevel.Builtins.Function);
}
@@ -319,6 +352,11 @@ protected static boolean prototypeDescSetter(
}
}
+ static DescriptorInfo createThrowingProp(Context cx, VarScope scope, ScriptableObject obj) {
+ var thrower = ScriptRuntime.typeErrorThrower(scope);
+ return new DescriptorInfo(false, NOT_FOUND, true, thrower, thrower, null);
+ }
+
protected final boolean defaultHas(String name) {
return super.has(name, this);
}
@@ -333,7 +371,10 @@ protected final void defaultPut(String name, Object value) {
@Override
public String getClassName() {
- return isGeneratorFunction() ? GENERATOR_FUNCTION_CLASS : FUNCTION_CLASS;
+ if (isGeneratorFunction()) {
+ return isAsync() ? "AsyncGeneratorFunction" : "GeneratorFunction";
+ }
+ return isAsync() ? "AsyncFunction" : FUNCTION_CLASS;
}
// Generated code will override this
@@ -395,18 +436,34 @@ public boolean hasInstance(Scriptable instance) {
Id_arguments = 5,
MAX_INSTANCE_ID = 5;
- static boolean isApply(KnownBuiltInFunction f) {
- return f.getTag() == APPLY_TAG;
+ static boolean isApply(Callable f) {
+ if (f instanceof KnownBuiltInFunction) {
+ var kf = (KnownBuiltInFunction) f;
+ var tag = kf.getTag();
+ return tag == APPLY_TAG;
+ }
+ if (f instanceof JSFunction) {
+ return ((JSFunction) f).getDescriptor() == APPLY_DESCRIPTOR;
+ }
+ return false;
}
- static boolean isApplyOrCall(KnownBuiltInFunction f) {
- var tag = f.getTag();
- return tag == APPLY_TAG || tag == CALL_TAG;
+ static boolean isApplyOrCall(Callable f) {
+ if (f instanceof KnownBuiltInFunction) {
+ var kf = (KnownBuiltInFunction) f;
+ var tag = kf.getTag();
+ return tag == APPLY_TAG || tag == CALL_TAG;
+ }
+ if (f instanceof JSFunction) {
+ var desc = ((JSFunction) f).getDescriptor();
+ return desc == APPLY_DESCRIPTOR || desc == CALL_DESCRIPTOR;
+ }
+ return false;
}
private static Object js_hasInstance(
- Context cx, VarScope scope, Object thisObj, Object[] args) {
- if (!(thisObj instanceof Callable)) {
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ if (!(thisObj instanceof Callable && thisObj instanceof Scriptable)) {
return false;
}
Object protoProp = null;
@@ -434,7 +491,8 @@ private static Object js_hasInstance(
: "unknown");
}
- private static Object js_bind(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_bind(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
if (!(thisObj instanceof Callable)) {
throw ScriptRuntime.notFunctionError(thisObj);
}
@@ -443,25 +501,29 @@ private static Object js_bind(Context cx, VarScope scope, Object thisObj, Object
final Scriptable boundThis;
final Object[] boundArgs;
if (argc > 0) {
- boundThis = ScriptRuntime.toObjectOrNull(cx, args[0], scope);
+ boundThis = ScriptRuntime.toObjectOrNull(cx, args[0], s);
boundArgs = new Object[argc - 1];
System.arraycopy(args, 1, boundArgs, 0, argc - 1);
} else {
boundThis = null;
boundArgs = ScriptRuntime.emptyArgs;
}
- return new BoundFunction(cx, scope, targetFunction, boundThis, boundArgs);
+ return new BoundFunction(cx, s, targetFunction, boundThis, boundArgs);
}
- private static Object js_apply(Context cx, VarScope scope, Object thisObj, Object[] args) {
- return ScriptRuntime.applyOrCall(true, cx, scope, (Scriptable) thisObj, args);
+ private static Object js_apply(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return ScriptRuntime.applyOrCall(true, cx, f.getDeclarationScope(), thisObj, args);
}
- private static Object js_call(Context cx, VarScope scope, Object thisObj, Object[] args) {
- return ScriptRuntime.applyOrCall(false, cx, scope, (Scriptable) thisObj, args);
+ private static Object js_call(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ var thisArg = ScriptRuntime.toObject(f.getDeclarationScope(), thisObj);
+ return ScriptRuntime.applyOrCall(false, cx, f.getDeclarationScope(), thisArg, args);
}
- private static Object js_toSource(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_toSource(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
BaseFunction realf = realFunction(thisObj, "toSource");
int indent = 0;
EnumSet flags = EnumSet.of(DecompilerFlag.TO_SOURCE);
@@ -476,39 +538,45 @@ private static Object js_toSource(Context cx, VarScope scope, Object thisObj, Ob
return realf.decompile(indent, flags);
}
- private static Object js_toString(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_toString(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
BaseFunction realf = realFunction(thisObj, "toString");
int indent = ScriptRuntime.toInt32(args, 0);
return realf.decompile(indent, EnumSet.noneOf(DecompilerFlag.class));
}
- private static Scriptable js_gen_constructorCall(
- Context cx, VarScope scope, Object thisObj, Object[] args) {
- return js_gen_constructor(cx, scope, args);
+ private static Scriptable js_constructor(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return jsConstructor(cx, f, nt, f.getDeclarationScope(), args, false);
}
- private static Scriptable js_constructor(Context cx, VarScope scope, Object[] args) {
- return jsConstructor(cx, scope, args, false);
+ private static Scriptable js_gen_constructor(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return jsConstructor(cx, f, nt, f.getDeclarationScope(), args, true);
}
- private static Scriptable js_constructorCall(
- Context cx, VarScope scope, Object thisObj, Object[] args) {
- return js_constructor(cx, scope, args);
+ private static Scriptable js_async_constructor(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return jsConstructor(cx, f, nt, f.getDeclarationScope(), args, false, true);
}
- private static Scriptable js_gen_constructor(Context cx, VarScope scope, Object[] args) {
- return jsConstructor(cx, scope, args, true);
+ private static Scriptable js_async_gen_constructor(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return jsConstructor(cx, f, nt, f.getDeclarationScope(), args, true, true);
}
private static BaseFunction realFunction(Object thisObj, String functionName) {
if (thisObj == null) {
throw ScriptRuntime.notFunctionError(null);
}
- Object x = ((Scriptable) thisObj).getDefaultValue(ScriptRuntime.FunctionClass);
- if (x instanceof Delegator) {
- x = ((Delegator) x).getDelegee();
+ if (thisObj instanceof Scriptable) {
+ Object x = ((Scriptable) thisObj).getDefaultValue(ScriptRuntime.FunctionClass);
+ if (x instanceof Delegator) {
+ x = ((Delegator) x).getDelegee();
+ }
+ return ensureType(x, BaseFunction.class, functionName);
}
- return ensureType(x, BaseFunction.class, functionName);
+ return ensureType(thisObj, BaseFunction.class, functionName);
}
/** Make value as DontEnum, DontDelete, ReadOnly prototype property of this Function object */
@@ -531,7 +599,7 @@ protected Scriptable getClassPrototype() {
/** Should be overridden. */
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
return Undefined.instance;
}
@@ -574,6 +642,11 @@ public Scriptable construct(Context cx, VarScope scope, Object[] args) {
return result;
}
+ @Override
+ public Scriptable construct(Context cx, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return construct(cx, s, args);
+ }
+
/**
* Creates new script object. The default implementation of {@link #construct} uses this method
* to to get the value for {@code thisObj} argument when invoking {@link #call}. The method is
@@ -588,6 +661,25 @@ public Scriptable createObject(Context cx, VarScope scope) {
return newInstance;
}
+ public Scriptable createObject(Context cx, VarScope scope, Object nt) {
+ Scriptable newInstance = new NativeObject();
+ Object proto;
+ if (nt instanceof JSFunction) {
+ proto = ((JSFunction) nt).getPrototypeProperty();
+ } else {
+ proto = Undefined.instance;
+ }
+
+ if (proto instanceof Scriptable) {
+ newInstance.setPrototype((Scriptable) proto);
+ } else {
+ newInstance.setPrototype(getClassPrototype());
+ }
+
+ newInstance.setParentScope(getParentScope());
+ return newInstance;
+ }
+
/**
* Decompile the source information associated with this js function/script back into a string.
*
@@ -724,14 +816,17 @@ Object getArguments() {
return argumentsObj;
}
Context cx = Context.getContext();
+ if (this instanceof JSFunction
+ && ((JSFunction) this).isStrict()
+ && cx.getLanguageVersion() >= Context.VERSION_ES6) {
+ ScriptRuntime.ThrowTypeError.throwNotAllowed();
+ }
+
NativeCall activation = ScriptRuntime.findFunctionActivation(cx, this);
// return (activation == null) ? null : activation.get("arguments", activation);
if (activation == null) {
return null;
}
- if (activation.function.isStrict() && cx.getLanguageVersion() >= Context.VERSION_ES6) {
- ScriptRuntime.ThrowTypeError.throwNotAllowed();
- }
Object arguments = activation.get("arguments", activation);
if (arguments instanceof Arguments && cx.getLanguageVersion() >= Context.VERSION_ES6) {
return new Arguments.ReadonlyArguments((Arguments) arguments, cx);
@@ -742,10 +837,29 @@ Object getArguments() {
void setArguments(Object caller) {}
private static Scriptable jsConstructor(
- Context cx, VarScope scope, Object[] args, boolean isGeneratorFunction) {
+ Context cx,
+ JSFunction f,
+ Object nt,
+ VarScope scope,
+ Object[] args,
+ boolean isGeneratorFunction) {
+ return jsConstructor(cx, f, nt, scope, args, isGeneratorFunction, false);
+ }
+
+ private static Scriptable jsConstructor(
+ Context cx,
+ JSFunction f,
+ Object nt,
+ VarScope scope,
+ Object[] args,
+ boolean isGeneratorFunction,
+ boolean isAsync) {
int arglen = args.length;
StringBuilder sourceBuf = new StringBuilder();
+ if (isAsync) {
+ sourceBuf.append("async ");
+ }
sourceBuf.append("function ");
if (isGeneratorFunction) {
sourceBuf.append("* ");
@@ -777,7 +891,7 @@ private static Scriptable jsConstructor(
String sourceURI = ScriptRuntime.makeUrlForGeneratedScript(false, filename, linep[0]);
- TopLevel global = ScriptableObject.getTopLevelScope(scope);
+ TopLevel global = ScriptableObject.getTopLevelScope(f.getDeclarationScope());
ErrorReporter reporter;
reporter = DefaultErrorReporter.forEval(cx.getErrorReporter());
@@ -789,7 +903,26 @@ private static Scriptable jsConstructor(
// Compile with explicit interpreter instance to force interpreter
// mode.
- return cx.compileFunction(global, source, evaluator, reporter, sourceURI, 1, null);
+ var res =
+ (JSFunction)
+ cx.compileFunction(global, source, evaluator, reporter, sourceURI, 1, null);
+
+ boolean resIsGenerator = res.getDescriptor().isES6Generator();
+ boolean resIsAsync = res.getDescriptor().isAsync();
+ if (resIsGenerator && resIsAsync) {
+ ScriptRuntime.setBuiltinProtoAndParent(
+ (ScriptableObject) res, f, nt, scope, TopLevel.Builtins.AsyncGeneratorFunction);
+ } else if (resIsGenerator) {
+ ScriptRuntime.setBuiltinProtoAndParent(
+ (ScriptableObject) res, f, nt, scope, TopLevel.Builtins.GeneratorFunction);
+ } else if (resIsAsync) {
+ ScriptRuntime.setBuiltinProtoAndParent(
+ (ScriptableObject) res, f, nt, scope, TopLevel.Builtins.AsyncFunction);
+ } else {
+ ScriptRuntime.setBuiltinProtoAndParent(
+ (ScriptableObject) res, f, nt, scope, TopLevel.Builtins.Function);
+ }
+ return res;
}
public void setHomeObject(Scriptable homeObject) {
@@ -806,15 +939,12 @@ public boolean isConstructor() {
&& this.getHomeObject() != null);
}
- private static final int Id_constructor = 1,
- Id_toString = 2,
- Id_toSource = 3,
- Id_apply = 4,
- Id_call = 5,
- Id_bind = 6,
- SymbolId_hasInstance = 7,
- MAX_PROTOTYPE_ID = SymbolId_hasInstance;
+ @Override
+ public VarScope getDeclarationScope() {
+ return declarationScope;
+ }
+ private final VarScope declarationScope;
private Object prototypeProperty;
private Object argumentsObj = NOT_FOUND;
private Object nameValue = null;
diff --git a/rhino/src/main/java/org/mozilla/javascript/BoundFunction.java b/rhino/src/main/java/org/mozilla/javascript/BoundFunction.java
index 554b8008b03..6092d0a2ad2 100644
--- a/rhino/src/main/java/org/mozilla/javascript/BoundFunction.java
+++ b/rhino/src/main/java/org/mozilla/javascript/BoundFunction.java
@@ -26,6 +26,7 @@ public BoundFunction(
Callable targetFunction,
Scriptable boundThis,
Object[] boundArgs) {
+ super(scope);
this.targetFunction = targetFunction;
this.boundThis = boundThis;
this.boundArgs = boundArgs;
@@ -58,7 +59,7 @@ void setArguments(Object caller) {
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] extraArgs) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] extraArgs) {
return targetFunction.call(cx, scope, getCallThis(), concat(boundArgs, extraArgs));
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/Callable.java b/rhino/src/main/java/org/mozilla/javascript/Callable.java
index 4fcca2b21be..bba87f56de0 100644
--- a/rhino/src/main/java/org/mozilla/javascript/Callable.java
+++ b/rhino/src/main/java/org/mozilla/javascript/Callable.java
@@ -20,5 +20,5 @@ public interface Callable {
* @param args the array of arguments
* @return the result of the call
*/
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args);
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args);
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/CatchScope.java b/rhino/src/main/java/org/mozilla/javascript/CatchScope.java
new file mode 100644
index 00000000000..8a264518658
--- /dev/null
+++ b/rhino/src/main/java/org/mozilla/javascript/CatchScope.java
@@ -0,0 +1,14 @@
+package org.mozilla.javascript;
+
+public class CatchScope extends DeclarationScope {
+ private static final long serialVersionUID = -7471457301304454454L;
+
+ public CatchScope(VarScope parentScope) {
+ super(parentScope);
+ }
+
+ @Override
+ public boolean isNestedScope() {
+ return true;
+ }
+}
diff --git a/rhino/src/main/java/org/mozilla/javascript/ClassDescriptor.java b/rhino/src/main/java/org/mozilla/javascript/ClassDescriptor.java
index 7f8b9c687fc..d6d98d069ee 100644
--- a/rhino/src/main/java/org/mozilla/javascript/ClassDescriptor.java
+++ b/rhino/src/main/java/org/mozilla/javascript/ClassDescriptor.java
@@ -211,7 +211,7 @@ public ScriptableObject populateGlobal(
ScriptableObject.defineProperty(
scope, ctorDesc.name.toString(), global, ctorDesc.attributes);
for (var e : ctorDescs) {
- var f = new JSFunction(scope, e.funcDesc, null, null);
+ var f = new JSFunction(scope, e.funcDesc, null, Undefined.instance, null);
f.setStandardPropertyAttributes(e.stdAttrs);
if (e.name instanceof String) {
global.put((String) e.name, global, f);
@@ -241,7 +241,7 @@ public JSFunction buildConstructor(
ScriptableObject proto,
boolean sealed,
BiConsumer customStep) {
- var ctor = new JSFunction(scope, ctorDesc.funcDesc, null, null);
+ var ctor = new JSFunction(scope, ctorDesc.funcDesc, null, Undefined.instance, null);
if (proto != null) {
ctor.setPrototypeProperty(proto);
@@ -258,7 +258,7 @@ public JSFunction buildConstructor(
}
for (var e : ctorDescs) {
- var f = new JSFunction(scope, e.funcDesc, null, null);
+ var f = new JSFunction(scope, e.funcDesc, null, Undefined.instance, null);
f.setStandardPropertyAttributes(e.stdAttrs);
if (e.name instanceof String) {
ctor.put((String) e.name, ctor, f);
@@ -280,7 +280,7 @@ public JSFunction buildConstructor(
}
proto.setAttributes("constructor", DONTENUM);
for (var e : protoDescs) {
- var f = new JSFunction(scope, e.funcDesc, null, null);
+ var f = new JSFunction(scope, e.funcDesc, null, Undefined.instance, null);
f.setStandardPropertyAttributes(e.stdAttrs);
if (e.name instanceof String) {
proto.put((String) e.name, proto, f);
@@ -782,7 +782,7 @@ public ClassDescriptor build() {
private static class BuiltInJSCode extends JSCode implements Serializable {
- private static final long serialVersionUID = 2691205302914111400L;
+ private static final long serialVersionUID = -346984669839537590L;
private final JSCodeExec exec;
private final JSCodeResume resume;
diff --git a/rhino/src/main/java/org/mozilla/javascript/CodeGenUtils.java b/rhino/src/main/java/org/mozilla/javascript/CodeGenUtils.java
index 412a64b272b..29419ed639d 100644
--- a/rhino/src/main/java/org/mozilla/javascript/CodeGenUtils.java
+++ b/rhino/src/main/java/org/mozilla/javascript/CodeGenUtils.java
@@ -26,17 +26,23 @@ public static void fillInForNestedFunction(
|| fnParent instanceof Block)) {
builder.declaredAsFunctionExpression = true;
boolean isArrow = fn.getFunctionType() == FunctionNode.ARROW_FUNCTION;
+ boolean isAsyncNonGenerator = fn.isAsync() && !fn.isES6Generator();
builder.hasLexicalThis = isArrow;
- builder.hasPrototype = !isArrow;
- if (!isArrow) {
+ builder.hasPrototype = !isArrow && !isAsyncNonGenerator;
+ if (!isArrow && !isAsyncNonGenerator) {
builder.constructor = builder.code;
} else {
builder.constructor = new JSCode.NullBuilder();
}
} else {
builder.hasLexicalThis = false;
- builder.hasPrototype = true;
- builder.constructor = builder.code;
+ boolean isAsyncNonGenerator = fn.isAsync() && !fn.isES6Generator();
+ builder.hasPrototype = !isAsyncNonGenerator;
+ if (!isAsyncNonGenerator) {
+ builder.constructor = builder.code;
+ } else {
+ builder.constructor = new JSCode.NullBuilder();
+ }
}
fillInForFunction(builder, fn);
@@ -55,6 +61,9 @@ private static void fillInForFunction(JSDescriptor.Builder builder, FunctionNode
if (fn.isES6Generator()) {
builder.isES6Generator = true;
}
+ if (fn.isAsync()) {
+ builder.isAsync = true;
+ }
if (fn.isShorthand()) {
builder.isShorthand = true;
}
@@ -124,7 +133,8 @@ public static > void setConstructor(
if (scriptOrFn instanceof FunctionNode) {
FunctionNode f = (FunctionNode) scriptOrFn;
boolean isArrow = f.getFunctionType() == FunctionNode.ARROW_FUNCTION;
- if (isArrow || f.isMethodDefinition() || f.isGenerator()) {
+ boolean isAsyncNonGenerator = f.isAsync() && !f.isES6Generator();
+ if (isArrow || f.isMethodDefinition() || f.isGenerator() || isAsyncNonGenerator) {
builder.constructor = new JSCode.NullBuilder();
} else {
builder.constructor = builder.code;
diff --git a/rhino/src/main/java/org/mozilla/javascript/CodeGenerator.java b/rhino/src/main/java/org/mozilla/javascript/CodeGenerator.java
index 0eb9c63b8c2..8b7123c7b27 100644
--- a/rhino/src/main/java/org/mozilla/javascript/CodeGenerator.java
+++ b/rhino/src/main/java/org/mozilla/javascript/CodeGenerator.java
@@ -283,7 +283,8 @@ private void visitStatement(Node node, int initialStackDepth) {
// at script/function start.
// In addition, function expressions can not be present here
// at statement level, they must only be present as expressions.
- if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
+ if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT
+ || fnType == FunctionNode.FUNCTION_BLOCK_SCOPED) {
addIndexOp(Icode_CLOSURE_STMT, fnIndex);
} else {
if (fnType != FunctionNode.FUNCTION_STATEMENT) {
@@ -311,6 +312,7 @@ private void visitStatement(Node node, int initialStackDepth) {
case Token.LABEL:
case Token.LOOP:
case Token.BLOCK:
+ case Token.SCOPE_BLOCK:
case Token.EMPTY:
case Token.WITH:
updateLineNumber(node);
@@ -328,8 +330,12 @@ private void visitStatement(Node node, int initialStackDepth) {
stackChange(-1);
break;
- case Token.LEAVEWITH:
- addToken(Token.LEAVEWITH);
+ case Token.ENTER_SCOPE:
+ visitEnterScope(node, child);
+ break;
+
+ case Token.LEAVE_SCOPE:
+ addToken(Token.LEAVE_SCOPE);
break;
case Token.LOCAL_BLOCK:
@@ -553,6 +559,25 @@ private void visitStatement(Node node, int initialStackDepth) {
}
}
+ private void visitEnterScope(Node node, Node child) {
+ addToken(Token.ENTER_SCOPE);
+ stackChange(1);
+ Object[] names = (Object[]) node.getProp(Node.OBJECT_IDS_PROP);
+ int i = 0;
+ while (child != null) {
+ addIcode(Icode_DUP);
+ stackChange(1);
+ visitExpression(child, 0);
+ addStringOp(Token.SETNAME, (String) names[i]);
+ addIcode(Icode_POP);
+ stackChange(-2);
+ child = child.getNext();
+ i++;
+ }
+ addIcode(Icode_POP);
+ stackChange(-1);
+ }
+
private void visitExpression(Node node, int contextFlags) {
int type = node.getType();
Node child = node.getFirstChild();
@@ -1052,6 +1077,7 @@ private void visitExpression(Node node, int contextFlags) {
case Token.THIS:
case Token.SUPER:
case Token.THISFN:
+ case Token.NEW_TARGET:
case Token.FALSE:
case Token.TRUE:
addToken(type);
@@ -1156,16 +1182,19 @@ private void visitExpression(Node node, int contextFlags) {
case Token.YIELD:
case Token.YIELD_STAR:
+ case Token.AWAIT:
if (child != null) {
visitExpression(child, 0);
} else {
addIcode(Icode_UNDEF);
stackChange(1);
}
- if (type == Token.YIELD) {
- addToken(Token.YIELD);
- } else {
+ if (type == Token.YIELD_STAR) {
addIcode(Icode_YIELD_STAR);
+ } else {
+ // Token.YIELD and Token.AWAIT both use the same yield opcode;
+ // the async Promise runner drives the generator for await.
+ addToken(Token.YIELD);
}
addUint16(node.getLineno() & 0xFFFF);
break;
@@ -1178,7 +1207,17 @@ private void visitExpression(Node node, int contextFlags) {
addToken(Token.ENTERWITH);
stackChange(-1);
visitExpression(with.getFirstChild(), 0);
- addToken(Token.LEAVEWITH);
+ addToken(Token.LEAVE_SCOPE);
+ break;
+ }
+
+ case Token.SCOPEEXPR:
+ {
+ Node enterScope = node.getFirstChild();
+ Node expr = enterScope.getNext();
+ visitEnterScope(enterScope, enterScope.getFirstChild());
+ visitExpression(expr.getFirstChild(), 0);
+ addToken(Token.LEAVE_SCOPE);
break;
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/Constructable.java b/rhino/src/main/java/org/mozilla/javascript/Constructable.java
index 28f7f2d7842..36e47736742 100644
--- a/rhino/src/main/java/org/mozilla/javascript/Constructable.java
+++ b/rhino/src/main/java/org/mozilla/javascript/Constructable.java
@@ -16,4 +16,8 @@ public interface Constructable {
* @return the allocated object
*/
Scriptable construct(Context cx, VarScope scope, Object[] args);
+
+ default Scriptable construct(Context cx, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return construct(cx, s, args);
+ }
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/ContextFactory.java b/rhino/src/main/java/org/mozilla/javascript/ContextFactory.java
index b8f60c13707..6300382e134 100644
--- a/rhino/src/main/java/org/mozilla/javascript/ContextFactory.java
+++ b/rhino/src/main/java/org/mozilla/javascript/ContextFactory.java
@@ -323,7 +323,7 @@ public final void initApplicationClassLoader(ClassLoader loader) {
* perform the real call. In this way execution of any script happens inside this function.
*/
protected Object doTopCall(
- Callable callable, Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ Callable callable, Context cx, VarScope scope, Object thisObj, Object[] args) {
Object result = callable.call(cx, scope, thisObj, args);
return result instanceof ConsString ? result.toString() : result;
}
@@ -333,7 +333,7 @@ protected Object doTopCall(
* will create the first stack frame with scriptable code, it calls this method to perform the
* real call. In this way execution of any script happens inside this function.
*/
- protected Object doTopCall(Script script, Context cx, VarScope scope, Scriptable thisObj) {
+ protected Object doTopCall(Script script, Context cx, VarScope scope, Object thisObj) {
Object result = script.exec(cx, scope, thisObj);
return result instanceof ConsString ? result.toString() : result;
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/DeclarationScope.java b/rhino/src/main/java/org/mozilla/javascript/DeclarationScope.java
index 1d9571fe169..9ddd57e833f 100644
--- a/rhino/src/main/java/org/mozilla/javascript/DeclarationScope.java
+++ b/rhino/src/main/java/org/mozilla/javascript/DeclarationScope.java
@@ -1,7 +1,7 @@
package org.mozilla.javascript;
public class DeclarationScope extends ScopeObject {
- private static final long serialVersionUID = -7471457301304454454L;
+ private static final long serialVersionUID = -7992031023451233550L;
public DeclarationScope(VarScope parentScope) {
super(parentScope);
diff --git a/rhino/src/main/java/org/mozilla/javascript/Delegator.java b/rhino/src/main/java/org/mozilla/javascript/Delegator.java
index ca7ed36146f..a706e020e14 100644
--- a/rhino/src/main/java/org/mozilla/javascript/Delegator.java
+++ b/rhino/src/main/java/org/mozilla/javascript/Delegator.java
@@ -253,7 +253,7 @@ public boolean hasInstance(Scriptable instance) {
* @see org.mozilla.javascript.Function#call
*/
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
return ((Function) getDelegee()).call(cx, scope, thisObj, args);
}
@@ -286,4 +286,22 @@ public Scriptable construct(Context cx, VarScope scope, Object[] args) {
}
return ((Constructable) myDelegee).construct(cx, scope, args);
}
+
+ @Override
+ public Scriptable construct(Context cx, Object nt, VarScope s, Object thisObj, Object[] args) {
+ Scriptable myDelegee = getDelegee();
+ if (myDelegee == null) {
+ // this little trick allows us to declare prototype objects for Delegators
+ Delegator n = newInstance();
+ Scriptable delegee;
+ if (args.length == 0) {
+ delegee = cx.newObject(s);
+ } else {
+ delegee = ScriptRuntime.toObject(cx, s, args[0]);
+ }
+ n.setDelegee(delegee);
+ return n;
+ }
+ return ((Constructable) myDelegee).construct(cx, nt, s, thisObj, args);
+ }
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/ES6Generator.java b/rhino/src/main/java/org/mozilla/javascript/ES6Generator.java
index 50c7d6a6046..9cc76c353bc 100644
--- a/rhino/src/main/java/org/mozilla/javascript/ES6Generator.java
+++ b/rhino/src/main/java/org/mozilla/javascript/ES6Generator.java
@@ -6,10 +6,30 @@
package org.mozilla.javascript;
-public final class ES6Generator extends ScriptableObject {
- private static final long serialVersionUID = 1645892441041347273L;
+import static org.mozilla.javascript.ClassDescriptor.Builder.value;
+import static org.mozilla.javascript.ClassDescriptor.Destination.CTOR;
+import static org.mozilla.javascript.Symbol.Kind.REGULAR;
- static final Object GENERATOR_TAG = "Generator";
+public final class ES6Generator extends ScriptableObject {
+ private static final long serialVersionUID = -1617667918827493330L;
+
+ static final SymbolKey GENERATOR_TAG = new SymbolKey("GeneratorPrototype", REGULAR);
+
+ private static final ClassDescriptor DESCRIPTOR;
+
+ static {
+ DESCRIPTOR =
+ new ClassDescriptor.Builder(GENERATOR_TAG)
+ .withMethod(CTOR, "next", 1, ES6Generator::js_next)
+ .withMethod(CTOR, "return", 1, ES6Generator::js_return)
+ .withMethod(CTOR, "throw", 1, ES6Generator::js_throw)
+ .withMethod(CTOR, SymbolKey.ITERATOR, 0, ES6Generator::js_iterator)
+ .withProp(
+ CTOR,
+ SymbolKey.TO_STRING_TAG,
+ value("Generator", DONTENUM | READONLY))
+ .build();
+ }
private JSFunction function;
private Object savedState;
@@ -18,33 +38,13 @@ public final class ES6Generator extends ScriptableObject {
private State state = State.SUSPENDED_START;
private Object delegee;
- static ES6Generator init(TopLevel scope, boolean sealed) {
-
- ES6Generator prototype = new ES6Generator();
- if (scope != null) {
- prototype.setParentScope(scope);
- prototype.setPrototype(getObjectPrototype(scope));
- }
+ static ScriptableObject init(Context cx, TopLevel scope, boolean sealed) {
- // Define prototype methods using LambdaFunction
- LambdaFunction next = new LambdaFunction(scope, "next", 1, ES6Generator::js_next);
- ScriptableObject.defineProperty(prototype, "next", next, DONTENUM);
+ NativeObject prototype = new NativeObject();
+ DESCRIPTOR.populateGlobal(cx, scope, prototype, sealed);
- LambdaFunction returnFunc = new LambdaFunction(scope, "return", 1, ES6Generator::js_return);
- ScriptableObject.defineProperty(prototype, "return", returnFunc, DONTENUM);
-
- LambdaFunction throwFunc = new LambdaFunction(scope, "throw", 1, ES6Generator::js_throw);
- ScriptableObject.defineProperty(prototype, "throw", throwFunc, DONTENUM);
-
- LambdaFunction iterator =
- new LambdaFunction(scope, "[Symbol.iterator]", 0, ES6Generator::js_iterator);
- prototype.defineProperty(SymbolKey.ITERATOR, iterator, DONTENUM);
-
- prototype.defineProperty(SymbolKey.TO_STRING_TAG, "Generator", DONTENUM | READONLY);
-
- if (sealed) {
- prototype.sealObject();
- }
+ var iterCtor = (JSFunction) scope.get("Iterator", scope);
+ prototype.setPrototype((Scriptable) iterCtor.getPrototypeProperty());
// Need to access Generator prototype when constructing
// Generator instances, but don't have a generator constructor
@@ -75,8 +75,8 @@ public ES6Generator(VarScope scope, JSFunction function, Object savedState) {
// If function.prototype is not an Object, use the intrinsic default prototype
// Ref: Ecma 2026, 10.1.14 GetPrototypeFromConstructor step 4.
// See test262: language/statements/generators/default-proto.js
- ES6Generator prototype =
- (ES6Generator) ScriptableObject.getTopScopeValue(top, GENERATOR_TAG);
+ ScriptableObject prototype =
+ (ScriptableObject) ScriptableObject.getTopScopeValue(top, GENERATOR_TAG);
this.setPrototype(prototype);
}
}
@@ -90,34 +90,38 @@ private static ES6Generator realThis(Object thisObj) {
return LambdaConstructor.convertThisObject(thisObj, ES6Generator.class);
}
- private static Object js_return(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_return(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
ES6Generator generator = realThis(thisObj);
Object value = args.length >= 1 ? args[0] : Undefined.instance;
if (generator.delegee == null) {
- return generator.resumeAbruptLocal(cx, scope, NativeGenerator.GENERATOR_CLOSE, value);
+ return generator.resumeAbruptLocal(cx, s, NativeGenerator.GENERATOR_CLOSE, value);
}
- return generator.resumeDelegeeReturn(cx, scope, value);
+ return generator.resumeDelegeeReturn(cx, s, value);
}
- private static Object js_next(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_next(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
ES6Generator generator = realThis(thisObj);
Object value = args.length >= 1 ? args[0] : Undefined.instance;
if (generator.delegee == null) {
- return generator.resumeLocal(cx, scope, value);
+ return generator.resumeLocal(cx, s, value);
}
- return generator.resumeDelegee(cx, scope, value);
+ return generator.resumeDelegee(cx, s, value);
}
- private static Object js_throw(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_throw(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
ES6Generator generator = realThis(thisObj);
Object value = args.length >= 1 ? args[0] : Undefined.instance;
if (generator.delegee == null) {
- return generator.resumeAbruptLocal(cx, scope, NativeGenerator.GENERATOR_THROW, value);
+ return generator.resumeAbruptLocal(cx, s, NativeGenerator.GENERATOR_THROW, value);
}
- return generator.resumeDelegeeThrow(cx, scope, value);
+ return generator.resumeDelegeeThrow(cx, s, value);
}
- private static Object js_iterator(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_iterator(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
return thisObj;
}
@@ -230,7 +234,7 @@ private Scriptable resumeDelegeeReturn(Context cx, VarScope scope, Object value)
}
}
- private Scriptable resumeLocal(Context cx, VarScope scope, Object value) {
+ Scriptable resumeLocal(Context cx, VarScope scope, Object value) {
if (state == State.COMPLETED) {
return ES6Iterator.makeIteratorResult(cx, scope, Boolean.TRUE);
}
@@ -304,7 +308,7 @@ private Scriptable resumeLocal(Context cx, VarScope scope, Object value) {
return result;
}
- private Scriptable resumeAbruptLocal(Context cx, VarScope scope, int op, Object value) {
+ Scriptable resumeAbruptLocal(Context cx, VarScope scope, int op, Object value) {
if (state == State.EXECUTING) {
throw ScriptRuntime.typeErrorById("msg.generator.executing");
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/ES6Iterator.java b/rhino/src/main/java/org/mozilla/javascript/ES6Iterator.java
index cec23c0bb74..60f7b3cb980 100644
--- a/rhino/src/main/java/org/mozilla/javascript/ES6Iterator.java
+++ b/rhino/src/main/java/org/mozilla/javascript/ES6Iterator.java
@@ -6,6 +6,9 @@
package org.mozilla.javascript;
+import static org.mozilla.javascript.ClassDescriptor.Builder.value;
+import static org.mozilla.javascript.ClassDescriptor.Destination.CTOR;
+
public abstract class ES6Iterator extends ScriptableObject {
private static final long serialVersionUID = 2438373029140003950L;
@@ -16,35 +19,26 @@ public abstract class ES6Iterator extends ScriptableObject {
public static final String VALUE_PROPERTY = "value";
public static final String RETURN_METHOD = "return";
- protected static void init(
- TopLevel scope, boolean sealed, ScriptableObject prototype, String tag) {
- if (scope != null) {
- prototype.setParentScope(scope);
- prototype.setPrototype(getObjectPrototype(scope));
- }
-
- // Define prototype methods using LambdaFunction
- LambdaFunction next = new LambdaFunction(scope, NEXT_METHOD, 0, ES6Iterator::js_next);
- ScriptableObject.defineProperty(prototype, NEXT_METHOD, next, DONTENUM);
-
- LambdaFunction iterator =
- new LambdaFunction(scope, "[Symbol.iterator]", 1, ES6Iterator::js_iterator);
- prototype.defineProperty(SymbolKey.ITERATOR, iterator, DONTENUM);
-
- prototype.defineProperty(
- SymbolKey.TO_STRING_TAG, prototype.getClassName(), DONTENUM | READONLY);
-
- if (sealed) {
- prototype.sealObject();
- }
+ public static ClassDescriptor makeDescriptor(String name, String tag) {
+ // Need a way to associate the built object with the tag. We
+ // kind of need this in general, and at the top level, but we
+ // can bodge it for now.
+ return new ClassDescriptor.Builder(name)
+ .withMethod(CTOR, "next", 0, ES6Iterator::js_next)
+ .withMethod(CTOR, SymbolKey.ITERATOR, 1, ES6Iterator::js_iterator)
+ .withProp(CTOR, SymbolKey.TO_STRING_TAG, value(tag, DONTENUM | READONLY))
+ .build();
+ }
- // Need to access Iterator prototype when constructing
- // Iterator instances, but don't have a iterator constructor
- // to use to find the prototype. Use the "associateValue"
- // approach instead.
- if (scope != null) {
- scope.associateValue(tag, prototype);
- }
+ public static void initialize(
+ ClassDescriptor desc,
+ Context cx,
+ TopLevel scope,
+ ScriptableObject obj,
+ boolean sealed,
+ String name) {
+ var global = desc.populateGlobal(cx, scope, obj, sealed);
+ scope.associateValue(name, global);
}
protected boolean exhausted = false;
@@ -67,12 +61,14 @@ private static ES6Iterator realThis(Object thisObj) {
return LambdaConstructor.convertThisObject(thisObj, ES6Iterator.class);
}
- private static Object js_next(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_next(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
ES6Iterator iterator = realThis(thisObj);
- return iterator.next(cx, scope);
+ return iterator.next(cx, s);
}
- private static Object js_iterator(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_iterator(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
return thisObj;
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/Function.java b/rhino/src/main/java/org/mozilla/javascript/Function.java
index 039d1b639c0..73970a1fa1b 100644
--- a/rhino/src/main/java/org/mozilla/javascript/Function.java
+++ b/rhino/src/main/java/org/mozilla/javascript/Function.java
@@ -29,7 +29,7 @@ public interface Function extends Scriptable, Callable, Constructable {
* @return the result of the call
*/
@Override
- Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args);
+ Object call(Context cx, VarScope scope, Object thisObj, Object[] args);
/**
* Call the function as a constructor.
@@ -46,6 +46,9 @@ public interface Function extends Scriptable, Callable, Constructable {
@Override
Scriptable construct(Context cx, VarScope scope, Object[] args);
+ @Override
+ Scriptable construct(Context cx, Object nt, VarScope s, Object thisObj, Object[] args);
+
/**
* Return the scope in which this function was declared or closed over. This is the
* "[[Environment]]" defined in https://tc39.es/ecma262/#sec-ecmascript-function-objects.
@@ -61,4 +64,9 @@ default VarScope getDeclarationScope() {
default boolean isConstructor() {
return true;
}
+
+ /** Returns whether this is an async function. */
+ default boolean isAsync() {
+ return false;
+ }
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/FunctionObject.java b/rhino/src/main/java/org/mozilla/javascript/FunctionObject.java
index bdc7f4c2683..ca0495492ae 100644
--- a/rhino/src/main/java/org/mozilla/javascript/FunctionObject.java
+++ b/rhino/src/main/java/org/mozilla/javascript/FunctionObject.java
@@ -16,7 +16,7 @@
import java.lang.reflect.Modifier;
public class FunctionObject extends BaseFunction {
- private static final long serialVersionUID = -5332312783643935019L;
+ private static final long serialVersionUID = 8880062939740158370L;
/**
* Create a JavaScript function object from a Java method.
@@ -77,6 +77,7 @@ public class FunctionObject extends BaseFunction {
* @see org.mozilla.javascript.Scriptable
*/
public FunctionObject(String name, Member methodOrConstructor, VarScope scope) {
+ super(scope);
if (methodOrConstructor instanceof Constructor) {
member = new MemberBox(scope, (Constructor>) methodOrConstructor);
isStatic = true; // well, doesn't take a 'this'
@@ -353,7 +354,7 @@ public static Object convertArg(Context cx, VarScope scope, Object arg, Class>
* @see org.mozilla.javascript.Function#call( Context, VarScope, Scriptable, Object[])
*/
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisArg, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisArg, Object[] args) {
Object result;
boolean checkMethodResult = false;
int argsLength = args.length;
diff --git a/rhino/src/main/java/org/mozilla/javascript/FunctionScope.java b/rhino/src/main/java/org/mozilla/javascript/FunctionScope.java
index f2ad393e45f..ed4017e7d2a 100644
--- a/rhino/src/main/java/org/mozilla/javascript/FunctionScope.java
+++ b/rhino/src/main/java/org/mozilla/javascript/FunctionScope.java
@@ -1,7 +1,7 @@
package org.mozilla.javascript;
public class FunctionScope extends DeclarationScope {
- private static final long serialVersionUID = -7471457301304454454L;
+ private static final long serialVersionUID = 4760825497832652202L;
public FunctionScope(ScopeObject parentScope) {
super(parentScope);
diff --git a/rhino/src/main/java/org/mozilla/javascript/IRFactory.java b/rhino/src/main/java/org/mozilla/javascript/IRFactory.java
index 50e9cc738b1..4e64efed97b 100644
--- a/rhino/src/main/java/org/mozilla/javascript/IRFactory.java
+++ b/rhino/src/main/java/org/mozilla/javascript/IRFactory.java
@@ -18,6 +18,7 @@
import org.mozilla.javascript.ast.Assignment;
import org.mozilla.javascript.ast.AstNode;
import org.mozilla.javascript.ast.AstRoot;
+import org.mozilla.javascript.ast.AwaitExpression;
import org.mozilla.javascript.ast.BigIntLiteral;
import org.mozilla.javascript.ast.Block;
import org.mozilla.javascript.ast.BreakStatement;
@@ -198,6 +199,7 @@ private Node transform(AstNode node) {
case Token.NULL:
case Token.UNDEFINED:
case Token.DEBUGGER:
+ case Token.NEW_TARGET:
return transformLiteral(node);
case Token.SUPER:
parser.setRequiresActivation();
@@ -235,6 +237,8 @@ private Node transform(AstNode node) {
case Token.YIELD:
case Token.YIELD_STAR:
return transformYield((Yield) node);
+ case Token.AWAIT:
+ return transformAwait((AwaitExpression) node);
default:
if (node instanceof ExpressionStatement) {
return transformExprStmt((ExpressionStatement) node);
@@ -650,6 +654,14 @@ private Node transformFunction(FunctionNode fn) {
Node destructuring = (Node) fn.getProp(Node.DESTRUCTURING_PARAMS);
fn.removeProp(Node.DESTRUCTURING_PARAMS);
+ // Async non-generator functions use generator machinery internally to implement
+ // await: each await expression becomes a yield point. Mark the function as a
+ // generator now so that default-parameter and return-statement handling below
+ // uses the correct (generator) code paths.
+ if (fn.isAsync() && !fn.isES6Generator()) {
+ fn.setIsGenerator();
+ }
+
int lineno = fn.getBody().getLineno(), column = fn.getBody().getColumn();
++parser.nestingOfFunction; // only for body, not params
Node body = transform(fn.getBody());
@@ -1384,6 +1396,12 @@ private Node transformYield(Yield node) {
return new Node(node.getType(), node.getLineno(), node.getColumn());
}
+ private Node transformAwait(AwaitExpression node) {
+ Node kid = node.getValue() == null ? null : transform(node.getValue());
+ if (kid != null) return new Node(Token.AWAIT, kid, node.getLineno(), node.getColumn());
+ return new Node(Token.AWAIT, node.getLineno(), node.getColumn());
+ }
+
private Node transformSpread(Spread node) {
Node kid = transform(node.getExpression());
return new Node(node.getType(), kid, node.getLineno(), node.getColumn());
@@ -1892,7 +1910,7 @@ private Node createTryCatchFinally(
// but prefix it with LEAVEWITH since try..catch produces
// "with"code in order to limit the scope of the exception
// object.
- catchStatement.addChildToBack(new Node(Token.LEAVEWITH));
+ catchStatement.addChildToBack(new Node(Token.LEAVE_SCOPE));
catchStatement.addChildToBack(makeJump(Token.GOTO, endCatch));
// Create condition "if" when present
@@ -1911,13 +1929,9 @@ private Node createTryCatchFinally(
catchScope.putIntProp(Node.CATCH_SCOPE_PROP, scopeIndex);
catchScopeBlock.addChildToBack(catchScope);
- // Add with statement based on catch scope object
- catchScopeBlock.addChildToBack(
- createWith(
- createUseLocal(catchScopeBlock),
- condStmt,
- catchLineno,
- catchColumn));
+ parser.setRequiresActivation();
+ catchScopeBlock.addChildToBack(condStmt);
+ catchScopeBlock.addChildToBack(new Node(Token.LEAVE_SCOPE));
// move to next cb
cb = cb.getNext();
@@ -1962,7 +1976,7 @@ private Node createWith(Node obj, Node body, int lineno, int column) {
result.addChildToBack(new Node(Token.ENTERWITH, obj));
Node bodyNode = new Node(Token.WITH, body, lineno, column);
result.addChildrenToBack(bodyNode);
- result.addChildToBack(new Node(Token.LEAVEWITH));
+ result.addChildToBack(new Node(Token.LEAVE_SCOPE));
return result;
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/IdFunctionObject.java b/rhino/src/main/java/org/mozilla/javascript/IdFunctionObject.java
index e81379675b7..cf3eec2e034 100644
--- a/rhino/src/main/java/org/mozilla/javascript/IdFunctionObject.java
+++ b/rhino/src/main/java/org/mozilla/javascript/IdFunctionObject.java
@@ -11,9 +11,10 @@
import java.util.Objects;
public class IdFunctionObject extends BaseFunction {
- private static final long serialVersionUID = -5332312783643935019L;
+ private static final long serialVersionUID = 4323463961654640261L;
public IdFunctionObject(IdFunctionCall idcall, Object tag, int id, int arity) {
+ super(null);
if (arity < 0) throw new IllegalArgumentException();
this.idcall = idcall;
@@ -81,17 +82,17 @@ public Scriptable getPrototype() {
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
// We need to do some sneakiness here for constructors...
return idcall.execIdCall(this, cx, scope, getThisObj(thisObj), args);
}
- public final Scriptable getThisObj(Scriptable thisObj) {
+ public final Scriptable getThisObj(Object thisObj) {
if (useCallAsConstructor && (thisObj == null || Undefined.isUndefined(thisObj))) {
var res = ScriptableObject.getTopLevelScope(getDeclarationScope()).getGlobalThis();
return res;
} else {
- return thisObj;
+ return ScriptRuntime.toObject(getDeclarationScope(), thisObj);
}
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/Interpreter.java b/rhino/src/main/java/org/mozilla/javascript/Interpreter.java
index 5d2e460f82a..1cc613c7fbd 100644
--- a/rhino/src/main/java/org/mozilla/javascript/Interpreter.java
+++ b/rhino/src/main/java/org/mozilla/javascript/Interpreter.java
@@ -75,7 +75,8 @@ private static class CallFrame implements Cloneable, Serializable {
final boolean useActivation;
boolean isContinuationsTopFrame;
- final Scriptable thisObj;
+ final Object thisObj;
+ final Object newTarget;
// The values that change during interpretation
@@ -93,7 +94,8 @@ private static class CallFrame implements Cloneable, Serializable {
CallFrame(
Context cx,
- Scriptable thisObj,
+ Object thisObj,
+ Object newTarget,
ScriptOrFn fnOrScript,
InterpreterData code,
CallFrame parentFrame,
@@ -116,6 +118,7 @@ private static class CallFrame implements Cloneable, Serializable {
this.fnOrScript = fnOrScript;
varSource = this;
this.thisObj = thisObj;
+ this.newTarget = newTarget;
this.parentFrame = parentFrame;
if (parentFrame == null) {
@@ -183,6 +186,7 @@ private CallFrame(
isContinuationsTopFrame = original.isContinuationsTopFrame;
thisObj = original.thisObj;
+ newTarget = original.newTarget;
result = original.result;
resultDbl = original.resultDbl;
@@ -235,6 +239,7 @@ private CallFrame(
isContinuationsTopFrame = original.isContinuationsTopFrame;
thisObj = original.thisObj;
+ newTarget = original.newTarget;
result = original.result;
resultDbl = original.resultDbl;
@@ -304,7 +309,7 @@ void initializeArgs(
// creation
// Ref: Ecma 2026, 10.2.11, FunctionDeclarationInstantiation
- if (desc.getFunctionCount() != 0 && !desc.isES6Generator()) {
+ if (desc.getFunctionCount() != 0 && !desc.isES6Generator() && !desc.isAsync()) {
if (desc.getFunctionType() != 0 && !desc.requiresActivationFrame()) Kit.codeBug();
for (int i = 0; i < desc.getFunctionCount(); i++) {
JSDescriptor fdesc = desc.getFunction(i);
@@ -1166,8 +1171,9 @@ static Object interpret(
InterpreterData idata,
Context cx,
VarScope scope,
- Scriptable thisObj,
- Object[] args) {
+ Object thisObj,
+ Object[] args,
+ Object newTarget) {
if (!ScriptRuntime.hasTopCall(cx)) Kit.codeBug();
var desc = ifun.getDescriptor();
@@ -1215,7 +1221,8 @@ static Object interpret(
args.length,
ifun,
idata,
- null);
+ null,
+ newTarget);
frame.isContinuationsTopFrame = cx.isContinuationsTopCall;
cx.isContinuationsTopCall = false;
@@ -1511,11 +1518,13 @@ static void dumpJumpTarget(String tname, ICodeDumpContext ctx) {
instructionObjs[base + Token.THIS] = new DoThis();
instructionObjs[base + Token.SUPER] = new DoSuper();
instructionObjs[base + Token.THISFN] = new DoThisFunction();
+ instructionObjs[base + Token.NEW_TARGET] = new DoNewTarget();
instructionObjs[base + Token.FALSE] = new DoFalse();
instructionObjs[base + Token.TRUE] = new DoTrue();
instructionObjs[base + Icode_UNDEF] = new DoUndef();
instructionObjs[base + Token.ENTERWITH] = new DoEnterWith();
- instructionObjs[base + Token.LEAVEWITH] = new DoLeaveWith();
+ instructionObjs[base + Token.ENTER_SCOPE] = new DoEnterScope();
+ instructionObjs[base + Token.LEAVE_SCOPE] = new DoLeaveScope();
instructionObjs[base + Token.CATCH_SCOPE] = new DoCatchScope();
instructionObjs[base + Token.ENUM_INIT_KEYS] = new DoEnumInit();
instructionObjs[base + Token.ENUM_INIT_VALUES] = new DoEnumInit();
@@ -1941,11 +1950,17 @@ private static void generatorCreate(Context cx, CallFrame frame) {
CallFrame generatorFrame = captureFrameForGenerator(frame);
generatorFrame.frozen = true;
if (cx.getLanguageVersion() >= Context.VERSION_ES6) {
- frame.result =
- new ES6Generator(
- frame.scope,
- (JSFunction) generatorFrame.fnOrScript,
- generatorFrame);
+ JSFunction fn = (JSFunction) generatorFrame.fnOrScript;
+ ES6Generator gen = new ES6Generator(frame.scope, fn, generatorFrame);
+ if (fn.isAsync() && !fn.isGeneratorFunction()) {
+ // Async non-generator function: drive via Promise runner.
+ // isGeneratorFunction() returns descriptor.isES6Generator(), which is
+ // false for async non-generators (we only called setIsGenerator(), not
+ // setIsES6Generator(), in IRFactory).
+ frame.result = NativePromise.createAsyncFunctionPromise(cx, frame.scope, gen);
+ } else {
+ frame.result = gen;
+ }
} else {
frame.result =
new NativeGenerator(
@@ -1979,7 +1994,10 @@ private static Object freezeGenerator(
frame.resultDbl = frame.sDbl[state.stackTop];
frame.savedStackTop = state.stackTop;
frame.pc--; // we want to come back here when we resume
- ScriptRuntime.exitActivationFunction(cx);
+ var desc = frame.fnOrScript.getDescriptor();
+ if (!desc.isES6Generator() && !desc.isAsync()) {
+ ScriptRuntime.exitActivationFunction(cx);
+ }
final Object result =
(frame.result != DOUBLE_MARK)
? frame.result
@@ -3407,7 +3425,7 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
// Check if the lookup result is a function and throw if it's not
// must not be done sooner according to the spec
Callable fun = result.getCallable();
- Scriptable funThisObj = result.getThis();
+ Object funThisObj = result.getThis();
Scriptable funHomeObj =
(fun instanceof BaseFunction) ? ((BaseFunction) fun).getHomeObject() : null;
if (op == Icode_CALL_ON_SUPER) {
@@ -3435,82 +3453,72 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
// if the function is already an interpreted function, which
// should be the majority of cases.
for (; ; ) {
- if (fun instanceof KnownBuiltInFunction) {
- KnownBuiltInFunction kfun = (KnownBuiltInFunction) fun;
- // Bug 405654 -- make the best effort to keep
- // Function.apply and Function.call within this
- // interpreter loop invocation
- if (BaseFunction.isApplyOrCall(kfun)) {
- // funThisObj becomes fun
- fun = ScriptRuntime.getCallable(funThisObj);
- // first arg becomes thisObj
- funThisObj =
- getApplyThis(
- cx,
+ if (BaseFunction.isApplyOrCall(fun)) {
+ // funThisObj becomes fun
+ var target = ScriptRuntime.getCallable(funThisObj);
+ // first arg becomes thisObj
+ funThisObj =
+ getApplyThis(
+ cx,
+ stack,
+ sDbl,
+ boundArgs,
+ state.stackTop + 1,
+ state.indexReg,
+ (Function) target,
+ frame);
+ if (BaseFunction.isApply(fun)) {
+ // Apply: second argument after new "this"
+ // should be array-like
+ // and we'll spread its elements on the stack
+ final Object[] callArgs;
+ if (blen > 1) {
+ callArgs = ScriptRuntime.getApplyArguments(cx, boundArgs[1]);
+ } else if (state.indexReg < 2) {
+ callArgs = ScriptRuntime.emptyArgs;
+ } else {
+ callArgs =
+ ScriptRuntime.getApplyArguments(
+ cx, stack[state.stackTop - blen + 2]);
+ }
+
+ int alen = callArgs.length;
+ // We're coming from the outside, so this
+ // is replacing any bound args we might
+ // have had already.
+ boundArgs = callArgs;
+ blen = alen;
+ state.indexReg = alen;
+ } else {
+ // Call: shift args left, starting from 2nd
+ if (state.indexReg > 0) {
+ if (state.indexReg > 1 && blen == 0) {
+ System.arraycopy(
+ stack,
+ state.stackTop + 2,
stack,
+ state.stackTop + 1,
+ state.indexReg - 1);
+ System.arraycopy(
+ sDbl,
+ state.stackTop + 2,
sDbl,
- boundArgs,
state.stackTop + 1,
- state.indexReg,
- (Function) fun,
- frame);
- if (BaseFunction.isApply(kfun)) {
- // Apply: second argument after new "this"
- // should be array-like
- // and we'll spread its elements on the stack
- final Object[] callArgs;
- if (blen > 1) {
- callArgs = ScriptRuntime.getApplyArguments(cx, boundArgs[1]);
- } else if (state.indexReg < 2) {
- callArgs = ScriptRuntime.emptyArgs;
+ state.indexReg - 1);
+ } else if (state.indexReg > 1) {
+ Object[] newBArgs = new Object[boundArgs.length - 1];
+ System.arraycopy(boundArgs, 1, newBArgs, 0, boundArgs.length - 1);
+ boundArgs = newBArgs;
+ blen = newBArgs.length;
} else {
- callArgs =
- ScriptRuntime.getApplyArguments(
- cx, stack[state.stackTop - blen + 2]);
- }
-
- int alen = callArgs.length;
- // We're coming from the outside, so this
- // is replacing any bound args we might
- // have had already.
- boundArgs = callArgs;
- blen = alen;
- state.indexReg = alen;
- } else {
- // Call: shift args left, starting from 2nd
- if (state.indexReg > 0) {
- if (state.indexReg > 1 && blen == 0) {
- System.arraycopy(
- stack,
- state.stackTop + 2,
- stack,
- state.stackTop + 1,
- state.indexReg - 1);
- System.arraycopy(
- sDbl,
- state.stackTop + 2,
- sDbl,
- state.stackTop + 1,
- state.indexReg - 1);
- } else if (state.indexReg > 1) {
- Object[] newBArgs = new Object[boundArgs.length - 1];
- System.arraycopy(
- boundArgs, 1, newBArgs, 0, boundArgs.length - 1);
- boundArgs = newBArgs;
- blen = newBArgs.length;
- } else {
- // Bound args is 1 long.
- boundArgs = new Object[0];
- blen = 0;
- }
- state.indexReg--;
+ // Bound args is 1 long.
+ boundArgs = new Object[0];
+ blen = 0;
}
+ state.indexReg--;
}
- } else {
- // Some other IdFunctionObject we don't know how to
- // reduce.
- break;
}
+ fun = target;
} else if (fun instanceof LambdaConstructor) {
break;
} else if (fun instanceof LambdaFunction) {
@@ -3555,8 +3563,9 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
if (fun instanceof JSFunction
&& ((JSFunction) fun).getDescriptor().getCode() instanceof InterpreterData) {
JSFunction ifun = (JSFunction) fun;
- JSDescriptor desc = ifun.getDescriptor();
- InterpreterData idata = (InterpreterData) desc.getCode();
+
+ JSDescriptor desc = ifun.getDescriptor();
+ var idata = (InterpreterData) desc.getCode();
if (frame.fnOrScript.getDescriptor().getSecurityDomain()
== desc.getSecurityDomain()) {
CallFrame callParentFrame = frame;
@@ -3598,7 +3607,8 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
state.indexReg,
ifun,
idata,
- callParentFrame);
+ callParentFrame,
+ ifun.getLexicalNewTarget());
if (op != Icode_TAIL_CALL) {
frame.savedStackTop = state.stackTop;
frame.savedCallOp = op;
@@ -3626,8 +3636,9 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
return BREAK_WITHOUT_EXTENSION;
}
- if (fun instanceof IdFunctionObject) {
- IdFunctionObject ifun = (IdFunctionObject) fun;
+ if (fun instanceof JSFunction) {
+ var ifun = (JSFunction) fun;
+
if (NativeContinuation.isContinuationConstructor(ifun)) {
frame.stack[state.stackTop] = captureContinuation(cx, frame.parentFrame, false);
return null;
@@ -3672,8 +3683,9 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
if (lhs instanceof JSFunction
&& ((JSFunction) lhs).getConstructor() instanceof InterpreterData) {
JSFunction f = (JSFunction) lhs;
- JSDescriptor desc = f.getDescriptor();
- InterpreterData idata = (InterpreterData) desc.getConstructor();
+
+ JSDescriptor desc = f.getDescriptor();
+ var idata = (InterpreterData) desc.getConstructor();
if (frame.fnOrScript.getDescriptor().getSecurityDomain()
== desc.getSecurityDomain()) {
if (cx.getLanguageVersion() >= Context.VERSION_ES6
@@ -3698,7 +3710,8 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
state.indexReg,
f,
idata,
- frame);
+ frame,
+ lhs);
frame.stack[state.stackTop] = newInstance;
frame.savedStackTop = state.stackTop;
@@ -3706,20 +3719,21 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
return new StateContinueResult(calleeFrame, state.indexReg);
}
}
- if (!(lhs instanceof Constructable)) {
- if (lhs == DOUBLE_MARK) lhs = ScriptRuntime.wrapNumber(frame.sDbl[state.stackTop]);
- throw ScriptRuntime.notFunctionError(lhs);
- }
- Constructable ctor = (Constructable) lhs;
+ if (lhs instanceof JSFunction) {
+ var f = (JSFunction) lhs;
- if (ctor instanceof IdFunctionObject) {
- IdFunctionObject ifun = (IdFunctionObject) ctor;
- if (NativeContinuation.isContinuationConstructor(ifun)) {
+ if (NativeContinuation.isContinuationConstructor(f)) {
frame.stack[state.stackTop] = captureContinuation(cx, frame.parentFrame, false);
return null;
}
}
+ if (!(lhs instanceof Constructable)) {
+ if (lhs == DOUBLE_MARK) lhs = ScriptRuntime.wrapNumber(frame.sDbl[state.stackTop]);
+ throw ScriptRuntime.notFunctionError(lhs);
+ }
+ Constructable ctor = (Constructable) lhs;
+
Object[] outArgs =
getArgsArray(frame.stack, frame.sDbl, state.stackTop + 1, state.indexReg);
frame.stack[state.stackTop] = ctor.construct(cx, frame.scope, outArgs);
@@ -4099,6 +4113,14 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
}
}
+ private static class DoNewTarget extends InstructionClass {
+ @Override
+ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
+ frame.stack[++state.stackTop] = frame.newTarget;
+ return null;
+ }
+ }
+
private static class DoFalse extends InstructionClass {
@Override
NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
@@ -4134,10 +4156,19 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
}
}
- private static class DoLeaveWith extends InstructionClass {
+ private static class DoEnterScope extends InstructionClass {
@Override
NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
- frame.scope = ScriptRuntime.leaveWith(frame.scope);
+ frame.scope = new LocalScope(frame.scope);
+ frame.stack[++state.stackTop] = frame.scope;
+ return null;
+ }
+ }
+
+ private static class DoLeaveScope extends InstructionClass {
+ @Override
+ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
+ frame.scope = ScriptRuntime.leaveScope(frame.scope);
return null;
}
}
@@ -4154,15 +4185,17 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
boolean afterFirstScope = (frame.idata.itsICode[frame.pc] != 0);
Throwable caughtException = (Throwable) frame.stack[state.stackTop + 1];
- Scriptable lastCatchScope;
+ VarScope lastCatchScope;
if (!afterFirstScope) {
lastCatchScope = null;
} else {
- lastCatchScope = (Scriptable) frame.stack[state.indexReg];
+ lastCatchScope = (VarScope) frame.stack[state.indexReg];
}
- frame.stack[state.indexReg] =
+ VarScope catchScope =
ScriptRuntime.newCatchScope(
caughtException, lastCatchScope, state.stringReg, cx, frame.scope);
+ frame.stack[state.indexReg] = catchScope;
+ frame.scope = catchScope;
++frame.pc;
return null;
}
@@ -4183,7 +4216,9 @@ NewState execute(Context cx, CallFrame frame, InterpreterState state, int op) {
state.indexReg += frame.idata.itsMaxVars;
int enumType =
op == Token.ENUM_INIT_KEYS
- ? ScriptRuntime.ENUMERATE_KEYS
+ ? cx.getLanguageVersion() <= Context.VERSION_1_8
+ ? ScriptRuntime.ENUMERATE_KEYS
+ : ScriptRuntime.ENUMERATE_KEYS_NO_ITERATOR
: op == Token.ENUM_INIT_VALUES
? ScriptRuntime.ENUMERATE_VALUES
: op == Token.ENUM_INIT_VALUES_IN_ORDER
@@ -5019,7 +5054,7 @@ private static Scriptable getApplyThis(
private static CallFrame initFrame(
Context cx,
VarScope callerScope,
- Scriptable thisObj,
+ Object thisObj,
Scriptable homeObj,
Object[] args,
double[] argsDbl,
@@ -5028,11 +5063,13 @@ private static CallFrame initFrame(
int argCount,
ScriptOrFn fnOrScript,
InterpreterData code,
- CallFrame parentFrame) {
+ CallFrame parentFrame,
+ Object newTarget) {
CallFrame frame =
new CallFrame(
cx,
thisObj,
+ newTarget,
fnOrScript,
code,
parentFrame,
@@ -5047,7 +5084,8 @@ private static CallFrame initFrame(
private static void enterFrame(
Context cx, CallFrame frame, Object[] args, boolean continuationRestart) {
- boolean usesActivation = frame.fnOrScript.getDescriptor().requiresActivationFrame();
+ var desc = frame.fnOrScript.getDescriptor();
+ boolean usesActivation = desc.requiresActivationFrame();
boolean isDebugged = frame.debuggerFrame != null;
if (usesActivation) {
VarScope scope = frame.scope;
@@ -5063,7 +5101,7 @@ private static void enterFrame(
// block ("catch" implicitly uses WithScope to create a scope
// to expose the exception variable).
for (; ; ) {
- if (scope instanceof WithScope) {
+ if (!(scope instanceof NativeCall)) {
scope = scope.getParentScope();
if (scope == null
|| (frame.parentFrame != null
@@ -5083,14 +5121,22 @@ private static void enterFrame(
if (isDebugged) {
frame.debuggerFrame.onEnter(cx, scope, frame.thisObj, args);
}
- ScriptRuntime.enterActivationFunction(cx, scope);
+ if (!(desc.isStrict() && cx.getLanguageVersion() >= Context.VERSION_ES6)
+ && !desc.isES6Generator()
+ && !desc.isAsync()) {
+ ScriptRuntime.enterActivationFunction(cx, scope);
+ }
} else if (isDebugged) {
frame.debuggerFrame.onEnter(cx, new DebugScope(frame), frame.thisObj, args);
}
}
private static void exitFrame(Context cx, CallFrame frame, Object throwable) {
- if (frame.fnOrScript.getDescriptor().requiresActivationFrame()) {
+ var desc = frame.fnOrScript.getDescriptor();
+ if (desc.requiresActivationFrame()
+ && !(desc.isStrict() && cx.getLanguageVersion() >= Context.VERSION_ES6)
+ && !desc.isES6Generator()
+ && !desc.isAsync()) {
ScriptRuntime.exitActivationFunction(cx);
}
@@ -5278,7 +5324,8 @@ private static JSFunction createClosure(Context cx, CallFrame frame, int index)
var desc = frame.fnOrScript.getDescriptor().getFunction(index);
boolean isArrow = desc.getFunctionType() == FunctionNode.ARROW_FUNCTION;
var homeObject = isArrow ? frame.fnOrScript.getHomeObject() : null;
- JSFunction f = new JSFunction(cx, frame.scope, desc, frame.thisObj, homeObject);
+ var newTarget = isArrow ? frame.newTarget : Undefined.instance;
+ JSFunction f = new JSFunction(cx, frame.scope, desc, frame.thisObj, newTarget, homeObject);
return f;
}
@@ -5286,7 +5333,8 @@ private static JSFunction createMethod(
Context cx, CallFrame frame, int index, Scriptable homeObject) {
var desc = frame.fnOrScript.getDescriptor().getFunction(index);
boolean isArrow = desc.getFunctionType() == FunctionNode.ARROW_FUNCTION;
- JSFunction f = new JSFunction(cx, frame.scope, desc, frame.thisObj, homeObject);
+ var newTarget = isArrow ? frame.newTarget : Undefined.instance;
+ JSFunction f = new JSFunction(cx, frame.scope, desc, frame.thisObj, newTarget, homeObject);
return f;
}
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/InterpreterData.java b/rhino/src/main/java/org/mozilla/javascript/InterpreterData.java
index a305fdf4978..1c33d4c8571 100644
--- a/rhino/src/main/java/org/mozilla/javascript/InterpreterData.java
+++ b/rhino/src/main/java/org/mozilla/javascript/InterpreterData.java
@@ -101,7 +101,7 @@ public Object execute(
VarScope scope,
Object thisObj,
Object[] args) {
- return Interpreter.interpret(executableObject, this, cx, scope, (Scriptable) thisObj, args);
+ return Interpreter.interpret(executableObject, this, cx, scope, thisObj, args, newTarget);
}
@Override
diff --git a/rhino/src/main/java/org/mozilla/javascript/JSCode.java b/rhino/src/main/java/org/mozilla/javascript/JSCode.java
index 84fc5450e49..92e218782e9 100644
--- a/rhino/src/main/java/org/mozilla/javascript/JSCode.java
+++ b/rhino/src/main/java/org/mozilla/javascript/JSCode.java
@@ -35,7 +35,7 @@ public JSCode build() {
private static class NotCallable extends JSCode implements Serializable {
- private static final long serialVersionUID = 2691205302914111400L;
+ private static final long serialVersionUID = -31340315773728063L;
@Override
public Object execute(
diff --git a/rhino/src/main/java/org/mozilla/javascript/JSDescriptor.java b/rhino/src/main/java/org/mozilla/javascript/JSDescriptor.java
index a05b05e430f..e85fa70b1a2 100644
--- a/rhino/src/main/java/org/mozilla/javascript/JSDescriptor.java
+++ b/rhino/src/main/java/org/mozilla/javascript/JSDescriptor.java
@@ -30,6 +30,8 @@ public final class JSDescriptor> implements Serializable
private static final int REQUIRES_ACTIVATION_FRAME_FLAG = 1 << 10;
private static final int REQUIRES_ARGUMENT_OBJECT_FLAG = 1 << 11;
private static final int DECLARED_AS_FUNCTION_EXPRESSION_FLAG = 1 << 12;
+ private static final int DERIVED_CONSTRUCTOR_FLAG = 1 << 13;
+ private static final int IS_ASYNC_FLAG = 1 << 14;
private final JSCode code;
private final JSCode constructor;
@@ -79,6 +81,8 @@ public JSDescriptor(
boolean requiresActivationFrame,
boolean requiresArgumentObject,
boolean declaredAsFunctionExpression,
+ boolean derivedConstructor,
+ boolean isAsync,
SecurityController securityController,
Object securityDomain,
int functionType) {
@@ -102,6 +106,8 @@ public JSDescriptor(
flags = flags | (requiresActivationFrame ? REQUIRES_ACTIVATION_FRAME_FLAG : 0);
flags = flags | (requiresArgumentObject ? REQUIRES_ARGUMENT_OBJECT_FLAG : 0);
flags = flags | (declaredAsFunctionExpression ? DECLARED_AS_FUNCTION_EXPRESSION_FLAG : 0);
+ flags = flags | (derivedConstructor ? DERIVED_CONSTRUCTOR_FLAG : 0);
+ flags = flags | (isAsync ? IS_ASYNC_FLAG : 0);
this.flags = flags;
this.sourceFile = sourceFile;
@@ -152,6 +158,10 @@ public boolean isES6Generator() {
return (flags & IS_ES6_GENERATOR_FLAG) != 0;
}
+ public boolean isAsync() {
+ return (flags & IS_ASYNC_FLAG) != 0;
+ }
+
public boolean isShorthand() {
return (flags & IS_SHORTHAND_FLAG) != 0;
}
@@ -297,6 +307,7 @@ public static class Builder> {
public boolean isScript;
public boolean isTopLevel;
public boolean isES6Generator;
+ public boolean isAsync;
public boolean isShorthand;
public boolean hasPrototype;
public boolean hasLexicalThis;
@@ -385,6 +396,8 @@ private JSDescriptor build(JSDescriptor> parent, Consumer>
requiresActivationFrame,
requiresArgumentObject,
declaredAsFunctionExpression,
+ false,
+ isAsync,
securityController,
securityDomain,
functionType);
diff --git a/rhino/src/main/java/org/mozilla/javascript/JSFunction.java b/rhino/src/main/java/org/mozilla/javascript/JSFunction.java
index a0816b1feb5..1c6c4ebd8ab 100644
--- a/rhino/src/main/java/org/mozilla/javascript/JSFunction.java
+++ b/rhino/src/main/java/org/mozilla/javascript/JSFunction.java
@@ -10,19 +10,24 @@
*/
public class JSFunction extends BaseFunction implements ScriptOrFn {
private final JSDescriptor descriptor;
- private final Scriptable lexicalThis;
+ private final Object lexicalThis;
+ private final Object lexicalNewTarget;
private final Scriptable homeObject;
public JSFunction(
Context cx,
VarScope scope,
JSDescriptor descriptor,
- Scriptable lexicalThis,
+ Object lexicalThis,
+ Object lexicalNewTarget,
Scriptable homeObject) {
+ super(scope);
this.descriptor = descriptor;
this.lexicalThis = lexicalThis;
+ this.lexicalNewTarget = lexicalNewTarget;
this.homeObject = homeObject;
- ScriptRuntime.setFunctionProtoAndParent(this, cx, scope, descriptor.isES6Generator());
+ ScriptRuntime.setFunctionProtoAndParent(
+ this, cx, scope, descriptor.isES6Generator(), descriptor.isAsync());
if (!descriptor.isShorthand()) {
setupDefaultPrototype(scope);
}
@@ -32,9 +37,12 @@ public JSFunction(
VarScope scope,
JSDescriptor descriptor,
Scriptable lexicalThis,
+ Object lexicalNewTarget,
Scriptable homeObject) {
+ super(scope);
this.descriptor = descriptor;
this.lexicalThis = lexicalThis;
+ this.lexicalNewTarget = lexicalNewTarget;
this.homeObject = homeObject;
setParentScope(scope);
setPrototype(ScriptableObject.getFunctionPrototype(scope));
@@ -91,6 +99,11 @@ protected boolean isGeneratorFunction() {
return descriptor.isES6Generator();
}
+ @Override
+ public boolean isAsync() {
+ return descriptor.isAsync();
+ }
+
@Override
public int getLength() {
return descriptor.getArity();
@@ -136,33 +149,36 @@ JSCode getConstructor() {
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
if (!ScriptRuntime.hasTopCall(cx)) {
return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args, isStrict());
}
var realThis = getThisObj(thisObj);
- return descriptor.getCode().execute(cx, this, Undefined.instance, scope, realThis, args);
+ return descriptor.getCode().execute(cx, this, lexicalNewTarget, scope, realThis, args);
}
- public final Scriptable getThisObj(Scriptable thisObj) {
+ public final Object getThisObj(Object thisObj) {
if (descriptor.hasLexicalThis()) {
return lexicalThis;
- } else if (!descriptor.isStrict() && (thisObj == null || Undefined.isUndefined(thisObj))) {
- var res = ScriptableObject.getTopLevelScope(getDeclarationScope()).getGlobalThis();
- return res;
+ } else if (!descriptor.isStrict()) {
+ if (thisObj == null || Undefined.isUndefined(thisObj)) {
+ return ScriptableObject.getTopLevelScope(getDeclarationScope()).getGlobalThis();
+ } else {
+ return ScriptRuntime.toObject(getDeclarationScope(), thisObj);
+ }
} else {
return thisObj;
}
}
@Override
- public Scriptable construct(Context cx, VarScope scope, Object[] args) {
+ public Scriptable construct(Context cx, Object nt, VarScope s, Object thisObj, Object[] args) {
if (!ScriptRuntime.hasTopCall(cx)) {
return (Scriptable)
ScriptRuntime.doTopCall(
(lcx, lscope, lthisObj, largs) -> construct(lcx, lscope, largs),
cx,
- scope,
+ s,
null,
args,
isStrict());
@@ -170,14 +186,22 @@ public Scriptable construct(Context cx, VarScope scope, Object[] args) {
if (descriptor.getConstructor() == null) {
throw ScriptRuntime.typeErrorById("msg.not.ctor", getFunctionName());
}
- var thisObj = homeObject == null ? createObject(cx, scope) : null;
+ if (nt == null || Undefined.isUndefined(nt)) {
+ nt = this;
+ }
+ thisObj = homeObject == null ? this.createObject(cx, s, nt) : null;
// Pass `this` in as new.target for now. This can change when
// the public `construct` signature changes.
- var res = descriptor.getConstructor().execute(cx, this, this, scope, thisObj, args);
+ var res = descriptor.getConstructor().execute(cx, this, nt, s, thisObj, args);
if (res instanceof Scriptable) {
thisObj = (Scriptable) res;
}
- return thisObj;
+ return (Scriptable) thisObj;
+ }
+
+ @Override
+ public Scriptable construct(Context cx, VarScope scope, Object[] args) {
+ return construct(cx, this, scope, null, args);
}
public boolean isScript() {
@@ -208,12 +232,16 @@ public Scriptable getHomeObject() {
return homeObject;
}
+ public Object getLexicalNewTarget() {
+ return lexicalNewTarget;
+ }
+
@Override
public void setHomeObject(Scriptable homeObject) {
throw new UnsupportedOperationException("Cannot set home object on JS function.");
}
- public Scriptable getFunctionThis(Scriptable functionThis) {
+ public Object getFunctionThis(Scriptable functionThis) {
if (descriptor.hasLexicalThis()) {
return this.lexicalThis;
} else {
@@ -237,7 +265,7 @@ public static JSFunction createFunction(
Scriptable homeObject,
Object staticSecurityDomain) {
assert (desc.getSecurityDomain() == staticSecurityDomain);
- JSFunction f = new JSFunction(cx, scope, desc, null, homeObject);
+ JSFunction f = new JSFunction(cx, scope, desc, null, Undefined.instance, homeObject);
return f;
}
@@ -245,7 +273,7 @@ public static JSFunction createFunction(
static JSFunction createFunction(
Context cx, VarScope scope, JSDescriptor> parent, int index, Scriptable homeObject) {
JSDescriptor desc = parent.getFunction(index);
- JSFunction f = new JSFunction(cx, scope, desc, null, homeObject);
+ JSFunction f = new JSFunction(cx, scope, desc, null, Undefined.instance, homeObject);
return f;
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/JSScript.java b/rhino/src/main/java/org/mozilla/javascript/JSScript.java
index 187c39c181e..665232e869f 100644
--- a/rhino/src/main/java/org/mozilla/javascript/JSScript.java
+++ b/rhino/src/main/java/org/mozilla/javascript/JSScript.java
@@ -29,7 +29,7 @@ JSCode getCode() {
}
@Override
- public Object exec(Context cx, VarScope scope, Scriptable thisObj) {
+ public Object exec(Context cx, VarScope scope, Object thisObj) {
Object ret;
if (!ScriptRuntime.hasTopCall(cx)) {
// It will go through "call" path. but they are equivalent
diff --git a/rhino/src/main/java/org/mozilla/javascript/JavaMembers.java b/rhino/src/main/java/org/mozilla/javascript/JavaMembers.java
index c8574d094fd..1f6f16bdb7d 100644
--- a/rhino/src/main/java/org/mozilla/javascript/JavaMembers.java
+++ b/rhino/src/main/java/org/mozilla/javascript/JavaMembers.java
@@ -109,7 +109,7 @@ Object get(Scriptable obj, VarScope scope, String name, Object javaObject, boole
return new FieldAndMethods(scope, withField);
} else {
var method = (ExecutableOverload) member;
- var built = new NativeJavaMethod(method.methods, method.name);
+ var built = new NativeJavaMethod(scope, method.methods, method.name);
ScriptRuntime.setFunctionProtoAndParent(
built, Context.getCurrentContext(), scope, false);
return built;
@@ -290,7 +290,7 @@ private Object getExplicitFunction(
Scriptable prototype = ScriptableObject.getFunctionPrototype(scope);
if (methodOrCtor.isConstructor()) {
- NativeJavaConstructor fun = new NativeJavaConstructor(methodOrCtor);
+ NativeJavaConstructor fun = new NativeJavaConstructor(scope, methodOrCtor);
fun.setPrototype(prototype);
member = fun;
ht.put(name, fun);
@@ -300,7 +300,7 @@ private Object getExplicitFunction(
if (member instanceof ExecutableOverload
&& ((ExecutableOverload) member).methods.length > 1) {
- NativeJavaMethod fun = new NativeJavaMethod(methodOrCtor, name);
+ NativeJavaMethod fun = new NativeJavaMethod(scope, methodOrCtor, name);
fun.setPrototype(prototype);
ht.put(name, fun);
member = fun;
@@ -458,7 +458,7 @@ private void reflect(
collectFields(accessibleFields, isStatic, typeFactory);
var table = isStatic ? staticMembers : members;
- table.putAll(extractBeaning(table, isStatic, includePrivate));
+ table.putAll(extractBeaning(scope, table, isStatic, includePrivate));
}
// Reflect constructors
@@ -467,7 +467,7 @@ private void reflect(
for (int i = 0; i != constructors.length; ++i) {
ctorMembers[i] = new ExecutableBox(constructors[i], typeFactory);
}
- ctors = new NativeJavaMethod(ctorMembers, cl.getSimpleName());
+ ctors = new NativeJavaMethod(scope, ctorMembers, cl.getSimpleName());
}
/**
@@ -592,7 +592,7 @@ private static String getBeanName(String nameComponent) {
* member table at this stage
*/
private static Map extractBeaning(
- Map members, boolean isStatic, boolean includePrivate) {
+ VarScope scope, Map members, boolean isStatic, boolean includePrivate) {
var beans = new HashMap();
for (var entry : members.entrySet()) {
var name = entry.getKey();
@@ -624,16 +624,16 @@ private static Map extractBeaning(
// prefer 'get' over 'is'
|| bean.getter.getFunctionName().startsWith("is")) {
if (method.methods.length == 1) {
- bean.getter = new NativeJavaMethod(method.methods, name);
+ bean.getter = new NativeJavaMethod(scope, method.methods, name);
} else {
- bean.getter = new NativeJavaMethod(candidate, name);
+ bean.getter = new NativeJavaMethod(scope, candidate, name);
}
}
}
} else { // isSetBeaning
var bean = beans.computeIfAbsent(beanName, BeanProperty::new);
// capture all possible setters for now, actual setter will be searched later
- bean.setter = new NativeJavaMethod(method.methods, name);
+ bean.setter = new NativeJavaMethod(scope, method.methods, name);
}
}
@@ -651,7 +651,7 @@ private static Map extractBeaning(
// We have a getter. Now, do we have a setter with matching type?
match = extractSetMethod(type, setterCandidates.methods, isStatic);
if (match != null) {
- bean.setter = new NativeJavaMethod(match, match.getName());
+ bean.setter = new NativeJavaMethod(scope, match, match.getName());
continue;
}
}
@@ -911,7 +911,7 @@ class FieldAndMethods extends NativeJavaMethod {
private static final long serialVersionUID = -9222428244284796755L;
FieldAndMethods(VarScope scope, ExecutableOverload.WithField withField) {
- super(withField.methods, withField.name);
+ super(scope, withField.methods, withField.name);
this.field = withField.field;
setParentScope(scope);
setPrototype(ScriptableObject.getFunctionPrototype(scope));
diff --git a/rhino/src/main/java/org/mozilla/javascript/KnownBuiltInFunction.java b/rhino/src/main/java/org/mozilla/javascript/KnownBuiltInFunction.java
index 56a3d5cda89..85bb7adfd34 100644
--- a/rhino/src/main/java/org/mozilla/javascript/KnownBuiltInFunction.java
+++ b/rhino/src/main/java/org/mozilla/javascript/KnownBuiltInFunction.java
@@ -12,7 +12,7 @@
*/
public class KnownBuiltInFunction extends LambdaFunction {
- private static final long serialVersionUID = -8388132362854748293L;
+ private static final long serialVersionUID = 4527445659952834584L;
private final Object tag;
diff --git a/rhino/src/main/java/org/mozilla/javascript/LambdaConstructor.java b/rhino/src/main/java/org/mozilla/javascript/LambdaConstructor.java
index 8d7d4ac56a4..ed3ef900807 100644
--- a/rhino/src/main/java/org/mozilla/javascript/LambdaConstructor.java
+++ b/rhino/src/main/java/org/mozilla/javascript/LambdaConstructor.java
@@ -124,7 +124,7 @@ protected Constructable getTargetConstructor() {
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
if ((flags & CONSTRUCTOR_FUNCTION) == 0) {
throw ScriptRuntime.typeErrorById("msg.constructor.no.function", getFunctionName());
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/LambdaFunction.java b/rhino/src/main/java/org/mozilla/javascript/LambdaFunction.java
index f6ae5f1e80e..7f24d1a56e7 100644
--- a/rhino/src/main/java/org/mozilla/javascript/LambdaFunction.java
+++ b/rhino/src/main/java/org/mozilla/javascript/LambdaFunction.java
@@ -13,7 +13,7 @@
*/
public class LambdaFunction extends BaseFunction {
- private static final long serialVersionUID = -8388132362854748293L;
+ private static final long serialVersionUID = 6594410813947157220L;
// The target is expected to be a lambda. Lambdas may be serialized, which
// requires this special interface.
@@ -38,6 +38,7 @@ public LambdaFunction(
int length,
SerializableCallable target,
boolean defaultPrototype) {
+ super(scope);
this.target = target;
this.name = name;
this.length = length;
@@ -78,6 +79,7 @@ public LambdaFunction(
int length,
Object prototype,
SerializableCallable target) {
+ super(scope);
this.target = target;
this.name = name;
this.length = length;
@@ -87,6 +89,7 @@ public LambdaFunction(
/** Create a new built-in function, with no name, and no default prototype. */
public LambdaFunction(VarScope scope, int length, SerializableCallable target) {
+ super(scope);
this.target = target;
this.length = length;
this.name = "";
@@ -94,7 +97,7 @@ public LambdaFunction(VarScope scope, int length, SerializableCallable target) {
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
return target.call(cx, getDeclarationScope(), thisObj, args);
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/LazilyLoadedCtor.java b/rhino/src/main/java/org/mozilla/javascript/LazilyLoadedCtor.java
index a08e568fc43..d7820a68138 100644
--- a/rhino/src/main/java/org/mozilla/javascript/LazilyLoadedCtor.java
+++ b/rhino/src/main/java/org/mozilla/javascript/LazilyLoadedCtor.java
@@ -17,7 +17,7 @@
* This improves startup time and average memory usage.
*/
public final class LazilyLoadedCtor> implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = -1531091529063000542L;
private static final int STATE_BEFORE_INIT = 0;
private static final int STATE_INITIALIZING = 1;
private static final int STATE_WITH_VALUE = 2;
diff --git a/rhino/src/main/java/org/mozilla/javascript/LocalScope.java b/rhino/src/main/java/org/mozilla/javascript/LocalScope.java
new file mode 100644
index 00000000000..6579204da3d
--- /dev/null
+++ b/rhino/src/main/java/org/mozilla/javascript/LocalScope.java
@@ -0,0 +1,18 @@
+package org.mozilla.javascript;
+
+public class LocalScope extends DeclarationScope {
+ private static final long serialVersionUID = -7471457301304454454L;
+
+ public LocalScope(VarScope parentScope) {
+ super(parentScope);
+ }
+
+ public boolean isNestedScope() {
+ return true;
+ }
+
+ @Override
+ public void putConst(String name, VarScope start, Object value) {
+ super.put(name, start, value);
+ }
+}
diff --git a/rhino/src/main/java/org/mozilla/javascript/MemberBox.java b/rhino/src/main/java/org/mozilla/javascript/MemberBox.java
index 1772a2d1b08..8445fd3f61a 100644
--- a/rhino/src/main/java/org/mozilla/javascript/MemberBox.java
+++ b/rhino/src/main/java/org/mozilla/javascript/MemberBox.java
@@ -171,7 +171,7 @@ Function asGetterFunction(final String name) {
public Object call(
Context cx,
VarScope callScope,
- Scriptable thisObj,
+ Object thisObj,
Object[] originalArgs) {
MemberBox nativeGetter = MemberBox.this;
if (nativeGetter.delegateTo == null) {
@@ -204,7 +204,7 @@ Function asSetterFunction(final String name) {
public Object call(
Context cx,
VarScope callScope,
- Scriptable thisObj,
+ Object thisObj,
Object[] originalArgs) {
MemberBox nativeSetter = MemberBox.this;
Object value =
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeArray.java b/rhino/src/main/java/org/mozilla/javascript/NativeArray.java
index 1601f788d2f..f245bd8c8e0 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeArray.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeArray.java
@@ -645,7 +645,7 @@ private static Object js_from(
final Scriptable items =
ScriptRuntime.toObject(s, (args.length >= 1) ? args[0] : Undefined.instance);
Object mapArg = (args.length >= 2) ? args[1] : Undefined.instance;
- Scriptable thisArg = null;
+ Object thisArg = null;
final boolean mapping = !Undefined.isUndefined(mapArg);
Function mapFn = null;
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeArrayIterator.java b/rhino/src/main/java/org/mozilla/javascript/NativeArrayIterator.java
index 5593f0fad1c..4f05fe8b4ed 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeArrayIterator.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeArrayIterator.java
@@ -15,13 +15,17 @@ public enum ARRAY_ITERATOR_TYPE {
VALUES
}
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 3370645355934941865L;
private static final String ITERATOR_TAG = "ArrayIterator";
+ private static final ClassDescriptor DESCRIPTOR =
+ ES6Iterator.makeDescriptor(ITERATOR_TAG, "Array Iterator");
+
private ARRAY_ITERATOR_TYPE type;
- static void init(TopLevel scope, boolean sealed) {
- ES6Iterator.init(scope, sealed, new NativeArrayIterator(), ITERATOR_TAG);
+ static void init(Context cx, VarScope scope, boolean sealed) {
+ ES6Iterator.initialize(
+ DESCRIPTOR, cx, (TopLevel) scope, new NativeArrayIterator(), sealed, ITERATOR_TAG);
}
/** Only for constructing the prototype object. */
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeBigInt.java b/rhino/src/main/java/org/mozilla/javascript/NativeBigInt.java
index f3322f6b233..56f5ae2dd56 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeBigInt.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeBigInt.java
@@ -6,6 +6,10 @@
package org.mozilla.javascript;
+import static org.mozilla.javascript.ClassDescriptor.Builder.value;
+import static org.mozilla.javascript.ClassDescriptor.Destination.CTOR;
+import static org.mozilla.javascript.ClassDescriptor.Destination.PROTO;
+
import java.math.BigInteger;
/** This class implements the BigInt native object. */
@@ -14,46 +18,33 @@ final class NativeBigInt extends ScriptableObject {
private static final String CLASS_NAME = "BigInt";
+ private static final ClassDescriptor DESCRIPTOR;
+
+ static {
+ DESCRIPTOR =
+ new ClassDescriptor.Builder(
+ CLASS_NAME,
+ 1,
+ NativeBigInt::js_constructorFunc,
+ NativeBigInt::js_constructor)
+ .withMethod(CTOR, "asIntN", 2, NativeBigInt::js_asIntN)
+ .withMethod(CTOR, "asUintN", 2, NativeBigInt::js_asUintN)
+ .withMethod(PROTO, "toString", 0, NativeBigInt::js_toString)
+ // Alias toLocaleString to toString
+ .withMethod(PROTO, "toLocaleString", 0, NativeBigInt::js_toString)
+ .withMethod(PROTO, "toSource", 0, NativeBigInt::js_toSource)
+ .withMethod(PROTO, "valueOf", 0, NativeBigInt::js_valueOf)
+ .withProp(
+ PROTO,
+ SymbolKey.TO_STRING_TAG,
+ value(CLASS_NAME, DONTENUM | READONLY))
+ .build();
+ }
+
private final BigInteger bigIntValue;
static Object init(Context cx, VarScope scope, boolean sealed) {
- LambdaConstructor constructor =
- new LambdaConstructor(
- scope,
- CLASS_NAME,
- 1,
- NativeBigInt::js_constructorFunc,
- NativeBigInt::js_constructor);
- constructor.setPrototypePropertyAttributes(DONTENUM | READONLY | PERMANENT);
- constructor.defineConstructorMethod(
- scope,
- "asIntN",
- 2,
- (Context lcx, VarScope lscope, Scriptable thisObj, Object[] args) ->
- js_asIntOrUintN(true, args));
- constructor.defineConstructorMethod(
- scope,
- "asUintN",
- 2,
- (Context lcx, VarScope lscope, Scriptable thisObj, Object[] args) ->
- js_asIntOrUintN(false, args));
- constructor.definePrototypeMethod(scope, "toString", 0, NativeBigInt::js_toString);
- // Alias toLocaleString to toString
- constructor.definePrototypeMethod(scope, "toLocaleString", 0, NativeBigInt::js_toString);
- constructor.definePrototypeMethod(scope, "toSource", 0, NativeBigInt::js_toSource);
- constructor.definePrototypeMethod(
- scope,
- "valueOf",
- 0,
- (Context lcx, VarScope lscope, Scriptable thisObj, Object[] args) ->
- toSelf(thisObj).bigIntValue);
- constructor.definePrototypeProperty(
- SymbolKey.TO_STRING_TAG, CLASS_NAME, DONTENUM | READONLY);
- if (sealed) {
- constructor.sealObject();
- ((ScriptableObject) constructor.getPrototypeProperty()).sealObject();
- }
- return constructor;
+ return DESCRIPTOR.buildConstructor(cx, scope, new NativeObject(), sealed);
}
NativeBigInt(BigInteger bigInt) {
@@ -70,15 +61,17 @@ private static NativeBigInt toSelf(Object thisObj) {
}
private static Object js_constructorFunc(
- Context cx, VarScope scope, Object thisObj, Object[] args) {
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
return (args.length >= 1) ? ScriptRuntime.toBigInt(args[0]) : BigInteger.ZERO;
}
- private static Scriptable js_constructor(Context cx, VarScope scope, Object[] args) {
+ private static Scriptable js_constructor(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
throw ScriptRuntime.typeErrorById("msg.no.new", CLASS_NAME);
}
- private static Object js_toString(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_toString(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
int base =
(args.length == 0 || args[0] == Undefined.instance)
? 10
@@ -87,10 +80,26 @@ private static Object js_toString(Context cx, VarScope scope, Object thisObj, Ob
return ScriptRuntime.bigIntToString(value, base);
}
- private static Object js_toSource(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_toSource(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
return "(new BigInt(" + ScriptRuntime.toString(toSelf(thisObj).bigIntValue) + "))";
}
+ private static Object js_asIntN(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return js_asIntOrUintN(true, args);
+ }
+
+ private static Object js_asUintN(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return js_asIntOrUintN(false, args);
+ }
+
+ private static Object js_valueOf(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return toSelf(thisObj).bigIntValue;
+ }
+
private static Object js_asIntOrUintN(boolean isSigned, Object[] args) {
int bits = ScriptRuntime.toIndex(args.length < 1 ? Undefined.instance : args[0]);
BigInteger bigInt = ScriptRuntime.toBigInt(args.length < 2 ? Undefined.instance : args[1]);
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeBoolean.java b/rhino/src/main/java/org/mozilla/javascript/NativeBoolean.java
index 26557459749..7658259ac47 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeBoolean.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeBoolean.java
@@ -71,8 +71,7 @@ private static NativeBoolean js_constructor(
Context cx, JSFunction fun, Object nt, VarScope s, Object thisObj, Object[] args) {
boolean b = ScriptRuntime.toBoolean(args.length > 0 ? args[0] : Undefined.instance);
var res = new NativeBoolean(b);
- res.setPrototype((Scriptable) fun.getPrototypeProperty());
- res.setParentScope(s);
+ ScriptRuntime.setBuiltinProtoAndParent(res, fun, nt, s, TopLevel.Builtins.Boolean);
return res;
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeCallSite.java b/rhino/src/main/java/org/mozilla/javascript/NativeCallSite.java
index a1fe0ef57b6..e0d34e5eba1 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeCallSite.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeCallSite.java
@@ -6,26 +6,45 @@
package org.mozilla.javascript;
+import static org.mozilla.javascript.ClassDescriptor.Destination.PROTO;
+
/**
* This class is used by the V8 extension "Error.prepareStackTrace." It is passed to that function,
* which may then use it to format the stack as it sees fit.
*/
-public class NativeCallSite extends IdScriptableObject {
+public class NativeCallSite extends ScriptableObject {
private static final long serialVersionUID = 2688372752566593594L;
- private static final String CALLSITE_TAG = "CallSite";
+
private ScriptStackElement element;
- static void init(VarScope scope, boolean sealed) {
- NativeCallSite cs = new NativeCallSite();
- cs.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);
+ private static final ClassDescriptor DESCRIPTOR;
+
+ static {
+ DESCRIPTOR =
+ new ClassDescriptor.Builder(
+ "CallSite",
+ 0,
+ NativeCallSite::js_constructor,
+ NativeCallSite::js_constructor)
+ .withMethod(PROTO, "getThis", 0, NativeCallSite::js_getThis)
+ .withMethod(PROTO, "getTypeName", 0, NativeCallSite::js_getTypeName)
+ .withMethod(PROTO, "getFunction", 0, NativeCallSite::js_getFunction)
+ .withMethod(PROTO, "getFunctionName", 0, NativeCallSite::js_getFunctionName)
+ .withMethod(PROTO, "getMethodName", 0, NativeCallSite::js_getMethodName)
+ .withMethod(PROTO, "getFileName", 0, NativeCallSite::js_getFileName)
+ .withMethod(PROTO, "getLineNumber", 0, NativeCallSite::js_getLineNumber)
+ .withMethod(PROTO, "getColumnNumber", 0, NativeCallSite::js_getColumnNumber)
+ .withMethod(PROTO, "getEvalOrigin", 0, NativeCallSite::js_getEvalOrigin)
+ .withMethod(PROTO, "isToplevel", 0, NativeCallSite::js_isToplevel)
+ .withMethod(PROTO, "isEval", 0, NativeCallSite::js_isEval)
+ .withMethod(PROTO, "isNative", 0, NativeCallSite::js_isNative)
+ .withMethod(PROTO, "isConstructor", 0, NativeCallSite::js_isConstructor)
+ .withMethod(PROTO, "toString", 0, NativeCallSite::js_toString)
+ .build();
}
- static NativeCallSite make(VarScope scope, Scriptable ctorObj) {
- NativeCallSite cs = new NativeCallSite();
- Scriptable proto = (Scriptable) ctorObj.get("prototype", ctorObj);
- cs.setParentScope(scope);
- cs.setPrototype(proto);
- return cs;
+ static void init(Context cx, VarScope scope, boolean sealed) {
+ DESCRIPTOR.buildConstructor(cx, scope, new NativeCallSite(), sealed);
}
private NativeCallSite() {}
@@ -39,113 +58,6 @@ public String getClassName() {
return "CallSite";
}
- @Override
- protected void initPrototypeId(int id) {
- String s;
- int arity;
- switch (id) {
- case Id_constructor:
- arity = 0;
- s = "constructor";
- break;
- case Id_getThis:
- arity = 0;
- s = "getThis";
- break;
- case Id_getTypeName:
- arity = 0;
- s = "getTypeName";
- break;
- case Id_getFunction:
- arity = 0;
- s = "getFunction";
- break;
- case Id_getFunctionName:
- arity = 0;
- s = "getFunctionName";
- break;
- case Id_getMethodName:
- arity = 0;
- s = "getMethodName";
- break;
- case Id_getFileName:
- arity = 0;
- s = "getFileName";
- break;
- case Id_getLineNumber:
- arity = 0;
- s = "getLineNumber";
- break;
- case Id_getColumnNumber:
- arity = 0;
- s = "getColumnNumber";
- break;
- case Id_getEvalOrigin:
- arity = 0;
- s = "getEvalOrigin";
- break;
- case Id_isToplevel:
- arity = 0;
- s = "isToplevel";
- break;
- case Id_isEval:
- arity = 0;
- s = "isEval";
- break;
- case Id_isNative:
- arity = 0;
- s = "isNative";
- break;
- case Id_isConstructor:
- arity = 0;
- s = "isConstructor";
- break;
- case Id_toString:
- arity = 0;
- s = "toString";
- break;
- default:
- throw new IllegalArgumentException(String.valueOf(id));
- }
- initPrototypeMethod(CALLSITE_TAG, id, s, arity);
- }
-
- @Override
- public Object execIdCall(
- IdFunctionObject f, Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
- if (!f.hasTag(CALLSITE_TAG)) {
- return super.execIdCall(f, cx, scope, thisObj, args);
- }
- int id = f.methodId();
- switch (id) {
- case Id_constructor:
- return make(scope, f);
- case Id_getFunctionName:
- return getFunctionName(thisObj);
- case Id_getFileName:
- return getFileName(thisObj);
- case Id_getLineNumber:
- return getLineNumber(thisObj);
- case Id_getThis:
- case Id_getTypeName:
- case Id_getFunction:
- case Id_getColumnNumber:
- return Undefined.instance;
- case Id_getMethodName:
- return null;
- case Id_getEvalOrigin:
- case Id_isEval:
- case Id_isConstructor:
- case Id_isNative:
- case Id_isToplevel:
- return Boolean.FALSE;
- case Id_toString:
- return js_toString(thisObj);
- default:
- throw new IllegalArgumentException(String.valueOf(id));
- }
- }
-
@Override
public String toString() {
if (element == null) {
@@ -154,6 +66,84 @@ public String toString() {
return element.toString();
}
+ private static Object js_constructor(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ var res = new NativeCallSite();
+ res.setPrototype((Scriptable) f.getPrototypeProperty());
+ res.setParentScope(s);
+ return res;
+ }
+
+ private static Object js_getThis(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return Undefined.instance;
+ }
+
+ private static Object js_getTypeName(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return Undefined.instance;
+ }
+
+ private static Object js_getFunction(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return Undefined.instance;
+ }
+
+ private static Object js_getFunctionName(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return getFunctionName((Scriptable) thisObj);
+ }
+
+ private static Object js_getMethodName(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return null;
+ }
+
+ private static Object js_getFileName(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return getFileName((Scriptable) thisObj);
+ }
+
+ private static Object js_getLineNumber(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return getLineNumber((Scriptable) thisObj);
+ }
+
+ private static Object js_getColumnNumber(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return Undefined.instance;
+ }
+
+ private static Object js_getEvalOrigin(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return Boolean.FALSE;
+ }
+
+ private static Object js_isToplevel(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return Boolean.FALSE;
+ }
+
+ private static Object js_isEval(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return Boolean.FALSE;
+ }
+
+ private static Object js_isNative(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return Boolean.FALSE;
+ }
+
+ private static Object js_isConstructor(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return Boolean.FALSE;
+ }
+
+ private static Object js_toString(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return js_toString((Scriptable) thisObj);
+ }
+
private static Object js_toString(Scriptable obj) {
while (obj != null && !(obj instanceof NativeCallSite)) {
obj = obj.getPrototype();
@@ -202,77 +192,4 @@ private static Object getLineNumber(Scriptable obj) {
}
return Integer.valueOf(cs.element.lineNumber);
}
-
- @Override
- protected int findPrototypeId(String s) {
- int id;
- switch (s) {
- case "constructor":
- id = Id_constructor;
- break;
- case "getThis":
- id = Id_getThis;
- break;
- case "getTypeName":
- id = Id_getTypeName;
- break;
- case "getFunction":
- id = Id_getFunction;
- break;
- case "getFunctionName":
- id = Id_getFunctionName;
- break;
- case "getMethodName":
- id = Id_getMethodName;
- break;
- case "getFileName":
- id = Id_getFileName;
- break;
- case "getLineNumber":
- id = Id_getLineNumber;
- break;
- case "getColumnNumber":
- id = Id_getColumnNumber;
- break;
- case "getEvalOrigin":
- id = Id_getEvalOrigin;
- break;
- case "isToplevel":
- id = Id_isToplevel;
- break;
- case "isEval":
- id = Id_isEval;
- break;
- case "isNative":
- id = Id_isNative;
- break;
- case "isConstructor":
- id = Id_isConstructor;
- break;
- case "toString":
- id = Id_toString;
- break;
- default:
- id = 0;
- break;
- }
- return id;
- }
-
- private static final int Id_constructor = 1,
- Id_getThis = 2,
- Id_getTypeName = 3,
- Id_getFunction = 4,
- Id_getFunctionName = 5,
- Id_getMethodName = 6,
- Id_getFileName = 7,
- Id_getLineNumber = 8,
- Id_getColumnNumber = 9,
- Id_getEvalOrigin = 10,
- Id_isToplevel = 11,
- Id_isEval = 12,
- Id_isNative = 13,
- Id_isConstructor = 14,
- Id_toString = 15,
- MAX_PROTOTYPE_ID = 15;
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeCollectionIterator.java b/rhino/src/main/java/org/mozilla/javascript/NativeCollectionIterator.java
index c84174b4167..82f78a168bc 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeCollectionIterator.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeCollectionIterator.java
@@ -18,10 +18,6 @@ enum Type {
BOTH
}
- static void init(TopLevel scope, String tag, boolean sealed) {
- ES6Iterator.init(scope, sealed, new NativeCollectionIterator(tag), tag);
- }
-
public NativeCollectionIterator(String tag) {
this.className = tag;
this.iterator = Collections.emptyIterator();
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeConsole.java b/rhino/src/main/java/org/mozilla/javascript/NativeConsole.java
index 6ac688d0c09..b1b8d86175a 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeConsole.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeConsole.java
@@ -255,7 +255,7 @@ private static String formatObj(Context cx, VarScope scope, Object arg) {
public Object call(
Context callCx,
VarScope callScope,
- Scriptable callThisObj,
+ Object callThisObj,
Object[] callArgs) {
Object value = callArgs[1];
while (value instanceof Delegator) {
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeContinuation.java b/rhino/src/main/java/org/mozilla/javascript/NativeContinuation.java
index b7dc353a464..61ab6da3a83 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeContinuation.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeContinuation.java
@@ -8,16 +8,34 @@
import java.util.Objects;
-public final class NativeContinuation extends IdScriptableObject implements Function {
+public final class NativeContinuation extends ScriptableObject implements Function {
private static final long serialVersionUID = 1794167133757605367L;
- private static final Object FTAG = "Continuation";
+ private static final String CLASS_NAME = "Continuation";
+
+ private static final ClassDescriptor DESCRIPTOR;
+ private static final JSDescriptor CTOR_DESCRIPTOR;
+
+ static {
+ DESCRIPTOR =
+ new ClassDescriptor.Builder(
+ CLASS_NAME,
+ 0,
+ NativeContinuation::js_constructor,
+ NativeContinuation::js_constructor)
+ .build();
+ CTOR_DESCRIPTOR = DESCRIPTOR.ctorDesc();
+ }
private Object implementation;
public static void init(Context cx, VarScope scope, boolean sealed) {
- NativeContinuation obj = new NativeContinuation();
- obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);
+ DESCRIPTOR.buildConstructor(cx, scope, new NativeContinuation(), sealed);
+ }
+
+ private static Object js_constructor(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ throw Context.reportRuntimeError("Direct call is not supported");
}
public Object getImplementation() {
@@ -39,15 +57,17 @@ public Scriptable construct(Context cx, VarScope scope, Object[] args) {
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Scriptable construct(Context cx, Object nt, VarScope s, Object thisObj, Object[] args) {
+ throw Context.reportRuntimeError("Direct call is not supported");
+ }
+
+ @Override
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
return Interpreter.restartContinuation(this, cx, scope, args);
}
- public static boolean isContinuationConstructor(IdFunctionObject f) {
- if (f.hasTag(FTAG) && f.methodId() == Id_constructor) {
- return true;
- }
- return false;
+ public static boolean isContinuationConstructor(JSFunction f) {
+ return f.getDescriptor() == CTOR_DESCRIPTOR;
}
/**
@@ -61,49 +81,4 @@ public static boolean isContinuationConstructor(IdFunctionObject f) {
public static boolean equalImplementations(NativeContinuation c1, NativeContinuation c2) {
return Objects.equals(c1.implementation, c2.implementation);
}
-
- @Override
- protected void initPrototypeId(int id) {
- String s;
- int arity;
- switch (id) {
- case Id_constructor:
- arity = 0;
- s = "constructor";
- break;
- default:
- throw new IllegalArgumentException(String.valueOf(id));
- }
- initPrototypeMethod(FTAG, id, s, arity);
- }
-
- @Override
- public Object execIdCall(
- IdFunctionObject f, Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
- if (!f.hasTag(FTAG)) {
- return super.execIdCall(f, cx, scope, thisObj, args);
- }
- int id = f.methodId();
- switch (id) {
- case Id_constructor:
- throw Context.reportRuntimeError("Direct call is not supported");
- }
- throw new IllegalArgumentException(String.valueOf(id));
- }
-
- @Override
- protected int findPrototypeId(String s) {
- int id;
- switch (s) {
- case "constructor":
- id = Id_constructor;
- break;
- default:
- id = 0;
- break;
- }
- return id;
- }
-
- private static final int Id_constructor = 1, MAX_PROTOTYPE_ID = 1;
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeError.java b/rhino/src/main/java/org/mozilla/javascript/NativeError.java
index 27ffa0f036d..4cdc61ae223 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeError.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeError.java
@@ -82,7 +82,7 @@ private static Object js_isError(
static void init(Context cx, VarScope scope, boolean sealed) {
var ctor = DESCRIPTOR.buildConstructor(cx, scope, new NativeObject(), sealed);
- NativeCallSite.init(scope, sealed);
+ NativeCallSite.init(cx, scope, sealed);
ProtoProps protoProps = new ProtoProps();
((ScriptableObject) ctor.getPrototypeProperty()).associateValue(ProtoProps.KEY, protoProps);
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeFunction.java b/rhino/src/main/java/org/mozilla/javascript/NativeFunction.java
index 2652854d81a..fd54e548d17 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeFunction.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeFunction.java
@@ -20,6 +20,10 @@ public abstract class NativeFunction extends BaseFunction {
private boolean isShorthand;
+ protected NativeFunction(VarScope scope) {
+ super(scope);
+ }
+
public final void initScriptFunction(
Context cx, VarScope scope, boolean es6GeneratorFunction, boolean isShorthand) {
ScriptRuntime.setFunctionProtoAndParent(this, cx, scope, es6GeneratorFunction);
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeGenerator.java b/rhino/src/main/java/org/mozilla/javascript/NativeGenerator.java
index fb89f2d7031..7e3b47565ab 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeGenerator.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeGenerator.java
@@ -6,40 +6,36 @@
package org.mozilla.javascript;
+import static org.mozilla.javascript.ClassDescriptor.Destination.CTOR;
+import static org.mozilla.javascript.Symbol.Kind.REGULAR;
+
/**
* This class implements generator objects. See Generators
*
* @author Norris Boyd
*/
-public final class NativeGenerator extends IdScriptableObject {
- private static final long serialVersionUID = 1645892441041347273L;
-
- private static final Object GENERATOR_TAG = "Generator";
-
- static NativeGenerator init(TopLevel scope, boolean sealed) {
- // Generator
- // Can't use "NativeGenerator().exportAsJSClass" since we don't want
- // to define "Generator" as a constructor in the top-level scope.
-
- NativeGenerator prototype = new NativeGenerator();
- if (scope != null) {
- prototype.setParentScope(scope);
- prototype.setPrototype(getObjectPrototype(scope));
- }
- prototype.activatePrototypeMap(MAX_PROTOTYPE_ID);
- if (sealed) {
- prototype.sealObject();
- }
-
- // Need to access Generator prototype when constructing
- // Generator instances, but don't have a generator constructor
- // to use to find the prototype. Use the "associateValue"
- // approach instead.
- if (scope != null) {
- scope.associateValue(GENERATOR_TAG, prototype);
- }
+public final class NativeGenerator extends ScriptableObject {
+ private static final long serialVersionUID = -1383456283657974338L;
+
+ private static final SymbolKey GENERATOR_TAG = new SymbolKey("GeneratorPrototype", REGULAR);
+ private static final ClassDescriptor DESCRIPTOR;
+
+ static {
+ DESCRIPTOR =
+ new ClassDescriptor.Builder(GENERATOR_TAG)
+ .withMethod(CTOR, "close", 1, NativeGenerator::js_close)
+ .withMethod(CTOR, "next", 1, NativeGenerator::js_next)
+ .withMethod(CTOR, "send", 0, NativeGenerator::js_send)
+ .withMethod(CTOR, "throw", 0, NativeGenerator::js_throw)
+ .withMethod(CTOR, "__iterator__", 1, NativeGenerator::js_iterator)
+ .build();
+ }
+ static NativeGenerator init(Context cx, TopLevel scope, boolean sealed) {
+ var prototype = new NativeGenerator();
+ DESCRIPTOR.populateGlobal(cx, scope, prototype, sealed);
+ scope.associateValue(GENERATOR_TAG, prototype);
return prototype;
}
@@ -66,78 +62,49 @@ public String getClassName() {
return "Generator";
}
- @Override
- protected void initPrototypeId(int id) {
- String s;
- int arity;
- switch (id) {
- case Id_close:
- arity = 1;
- s = "close";
- break;
- case Id_next:
- arity = 1;
- s = "next";
- break;
- case Id_send:
- arity = 0;
- s = "send";
- break;
- case Id_throw:
- arity = 0;
- s = "throw";
- break;
- case Id___iterator__:
- arity = 1;
- s = "__iterator__";
- break;
- default:
- throw new IllegalArgumentException(String.valueOf(id));
- }
- initPrototypeMethod(GENERATOR_TAG, id, s, arity);
+ private static Object js_close(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ // need to run any pending finally clauses
+ var generator = realThis(thisObj);
+ return generator.resume(cx, s, GENERATOR_CLOSE, new GeneratorClosedException());
}
- @Override
- public Object execIdCall(
- IdFunctionObject f, Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
- if (!f.hasTag(GENERATOR_TAG)) {
- return super.execIdCall(f, cx, scope, thisObj, args);
- }
- int id = f.methodId();
-
- NativeGenerator generator = ensureType(thisObj, NativeGenerator.class, f);
-
- switch (id) {
- case Id_close:
- // need to run any pending finally clauses
- return generator.resume(cx, scope, GENERATOR_CLOSE, new GeneratorClosedException());
-
- case Id_next:
- // arguments to next() are ignored
- generator.firstTime = false;
- return generator.resume(cx, scope, GENERATOR_SEND, Undefined.instance);
-
- case Id_send:
- {
- Object arg = args.length > 0 ? args[0] : Undefined.instance;
- if (generator.firstTime && !arg.equals(Undefined.instance)) {
- throw ScriptRuntime.typeErrorById("msg.send.newborn");
- }
- return generator.resume(cx, scope, GENERATOR_SEND, arg);
- }
-
- case Id_throw:
- return generator.resume(
- cx, scope, GENERATOR_THROW, args.length > 0 ? args[0] : Undefined.instance);
-
- case Id___iterator__:
- return thisObj;
-
- default:
- throw new IllegalArgumentException(String.valueOf(id));
+ private static Object js_next(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ // arguments to next() are ignored
+ var generator = realThis(thisObj);
+ generator.firstTime = false;
+ return generator.resume(cx, s, GENERATOR_SEND, Undefined.instance);
+ }
+
+ private static Object js_send(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ {
+ var generator = realThis(thisObj);
+ Object arg = args.length > 0 ? args[0] : Undefined.instance;
+ if (generator.firstTime && !arg.equals(Undefined.instance)) {
+ throw ScriptRuntime.typeErrorById("msg.send.newborn");
+ }
+ return generator.resume(cx, s, GENERATOR_SEND, arg);
}
}
+ private static Object js_throw(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ var generator = realThis(thisObj);
+ return generator.resume(
+ cx, s, GENERATOR_THROW, args.length > 0 ? args[0] : Undefined.instance);
+ }
+
+ private static Object js_iterator(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return thisObj;
+ }
+
+ private static NativeGenerator realThis(Object thisObj) {
+ return LambdaConstructor.convertThisObject(thisObj, NativeGenerator.class);
+ }
+
private Object resume(Context cx, VarScope scope, int operation, Object value) {
if (savedState == null) {
if (operation == GENERATOR_CLOSE) return Undefined.instance;
@@ -176,39 +143,6 @@ private Object resume(Context cx, VarScope scope, int operation, Object value) {
}
}
- @Override
- protected int findPrototypeId(String s) {
- int id;
- switch (s) {
- case "close":
- id = Id_close;
- break;
- case "next":
- id = Id_next;
- break;
- case "send":
- id = Id_send;
- break;
- case "throw":
- id = Id_throw;
- break;
- case "__iterator__":
- id = Id___iterator__;
- break;
- default:
- id = 0;
- break;
- }
- return id;
- }
-
- private static final int Id_close = 1,
- Id_next = 2,
- Id_send = 3,
- Id_throw = 4,
- Id___iterator__ = 5,
- MAX_PROTOTYPE_ID = 5;
-
private JSFunction function;
private Object savedState;
private String lineSource;
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeGlobal.java b/rhino/src/main/java/org/mozilla/javascript/NativeGlobal.java
index 92705b18b21..0438cb27460 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeGlobal.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeGlobal.java
@@ -6,11 +6,14 @@
package org.mozilla.javascript;
+import static org.mozilla.javascript.ClassDescriptor.Builder.value;
+import static org.mozilla.javascript.ClassDescriptor.Destination.CTOR;
+import static org.mozilla.javascript.ClassDescriptor.Destination.PROTO;
import static org.mozilla.javascript.ScriptableObject.DONTENUM;
-import static org.mozilla.javascript.ScriptableObject.PERMANENT;
-import static org.mozilla.javascript.ScriptableObject.READONLY;
import java.io.Serializable;
+import java.util.EnumMap;
+import java.util.Map;
import org.mozilla.javascript.xml.XMLLib;
/**
@@ -23,37 +26,73 @@
public class NativeGlobal implements Serializable {
static final long serialVersionUID = 6080442165748707530L;
+ private static final ClassDescriptor DESCRIPTOR;
+ private static final JSDescriptor EVAL_DESCRIPTOR;
+ private static final Map ERROR_DESCRIPTORS;
+
+ static {
+ DESCRIPTOR =
+ new ClassDescriptor.Builder("globalThis")
+ .withMethod(CTOR, "decodeURI", 1, NativeGlobal::js_decodeURI)
+ .withMethod(
+ CTOR, "decodeURIComponent", 1, NativeGlobal::js_decodeURIComponent)
+ .withMethod(CTOR, "encodeURI", 1, NativeGlobal::js_encodeURI)
+ .withMethod(
+ CTOR, "encodeURIComponent", 1, NativeGlobal::js_encodeURIComponent)
+ .withMethod(CTOR, "escape", 1, NativeGlobal::js_escape)
+ .withMethod(CTOR, "isFinite", 1, NativeGlobal::js_isFinite)
+ .withMethod(CTOR, "isNaN", 1, NativeGlobal::js_isNaN)
+ .withMethod(CTOR, "isXMLName", 1, NativeGlobal::js_isXMLName)
+ .withMethod(CTOR, "parseFloat", 1, NativeGlobal::js_parseFloat)
+ .withMethod(CTOR, "parseInt", 2, NativeGlobal::js_parseInt)
+ .withMethod(CTOR, "unescape", 1, NativeGlobal::js_unescape)
+ .withMethod(CTOR, "uneval", 1, NativeGlobal::js_uneval)
+ .withMethod(CTOR, "eval", 1, NativeGlobal::js_eval)
+ .withProp(CTOR, "NaN", value(ScriptRuntime.NaNobj))
+ .withProp(CTOR, "Infinity", value(Double.POSITIVE_INFINITY))
+ .withProp(CTOR, "undefined", value(Undefined.instance))
+ .build();
+ EVAL_DESCRIPTOR = DESCRIPTOR.findCtorDesc("eval");
+
+ var errorDescs =
+ new EnumMap(TopLevel.NativeErrors.class);
+ for (var e : TopLevel.NativeErrors.values()) {
+ if (e == TopLevel.NativeErrors.Error) continue;
+ ClassDescriptor.Builder builder;
+ if (e != TopLevel.NativeErrors.AggregateError) {
+ builder =
+ new ClassDescriptor.Builder(
+ e.name(),
+ 1,
+ (c, f, nt, s, thisObj, args) -> NativeError.make(c, s, f, args),
+ (c, f, nt, s, thisObj, args) -> NativeError.make(c, s, f, args));
+ } else {
+ builder =
+ new ClassDescriptor.Builder(
+ e.name(),
+ 2,
+ (c, f, nt, s, thisObj, args) ->
+ NativeError.makeAggregate(c, s, f, args),
+ (c, f, nt, s, thisObj, args) ->
+ NativeError.makeAggregate(c, s, f, args));
+ }
+ errorDescs.put(
+ e,
+ builder.withProp(PROTO, "name", value(e.name(), DONTENUM))
+ .withProp(PROTO, "message", value("", DONTENUM))
+ .build());
+ }
+ ERROR_DESCRIPTORS = Map.copyOf(errorDescs);
+ }
+
public static void init(Context cx, TopLevel scope, boolean sealed) {
- defineGlobalFunction(scope, sealed, "decodeURI", 1, NativeGlobal::js_decodeURI);
- defineGlobalFunction(
- scope, sealed, "decodeURIComponent", 1, NativeGlobal::js_decodeURIComponent);
- defineGlobalFunction(scope, sealed, "encodeURI", 1, NativeGlobal::js_encodeURI);
- defineGlobalFunction(
- scope, sealed, "encodeURIComponent", 1, NativeGlobal::js_encodeURIComponent);
- defineGlobalFunction(scope, sealed, "escape", 1, NativeGlobal::js_escape);
- defineGlobalFunction(scope, sealed, "isFinite", 1, NativeGlobal::js_isFinite);
- defineGlobalFunction(scope, sealed, "isNaN", 1, NativeGlobal::js_isNaN);
- defineGlobalFunction(scope, sealed, "isXMLName", 1, NativeGlobal::js_isXMLName);
- defineGlobalFunction(scope, sealed, "parseFloat", 1, NativeGlobal::js_parseFloat);
- defineGlobalFunction(scope, sealed, "parseInt", 2, NativeGlobal::js_parseInt);
- defineGlobalFunction(scope, sealed, "unescape", 1, NativeGlobal::js_unescape);
- defineGlobalFunction(scope, sealed, "uneval", 1, NativeGlobal::js_uneval);
- defineGlobalFunctionEval(scope, sealed);
-
- ScriptableObject.defineProperty(
- scope, "NaN", ScriptRuntime.NaNobj, READONLY | DONTENUM | PERMANENT);
- ScriptableObject.defineProperty(
- scope, "Infinity", Double.POSITIVE_INFINITY, READONLY | DONTENUM | PERMANENT);
- ScriptableObject.defineProperty(
- scope, "undefined", Undefined.instance, READONLY | DONTENUM | PERMANENT);
var globalThis = scope.getGlobalThis();
+ DESCRIPTOR.populateGlobal(cx, scope, globalThis, false);
var obj = (Scriptable) scope.get("Object", scope);
var objProto = (Scriptable) obj.get("prototype", obj);
globalThis.setPrototype(objProto);
- ScriptableObject.defineProperty(scope, "globalThis", globalThis, DONTENUM);
-
/*
Each error constructor gets its own Error object as a prototype,
with the 'name' property set to the name of the error.
@@ -64,119 +103,43 @@ public static void init(Context cx, TopLevel scope, boolean sealed) {
ScriptableObject.ensureScriptable(
ScriptableObject.getProperty(nativeError, "prototype"));
- for (TopLevel.NativeErrors error : TopLevel.NativeErrors.values()) {
- if (error == TopLevel.NativeErrors.Error) {
- // Error is initialized elsewhere and we should not overwrite it.
- continue;
- }
- String name = error.name();
- TopLevel topLevelScope = ScriptableObject.getTopLevelScope(scope);
- Function builtinErrorCtor =
- TopLevel.getBuiltinCtor(cx, topLevelScope, TopLevel.Builtins.Error);
- ScriptableObject errorProto = NativeError.makeProto(topLevelScope, builtinErrorCtor);
- errorProto.defineProperty("name", name, DONTENUM);
- errorProto.defineProperty("message", "", DONTENUM);
-
- BaseFunction ctor;
-
- // Building errors is complex because of the prototype chain requirements. This is a bit
- // arcane, but it's a combination that makes test262 happy.
- if (error == TopLevel.NativeErrors.AggregateError) {
- var target =
- new SerializableConstructable() {
- // We need a reference to the LambdaFunction, so we use this "lateBound"
- // trick. It ain't great, but it's the only idea I have.
- private Function lateBoundCtor;
-
- @Override
- public Scriptable construct(
- Context callCx, VarScope callScope, Object[] args) {
- return NativeError.makeAggregate(
- callCx, callScope, lateBoundCtor, args);
- }
- };
- ctor =
- new LambdaConstructor(scope, name, 2, target) {
- // Necessary to make the test262 case
- // built-ins/NativeErrors/AggregateError/newtarget-proto-custom.js work
- // correctly
- @Override
- public Scriptable createObject(Context cx, VarScope scope) {
- return null;
- }
- };
- target.lateBoundCtor = ctor;
- } else {
- var target =
- new SerializableConstructable() {
- private Function lateBoundCtor;
-
- @Override
- public Scriptable construct(
- Context callCx, VarScope callScope, Object[] args) {
- return NativeError.make(callCx, callScope, lateBoundCtor, args);
- }
- };
- ctor = new LambdaConstructor(scope, name, 1, target);
- target.lateBoundCtor = ctor;
- }
-
- ctor.setImmunePrototypeProperty(errorProto);
- ctor.setPrototype(nativeError);
- errorProto.put("constructor", errorProto, ctor);
- errorProto.setAttributes("constructor", ScriptableObject.DONTENUM);
- errorProto.setPrototype(nativeErrorProto);
- ctor.setAttributes("name", DONTENUM | READONLY);
- ctor.setAttributes("length", DONTENUM | READONLY);
- if (sealed) {
- errorProto.sealObject();
- ctor.sealObject();
- }
-
- ScriptableObject.defineProperty(scope, name, ctor, DONTENUM);
- }
- }
-
- private static void defineGlobalFunction(
- VarScope scope,
- boolean sealed,
- String name,
- int length,
- SerializableCallable callable) {
- LambdaFunction fun = new LambdaFunction(scope, name, length, null, callable);
- registerGlobalFunction(scope, sealed, name, fun);
- }
-
- private static void registerGlobalFunction(
- VarScope scope, boolean sealed, String name, LambdaFunction fun) {
- ScriptableObject.defineProperty(scope, name, fun, DONTENUM);
- if (sealed) {
- fun.sealObject();
+ Function builtinErrorCtor = TopLevel.getBuiltinCtor(cx, scope, TopLevel.Builtins.Error);
+ for (var e : ERROR_DESCRIPTORS.entrySet()) {
+ var name = e.getKey().name();
+ var desc = e.getValue();
+ var errorProto = NativeError.makeProto(scope, builtinErrorCtor);
+ desc.buildConstructor(
+ cx,
+ scope,
+ errorProto,
+ sealed,
+ (c, ctor) -> {
+ ctor.setPrototype(nativeError);
+ errorProto.setPrototype(nativeErrorProto);
+ });
}
}
- // Eval is special because we need to "recognize" it in isEvalFunction
- private static void defineGlobalFunctionEval(VarScope scope, boolean sealed) {
- LambdaFunction evalFun = new EvalLambdaFunction(scope);
- registerGlobalFunction(scope, sealed, "eval", evalFun);
- }
-
static boolean isEvalFunction(Object functionObj) {
- return functionObj instanceof EvalLambdaFunction;
+ return functionObj instanceof JSFunction
+ && ((JSFunction) functionObj).getDescriptor() == EVAL_DESCRIPTOR;
}
- private static String js_uneval(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static String js_uneval(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
Object value = (args.length != 0) ? args[0] : Undefined.instance;
- return ScriptRuntime.uneval(cx, scope, value);
+ return ScriptRuntime.uneval(cx, s, value);
}
- private static Boolean js_isXMLName(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Boolean js_isXMLName(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
Object name = (args.length == 0) ? Undefined.instance : args[0];
- XMLLib xmlLib = XMLLib.extractFromScope(scope);
+ XMLLib xmlLib = XMLLib.extractFromScope(s);
return xmlLib.isXMLName(cx, name);
}
- private static Boolean js_isNaN(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Boolean js_isNaN(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
// The global method isNaN, as per ECMA-262 15.1.2.6.
if (args.length < 1) {
return true;
@@ -186,48 +149,52 @@ private static Boolean js_isNaN(Context cx, VarScope scope, Object thisObj, Obje
}
}
- private static Object js_isFinite(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_isFinite(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
if (args.length < 1) {
return Boolean.FALSE;
}
return NativeNumber.isFinite(args[0]);
}
- private static String js_decodeURI(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static String js_decodeURI(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
String str = ScriptRuntime.toString(args, 0);
return decode(str, true);
}
private static String js_decodeURIComponent(
- Context cx, VarScope scope, Object thisObj, Object[] args) {
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
String str = ScriptRuntime.toString(args, 0);
return decode(str, false);
}
- private static String js_encodeURI(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static String js_encodeURI(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
String str = ScriptRuntime.toString(args, 0);
return encode(str, true);
}
private static String js_encodeURIComponent(
- Context cx, VarScope scope, Object thisObj, Object[] args) {
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
String str = ScriptRuntime.toString(args, 0);
return encode(str, false);
}
/** The global method parseInt, as per ECMA-262 15.1.2.2. */
- static Object js_parseInt(Context cx, VarScope scope, Object thisObj, Object[] args) {
- String s = ScriptRuntime.toString(args, 0);
+ static Object js_parseInt(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ String str = ScriptRuntime.toString(args, 0);
int radix = ScriptRuntime.toInt32(args, 1);
- int len = s.length();
+ int len = str.length();
if (len == 0) return ScriptRuntime.NaNobj;
boolean negative = false;
int start = 0;
char c;
do {
- c = s.charAt(start);
+ c = str.charAt(start);
if (!ScriptRuntime.isStrWhiteSpaceChar(c)) break;
start++;
} while (start < len);
@@ -239,15 +206,15 @@ static Object js_parseInt(Context cx, VarScope scope, Object thisObj, Object[] a
radix = NO_RADIX;
} else if (radix < 2 || radix > 36) {
return ScriptRuntime.NaNobj;
- } else if (radix == 16 && len - start > 1 && s.charAt(start) == '0') {
- c = s.charAt(start + 1);
+ } else if (radix == 16 && len - start > 1 && str.charAt(start) == '0') {
+ c = str.charAt(start + 1);
if (c == 'x' || c == 'X') start += 2;
}
if (radix == NO_RADIX) {
radix = 10;
- if (len - start > 1 && s.charAt(start) == '0') {
- c = s.charAt(start + 1);
+ if (len - start > 1 && str.charAt(start) == '0') {
+ c = str.charAt(start + 1);
if (c == 'x' || c == 'X') {
radix = 16;
start += 2;
@@ -260,7 +227,7 @@ static Object js_parseInt(Context cx, VarScope scope, Object thisObj, Object[] a
}
}
- double d = ScriptRuntime.stringPrefixToNumber(s, start, radix);
+ double d = ScriptRuntime.stringPrefixToNumber(str, start, radix);
return negative ? -d : d;
}
@@ -269,11 +236,12 @@ static Object js_parseInt(Context cx, VarScope scope, Object thisObj, Object[] a
*
* @param args the arguments to parseFloat, ignoring args[>=1]
*/
- static Object js_parseFloat(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ static Object js_parseFloat(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
if (args.length < 1) return ScriptRuntime.NaNobj;
- String s = ScriptRuntime.toString(args[0]);
- int len = s.length();
+ String str = ScriptRuntime.toString(args[0]);
+ int len = str.length();
int start = 0;
// Scan forward to skip whitespace
char c;
@@ -281,7 +249,7 @@ static Object js_parseFloat(Context cx, VarScope scope, Object thisObj, Object[]
if (start == len) {
return ScriptRuntime.NaNobj;
}
- c = s.charAt(start);
+ c = str.charAt(start);
if (!ScriptRuntime.isStrWhiteSpaceChar(c)) {
break;
}
@@ -294,13 +262,13 @@ static Object js_parseFloat(Context cx, VarScope scope, Object thisObj, Object[]
if (i == len) {
return ScriptRuntime.NaNobj;
}
- c = s.charAt(i);
+ c = str.charAt(i);
}
if (c == 'I') {
// check for "Infinity"
- if (i + 8 <= len && s.regionMatches(i, "Infinity", 0, 8)) {
- if (s.charAt(start) == '-') {
+ if (i + 8 <= len && str.regionMatches(i, "Infinity", 0, 8)) {
+ if (str.charAt(start) == '-') {
return Double.NEGATIVE_INFINITY;
} else {
return Double.POSITIVE_INFINITY;
@@ -314,7 +282,7 @@ static Object js_parseFloat(Context cx, VarScope scope, Object thisObj, Object[]
int exponent = -1;
boolean exponentValid = false;
for (; i < len; i++) {
- switch (s.charAt(i)) {
+ switch (str.charAt(i)) {
case '.':
if (decimal != -1) // Only allow a single decimal point.
break;
@@ -365,9 +333,9 @@ static Object js_parseFloat(Context cx, VarScope scope, Object thisObj, Object[]
if (exponent != -1 && !exponentValid) {
i = exponent;
}
- s = s.substring(start, i);
+ str = str.substring(start, i);
try {
- return Double.valueOf(s);
+ return Double.valueOf(str);
} catch (NumberFormatException ex) {
return ScriptRuntime.NaNobj;
}
@@ -379,10 +347,11 @@ static Object js_parseFloat(Context cx, VarScope scope, Object thisObj, Object[]
* Includes code for the 'mask' argument supported by the C escape method, which used to be
* part of the browser embedding. Blame for the strange constant names should be directed there.
*/
- private static Object js_escape(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_escape(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
final int URL_XALPHAS = 1, URL_XPALPHAS = 2, URL_PATH = 4;
- String s = ScriptRuntime.toString(args, 0);
+ String str = ScriptRuntime.toString(args, 0);
int mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
if (args.length > 1) { // the 'mask' argument. Non-ECMA.
@@ -395,8 +364,8 @@ private static Object js_escape(Context cx, VarScope scope, Object thisObj, Obje
}
StringBuilder sb = null;
- for (int k = 0, L = s.length(); k != L; ++k) {
- int c = s.charAt(k);
+ for (int k = 0, L = str.length(); k != L; ++k) {
+ int c = str.charAt(k);
if (mask != 0
&& ((c >= '0' && c <= '9')
|| (c >= 'A' && c <= 'Z')
@@ -440,16 +409,17 @@ private static Object js_escape(Context cx, VarScope scope, Object thisObj, Obje
}
}
- return (sb == null) ? s : sb.toString();
+ return (sb == null) ? str : sb.toString();
}
/** The global unescape method, as per ECMA-262 15.1.2.5. */
- private static Object js_unescape(Context cx, VarScope scope, Object thisObj, Object[] args) {
- String s = ScriptRuntime.toString(args, 0);
- int firstEscapePos = s.indexOf('%');
+ private static Object js_unescape(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ String str = ScriptRuntime.toString(args, 0);
+ int firstEscapePos = str.indexOf('%');
if (firstEscapePos >= 0) {
- int L = s.length();
- char[] buf = s.toCharArray();
+ int L = str.length();
+ char[] buf = str.toCharArray();
int destination = firstEscapePos;
for (int k = firstEscapePos; k != L; ) {
char c = buf[k];
@@ -477,17 +447,18 @@ private static Object js_unescape(Context cx, VarScope scope, Object thisObj, Ob
buf[destination] = c;
++destination;
}
- s = new String(buf, 0, destination);
+ str = new String(buf, 0, destination);
}
- return s;
+ return str;
}
/**
* This is an indirect call to eval, and thus uses the global environment. Direct calls are
* executed via ScriptRuntime.callSpecial().
*/
- private static Object js_eval(Context cx, VarScope scope, Object[] args) {
- TopLevel top = ScriptableObject.getTopLevelScope(scope);
+ private static Object js_eval(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ TopLevel top = ScriptableObject.getTopLevelScope(f.getDeclarationScope());
return ScriptRuntime.evalSpecial(cx, top, top.getGlobalThis(), args, "eval code", 1);
}
@@ -740,20 +711,4 @@ private static int oneUcs4ToUtf8Char(byte[] utf8Buffer, int ucs4Char) {
}
return utf8Length;
}
-
- /**
- * A simple subclass of {@link LambdaFunction} used to "tag" eval, so that we can recognize it
- * in {@link NativeGlobal#isEvalFunction}
- */
- private static class EvalLambdaFunction extends LambdaFunction {
- public EvalLambdaFunction(VarScope scope) {
- super(
- scope,
- "eval",
- 1,
- null,
- (callCx, callScope, thisObj, args) ->
- NativeGlobal.js_eval(callCx, callScope, args));
- }
- }
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeIterator.java b/rhino/src/main/java/org/mozilla/javascript/NativeIterator.java
index ccbd64a74b9..6c3404897b1 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeIterator.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeIterator.java
@@ -6,6 +6,8 @@
package org.mozilla.javascript;
+import static org.mozilla.javascript.ClassDescriptor.Destination.PROTO;
+
import java.util.Iterator;
/**
@@ -21,48 +23,44 @@ public final class NativeIterator extends ScriptableObject {
private Object objectIterator;
+ private static final String STOP_ITERATION = "StopIteration";
+ public static final String ITERATOR_PROPERTY_NAME = "__iterator__";
+
+ private static final ClassDescriptor DESCRIPTOR;
+
+ private static final ClassDescriptor STOP_ITER_DESCRIPTOR;
+
+ static {
+ DESCRIPTOR =
+ new ClassDescriptor.Builder(
+ CLASS_NAME,
+ 2,
+ NativeIterator::jsConstructorCall,
+ NativeIterator::jsConstructor)
+ .withMethod(PROTO, "next", 0, NativeIterator::js_next)
+ .withMethod(
+ PROTO, ITERATOR_PROPERTY_NAME, 1, NativeIterator::js_iteratorMethod)
+ .build();
+ STOP_ITER_DESCRIPTOR = new ClassDescriptor.Builder(STOP_ITERATION, 0, null, null).build();
+ }
+
static void init(Context cx, TopLevel scope, boolean sealed) {
- LambdaConstructor constructor =
- new LambdaConstructor(
- scope,
- CLASS_NAME,
- 2,
- NativeIterator::jsConstructorCall,
- NativeIterator::jsConstructor);
- constructor.setPrototypePropertyAttributes(PERMANENT | READONLY | DONTENUM);
-
- NativeIterator proto = new NativeIterator();
- constructor.setPrototypeScriptable(proto);
-
- constructor.definePrototypeMethod(scope, "next", 0, NativeIterator::js_next);
- constructor.definePrototypeMethod(
- scope, ITERATOR_PROPERTY_NAME, 1, NativeIterator::js_iteratorMethod);
-
- ScriptableObject.defineProperty(scope, CLASS_NAME, constructor, ScriptableObject.DONTENUM);
- if (sealed) {
- constructor.sealObject();
- ((ScriptableObject) constructor.getPrototypeProperty()).sealObject();
- }
+ NativeObject proto = new NativeObject();
+ var ctor = DESCRIPTOR.buildConstructor(cx, scope, proto, sealed);
// Generator
if (cx.getLanguageVersion() >= Context.VERSION_ES6) {
- ES6Generator.init(scope, sealed);
+ ES6Generator.init(cx, scope, sealed);
} else {
- NativeGenerator.init(scope, sealed);
+ NativeGenerator.init(cx, scope, sealed);
}
// StopIteration
- NativeObject obj = new StopIteration();
- obj.setPrototype(getObjectPrototype(scope));
- obj.setParentScope(scope);
- if (sealed) {
- obj.sealObject();
- }
- ScriptableObject.defineProperty(scope, STOP_ITERATION, obj, ScriptableObject.DONTENUM);
+ var stopCtor = STOP_ITER_DESCRIPTOR.populateGlobal(cx, scope, new StopIteration(), sealed);
// Use "associateValue" so that generators can continue to
// throw StopIteration even if the property of the global
// scope is replaced or deleted.
- scope.associateValue(ITERATOR_TAG, obj);
+ scope.associateValue(ITERATOR_TAG, stopCtor);
}
/** Only for constructing the prototype object. */
@@ -85,9 +83,6 @@ public static Object getStopIterationObject(VarScope scope) {
return ScriptableObject.getTopScopeValue(top, ITERATOR_TAG);
}
- private static final String STOP_ITERATION = "StopIteration";
- public static final String ITERATOR_PROPERTY_NAME = "__iterator__";
-
public static class StopIteration extends NativeObject {
private static final long serialVersionUID = 2485151085722377663L;
@@ -123,13 +118,13 @@ public String getClassName() {
}
private static Object jsConstructorCall(
- Context cx, VarScope scope, Object thisObj, Object[] args) {
- Scriptable target = requireIteratorTarget(cx, scope, args);
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ Scriptable target = requireIteratorTarget(cx, s, args);
boolean keyOnly = isKeyOnly(args);
Iterator> iterator = getJavaIterator(target);
if (iterator != null) {
- VarScope topScope = ScriptableObject.getTopLevelScope(scope);
+ VarScope topScope = ScriptableObject.getTopLevelScope(s);
return cx.getWrapFactory()
.wrap(
cx,
@@ -143,13 +138,14 @@ private static Object jsConstructorCall(
return jsIterator;
}
- return createNativeIterator(cx, scope, target, keyOnly);
+ return createNativeIterator(cx, s, target, keyOnly);
}
- private static Scriptable jsConstructor(Context cx, VarScope scope, Object[] args) {
- Scriptable target = requireIteratorTarget(cx, scope, args);
+ private static Scriptable jsConstructor(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
+ Scriptable target = requireIteratorTarget(cx, s, args);
boolean keyOnly = isKeyOnly(args);
- return createNativeIterator(cx, scope, target, keyOnly);
+ return createNativeIterator(cx, s, target, keyOnly);
}
private static Scriptable requireIteratorTarget(Context cx, VarScope scope, Object[] args) {
@@ -165,9 +161,10 @@ private static boolean isKeyOnly(Object[] args) {
return args.length > 1 && ScriptRuntime.toBoolean(args[1]);
}
- private static Object js_next(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object js_next(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
NativeIterator iterator = realThis(thisObj);
- return iterator.next(cx, scope);
+ return iterator.next(cx, s);
}
private static NativeIterator createNativeIterator(
@@ -188,7 +185,7 @@ private static NativeIterator createNativeIterator(
}
private static Object js_iteratorMethod(
- Context cx, VarScope scope, Object thisObj, Object[] args) {
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
return realThis(thisObj);
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJSON.java b/rhino/src/main/java/org/mozilla/javascript/NativeJSON.java
index 1c70459eb3e..965feb3df12 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeJSON.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeJSON.java
@@ -6,6 +6,9 @@
package org.mozilla.javascript;
+import static org.mozilla.javascript.ClassDescriptor.Builder.value;
+import static org.mozilla.javascript.ClassDescriptor.Destination.CTOR;
+
import java.lang.reflect.Array;
import java.math.BigInteger;
import java.util.ArrayDeque;
@@ -30,21 +33,21 @@ public final class NativeJSON extends ScriptableObject {
private static final int MAX_STRINGIFY_GAP_LENGTH = 10;
- static Object init(Context cx, VarScope scope, boolean sealed) {
- NativeJSON json = new NativeJSON();
- json.setPrototype(getObjectPrototype(scope));
- json.setParentScope(scope);
-
- json.defineBuiltinProperty(scope, "parse", 2, NativeJSON::parse);
- json.defineBuiltinProperty(scope, "stringify", 3, NativeJSON::stringify);
-
- json.defineProperty("toSource", "JSON", DONTENUM | READONLY | PERMANENT);
+ private static final ClassDescriptor DESCRIPTION;
+
+ static {
+ DESCRIPTION =
+ new ClassDescriptor.Builder(JSON_TAG)
+ .withMethod(CTOR, "parse", 2, NativeJSON::parse)
+ .withMethod(CTOR, "stringify", 3, NativeJSON::stringify)
+ .withProp(CTOR, "toSource", value("JSON"))
+ .withProp(
+ CTOR, SymbolKey.TO_STRING_TAG, value(JSON_TAG, DONTENUM | READONLY))
+ .build();
+ }
- json.defineProperty(SymbolKey.TO_STRING_TAG, JSON_TAG, DONTENUM | READONLY);
- if (sealed) {
- json.sealObject();
- }
- return json;
+ static Object init(Context cx, VarScope scope, boolean sealed) {
+ return DESCRIPTION.populateGlobal(cx, scope, new NativeJSON(), sealed);
}
private NativeJSON() {}
@@ -54,19 +57,21 @@ public String getClassName() {
return "JSON";
}
- private static Object parse(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object parse(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
String jtext = ScriptRuntime.toString(args, 0);
Object reviver = null;
if (args.length > 1) {
reviver = args[1];
}
if (reviver instanceof Callable) {
- return parse(cx, scope, jtext, (Callable) reviver);
+ return parse(cx, f.getDeclarationScope(), jtext, (Callable) reviver);
}
- return parse(cx, scope, jtext);
+ return parse(cx, f.getDeclarationScope(), jtext);
}
- private static Object stringify(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object stringify(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
Object value = Undefined.instance, replacer = null, space = null;
if (args.length > 0) {
@@ -78,7 +83,7 @@ private static Object stringify(Context cx, VarScope scope, Object thisObj, Obje
}
}
}
- return stringify(cx, scope, value, replacer, space);
+ return stringify(cx, s, value, replacer, space);
}
private static Object parse(Context cx, VarScope scope, String jtext) {
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaClass.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaClass.java
index 1b34ad1787d..080e1bd2f8a 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaClass.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaClass.java
@@ -116,7 +116,7 @@ public Object getDefaultValue(Class> hint) {
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
// If it looks like a "cast" of an object to this class type,
// walk the prototype chain to see if there's a wrapper of a
// object that's an instanceof this class.
@@ -180,6 +180,10 @@ public Scriptable construct(Context cx, VarScope scope, Object[] args) {
throw Context.reportRuntimeErrorById("msg.cant.instantiate", msg, classObject.getName());
}
+ public Scriptable construct(Context cx, Object nt, VarScope s, Object thisObj, Object args[]) {
+ return construct(cx, s, args);
+ }
+
static Scriptable constructSpecific(
Context cx, VarScope scope, Object[] args, ExecutableBox ctor) {
Object instance = constructInternal(args, ctor);
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaConstructor.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaConstructor.java
index 810221989cc..19aed2c415b 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaConstructor.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaConstructor.java
@@ -25,12 +25,13 @@ public class NativeJavaConstructor extends BaseFunction {
ExecutableBox ctor;
- public NativeJavaConstructor(ExecutableBox ctor) {
+ public NativeJavaConstructor(VarScope scope, ExecutableBox ctor) {
+ super(scope);
this.ctor = ctor;
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
return NativeJavaClass.constructSpecific(cx, scope, args, ctor);
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaMap.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaMap.java
index 7b4d86a449f..21a0cc50fe9 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaMap.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaMap.java
@@ -30,8 +30,8 @@ public class NativeJavaMap extends NativeJavaObject {
private final TypeInfo keyType;
private final TypeInfo valueType;
- static void init(TopLevel scope, boolean sealed) {
- NativeJavaMapIterator.init(scope, sealed);
+ static void init(Context cx, TopLevel scope, boolean sealed) {
+ NativeJavaMapIterator.init(cx, scope, sealed);
}
@SuppressWarnings("unchecked")
@@ -160,7 +160,7 @@ public int hashCode() {
}
private static Callable symbol_iterator =
- (Context cx, VarScope scope, Scriptable thisObj, Object[] args) -> {
+ (cx, scope, thisObj, args) -> {
if (!(thisObj instanceof NativeJavaMap)) {
throw ScriptRuntime.typeErrorById("msg.incompat.call", SymbolKey.ITERATOR);
}
@@ -168,11 +168,20 @@ public int hashCode() {
};
private static final class NativeJavaMapIterator extends ES6Iterator {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = -6354388021424261488L;
private static final String ITERATOR_TAG = "JavaMapIterator";
- static void init(TopLevel scope, boolean sealed) {
- ES6Iterator.init(scope, sealed, new NativeJavaMapIterator(), ITERATOR_TAG);
+ private static final ClassDescriptor DESCRIPTOR =
+ ES6Iterator.makeDescriptor(ITERATOR_TAG, "Java Map Iterator");
+
+ static void init(Context cx, VarScope scope, boolean sealed) {
+ ES6Iterator.initialize(
+ DESCRIPTOR,
+ cx,
+ (TopLevel) scope,
+ new NativeJavaMapIterator(),
+ sealed,
+ ITERATOR_TAG);
}
/** Only for constructing the prototype object. */
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java
index 8a71ae9cabf..e5724c30514 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java
@@ -37,19 +37,24 @@ public class NativeJavaMethod extends BaseFunction {
private final transient CopyOnWriteArrayList overloadCache =
new CopyOnWriteArrayList<>();
- NativeJavaMethod(ExecutableBox[] methods, String name) {
+ NativeJavaMethod(VarScope scope, ExecutableBox[] methods, String name) {
+ super(scope);
this.functionName = name;
this.methods = methods;
}
- NativeJavaMethod(ExecutableBox method, String name) {
+ NativeJavaMethod(VarScope scope, ExecutableBox method, String name) {
+ super(scope);
this.functionName = name;
this.methods = new ExecutableBox[] {method};
}
@Deprecated
public NativeJavaMethod(VarScope scope, Method method, String name) {
- this(new ExecutableBox(method, TypeInfoFactory.GLOBAL, method.getDeclaringClass()), name);
+ this(
+ scope,
+ new ExecutableBox(method, TypeInfoFactory.GLOBAL, method.getDeclaringClass()),
+ name);
}
@Override
@@ -129,7 +134,7 @@ public String toString() {
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
// Find a method that matches the types given.
if (methods.length == 0) {
throw new RuntimeException("No methods defined for call");
@@ -159,7 +164,7 @@ public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args
if (meth.isStatic()) {
javaObject = null; // don't need an object
} else {
- Scriptable o = thisObj;
+ Scriptable o = ScriptRuntime.toObject(getDeclarationScope(), thisObj);
Class> c = meth.getDeclaringClass();
for (; ; ) {
if (o == null) {
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java
index 20bccc80d91..a78ed395992 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java
@@ -35,8 +35,8 @@ public class NativeJavaObject implements Scriptable, SymbolScriptable, Wrapper,
private static final long serialVersionUID = -6948590651130498591L;
- static void init(TopLevel scope, boolean sealed) {
- JavaIterableIterator.init(scope, sealed);
+ static void init(Context cx, TopLevel scope, boolean sealed) {
+ JavaIterableIterator.init(cx, scope, sealed);
}
public NativeJavaObject() {}
@@ -904,7 +904,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
}
private static Callable symbol_iterator =
- (Context cx, VarScope scope, Scriptable thisObj, Object[] args) -> {
+ (cx, scope, thisObj, args) -> {
if (!(thisObj instanceof NativeJavaObject)) {
throw ScriptRuntime.typeErrorById("msg.incompat.call", SymbolKey.ITERATOR);
}
@@ -916,11 +916,15 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
};
private static final class JavaIterableIterator extends ES6Iterator {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = -2636492890037940863L;
private static final String ITERATOR_TAG = "JavaIterableIterator";
- static void init(TopLevel scope, boolean sealed) {
- ES6Iterator.init(scope, sealed, new JavaIterableIterator(), ITERATOR_TAG);
+ private static final ClassDescriptor DESCRIPTOR =
+ ES6Iterator.makeDescriptor(ITERATOR_TAG, "Java Iterable Iterator");
+
+ static void init(Context cx, TopLevel scope, boolean sealed) {
+ ES6Iterator.initialize(
+ DESCRIPTOR, cx, scope, new JavaIterableIterator(), sealed, ITERATOR_TAG);
}
/** Only for constructing the prototype object. */
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaTopPackage.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaTopPackage.java
index 517d2b79195..85cc53c576c 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaTopPackage.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaTopPackage.java
@@ -38,7 +38,7 @@ public class NativeJavaTopPackage extends NativeJavaPackage implements Function,
}
@Override
- public Object call(Context cx, VarScope scope, Scriptable thisObj, Object[] args) {
+ public Object call(Context cx, VarScope scope, Object thisObj, Object[] args) {
return construct(cx, scope, args);
}
@@ -63,6 +63,10 @@ public Scriptable construct(Context cx, VarScope scope, Object[] args) {
return pkg;
}
+ public Scriptable construct(Context cx, Object nt, VarScope s, Object thisObj, Object[] args) {
+ return construct(cx, s, args);
+ }
+
public static void init(Context cx, VarScope scope, boolean sealed) {
ClassLoader loader = cx.getApplicationClassLoader();
final NativeJavaTopPackage top = new NativeJavaTopPackage(loader);
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeMap.java b/rhino/src/main/java/org/mozilla/javascript/NativeMap.java
index 2c09bbd68df..c9ee3b7d76a 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeMap.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeMap.java
@@ -6,6 +6,11 @@
package org.mozilla.javascript;
+import static org.mozilla.javascript.ClassDescriptor.Builder.alias;
+import static org.mozilla.javascript.ClassDescriptor.Builder.value;
+import static org.mozilla.javascript.ClassDescriptor.Destination.CTOR;
+import static org.mozilla.javascript.ClassDescriptor.Destination.PROTO;
+
import java.util.List;
import java.util.Map;
@@ -14,60 +19,61 @@ public class NativeMap extends ScriptableObject {
private static final String CLASS_NAME = "Map";
static final String ITERATOR_TAG = "Map Iterator";
+ private static final ClassDescriptor DESCRIPTOR;
+ private static final ClassDescriptor ITER_DESCRIPTOR =
+ ES6Iterator.makeDescriptor(ITERATOR_TAG, ITERATOR_TAG);
+
+ static {
+ DESCRIPTOR =
+ new ClassDescriptor.Builder(
+ CLASS_NAME,
+ 0,
+ ClassDescriptor.typeError(),
+ NativeMap::js_constructor)
+ .withMethod(CTOR, "groupBy", 2, NativeMap::jsGroupBy)
+ .withMethod(PROTO, "set", 2, NativeMap::js_set)
+ .withMethod(PROTO, "delete", 1, NativeMap::js_delete)
+ .withMethod(PROTO, "get", 1, NativeMap::js_get)
+ .withMethod(PROTO, "has", 1, NativeMap::js_has)
+ .withMethod(PROTO, "clear", 0, NativeMap::js_clear)
+ .withMethod(PROTO, "keys", 0, NativeMap::js_keys)
+ .withMethod(PROTO, "values", 0, NativeMap::js_values)
+ .withMethod(PROTO, "forEach", 1, NativeMap::js_forEach)
+ .withMethod(PROTO, "entries", 0, NativeMap::js_entries)
+ .withProp(PROTO, SymbolKey.ITERATOR, alias("entries", DONTENUM))
+ .withProp(
+ PROTO,
+ "size",
+ (thisObj) -> realThis(thisObj, "size").js_getSize(),
+ null,
+ DONTENUM)
+ .withProp(
+ PROTO,
+ NativeSet.GETSIZE,
+ (thisObj) -> realThis(thisObj, "size").js_getSize(),
+ null,
+ DONTENUM | PERMANENT)
+ .withProp(
+ PROTO,
+ SymbolKey.TO_STRING_TAG,
+ value(CLASS_NAME, DONTENUM | READONLY))
+ .withProp(CTOR, SymbolKey.SPECIES, ScriptRuntimeES6::symbolSpecies)
+ .build();
+ }
+
private final Hashtable entries = new Hashtable();
private boolean instanceOfMap = false;
static Object init(Context cx, VarScope scope, boolean sealed) {
- LambdaConstructor constructor =
- new LambdaConstructor(
- scope,
- CLASS_NAME,
- 0,
- LambdaConstructor.CONSTRUCTOR_NEW,
- NativeMap::jsConstructor);
- constructor.setPrototypePropertyAttributes(DONTENUM | READONLY | PERMANENT);
-
- constructor.defineConstructorMethod(scope, "groupBy", 2, NativeMap::jsGroupBy);
-
- constructor.definePrototypeMethod(scope, "set", 2, NativeMap::js_set);
- constructor.definePrototypeMethod(scope, "delete", 1, NativeMap::js_delete);
- constructor.definePrototypeMethod(scope, "get", 1, NativeMap::js_get);
- constructor.definePrototypeMethod(scope, "has", 1, NativeMap::js_has);
- constructor.definePrototypeMethod(scope, "clear", 0, NativeMap::js_clear);
- constructor.definePrototypeMethod(scope, "keys", 0, NativeMap::js_keys);
- constructor.definePrototypeMethod(scope, "values", 0, NativeMap::js_values);
- constructor.definePrototypeMethod(scope, "forEach", 1, NativeMap::js_forEach);
-
- constructor.definePrototypeMethod(scope, "entries", 0, NativeMap::js_entries);
- constructor.definePrototypeAlias("entries", SymbolKey.ITERATOR, DONTENUM);
-
- // The spec requires very specific handling of the "size" prototype
- // property that's not like other things that we already do.
- ScriptableObject desc = (ScriptableObject) cx.newObject(scope);
- desc.put("enumerable", desc, Boolean.FALSE);
- desc.put("configurable", desc, Boolean.TRUE);
- LambdaFunction sizeFunc =
- new LambdaFunction(
- scope,
- "get size",
- 0,
- (Context lcx, VarScope lscope, Scriptable thisObj, Object[] args) ->
- realThis(thisObj, "size").js_getSize(),
- false);
- desc.put("get", desc, sizeFunc);
- constructor.definePrototypeProperty(cx, "size", desc);
- constructor.definePrototypeProperty(cx, NativeSet.GETSIZE, desc);
-
- constructor.definePrototypeProperty(
- SymbolKey.TO_STRING_TAG, CLASS_NAME, DONTENUM | READONLY);
-
- ScriptRuntimeES6.addSymbolSpecies(cx, scope, constructor);
- if (sealed) {
- constructor.sealObject();
- ((ScriptableObject) constructor.getPrototypeProperty()).sealObject();
- }
- return constructor;
+ ES6Iterator.initialize(
+ ITER_DESCRIPTOR,
+ cx,
+ (TopLevel) scope,
+ new NativeCollectionIterator(ITERATOR_TAG),
+ sealed,
+ ITERATOR_TAG);
+ return DESCRIPTOR.buildConstructor(cx, scope, new NativeObject(), sealed);
}
@Override
@@ -75,40 +81,44 @@ public String getClassName() {
return CLASS_NAME;
}
- private static Scriptable jsConstructor(Context cx, VarScope scope, Object[] args) {
+ private static Scriptable js_constructor(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
NativeMap nm = new NativeMap();
nm.instanceOfMap = true;
if (args.length > 0) {
- loadFromIterable(cx, scope, nm, key(args));
+ loadFromIterable(cx, s, nm, key(args));
}
+ ScriptRuntime.setBuiltinProtoAndParent(nm, f, nt, s, TopLevel.Builtins.Map);
return nm;
}
- private static Object jsGroupBy(Context cx, VarScope scope, Object thisObj, Object[] args) {
+ private static Object jsGroupBy(
+ Context cx, JSFunction f, Object nt, VarScope s, Object thisObj, Object[] args) {
Object items = args.length < 1 ? Undefined.instance : args[0];
Object callback = args.length < 2 ? Undefined.instance : args[1];
Map