diff --git a/examples/src/main/java/Shell.java b/examples/src/main/java/Shell.java index 2b227d097af..2c5bfda3167 100644 --- a/examples/src/main/java/Shell.java +++ b/examples/src/main/java/Shell.java @@ -15,6 +15,7 @@ import org.mozilla.javascript.JavaScriptException; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; import org.mozilla.javascript.WrappedException; /** @@ -49,12 +50,13 @@ public static void main(String args[]) { // Initialize the standard objects (Object, Function, etc.) // This must be done before scripts can be executed. Shell shell = new Shell(); - cx.initStandardObjects(shell); + TopLevel topLevel = new TopLevel(shell); + cx.initStandardObjects(topLevel); // Define some global functions particular to the shell. Note // that these functions are not part of ECMA. String[] names = {"print", "quit", "version", "load", "help"}; - shell.defineFunctionProperties(names, Shell.class, ScriptableObject.DONTENUM); + shell.defineFunctionProperties(topLevel, names, Shell.class, ScriptableObject.DONTENUM); args = processOptions(cx, args); @@ -202,7 +204,7 @@ public static double version(Context cx, Scriptable thisObj, Object[] args, Func * @param funObj the function object of the invoked JavaScript function */ public static void load(Context cx, Scriptable thisObj, Object[] args, Function funObj) { - Shell shell = (Shell) getTopLevelScope(thisObj); + Shell shell = (Shell) getTopLevelScope(thisObj).getGlobalThis(); for (int i = 0; i < args.length; i++) { shell.processSource(cx, Context.toString(args[i])); } diff --git a/it-android/src/main/java/org/mozilla/javascript/android/TestCase.java b/it-android/src/main/java/org/mozilla/javascript/android/TestCase.java index 2596e5bcd86..c055c5689d3 100644 --- a/it-android/src/main/java/org/mozilla/javascript/android/TestCase.java +++ b/it-android/src/main/java/org/mozilla/javascript/android/TestCase.java @@ -13,7 +13,7 @@ import org.mozilla.javascript.ContextFactory; import org.mozilla.javascript.ScriptRuntime; import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; /** * Utility class, that search for testcases in "assets/tests". @@ -25,7 +25,7 @@ public abstract class TestCase { protected final String name; - protected final Scriptable global; + protected final TopLevel global; private static final ContextFactory factory = new ContextFactory() { @@ -47,7 +47,7 @@ protected Context makeContext() { } }; - public TestCase(String name, Scriptable global) { + public TestCase(String name, TopLevel global) { this.name = name; this.global = global; } @@ -55,9 +55,7 @@ public TestCase(String name, Scriptable global) { public String run() { Context cx = factory.enterContext(); try { - Scriptable scope = cx.newObject(global); - scope.setPrototype(global); - scope.setParentScope(null); + Scriptable scope = TopLevel.createIsolate(global); return ScriptRuntime.toString(runTest(cx, scope)); } finally { Context.exit(); @@ -74,7 +72,7 @@ public String toString() { public static class AssetScript extends TestCase { protected final AssetManager assetManager; - public AssetScript(String name, Scriptable global, AssetManager assetManager) { + public AssetScript(String name, TopLevel global, AssetManager assetManager) { super(name, global); this.assetManager = assetManager; } @@ -94,7 +92,7 @@ public static List getTestCases(android.content.Context context) throw AssetManager assetManager = context.getAssets(); // define assert object - ScriptableObject global; + TopLevel global; Context cx = factory.enterContext(); try (InputStream in = assetManager.open("assert.js"); Reader rdr = new InputStreamReader(in, StandardCharsets.UTF_8)) { diff --git a/it-android/src/main/java/org/mozilla/javascript/android/TypeInfoFactoryTestCase.java b/it-android/src/main/java/org/mozilla/javascript/android/TypeInfoFactoryTestCase.java index 2d52707ba77..97f87bc59f0 100644 --- a/it-android/src/main/java/org/mozilla/javascript/android/TypeInfoFactoryTestCase.java +++ b/it-android/src/main/java/org/mozilla/javascript/android/TypeInfoFactoryTestCase.java @@ -2,6 +2,7 @@ import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.TopLevel; import org.mozilla.javascript.lc.type.TypeInfoFactory; import org.mozilla.javascript.lc.type.impl.factory.ClassValueCacheFactory; @@ -9,7 +10,7 @@ * @author ZZZank */ public class TypeInfoFactoryTestCase extends TestCase { - public TypeInfoFactoryTestCase(String name, Scriptable global) { + public TypeInfoFactoryTestCase(String name, TopLevel global) { super(name, global); } 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 a98536564c4..6e2715ddffa 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 @@ -47,7 +47,7 @@ void register(Context cx, ScriptableObject scope, ScriptContext sc) { private static Object print(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { try { - Builtins self = getSelf(thisObj); + Builtins self = getSelf(scope); for (Object arg : args) { self.stdout.write(ScriptRuntime.toString(arg)); } diff --git a/rhino-engine/src/main/java/org/mozilla/javascript/engine/RhinoScriptEngine.java b/rhino-engine/src/main/java/org/mozilla/javascript/engine/RhinoScriptEngine.java index 02c5399220c..5c09b35d3cb 100644 --- a/rhino-engine/src/main/java/org/mozilla/javascript/engine/RhinoScriptEngine.java +++ b/rhino-engine/src/main/java/org/mozilla/javascript/engine/RhinoScriptEngine.java @@ -25,6 +25,7 @@ import org.mozilla.javascript.Script; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; /** * This is the implementation of the standard ScriptEngine interface for Rhino. @@ -76,7 +77,7 @@ public class RhinoScriptEngine extends AbstractScriptEngine implements Compilabl private final RhinoScriptEngineFactory factory; private final Builtins builtins; - private ScriptableObject topLevelScope = null; + private TopLevel topLevelScope = null; RhinoScriptEngine(RhinoScriptEngineFactory factory) { this.factory = factory; @@ -94,18 +95,17 @@ private Scriptable initScope(Context cx, ScriptContext sc) throws ScriptExceptio builtins.register(cx, topLevelScope, sc); } - Scriptable engineScope = new BindingsObject(sc.getBindings(ScriptContext.ENGINE_SCOPE)); - engineScope.setParentScope(null); - engineScope.setPrototype(topLevelScope); - if (sc.getBindings(ScriptContext.GLOBAL_SCOPE) != null) { - Scriptable globalScope = new BindingsObject(sc.getBindings(ScriptContext.GLOBAL_SCOPE)); - globalScope.setParentScope(null); - globalScope.setPrototype(topLevelScope); - engineScope.setPrototype(globalScope); + var globalScope = + TopLevel.createIsolate( + topLevelScope, + new BindingsObject(sc.getBindings(ScriptContext.GLOBAL_SCOPE))); + return TopLevel.createIsolate( + globalScope, new BindingsObject(sc.getBindings(ScriptContext.ENGINE_SCOPE))); + } else { + return TopLevel.createIsolate( + topLevelScope, new BindingsObject(sc.getBindings(ScriptContext.ENGINE_SCOPE))); } - - return engineScope; } @Override diff --git a/rhino-tools/src/main/java/org/mozilla/javascript/tools/debugger/Main.java b/rhino-tools/src/main/java/org/mozilla/javascript/tools/debugger/Main.java index 598cf659b31..867aaf64a83 100644 --- a/rhino-tools/src/main/java/org/mozilla/javascript/tools/debugger/Main.java +++ b/rhino-tools/src/main/java/org/mozilla/javascript/tools/debugger/Main.java @@ -16,6 +16,7 @@ import org.mozilla.javascript.ContextFactory; import org.mozilla.javascript.Kit; import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.commonjs.module.ModuleScope; import org.mozilla.javascript.tools.shell.Global; @@ -180,7 +181,7 @@ public static void main(String[] args) { global.installRequire(cx, List.of(), false); URI uri = new File(System.getProperty("user.dir")).toURI(); - ModuleScope scope = new ModuleScope(global, uri, null); + ScriptableObject scope = ModuleScope.createModuleScope(global, uri, null); main.setScope(scope); 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 275eb0bb0c2..9998d1a9b2b 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 @@ -97,9 +97,12 @@ public class Global extends ImporterTopLevel { private static final String[] prompts = {"js> ", " > "}; private HashMap doctestCanonicalizations; - public Global() {} + public Global() { + super(true); + } public Global(Context cx) { + super(true); init(cx); } @@ -128,7 +131,7 @@ public void init(Context cx) { // that these functions are not part of ECMA. initStandardObjects(cx, sealedStdLib); NativeConsole.init(this, sealedStdLib, new ShellConsolePrinter()); - defineFunctionProperties(TOP_COMMANDS, Global.class, ScriptableObject.DONTENUM); + defineFunctionProperties(this, TOP_COMMANDS, Global.class, ScriptableObject.DONTENUM); // Set up "environment" in the global scope to provide access to the // System environment variables. @@ -261,7 +264,7 @@ public static void load(Context cx, Scriptable thisObj, Object[] args, Function for (Object arg : args) { String file = Context.toString(arg); try { - Main.processFile(cx, thisObj, file); + Main.processFile(cx, funObj.getDeclarationScope(), file); } catch (IOException ioex) { String msg = ToolErrorReporter.getMessage( @@ -295,7 +298,8 @@ public static void defineClass(Context cx, Scriptable thisObj, Object[] args, Fu if (!Scriptable.class.isAssignableFrom(clazz)) { throw reportRuntimeError("msg.must.implement.Scriptable"); } - ScriptableObject.defineClass(thisObj, (Class) clazz); + ScriptableObject.defineClass( + funObj.getDeclarationScope(), (Class) clazz); } /** @@ -348,7 +352,7 @@ public static void serialize(Context cx, Scriptable thisObj, Object[] args, Func Object obj = args[0]; String filename = Context.toString(args[1]); FileOutputStream fos = new FileOutputStream(filename); - Scriptable scope = ScriptableObject.getTopLevelScope(thisObj); + Scriptable scope = ScriptableObject.getTopLevelScope(funObj.getDeclarationScope()); try (ScriptableOutputStream out = new ScriptableOutputStream(fos, scope)) { out.writeObject(obj); } @@ -361,7 +365,7 @@ public static Object deserialize(Context cx, Scriptable thisObj, Object[] args, } String filename = Context.toString(args[0]); try (FileInputStream fis = new FileInputStream(filename)) { - Scriptable scope = ScriptableObject.getTopLevelScope(thisObj); + Scriptable scope = ScriptableObject.getTopLevelScope(funObj.getDeclarationScope()); try (ObjectInputStream in = new ScriptableInputStream(fis, scope)) { Object deserialized = in.readObject(); return Context.toObject(deserialized, scope); diff --git a/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Main.java b/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Main.java index dc5f93b3156..58c6e805f77 100644 --- a/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Main.java +++ b/rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Main.java @@ -251,7 +251,7 @@ static Scriptable getScope(String path) { uri = new File(path).toURI(); } } - return new ModuleScope(global, uri, null); + return ModuleScope.createModuleScope(global, uri, null); } return global; } diff --git a/rhino/src/main/java/org/mozilla/javascript/AccessorSlot.java b/rhino/src/main/java/org/mozilla/javascript/AccessorSlot.java index fe250a6923c..364324d4366 100644 --- a/rhino/src/main/java/org/mozilla/javascript/AccessorSlot.java +++ b/rhino/src/main/java/org/mozilla/javascript/AccessorSlot.java @@ -169,7 +169,7 @@ public Object getValue(Scriptable start) { @Override public Function asGetterFunction(String name, Scriptable scope) { - return member.asGetterFunction(name, scope); + return member.asGetterFunction(name); } @Override @@ -246,7 +246,7 @@ public boolean setValue(Object value, Scriptable owner, Scriptable start) { @Override public Function asSetterFunction(String name, Scriptable scope) { - return member.asSetterFunction(name, scope); + return member.asSetterFunction(name); } @Override diff --git a/rhino/src/main/java/org/mozilla/javascript/ArrayLikeAbstractOperations.java b/rhino/src/main/java/org/mozilla/javascript/ArrayLikeAbstractOperations.java index b311e5aa893..e9a372b4238 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ArrayLikeAbstractOperations.java +++ b/rhino/src/main/java/org/mozilla/javascript/ArrayLikeAbstractOperations.java @@ -137,10 +137,10 @@ public static Object coercibleIterativeMethod( Object callbackArg = args.length > 0 ? args[0] : Undefined.instance; Function f = getCallbackArg(cx, callbackArg); - Scriptable parent = ScriptableObject.getTopLevelScope(f); + TopLevel parent = ScriptableObject.getTopLevelScope(f); Scriptable thisArg; if (args.length < 2 || args[1] == null || args[1] == Undefined.instance) { - thisArg = parent; + thisArg = parent.getGlobalThis(); } else { thisArg = ScriptRuntime.toObject(cx, scope, args[1]); } @@ -339,7 +339,8 @@ public static Object reduceMethodWithLength( throw ScriptRuntime.notFunctionError(callbackArg); } Function f = (Function) callbackArg; - Scriptable parent = ScriptableObject.getTopLevelScope(f); + TopLevel parent = ScriptableObject.getTopLevelScope(f); + Scriptable globalThis = parent.getGlobalThis(); // hack to serve both reduce and reduceRight with the same loop boolean movingLeft = operation == ReduceOperation.REDUCE; Object value = args.length > 1 ? args[1] : NOT_FOUND; @@ -354,7 +355,7 @@ public static Object reduceMethodWithLength( value = elem; } else { Object[] innerArgs = {value, elem, index, o}; - value = f.call(cx, parent, parent, innerArgs); + value = f.call(cx, parent, globalThis, innerArgs); } } if (value == NOT_FOUND) { diff --git a/rhino/src/main/java/org/mozilla/javascript/BoundFunction.java b/rhino/src/main/java/org/mozilla/javascript/BoundFunction.java index 2eaaf816801..f41c09ab6d5 100644 --- a/rhino/src/main/java/org/mozilla/javascript/BoundFunction.java +++ b/rhino/src/main/java/org/mozilla/javascript/BoundFunction.java @@ -109,11 +109,12 @@ Object[] getBoundArgs() { Scriptable getCallThis(Context cx, Scriptable scope) { Scriptable callThis = boundThis; - if (callThis == null && ScriptRuntime.hasTopCall(cx)) { - callThis = ScriptRuntime.getTopCallScope(cx); - } if (callThis == null) { - callThis = getTopLevelScope(scope); + if (ScriptRuntime.hasTopCall(cx)) { + callThis = ScriptRuntime.getTopCallScope(cx).getGlobalThis(); + } else { + callThis = getTopLevelScope(scope).getGlobalThis(); + } } return callThis; } diff --git a/rhino/src/main/java/org/mozilla/javascript/ClassCache.java b/rhino/src/main/java/org/mozilla/javascript/ClassCache.java index 484157d4262..48a58c90c99 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ClassCache.java +++ b/rhino/src/main/java/org/mozilla/javascript/ClassCache.java @@ -77,12 +77,6 @@ public static ClassCache get(Scriptable scope) { if (cache == null) { // we expect this to not happen frequently, so computing top scope twice is acceptable var topScope = ScriptableObject.getTopLevelScope(scope); - if (!(topScope instanceof ScriptableObject)) { - // Note: it's originally a RuntimeException, the super class of - // IllegalArgumentException, so this will not break error catching - throw new IllegalArgumentException( - "top scope have no associated ClassCache and cannot have ClassCache associated due to not being a ScriptableObject"); - } cache = new ClassCache(); cache.associate(((ScriptableObject) topScope)); } diff --git a/rhino/src/main/java/org/mozilla/javascript/ClassDescriptor.java b/rhino/src/main/java/org/mozilla/javascript/ClassDescriptor.java index 17e6bef4413..c4a47ec0b81 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ClassDescriptor.java +++ b/rhino/src/main/java/org/mozilla/javascript/ClassDescriptor.java @@ -107,9 +107,9 @@ private static class LambdaGetSetPropDesc extends PropDesc { @Override void makeProp(Context cx, Scriptable scope, ScriptableObject obj) { if (name instanceof String) { - obj.defineProperty(cx, (String) name, getter, setter, attributes); + obj.defineProperty(cx, scope, (String) name, getter, setter, attributes); } else { - obj.defineProperty(cx, (SymbolKey) name, getter, setter, attributes); + obj.defineProperty(cx, scope, (SymbolKey) name, getter, setter, attributes); } } } diff --git a/rhino/src/main/java/org/mozilla/javascript/Context.java b/rhino/src/main/java/org/mozilla/javascript/Context.java index a27f0d02113..0f78f1401f9 100644 --- a/rhino/src/main/java/org/mozilla/javascript/Context.java +++ b/rhino/src/main/java/org/mozilla/javascript/Context.java @@ -1052,7 +1052,7 @@ public static EvaluatorException reportRuntimeError(String message) { * * @return the initialized scope */ - public final ScriptableObject initStandardObjects() { + public final TopLevel initStandardObjects() { return initStandardObjects(null, false); } @@ -1095,7 +1095,7 @@ public final ScriptableObject initSafeStandardObjects() { * @return the initialized scope. The method returns the value of the scope argument if it is * not null or newly allocated scope object which is an instance {@link ScriptableObject}. */ - public final Scriptable initStandardObjects(ScriptableObject scope) { + public final TopLevel initStandardObjects(TopLevel scope) { return initStandardObjects(scope, false); } @@ -1121,7 +1121,7 @@ public final Scriptable initStandardObjects(ScriptableObject scope) { * @return the initialized scope. The method returns the value of the scope argument if it is * not null or newly allocated scope object which is an instance {@link ScriptableObject}. */ - public final Scriptable initSafeStandardObjects(ScriptableObject scope) { + public final TopLevel initSafeStandardObjects(TopLevel scope) { return initSafeStandardObjects(scope, false); } @@ -1148,7 +1148,7 @@ public final Scriptable initSafeStandardObjects(ScriptableObject scope) { * not null or newly allocated scope object. * @since 1.4R3 */ - public ScriptableObject initStandardObjects(ScriptableObject scope, boolean sealed) { + public TopLevel initStandardObjects(TopLevel scope, boolean sealed) { return ScriptRuntime.initStandardObjects(this, scope, sealed); } @@ -1181,7 +1181,7 @@ public ScriptableObject initStandardObjects(ScriptableObject scope, boolean seal * not null or newly allocated scope object. * @since 1.7.6 */ - public ScriptableObject initSafeStandardObjects(ScriptableObject scope, boolean sealed) { + public TopLevel initSafeStandardObjects(TopLevel scope, boolean sealed) { return ScriptRuntime.initSafeStandardObjects(this, scope, sealed); } @@ -1210,7 +1210,8 @@ public final Object evaluateString( Scriptable scope, String source, String sourceName, int lineno, Object securityDomain) { Script script = compileString(source, sourceName, lineno, securityDomain); if (script != null) { - return script.exec(this, scope, scope); + return script.exec( + this, scope, ScriptableObject.getTopLevelScope(scope).getGlobalThis()); } return null; } @@ -2790,7 +2791,7 @@ public static boolean isCurrentContextStrict() { private boolean sealed; private Object sealKey; - Scriptable topCallScope; + TopLevel topCallScope; boolean isContinuationsTopCall; NativeCall currentActivationCall; private boolean isStrict; diff --git a/rhino/src/main/java/org/mozilla/javascript/ES6Generator.java b/rhino/src/main/java/org/mozilla/javascript/ES6Generator.java index 7bdb4ae6491..8b97fbe1213 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ES6Generator.java +++ b/rhino/src/main/java/org/mozilla/javascript/ES6Generator.java @@ -18,7 +18,7 @@ public final class ES6Generator extends ScriptableObject { private State state = State.SUSPENDED_START; private Object delegee; - static ES6Generator init(ScriptableObject scope, boolean sealed) { + static ES6Generator init(TopLevel scope, boolean sealed) { ES6Generator prototype = new ES6Generator(); if (scope != null) { diff --git a/rhino/src/main/java/org/mozilla/javascript/ES6Iterator.java b/rhino/src/main/java/org/mozilla/javascript/ES6Iterator.java index c871ea53510..52e426a63f0 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ES6Iterator.java +++ b/rhino/src/main/java/org/mozilla/javascript/ES6Iterator.java @@ -17,7 +17,7 @@ public abstract class ES6Iterator extends ScriptableObject { public static final String RETURN_METHOD = "return"; protected static void init( - ScriptableObject scope, boolean sealed, ScriptableObject prototype, String tag) { + TopLevel scope, boolean sealed, ScriptableObject prototype, String tag) { if (scope != null) { prototype.setParentScope(scope); prototype.setPrototype(getObjectPrototype(scope)); diff --git a/rhino/src/main/java/org/mozilla/javascript/FunctionObject.java b/rhino/src/main/java/org/mozilla/javascript/FunctionObject.java index 47bf82ea1ea..83e41c501ea 100644 --- a/rhino/src/main/java/org/mozilla/javascript/FunctionObject.java +++ b/rhino/src/main/java/org/mozilla/javascript/FunctionObject.java @@ -14,7 +14,6 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import org.mozilla.javascript.commonjs.module.ModuleScope; public class FunctionObject extends BaseFunction { private static final long serialVersionUID = -5332312783643935019L; @@ -79,10 +78,10 @@ public class FunctionObject extends BaseFunction { */ public FunctionObject(String name, Member methodOrConstructor, Scriptable scope) { if (methodOrConstructor instanceof Constructor) { - member = new MemberBox((Constructor) methodOrConstructor); + member = new MemberBox(scope, (Constructor) methodOrConstructor); isStatic = true; // well, doesn't take a 'this' } else { - member = new MemberBox((Method) methodOrConstructor); + member = new MemberBox(scope, (Method) methodOrConstructor); isStatic = member.isStatic(); } String methodName = member.getName(); @@ -387,22 +386,8 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] ar thisObj = ((Delegator) thisObj).getDelegee(); } if (!clazz.isInstance(thisObj)) { - boolean compatible = false; - if (thisObj == scope || thisObj instanceof ModuleScope) { - Scriptable parentScope = getDeclarationScope(); - if (scope != parentScope) { - // Call with dynamic scope for standalone function, - // use parentScope as thisObj - compatible = clazz.isInstance(parentScope); - if (compatible) { - thisObj = parentScope; - } - } - } - if (!compatible) { - // Couldn't find an object to call this on. - throw ScriptRuntime.typeErrorById("msg.incompat.call", functionName); - } + // Couldn't find an object to call this on. + throw ScriptRuntime.typeErrorById("msg.incompat.call", functionName); } } diff --git a/rhino/src/main/java/org/mozilla/javascript/ImporterTopLevel.java b/rhino/src/main/java/org/mozilla/javascript/ImporterTopLevel.java index 55b3726e60d..10684763269 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ImporterTopLevel.java +++ b/rhino/src/main/java/org/mozilla/javascript/ImporterTopLevel.java @@ -47,16 +47,80 @@ public class ImporterTopLevel extends TopLevel { private static final long serialVersionUID = -9095380847465315412L; - public ImporterTopLevel() {} + public static class ImporterGlobalThis extends TopLevel.GlobalThis { + + private ImporterGlobalThis(boolean isTopScope) { + topScopeFlag = isTopScope; + } + + @Override + public String getClassName() { + return topScopeFlag ? "global" : "JavaImporter"; + } + + @Override + public boolean has(String name, Scriptable start) { + return super.has(name, start) || getPackageProperty(name, start) != NOT_FOUND; + } + + @Override + public Object get(String name, Scriptable start) { + Object result = super.get(name, start); + if (result != NOT_FOUND) return result; + result = getPackageProperty(name, start); + return result; + } + + private Object getPackageProperty(String name, Scriptable start) { + Object result = NOT_FOUND; + Scriptable scope = start; + Object[] elements = getNativeJavaPackages(scope); + if (elements == null) { + return result; + } + for (Object element : elements) { + NativeJavaPackage p = (NativeJavaPackage) element; + Object v = p.getPkgProperty(name, start, false); + if (v != null && !(v instanceof NativeJavaPackage)) { + if (result == NOT_FOUND) { + result = v; + } else { + throw Context.reportRuntimeErrorById( + "msg.ambig.import", result.toString(), v.toString()); + } + } + } + + return result; + } + + private final boolean topScopeFlag; + } + + public ImporterTopLevel() { + this(true); + } + + public ImporterTopLevel(boolean topLevel) { + super(new ImporterGlobalThis(topLevel)); + topScopeFlag = topLevel; + } public ImporterTopLevel(Context cx) { this(cx, false); } public ImporterTopLevel(Context cx, boolean sealed) { + super(new ImporterGlobalThis(true)); + topScopeFlag = true; initStandardObjects(cx, sealed); } + private ImporterTopLevel(ScriptableObject scope) { + super(scope); + topScopeFlag = true; + } + @Override public String getClassName() { return topScopeFlag ? "global" : "JavaImporter"; @@ -91,7 +155,6 @@ public void initStandardObjects(Context cx, boolean sealed) { // Assume that Context.initStandardObjects initialize JavaImporter // property lazily so the above init call is not yet called cx.initStandardObjects(this, sealed); - topScopeFlag = true; // If seal is true then exportAsJSClass(cx, seal) would seal // this obj. Since this is scope as well, it would not allow // to add variables. @@ -104,45 +167,6 @@ public void initStandardObjects(Context cx, boolean sealed) { delete("constructor"); } - @Override - public boolean has(String name, Scriptable start) { - return super.has(name, start) || getPackageProperty(name, start) != NOT_FOUND; - } - - @Override - public Object get(String name, Scriptable start) { - Object result = super.get(name, start); - if (result != NOT_FOUND) return result; - result = getPackageProperty(name, start); - return result; - } - - private Object getPackageProperty(String name, Scriptable start) { - Object result = NOT_FOUND; - Scriptable scope = start; - if (topScopeFlag) { - scope = ScriptableObject.getTopLevelScope(scope); - } - Object[] elements = getNativeJavaPackages(scope); - if (elements == null) { - return result; - } - for (Object element : elements) { - NativeJavaPackage p = (NativeJavaPackage) element; - Object v = p.getPkgProperty(name, start, false); - if (v != null && !(v instanceof NativeJavaPackage)) { - if (result == NOT_FOUND) { - result = v; - } else { - throw Context.reportRuntimeErrorById( - "msg.ambig.import", result.toString(), v.toString()); - } - } - } - - return result; - } - private static Object[] getNativeJavaPackages(Scriptable scope) { // retrivee the native java packages stored in top scope. synchronized (scope) { @@ -167,8 +191,11 @@ public void importPackage(Context cx, Scriptable thisObj, Object[] args, Functio js_importPackage(cx, funObj.getDeclarationScope(), this, args); } + // The result from the constructor needs to be an object rather + // than a scope, and then we need to work out to how make the + // import work on the correct thing. private static Scriptable js_construct(Context cx, Scriptable scope, Object[] args) { - ImporterTopLevel result = new ImporterTopLevel(); + ImporterGlobalThis result = new ImporterGlobalThis(false); for (int i = 0; i != args.length; ++i) { Object arg = args[i]; if (arg instanceof NativeJavaClass) { @@ -208,6 +235,7 @@ private static Object js_importPackage( if (!(arg instanceof NativeJavaPackage)) { throw Context.reportRuntimeErrorById("msg.not.pkg", Context.toString(arg)); } + importPackage((ScriptableObject) thisObj, (NativeJavaPackage) arg); } return Undefined.instance; @@ -247,6 +275,24 @@ private static void importClass(Scriptable scope, NativeJavaClass cl) { scope.put(n, scope, cl); } + @Override + public ImporterGlobalThis getGlobalThis() { + return (ImporterGlobalThis) super.getGlobalThis(); + } + + public static TopLevel createIsolate(Context cx, TopLevel parent) { + var newGlobal = new ImporterGlobalThis(true); + newGlobal.setPrototype(parent.getGlobalThis()); + newGlobal.setParentScope(null); + newGlobal.put("globalThis", newGlobal, newGlobal); + newGlobal.setAttributes("globalThis", ScriptableObject.DONTENUM); + var isolate = new ImporterTopLevel(newGlobal); + isolate.copyAssociatedValue(parent); + isolate.copyBuiltins(parent, false); + ImporterTopLevel.init(cx, isolate, false, true); + return isolate; + } + private static final String AKEY = "importedPackages"; - private boolean topScopeFlag; + private final boolean topScopeFlag; } diff --git a/rhino/src/main/java/org/mozilla/javascript/JSScript.java b/rhino/src/main/java/org/mozilla/javascript/JSScript.java index a026283bf56..be43cd8688c 100644 --- a/rhino/src/main/java/org/mozilla/javascript/JSScript.java +++ b/rhino/src/main/java/org/mozilla/javascript/JSScript.java @@ -31,6 +31,9 @@ JSCode getCode() { @Override public Object exec(Context cx, Scriptable scope, Scriptable thisObj) { Object ret; + if (thisObj instanceof TopLevel) { + thisObj = ((TopLevel) thisObj).getGlobalThis(); + } if (!ScriptRuntime.hasTopCall(cx)) { // It will go through "call" path. but they are equivalent ret = ScriptRuntime.doTopCall(this, cx, scope, thisObj, descriptor.isStrict()); diff --git a/rhino/src/main/java/org/mozilla/javascript/LambdaConstructor.java b/rhino/src/main/java/org/mozilla/javascript/LambdaConstructor.java index 42cd2a20b81..47fe08099fe 100644 --- a/rhino/src/main/java/org/mozilla/javascript/LambdaConstructor.java +++ b/rhino/src/main/java/org/mozilla/javascript/LambdaConstructor.java @@ -302,7 +302,12 @@ public void definePrototypeProperty(Context cx, Symbol key, ScriptableObject des public void definePrototypeProperty( Context cx, String name, ScriptableObject.LambdaGetterFunction getter, int attributes) { ScriptableObject proto = getPrototypeScriptable(); - proto.defineProperty(cx, name, getter, null, attributes); + proto.defineProperty(cx, getDeclarationScope(), name, getter, null, attributes); + } + + public void defineProperty( + Context cx, String name, LambdaGetterFunction getter, int attributes) { + defineProperty(cx, name, getter, null, attributes); } public void definePrototypeProperty( @@ -313,7 +318,7 @@ public void definePrototypeProperty( public void definePrototypeProperty( Context cx, Symbol key, ScriptableObject.LambdaGetterFunction getter, int attributes) { ScriptableObject proto = getPrototypeScriptable(); - proto.defineProperty(cx, key, getter, null, attributes); + proto.defineProperty(cx, getDeclarationScope(), key, getter, null, attributes); } /** @@ -328,7 +333,7 @@ public void definePrototypeProperty( ScriptableObject.LambdaSetterFunction setter, int attributes) { ScriptableObject proto = getPrototypeScriptable(); - proto.defineProperty(cx, name, getter, setter, attributes); + proto.defineProperty(cx, getDeclarationScope(), name, getter, setter, attributes); } public void definePrototypeProperty( @@ -346,7 +351,7 @@ public void definePrototypeProperty( ScriptableObject.LambdaSetterFunction setter, int attributes) { ScriptableObject proto = getPrototypeScriptable(); - proto.defineProperty(cx, key, getter, setter, attributes); + proto.defineProperty(cx, getDeclarationScope(), key, getter, setter, attributes); } public void definePrototypeProperty( @@ -371,6 +376,15 @@ public void definePrototypeAlias(String name, String alias, int attributes) { proto.defineProperty(alias, val, attributes); } + public void defineProperty( + Context cx, + String name, + LambdaGetterFunction getter, + LambdaSetterFunction setter, + int attributes) { + defineProperty(cx, getDeclarationScope(), name, getter, setter, attributes); + } + /** * Define a function property directly on the constructor that is implemented under the covers * by a LambdaFunction. diff --git a/rhino/src/main/java/org/mozilla/javascript/MemberBox.java b/rhino/src/main/java/org/mozilla/javascript/MemberBox.java index b1b5453c596..b583ad9300f 100644 --- a/rhino/src/main/java/org/mozilla/javascript/MemberBox.java +++ b/rhino/src/main/java/org/mozilla/javascript/MemberBox.java @@ -36,14 +36,18 @@ final class MemberBox implements Serializable { transient Function asSetterFunction; transient Object delegateTo; + private final Scriptable scope; + private static final NullabilityDetector nullDetector = ScriptRuntime.loadOneServiceImplementation(NullabilityDetector.class); - MemberBox(Method method) { + MemberBox(Scriptable scope, Method method) { + this.scope = scope; init(method); } - MemberBox(Constructor constructor) { + MemberBox(Scriptable scope, Constructor constructor) { + this.scope = scope; init(constructor); } @@ -156,7 +160,7 @@ boolean isSameSetterFunction(Object function) { } /** Function returned by calls to __lookupGetter__ */ - Function asGetterFunction(final String name, final Scriptable scope) { + Function asGetterFunction(final String name) { // Note: scope is the scriptable this function is related to; therefore this function // is constant for this member box. // Because of this we can cache the function in the attribute @@ -188,7 +192,7 @@ public String getFunctionName() { } /** Function returned by calls to __lookupSetter__ */ - Function asSetterFunction(final String name, final Scriptable scope) { + Function asSetterFunction(final String name) { // Note: scope is the scriptable this function is related to; therefore this function // is constant for this member box. // Because of this we can cache the function in the attribute diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeArrayIterator.java b/rhino/src/main/java/org/mozilla/javascript/NativeArrayIterator.java index 68f5ec9ba0f..adcc0fe1cf9 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeArrayIterator.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeArrayIterator.java @@ -20,7 +20,7 @@ public enum ARRAY_ITERATOR_TYPE { private ARRAY_ITERATOR_TYPE type; - static void init(ScriptableObject scope, boolean sealed) { + static void init(TopLevel scope, boolean sealed) { ES6Iterator.init(scope, sealed, new NativeArrayIterator(), ITERATOR_TAG); } diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeCollectionIterator.java b/rhino/src/main/java/org/mozilla/javascript/NativeCollectionIterator.java index a4f6b6f66df..f617441314f 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeCollectionIterator.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeCollectionIterator.java @@ -18,7 +18,7 @@ enum Type { BOTH } - static void init(ScriptableObject scope, String tag, boolean sealed) { + static void init(TopLevel scope, String tag, boolean sealed) { ES6Iterator.init(scope, sealed, new NativeCollectionIterator(tag), tag); } diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeGenerator.java b/rhino/src/main/java/org/mozilla/javascript/NativeGenerator.java index 586637832e4..fcc7610735c 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeGenerator.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeGenerator.java @@ -17,7 +17,7 @@ public final class NativeGenerator extends IdScriptableObject { private static final Object GENERATOR_TAG = "Generator"; - static NativeGenerator init(ScriptableObject scope, boolean sealed) { + 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. diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeGlobal.java b/rhino/src/main/java/org/mozilla/javascript/NativeGlobal.java index 06d75757a45..8994c286c33 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeGlobal.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeGlobal.java @@ -23,7 +23,7 @@ public class NativeGlobal implements Serializable { static final long serialVersionUID = 6080442165748707530L; - public static void init(Context cx, Scriptable scope, boolean sealed) { + 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); @@ -46,7 +46,13 @@ public static void init(Context cx, Scriptable scope, boolean sealed) { scope, "Infinity", Double.POSITIVE_INFINITY, READONLY | DONTENUM | PERMANENT); ScriptableObject.defineProperty( scope, "undefined", Undefined.instance, READONLY | DONTENUM | PERMANENT); - ScriptableObject.defineProperty(scope, "globalThis", scope, DONTENUM); + var globalThis = scope.getGlobalThis(); + + 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, diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeIterator.java b/rhino/src/main/java/org/mozilla/javascript/NativeIterator.java index ae70d9d5faf..c507c9dfb33 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeIterator.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeIterator.java @@ -21,7 +21,7 @@ public final class NativeIterator extends ScriptableObject { private Object objectIterator; - static void init(Context cx, ScriptableObject scope, boolean sealed) { + static void init(Context cx, TopLevel scope, boolean sealed) { LambdaConstructor constructor = new LambdaConstructor( scope, diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaMap.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaMap.java index f01c2628725..6522544fd55 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaMap.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaMap.java @@ -30,7 +30,7 @@ public class NativeJavaMap extends NativeJavaObject { private final TypeInfo keyType; private final TypeInfo valueType; - static void init(ScriptableObject scope, boolean sealed) { + static void init(TopLevel scope, boolean sealed) { NativeJavaMapIterator.init(scope, sealed); } @@ -171,7 +171,7 @@ private static final class NativeJavaMapIterator extends ES6Iterator { private static final long serialVersionUID = 1L; private static final String ITERATOR_TAG = "JavaMapIterator"; - static void init(ScriptableObject scope, boolean sealed) { + static void init(TopLevel scope, boolean sealed) { ES6Iterator.init(scope, sealed, new NativeJavaMapIterator(), ITERATOR_TAG); } diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java index 62ef1624579..770074f5ee4 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaMethod.java @@ -53,7 +53,7 @@ public class NativeJavaMethod extends BaseFunction { } @Deprecated - public NativeJavaMethod(Method method, String name) { + public NativeJavaMethod(Scriptable scope, Method method, String name) { this(new ExecutableBox(method, TypeInfoFactory.GLOBAL, method.getDeclaringClass()), name); } diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java index e675bf10b6e..f0dc4d9ce49 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java @@ -35,7 +35,7 @@ public class NativeJavaObject implements Scriptable, SymbolScriptable, Wrapper, private static final long serialVersionUID = -6948590651130498591L; - static void init(ScriptableObject scope, boolean sealed) { + static void init(TopLevel scope, boolean sealed) { JavaIterableIterator.init(scope, sealed); } @@ -923,7 +923,7 @@ private static final class JavaIterableIterator extends ES6Iterator { private static final long serialVersionUID = 1L; private static final String ITERATOR_TAG = "JavaIterableIterator"; - static void init(ScriptableObject scope, boolean sealed) { + static void init(TopLevel scope, boolean sealed) { ES6Iterator.init(scope, sealed, new JavaIterableIterator(), ITERATOR_TAG); } diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeMap.java b/rhino/src/main/java/org/mozilla/javascript/NativeMap.java index 7a208935174..f9b17e544b7 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeMap.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeMap.java @@ -208,7 +208,7 @@ private Object js_forEach(Context cx, Scriptable scope, Object arg1, Object arg2 Scriptable thisObj = ScriptRuntime.toObjectOrNull(cx, arg2, scope); if (thisObj == null && !isStrict) { - thisObj = scope; + thisObj = ScriptableObject.getTopLevelScope(scope).getGlobalThis(); } if (thisObj == null) { thisObj = Undefined.SCRIPTABLE_UNDEFINED; diff --git a/rhino/src/main/java/org/mozilla/javascript/NativePromise.java b/rhino/src/main/java/org/mozilla/javascript/NativePromise.java index b8a3a2cef57..2dc8d8887d3 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativePromise.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativePromise.java @@ -72,9 +72,9 @@ private static Scriptable constructor(Context cx, Scriptable scope, Object[] arg Scriptable thisObj = Undefined.SCRIPTABLE_UNDEFINED; if (!cx.isStrictMode()) { - Scriptable tcs = cx.topCallScope; + TopLevel tcs = cx.topCallScope; if (tcs != null) { - thisObj = tcs; + thisObj = tcs.getGlobalThis(); } } diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeSet.java b/rhino/src/main/java/org/mozilla/javascript/NativeSet.java index 74144c791cf..93d5fa17f89 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeSet.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeSet.java @@ -202,7 +202,7 @@ private Object js_forEach(Context cx, Scriptable scope, Object arg1, Object arg2 Scriptable thisObj = ScriptRuntime.toObjectOrNull(cx, arg2, scope); if (thisObj == null && !isStrict) { - thisObj = scope; + thisObj = ScriptableObject.getTopLevelScope(scope).getGlobalThis(); } if (thisObj == null) { thisObj = Undefined.SCRIPTABLE_UNDEFINED; diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeStringIterator.java b/rhino/src/main/java/org/mozilla/javascript/NativeStringIterator.java index b55fe3fef59..56a32f283ba 100644 --- a/rhino/src/main/java/org/mozilla/javascript/NativeStringIterator.java +++ b/rhino/src/main/java/org/mozilla/javascript/NativeStringIterator.java @@ -10,7 +10,7 @@ public final class NativeStringIterator extends ES6Iterator { private static final long serialVersionUID = 1L; private static final String ITERATOR_TAG = "StringIterator"; - static void init(ScriptableObject scope, boolean sealed) { + static void init(TopLevel scope, boolean sealed) { ES6Iterator.init(scope, sealed, new NativeStringIterator(), ITERATOR_TAG); } diff --git a/rhino/src/main/java/org/mozilla/javascript/RegExpProxy.java b/rhino/src/main/java/org/mozilla/javascript/RegExpProxy.java index c9abe507799..cead767b7e3 100644 --- a/rhino/src/main/java/org/mozilla/javascript/RegExpProxy.java +++ b/rhino/src/main/java/org/mozilla/javascript/RegExpProxy.java @@ -18,7 +18,7 @@ public interface RegExpProxy { public static final int RA_REPLACE_ALL = 3; public static final int RA_SEARCH = 4; - public void register(ScriptableObject scope, boolean sealed); + public void register(TopLevel scope, boolean sealed); public boolean isRegExp(Scriptable obj); diff --git a/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java b/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java index 66c4e687571..d5cdf53dc7c 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java +++ b/rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java @@ -189,17 +189,16 @@ public static boolean isRhinoRuntimeType(Class cl) { || ScriptableClass.isAssignableFrom(cl)); } - public static ScriptableObject initSafeStandardObjects( - Context cx, ScriptableObject scope, boolean sealed) { + public static TopLevel initSafeStandardObjects(Context cx, TopLevel scope, boolean sealed) { if (scope == null) { - scope = new NativeObject(); - } else if (scope instanceof TopLevel) { - ((TopLevel) scope).clearCache(); + scope = new TopLevel(); } - scope.put("global", scope, scope); + scope.put("global", scope, scope.getGlobalThis()); + scope.clearCache(); scope.associateValue(LIBRARY_SCOPE_KEY, scope); + new ClassCache().associate(scope); var typeFactory = (androidApi >= 34 || androidApi < 0) @@ -298,23 +297,20 @@ public static ScriptableObject initSafeStandardObjects( new LazilyLoadedCtor(scope, "Reflect", sealed, true, NativeReflect::init); } - if (scope instanceof TopLevel) { - ((TopLevel) scope).cacheBuiltins(scope, sealed); - } + scope.cacheBuiltins(sealed); return scope; } - private static void registerRegExp(Context cx, ScriptableObject scope, boolean sealed) { + private static void registerRegExp(Context cx, TopLevel scope, boolean sealed) { RegExpProxy regExpProxy = getRegExpProxy(cx); if (regExpProxy != null) { regExpProxy.register(scope, sealed); } } - public static ScriptableObject initStandardObjects( - Context cx, ScriptableObject scope, boolean sealed) { - ScriptableObject s = initSafeStandardObjects(cx, scope, sealed); + public static TopLevel initStandardObjects(Context cx, TopLevel scope, boolean sealed) { + TopLevel s = initSafeStandardObjects(cx, scope, sealed); // These depend on the legacy initialization behavior of the lazy loading mechanism new LazilyLoadedCtor( @@ -3355,6 +3351,7 @@ private static Callable getValueFunctionAndThisInner( // nested functions should have top scope as their thisObj thisObj = ScriptableObject.getTopLevelScope(thisObj); } + storeScriptable(cx, thisObj); return f; } @@ -3396,6 +3393,7 @@ private static LookupResult getValueAndThisInner( // nested functions should have top scope as their thisObj thisObj = ScriptableObject.getTopLevelScope(thisObj); } + return new LookupResult(f, thisObj, value); } @@ -3543,7 +3541,7 @@ public static Scriptable getApplyOrCallThis( } if (callThis == null) { // This covers the case of args[0] == (null|undefined) as well. - callThis = getTopCallScope(cx); + callThis = getTopCallScope(cx).getGlobalThis(); } } else { // Spec-compliant behavior @@ -3562,7 +3560,7 @@ public static Scriptable getApplyOrCallThis( boolean isFunctionStrict = !(target instanceof JSFunction) || ((JSFunction) target).isStrict(); if (missingCallThis && !isFunctionStrict) { - callThis = getTopCallScope(cx); + callThis = getTopCallScope(cx).getGlobalThis(); } } @@ -4868,8 +4866,8 @@ public static boolean hasTopCall(Context cx) { return (cx.topCallScope != null); } - public static Scriptable getTopCallScope(Context cx) { - Scriptable scope = cx.topCallScope; + public static TopLevel getTopCallScope(Context cx) { + var scope = cx.topCallScope; if (scope == null) { throw new IllegalStateException(); } @@ -5383,9 +5381,9 @@ public static void setObjectProtoAndParent(ScriptableObject object, Scriptable s public static void setBuiltinProtoAndParent( ScriptableObject object, Scriptable scope, TopLevel.Builtins type) { - scope = ScriptableObject.getTopLevelScope(scope); - object.setParentScope(scope); - object.setPrototype(TopLevel.getBuiltinPrototype(scope, type)); + TopLevel top = ScriptableObject.getTopLevelScope(scope); + object.setParentScope(top); + object.setPrototype(TopLevel.getBuiltinPrototype(top, type)); } public static void setBuiltinProtoAndParent( @@ -6197,7 +6195,8 @@ public static final class LookupResult implements Serializable { LookupResult(Object result, Scriptable thisObj, Object name) { this.result = result; - this.thisObj = thisObj; + this.thisObj = + thisObj instanceof TopLevel ? ((TopLevel) thisObj).getGlobalThis() : thisObj; this.name = name; } diff --git a/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java b/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java index 4bf1f69dbe8..1a41a570b1e 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java +++ b/rhino/src/main/java/org/mozilla/javascript/ScriptableObject.java @@ -700,14 +700,14 @@ void addLazilyInitializedValue(Symbol key, int index, LazilyLoadedCtor init, int * to regular property access. * @since 1.7.6 */ - public void setExternalArrayData(ExternalArrayData array) { + public void setExternalArrayData(Scriptable scope, ExternalArrayData array) { externalData = array; if (array == null) { delete("length"); } else { // Define "length" to return whatever length the List gives us. - defineProperty("length", null, GET_ARRAY_LENGTH, null, READONLY | DONTENUM); + defineProperty(scope, "length", null, GET_ARRAY_LENGTH, null, READONLY | DONTENUM); } } @@ -1228,7 +1228,7 @@ static BaseFunction buildClassCtor( ScriptableObject.PERMANENT | ScriptableObject.DONTENUM | (setter != null ? 0 : ScriptableObject.READONLY); - ((ScriptableObject) proto).defineProperty(name, null, method, setter, attr); + ((ScriptableObject) proto).defineProperty(scope, name, null, method, setter, attr); continue; } @@ -1468,7 +1468,8 @@ public static void defineConstProperty(Scriptable destination, String propertyNa * @param attributes the attributes of the JavaScript property * @see org.mozilla.javascript.Scriptable#put(String, Scriptable, Object) */ - public void defineProperty(String propertyName, Class clazz, int attributes) { + public void defineProperty( + Scriptable scope, String propertyName, Class clazz, int attributes) { int length = propertyName.length(); if (length == 0) throw new IllegalArgumentException(); char[] buf = new char[3 + length]; @@ -1485,7 +1486,8 @@ public void defineProperty(String propertyName, Class clazz, int attributes) Method getter = FunctionObject.findSingleMethod(methods, getterName); Method setter = FunctionObject.findSingleMethod(methods, setterName); if (setter == null) attributes |= ScriptableObject.READONLY; - defineProperty(propertyName, null, getter, setter == null ? null : setter, attributes); + defineProperty( + scope, propertyName, null, getter, setter == null ? null : setter, attributes); } /** @@ -1536,10 +1538,15 @@ public void defineProperty(String propertyName, Class clazz, int attributes) * @param attributes the attributes of the JavaScript property */ public void defineProperty( - String propertyName, Object delegateTo, Method getter, Method setter, int attributes) { + Scriptable scope, + String propertyName, + Object delegateTo, + Method getter, + Method setter, + int attributes) { MemberBox getterBox = null; if (getter != null) { - getterBox = new MemberBox(getter); + getterBox = new MemberBox(scope, getter); boolean delegatedForm; if (!Modifier.isStatic(getter.getModifiers())) { @@ -1580,7 +1587,7 @@ public void defineProperty( if (setter.getReturnType() != Void.TYPE) throw Context.reportRuntimeErrorById("msg.setter.return", setter.toString()); - setterBox = new MemberBox(setter); + setterBox = new MemberBox(scope, setter); boolean delegatedForm; if (!Modifier.isStatic(setter.getModifiers())) { @@ -2020,6 +2027,7 @@ public interface LambdaSetterFunction extends Serializable { */ public void defineProperty( Context cx, + Scriptable scope, String name, LambdaGetterFunction getter, LambdaSetterFunction setter, @@ -2027,17 +2035,23 @@ public void defineProperty( if (getter == null && setter == null) throw ScriptRuntime.typeError("at least one of {getter, setter} is required"); - LambdaAccessorSlot newSlot = createLambdaAccessorSlot(name, 0, getter, setter, attributes); + LambdaAccessorSlot newSlot = + createLambdaAccessorSlot(name, 0, getter, setter, attributes, scope); replaceLambdaAccessorSlot(cx, name, newSlot); } public void defineProperty( - Context cx, String name, LambdaGetterFunction getter, int attributes) { - defineProperty(cx, name, getter, null, attributes); + Context cx, + Scriptable scope, + String name, + LambdaGetterFunction getter, + int attributes) { + defineProperty(cx, scope, name, getter, null, attributes); } public void defineProperty( Context cx, + Scriptable scope, Symbol key, LambdaGetterFunction getter, LambdaSetterFunction setter, @@ -2045,7 +2059,8 @@ public void defineProperty( if (getter == null && setter == null) throw ScriptRuntime.typeError("at least one of {getter, setter} is required"); - LambdaAccessorSlot newSlot = createLambdaAccessorSlot(key, 0, getter, setter, attributes); + LambdaAccessorSlot newSlot = + createLambdaAccessorSlot(key, 0, getter, setter, attributes, scope); replaceLambdaAccessorSlot(cx, key, newSlot); } @@ -2089,10 +2104,11 @@ private LambdaAccessorSlot createLambdaAccessorSlot( int index, LambdaGetterFunction getter, LambdaSetterFunction setter, - int attributes) { + int attributes, + Scriptable scope) { LambdaAccessorSlot slot = new LambdaAccessorSlot(name, index); - slot.setGetter(this, getter); - slot.setSetter(this, setter); + slot.setGetter(scope, getter); + slot.setSetter(scope, setter); slot.setAttributes(attributes); return slot; } @@ -2315,19 +2331,21 @@ protected static ScriptableObject ensureScriptableObjectButNotSymbol(Object arg) * constructed from the methods found, and are added to this object as properties with the given * names. * + * @param scope the declaration scope for the created function. * @param names the names of the Methods to add as function properties * @param clazz the class to search for the Methods * @param attributes the attributes of the new properties * @see org.mozilla.javascript.FunctionObject */ - public void defineFunctionProperties(String[] names, Class clazz, int attributes) { + public void defineFunctionProperties( + Scriptable scope, String[] names, Class clazz, int attributes) { Method[] methods = FunctionObject.getMethodList(clazz); for (String name : names) { Method m = FunctionObject.findSingleMethod(methods, name); if (m == null) { throw Context.reportRuntimeErrorById("msg.method.not.found", name, clazz.getName()); } - FunctionObject f = new FunctionObject(name, m, this); + FunctionObject f = new FunctionObject(name, m, scope); defineProperty(name, f, attributes); } } @@ -2398,11 +2416,14 @@ public static Scriptable getClassPrototype(Scriptable scope, String className) { * @param obj a JavaScript object * @return the corresponding global scope */ - public static Scriptable getTopLevelScope(Scriptable obj) { + public static TopLevel getTopLevelScope(Scriptable obj) { for (; ; ) { Scriptable parent = obj.getParentScope(); if (parent == null) { - return obj; + if (obj instanceof TopLevel) { + return (TopLevel) obj; + } + throw new Error("Non-top level scope without parent"); } obj = parent; } @@ -2939,6 +2960,12 @@ public final Object getAssociatedValue(Object key) { return h.get(key); } + protected void copyAssociatedValue(ScriptableObject other) { + for (var e : other.associatedValues.entrySet()) { + associateValue(e.getKey(), e.getValue()); + } + } + /** * Get arbitrary application-specific value associated with the top scope of the given scope. * The method first calls {@link #getTopLevelScope(Scriptable scope)} and then searches the @@ -2950,20 +2977,8 @@ public final Object getAssociatedValue(Object key) { * @see #getAssociatedValue(Object key) */ public static Object getTopScopeValue(Scriptable scope, Object key) { - scope = ScriptableObject.getTopLevelScope(scope); - for (; ; ) { - if (scope instanceof ScriptableObject) { - ScriptableObject so = (ScriptableObject) scope; - Object value = so.getAssociatedValue(key); - if (value != null) { - return value; - } - } - scope = scope.getPrototype(); - if (scope == null) { - return null; - } - } + var topScope = ScriptableObject.getTopLevelScope(scope); + return topScope.getAssociatedValue(key); } /** diff --git a/rhino/src/main/java/org/mozilla/javascript/SlotMapOwner.java b/rhino/src/main/java/org/mozilla/javascript/SlotMapOwner.java index aebb932108b..2ee3a45929e 100644 --- a/rhino/src/main/java/org/mozilla/javascript/SlotMapOwner.java +++ b/rhino/src/main/java/org/mozilla/javascript/SlotMapOwner.java @@ -332,7 +332,7 @@ protected static SlotMap createSlotMap(int initialSize) { } } - final SlotMap getMap() { + SlotMap getMap() { return slotMap; } diff --git a/rhino/src/main/java/org/mozilla/javascript/TopLevel.java b/rhino/src/main/java/org/mozilla/javascript/TopLevel.java index 43834a060ff..1962d5a35b8 100644 --- a/rhino/src/main/java/org/mozilla/javascript/TopLevel.java +++ b/rhino/src/main/java/org/mozilla/javascript/TopLevel.java @@ -6,6 +6,9 @@ package org.mozilla.javascript; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.EnumMap; /** @@ -26,8 +29,8 @@ *

Calling {@link org.mozilla.javascript.Context#initStandardObjects()} with an instance of this * class as argument will automatically cache built-in classes after initialization. For other * setups involving top-level scopes that inherit global properties from their prototypes (e.g. with - * dynamic scopes) embeddings should explicitly call {@link #cacheBuiltins(Scriptable, boolean)} to - * initialize the class cache for each top-level scope. + * dynamic scopes) embeddings should explicitly call {@link #cacheBuiltins(boolean)} to initialize + * the class cache for each top-level scope. */ public class TopLevel extends ScriptableObject { @@ -99,12 +102,72 @@ enum NativeErrors { JavaException } + public static class GlobalThis extends ScriptableObject { + + @Override + public String getClassName() { + return "global"; + } + } + private EnumMap ctors; private EnumMap errors; + private transient ScriptableObject globalThis; + + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(globalThis); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + globalThis = (ScriptableObject) in.readObject(); + } + + public TopLevel() { + this(new GlobalThis()); + } + + public TopLevel(ScriptableObject customGlobal) { + globalThis = customGlobal; + } + + public static TopLevel createIsolate(TopLevel parent) { + var newGlobal = new NativeObject(); + newGlobal.setPrototype(parent.getGlobalThis()); + newGlobal.setParentScope(null); + var isolate = new TopLevel(newGlobal); + isolate.copyAssociatedValue(parent); + isolate.copyBuiltins(parent, false); + return isolate; + } + + public static TopLevel createIsolate(TopLevel parent, ScriptableObject customGlobal) { + customGlobal.setParentScope(null); + customGlobal.setPrototype(parent.getGlobalThis()); + var isolate = new TopLevel(customGlobal); + isolate.copyAssociatedValue(parent); + isolate.copyBuiltins(parent, false); + return isolate; + } + + /** + * Only use this function if you have already set the customGlobal's prototype chain to point to + * this top level's global object. This should only be done if you know for certain that no + * other use will be made of this prototype chain. + */ + public static TopLevel createIsolateCustomPrototypeChain( + TopLevel parent, ScriptableObject customGlobal) { + customGlobal.setParentScope(null); + var isolate = new TopLevel(customGlobal); + isolate.copyAssociatedValue(parent); + isolate.copyBuiltins(parent, false); + return isolate; + } @Override public String getClassName() { - return "global"; + return "topLevel"; } /** @@ -113,8 +176,16 @@ public String getClassName() { * ScriptRuntime.initStandardObjects} if the scope argument is an instance of this class. It * only has to be called by the embedding if a top-level scope is not initialized through {@code * initStandardObjects()}. + * + *

This method is deprecated and kept for compatibility. Please use either {@link + * cacheBuiltins(boolean)} or {@link copyBuiltins(TopLevel, boolean)} instead. */ - public void cacheBuiltins(Scriptable scope, boolean sealed) { + @Deprecated + public void cacheBuiltins(TopLevel scope, boolean sealed) { + cacheBuiltins(sealed); + } + + public void cacheBuiltins(boolean sealed) { ctors = new EnumMap<>(Builtins.class); for (Builtins builtin : Builtins.values()) { Object value = ScriptableObject.getProperty(this, builtin.name()); @@ -124,8 +195,7 @@ public void cacheBuiltins(Scriptable scope, boolean sealed) { // Handle weird situation of "GeneratorFunction" being a real constructor // which is never registered in the top-level scope ctors.put( - builtin, - (BaseFunction) BaseFunction.initAsGeneratorFunction(scope, sealed)); + builtin, (BaseFunction) BaseFunction.initAsGeneratorFunction(this, sealed)); } } errors = new EnumMap<>(NativeErrors.class); @@ -137,6 +207,11 @@ public void cacheBuiltins(Scriptable scope, boolean sealed) { } } + public void copyBuiltins(TopLevel other, boolean sealed) { + ctors = other.ctors; + errors = other.errors; + } + /** Clears the cache; this is necessary, when standard objects are reinitialized. */ void clearCache() { ctors = null; @@ -207,15 +282,13 @@ static Function getNativeErrorCtor(Context cx, Scriptable scope, NativeErrors ty * @param type the built-in type * @return the built-in prototype */ - public static Scriptable getBuiltinPrototype(Scriptable scope, Builtins type) { + public static Scriptable getBuiltinPrototype(TopLevel scope, Builtins type) { // must be called with top level scope - assert scope.getParentScope() == null; - if (scope instanceof TopLevel) { - Scriptable result = ((TopLevel) scope).getBuiltinPrototype(type); - if (result != null) { - return result; - } + Scriptable result = ((TopLevel) scope).getBuiltinPrototype(type); + if (result != null) { + return result; } + // fall back to normal prototype lookup String typeName; if (type == Builtins.GeneratorFunction) { @@ -231,8 +304,7 @@ public static Scriptable getBuiltinPrototype(Scriptable scope, Builtins type) { /** * Get the cached built-in object constructor from this scope with the given {@code type}. - * Returns null if {@link #cacheBuiltins(Scriptable, boolean)} has not been called on this - * object. + * Returns null if {@link #cacheBuiltins(boolean)} has not been called on this object. * * @param type the built-in type * @return the built-in constructor @@ -243,7 +315,7 @@ public BaseFunction getBuiltinCtor(Builtins type) { /** * Get the cached native error constructor from this scope with the given {@code type}. Returns - * null if {@link #cacheBuiltins(Scriptable, boolean)} has not been called on this object. + * null if {@link #cacheBuiltins(boolean)} has not been called on this object. * * @param type the native error type * @return the native error constructor @@ -254,7 +326,7 @@ BaseFunction getNativeErrorCtor(NativeErrors type) { /** * Get the cached built-in object prototype from this scope with the given {@code type}. Returns - * null if {@link #cacheBuiltins(Scriptable, boolean)} has not been called on this object. + * null if {@link #cacheBuiltins(boolean)} has not been called on this object. * * @param type the built-in type * @return the built-in prototype @@ -264,4 +336,91 @@ public Scriptable getBuiltinPrototype(Builtins type) { Object proto = func != null ? func.getPrototypeProperty() : null; return proto instanceof Scriptable ? (Scriptable) proto : null; } + + public ScriptableObject getGlobalThis() { + return globalThis; + } + + @Override + public Object get(String name, Scriptable start) { + var res = super.get(name, start); + if (res != NOT_FOUND) { + return res; + } + return ScriptableObject.getProperty(globalThis, name); + } + + @Override + public void put(String name, Scriptable start, Object value) { + ScriptableObject.putProperty(globalThis, name, value); + } + + @Override + public boolean has(String name, Scriptable start) { + return super.has(name, start) || ScriptableObject.hasProperty(globalThis, name); + } + + @Override + public void delete(String name) { + globalThis.delete(name); + } + + @Override + public void sealObject() { + globalThis.sealObject(); + super.sealObject(); + } + + @Override + public void defineProperty(String propertyName, Object value, int attributes) { + globalThis.defineProperty(propertyName, value, attributes); + } + + @Override + void addLazilyInitializedValue(String name, int index, LazilyLoadedCtor init, int attributes) { + globalThis.addLazilyInitializedValue(name, index, init, attributes); + } + + @Override + public void setAttributes(String name, int attributes) { + if (super.get(name, this) != NOT_FOUND) { + super.setAttributes(name, attributes); + } else { + globalThis.setAttributes(name, attributes); + } + } + + @Override + public int getAttributes(String name) { + if (super.get(name, this) != NOT_FOUND) { + return super.getAttributes(name); + } else { + return globalThis.getAttributes(name); + } + } + + // Technically this is wrong, but there are currently tests that + // depend const variable being defined on globalThis. + // + // In a compliant implementation const declarations should bind + // the values on the global scope but not on the global object. + + @Override + public boolean isConst(String name) { + if (super.get(name, this) != NOT_FOUND) { + return super.isConst(name); + } else { + return globalThis.isConst(name); + } + } + + @Override + public void putConst(String name, Scriptable start, Object value) { + globalThis.putConst(name, globalThis, value); + } + + @Override + public void defineConst(String name, Scriptable start) { + globalThis.defineConst(name, globalThis); + } } diff --git a/rhino/src/main/java/org/mozilla/javascript/commonjs/module/ModuleScope.java b/rhino/src/main/java/org/mozilla/javascript/commonjs/module/ModuleScope.java index 8be9e77a329..791d674a3e5 100644 --- a/rhino/src/main/java/org/mozilla/javascript/commonjs/module/ModuleScope.java +++ b/rhino/src/main/java/org/mozilla/javascript/commonjs/module/ModuleScope.java @@ -6,22 +6,27 @@ import java.net.URI; import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.TopLevel; /** * A top-level module scope. This class provides methods to retrieve the module's source and base * URIs in order to resolve relative module IDs and check sandbox constraints. */ -public class ModuleScope extends TopLevel { +public class ModuleScope extends ScriptableObject { private static final long serialVersionUID = 1L; private final URI uri; private final URI base; - public ModuleScope(Scriptable prototype, URI uri, URI base) { + private ModuleScope(URI uri, URI base) { this.uri = uri; this.base = base; - setPrototype(prototype); - cacheBuiltins(prototype, false); + } + + public static ScriptableObject createModuleScope(TopLevel global, URI uri, URI base) { + var moduleScope = new ModuleScope(uri, base); + moduleScope.setParentScope(global); + return moduleScope; } public URI getUri() { @@ -31,4 +36,21 @@ public URI getUri() { public URI getBase() { return base; } + + @Override + public String getClassName() { + return "module"; + } + + /** Search up the chain of scopes to find a module scope. */ + public static ModuleScope findModuleScope(Scriptable scope) { + Scriptable current = scope; + while (current != null) { + if (current instanceof ModuleScope) { + return (ModuleScope) current; + } + current = current.getParentScope(); + } + return null; + } } diff --git a/rhino/src/main/java/org/mozilla/javascript/commonjs/module/Require.java b/rhino/src/main/java/org/mozilla/javascript/commonjs/module/Require.java index 5169c2df5b4..8ce6d32d582 100644 --- a/rhino/src/main/java/org/mozilla/javascript/commonjs/module/Require.java +++ b/rhino/src/main/java/org/mozilla/javascript/commonjs/module/Require.java @@ -16,6 +16,8 @@ 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; /** * Implements the require() function as defined by clazz) { * @throws IllegalArgumentException if provided scope is not top scope * @see #get(Scriptable scope) */ - default TypeInfoFactory associate(ScriptableObject topScope) { + default TypeInfoFactory associate(TopLevel topScope) { if (topScope.getParentScope() != null) { throw new IllegalArgumentException("provided scope not top scope"); } diff --git a/rhino/src/main/java/org/mozilla/javascript/regexp/NativeRegExpStringIterator.java b/rhino/src/main/java/org/mozilla/javascript/regexp/NativeRegExpStringIterator.java index 170ec373549..91ffa82835a 100644 --- a/rhino/src/main/java/org/mozilla/javascript/regexp/NativeRegExpStringIterator.java +++ b/rhino/src/main/java/org/mozilla/javascript/regexp/NativeRegExpStringIterator.java @@ -10,7 +10,7 @@ import org.mozilla.javascript.ES6Iterator; 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; // See ECMAScript spec 22.2.9.1 @@ -25,7 +25,7 @@ public final class NativeRegExpStringIterator extends ES6Iterator { private boolean nextDone; private Object next = null; - public static void init(ScriptableObject scope, boolean sealed) { + public static void init(TopLevel scope, boolean sealed) { ES6Iterator.init(scope, sealed, new NativeRegExpStringIterator(), ITERATOR_TAG); } diff --git a/rhino/src/main/java/org/mozilla/javascript/regexp/RegExpImpl.java b/rhino/src/main/java/org/mozilla/javascript/regexp/RegExpImpl.java index 7f6b0d57f58..54093c291e5 100644 --- a/rhino/src/main/java/org/mozilla/javascript/regexp/RegExpImpl.java +++ b/rhino/src/main/java/org/mozilla/javascript/regexp/RegExpImpl.java @@ -14,13 +14,14 @@ 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; /** */ public class RegExpImpl implements RegExpProxy { @Override - public void register(ScriptableObject scope, boolean sealed) { + public void register(TopLevel scope, boolean sealed) { NativeRegExpStringIterator.init(scope, sealed); new LazilyLoadedCtor(scope, "RegExp", sealed, true, NativeRegExp::init); } diff --git a/rhino/src/test/java/org/mozilla/javascript/NullabilityDetectorTest.java b/rhino/src/test/java/org/mozilla/javascript/NullabilityDetectorTest.java index 32a08cb655f..4beda535640 100644 --- a/rhino/src/test/java/org/mozilla/javascript/NullabilityDetectorTest.java +++ b/rhino/src/test/java/org/mozilla/javascript/NullabilityDetectorTest.java @@ -11,37 +11,43 @@ public class NullabilityDetectorTest { @Test public void testNullableDetectorForMethodWithoutArgs() { - MemberBox memberBox = new MemberBox(getTestClassMethod("function1")); + var scope = new TopLevel(); + MemberBox memberBox = new MemberBox(scope, getTestClassMethod("function1")); assertNullabilityMatch(memberBox.getArgNullability()); } @Test public void testNullableDetectorForMethodWithOneArg() { - MemberBox memberBox = new MemberBox(getTestClassMethod("function2")); + var scope = new TopLevel(); + MemberBox memberBox = new MemberBox(scope, getTestClassMethod("function2")); assertNullabilityMatch(memberBox.getArgNullability(), true); } @Test public void testNullableDetectorForMethodWithSeveralArgs() { - MemberBox memberBox = new MemberBox(getTestClassMethod("function3")); + var scope = new TopLevel(); + MemberBox memberBox = new MemberBox(scope, getTestClassMethod("function3")); assertNullabilityMatch(memberBox.getArgNullability(), true, true, true, true); } @Test public void testNullableDetectorForConstructorWithoutArgs() { - MemberBox memberBox = new MemberBox(getTestClassConstructor(0)); + var scope = new TopLevel(); + MemberBox memberBox = new MemberBox(scope, getTestClassConstructor(0)); assertNullabilityMatch(memberBox.getArgNullability()); } @Test public void testNullableDetectorForConstructorWithOneArg() { - MemberBox memberBox = new MemberBox(getTestClassConstructor(1)); + var scope = new TopLevel(); + MemberBox memberBox = new MemberBox(scope, getTestClassConstructor(1)); assertNullabilityMatch(memberBox.getArgNullability(), true); } @Test public void testNullableDetectorForConstructorWithSeveralArgs() { - MemberBox memberBox = new MemberBox(getTestClassConstructor(4)); + var scope = new TopLevel(); + MemberBox memberBox = new MemberBox(scope, getTestClassConstructor(4)); assertNullabilityMatch(memberBox.getArgNullability(), true, false, true, false); } diff --git a/rhino/src/test/java/org/mozilla/javascript/SuperTest.java b/rhino/src/test/java/org/mozilla/javascript/SuperTest.java index e1a698a6664..8d4198d7d6f 100644 --- a/rhino/src/test/java/org/mozilla/javascript/SuperTest.java +++ b/rhino/src/test/java/org/mozilla/javascript/SuperTest.java @@ -372,7 +372,10 @@ public void error( int line, String lineSource, int lineOffset) { - fail("should not have been called"); + fail( + String.format( + "should not have been called but was with %s", + message)); } @Override @@ -382,7 +385,10 @@ public EvaluatorException runtimeError( int line, String lineSource, int lineOffset) { - fail("should not have been called"); + fail( + String.format( + "should not have been called but was with %s", + message)); return null; } }); diff --git a/rhino/src/test/java/org/mozilla/javascript/tests/Bug685403Test.java b/rhino/src/test/java/org/mozilla/javascript/tests/Bug685403Test.java index 9c9f49748a2..db2b703deb6 100755 --- a/rhino/src/test/java/org/mozilla/javascript/tests/Bug685403Test.java +++ b/rhino/src/test/java/org/mozilla/javascript/tests/Bug685403Test.java @@ -53,7 +53,8 @@ public void test() { source += "state"; String[] functions = new String[] {"continuation"}; - scope.defineFunctionProperties(functions, Bug685403Test.class, ScriptableObject.DONTENUM); + scope.defineFunctionProperties( + scope, functions, Bug685403Test.class, ScriptableObject.DONTENUM); Object state = null; Script script = cx.compileString(source, "", 1, null); diff --git a/rhino/src/test/java/org/mozilla/javascript/tests/Bug783797Test.java b/rhino/src/test/java/org/mozilla/javascript/tests/Bug783797Test.java index a0581122176..0a05079a953 100755 --- a/rhino/src/test/java/org/mozilla/javascript/tests/Bug783797Test.java +++ b/rhino/src/test/java/org/mozilla/javascript/tests/Bug783797Test.java @@ -13,6 +13,7 @@ import org.mozilla.javascript.ContextAction; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; /** * @author André Bargull @@ -513,13 +514,15 @@ public void returnThis() { @Override public void run( Context cx, ScriptableObject scope1, ScriptableObject scope2) { - assertSame(scope2, eval(cx, scope2, "test()")); - assertSame(scope2, eval(cx, scope2, "test.call(null)")); - assertSame(scope2, eval(cx, scope1, "scope2.test()")); - assertSame(scope1, eval(cx, scope1, "scope2.test.call(null)")); - assertSame(scope1, eval(cx, scope1, "var t=scope2.test; t()")); + var globalThis1 = ((TopLevel) scope1).getGlobalThis(); + var globalThis2 = ((TopLevel) scope2).getGlobalThis(); + assertSame(globalThis2, eval(cx, scope2, "test()")); + assertSame(globalThis2, eval(cx, scope2, "test.call(null)")); + assertSame(globalThis2, eval(cx, scope1, "scope2.test()")); + assertSame(globalThis1, eval(cx, scope1, "scope2.test.call(null)")); + assertSame(globalThis1, eval(cx, scope1, "var t=scope2.test; t()")); assertSame( - scope1, + globalThis1, eval(cx, scope1, "var t=scope2.test; t.call(null)")); } })); @@ -535,13 +538,14 @@ public void returnThisNested() { @Override public void run( Context cx, ScriptableObject scope1, ScriptableObject scope2) { - assertSame(scope2, eval(cx, scope2, "test()")); - assertSame(scope2, eval(cx, scope2, "test.call(null)")); - assertSame(scope2, eval(cx, scope1, "scope2.test()")); - assertSame(scope2, eval(cx, scope1, "scope2.test.call(null)")); - assertSame(scope2, eval(cx, scope1, "var t=scope2.test; t()")); + var globalThis = ((TopLevel) scope2).getGlobalThis(); + assertSame(globalThis, eval(cx, scope2, "test()")); + assertSame(globalThis, eval(cx, scope2, "test.call(null)")); + assertSame(globalThis, eval(cx, scope1, "scope2.test()")); + assertSame(globalThis, eval(cx, scope1, "scope2.test.call(null)")); + assertSame(globalThis, eval(cx, scope1, "var t=scope2.test; t()")); assertSame( - scope2, + globalThis, eval(cx, scope1, "var t=scope2.test; t.call(null)")); } })); @@ -557,24 +561,29 @@ public void returnThisNestedCall() { @Override public void run( Context cx, ScriptableObject scope1, ScriptableObject scope2) { - assertSame(scope2, eval(cx, scope2, "test()")); - assertSame(scope2, eval(cx, scope2, "test(null)")); - assertSame(scope2, eval(cx, scope2, "test.call(null)")); - assertSame(scope2, eval(cx, scope2, "test.call(null, null)")); - - assertSame(scope1, eval(cx, scope1, "scope2.test()")); - assertSame(scope1, eval(cx, scope1, "scope2.test(null)")); - assertSame(scope1, eval(cx, scope1, "scope2.test.call(null)")); + var globalThis1 = ((TopLevel) scope1).getGlobalThis(); + var globalThis2 = ((TopLevel) scope2).getGlobalThis(); + assertSame(globalThis2, eval(cx, scope2, "test()")); + assertSame(globalThis2, eval(cx, scope2, "test(null)")); + assertSame(globalThis2, eval(cx, scope2, "test.call(null)")); + assertSame(globalThis2, eval(cx, scope2, "test.call(null, null)")); + + assertSame(globalThis1, eval(cx, scope1, "scope2.test()")); + assertSame(globalThis1, eval(cx, scope1, "scope2.test(null)")); + assertSame(globalThis1, eval(cx, scope1, "scope2.test.call(null)")); assertSame( - scope1, eval(cx, scope1, "scope2.test.call(null, null)")); + globalThis1, + eval(cx, scope1, "scope2.test.call(null, null)")); - assertSame(scope1, eval(cx, scope1, "var t=scope2.test; t()")); - assertSame(scope1, eval(cx, scope1, "var t=scope2.test; t(null)")); + assertSame(globalThis1, eval(cx, scope1, "var t=scope2.test; t()")); assertSame( - scope1, + globalThis1, + eval(cx, scope1, "var t=scope2.test; t(null)")); + assertSame( + globalThis1, eval(cx, scope1, "var t=scope2.test; t.call(null)")); assertSame( - scope1, + globalThis1, eval(cx, scope1, "var t=scope2.test; t.call(null, null)")); } })); diff --git a/rhino/src/test/java/org/mozilla/javascript/tests/ConsStringTest.java b/rhino/src/test/java/org/mozilla/javascript/tests/ConsStringTest.java index 98ed765984a..11d651fdc2e 100644 --- a/rhino/src/test/java/org/mozilla/javascript/tests/ConsStringTest.java +++ b/rhino/src/test/java/org/mozilla/javascript/tests/ConsStringTest.java @@ -63,7 +63,8 @@ public void doNotLeakConsStringIntoSetter() throws Exception { // define custom getter method final Method getter = MyHostObject.class.getMethod("getFoo"); final Method setter = MyHostObject.class.getMethod("setFoo", Object.class); - myHostObject.defineProperty("foo", null, getter, setter, ScriptableObject.EMPTY); + myHostObject.defineProperty( + topScope, "foo", null, getter, setter, ScriptableObject.EMPTY); topScope.put("MyHostObject", topScope, myHostObject); final String script = diff --git a/rhino/src/test/java/org/mozilla/javascript/tests/CustomSetterAcceptNullScriptableTest.java b/rhino/src/test/java/org/mozilla/javascript/tests/CustomSetterAcceptNullScriptableTest.java index 44d16bf2404..8a5b9c92057 100644 --- a/rhino/src/test/java/org/mozilla/javascript/tests/CustomSetterAcceptNullScriptableTest.java +++ b/rhino/src/test/java/org/mozilla/javascript/tests/CustomSetterAcceptNullScriptableTest.java @@ -52,7 +52,8 @@ public void setNullForScriptableSetter() throws Exception { // define custom setter method final Method setMyPropMethod = Foo.class.getMethod("setMyProp", Foo2.class); - foo.defineProperty("myProp", null, null, setMyPropMethod, ScriptableObject.EMPTY); + foo.defineProperty( + topScope, "myProp", null, null, setMyPropMethod, ScriptableObject.EMPTY); topScope.put("foo", topScope, foo); diff --git a/rhino/src/test/java/org/mozilla/javascript/tests/DefineFunctionPropertiesTest.java b/rhino/src/test/java/org/mozilla/javascript/tests/DefineFunctionPropertiesTest.java index f9bda83c156..5cf7bf2a185 100644 --- a/rhino/src/test/java/org/mozilla/javascript/tests/DefineFunctionPropertiesTest.java +++ b/rhino/src/test/java/org/mozilla/javascript/tests/DefineFunctionPropertiesTest.java @@ -12,6 +12,7 @@ import org.mozilla.javascript.Function; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; import org.mozilla.javascript.Undefined; /** @@ -21,7 +22,7 @@ */ public class DefineFunctionPropertiesTest { - ScriptableObject global; + TopLevel global; static Object key = "DefineFunctionPropertiesTest"; /** @@ -31,10 +32,10 @@ public class DefineFunctionPropertiesTest { @Before public void setUp() { try (Context cx = Context.enter()) { - global = cx.initStandardObjects(); + global = (TopLevel) cx.initStandardObjects(); String[] names = {"f", "g"}; global.defineFunctionProperties( - names, DefineFunctionPropertiesTest.class, ScriptableObject.DONTENUM); + global, names, DefineFunctionPropertiesTest.class, ScriptableObject.DONTENUM); } } @@ -71,7 +72,7 @@ public static Object g(Context cx, Scriptable thisObj, Object[] args, Function f @Test public void privateData() { try (Context cx = Context.enter()) { - global.associateValue(key, "bar"); + global.getGlobalThis().associateValue(key, "bar"); Object result = cx.evaluateString(global, "g('foo');", "test source", 1, null); assertEquals("foobar", result); } diff --git a/rhino/src/test/java/org/mozilla/javascript/tests/DynamicScopeTest.java b/rhino/src/test/java/org/mozilla/javascript/tests/DynamicScopeTest.java index 0386b77e3c4..81f9aacb11c 100644 --- a/rhino/src/test/java/org/mozilla/javascript/tests/DynamicScopeTest.java +++ b/rhino/src/test/java/org/mozilla/javascript/tests/DynamicScopeTest.java @@ -99,7 +99,7 @@ public void standardMethodObjectCreate() { // Used to fail with org.mozilla.javascript.EvaluatorException: Cannot modify a property // of a sealed object: iterator. - final ScriptableObject someScope = cx.initStandardObjects(); + final TopLevel someScope = cx.initStandardObjects(); Scriptable someObj = (Scriptable) @@ -113,12 +113,12 @@ public void standardMethodObjectCreate() { "source2", 1, null); - subScope.setParentScope(null); + var newTopLevel = TopLevel.createIsolate(someScope, (ScriptableObject) subScope); Scriptable subObj = (Scriptable) cx.evaluateString( - subScope, + newTopLevel, "var subObj = Object.create(obj); subObj;", "source3", 1, diff --git a/rhino/src/test/java/org/mozilla/javascript/tests/IterableTest.java b/rhino/src/test/java/org/mozilla/javascript/tests/IterableTest.java index c65e3fea5bb..ac87f30c378 100644 --- a/rhino/src/test/java/org/mozilla/javascript/tests/IterableTest.java +++ b/rhino/src/test/java/org/mozilla/javascript/tests/IterableTest.java @@ -28,14 +28,14 @@ public class IterableTest { public static final class FooWithoutSymbols extends FooBoilerplate { - public FooWithoutSymbols(final Scriptable scope) { + public FooWithoutSymbols(TopLevel scope) { super(scope); } } public static final class FooWithSymbols extends SymbolFooBoilerplate { - public FooWithSymbols(final Scriptable scope) { + public FooWithSymbols(TopLevel scope) { super(scope); } @@ -47,7 +47,7 @@ public boolean has(Symbol key, Scriptable start) { public static final class FooWithArrayIterator extends SymbolFooBoilerplate { - public FooWithArrayIterator(final Scriptable scope) { + public FooWithArrayIterator(TopLevel scope) { super(scope); } @@ -97,7 +97,7 @@ public void forOfUsingNonSymbolScriptable() { Utils.runWithAllModes( cx -> { cx.setLanguageVersion(Context.VERSION_ES6); - ScriptableObject scope = cx.initStandardObjects(); + TopLevel scope = cx.initStandardObjects(); Scriptable foo = new FooWithoutSymbols(scope); ScriptableObject.putProperty(scope, "foo", foo); @@ -131,7 +131,7 @@ public void forOfUsingNonIterable() { Utils.runWithAllModes( cx -> { cx.setLanguageVersion(Context.VERSION_ES6); - ScriptableObject scope = cx.initStandardObjects(); + TopLevel scope = cx.initStandardObjects(); Scriptable foo = new FooWithSymbols(scope); ScriptableObject.putProperty(scope, "foo", foo); @@ -161,7 +161,7 @@ public void forOfUsingArrayIterator() { Utils.runWithAllModes( cx -> { cx.setLanguageVersion(Context.VERSION_ES6); - ScriptableObject scope = cx.initStandardObjects(); + TopLevel scope = cx.initStandardObjects(); Scriptable foo = new FooWithArrayIterator(scope); ScriptableObject.putProperty(scope, "foo", foo); @@ -191,9 +191,9 @@ public void forOfUsingArrayIterator() { // Explicitly not a ScriptableObject public static class FooBoilerplate implements Scriptable { - protected final Scriptable scope; + protected final TopLevel scope; - public FooBoilerplate(final Scriptable scope) { + public FooBoilerplate(TopLevel scope) { this.scope = scope; } @@ -283,7 +283,7 @@ public boolean hasInstance(Scriptable instance) { public static class SymbolFooBoilerplate extends FooBoilerplate implements SymbolScriptable { - public SymbolFooBoilerplate(final Scriptable scope) { + public SymbolFooBoilerplate(TopLevel scope) { super(scope); } diff --git a/rhino/src/test/java/org/mozilla/javascript/tests/LookupSetterTest.java b/rhino/src/test/java/org/mozilla/javascript/tests/LookupSetterTest.java index faad37a764e..2dbd2451d9b 100644 --- a/rhino/src/test/java/org/mozilla/javascript/tests/LookupSetterTest.java +++ b/rhino/src/test/java/org/mozilla/javascript/tests/LookupSetterTest.java @@ -11,6 +11,7 @@ import org.mozilla.javascript.ContextAction; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; import org.mozilla.javascript.testutils.Utils; public class LookupSetterTest { @@ -149,7 +150,7 @@ public String getClassName() { } } - public static class TopScope extends ScriptableObject { + public static class TopScope extends TopLevel { @Override public String getClassName() { return "TopScope"; diff --git a/rhino/src/test/java/org/mozilla/javascript/tests/PrimitiveTypeScopeResolutionTest.java b/rhino/src/test/java/org/mozilla/javascript/tests/PrimitiveTypeScopeResolutionTest.java index ea627ef5ef9..d43e8f44961 100644 --- a/rhino/src/test/java/org/mozilla/javascript/tests/PrimitiveTypeScopeResolutionTest.java +++ b/rhino/src/test/java/org/mozilla/javascript/tests/PrimitiveTypeScopeResolutionTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; import org.mozilla.javascript.testutils.Utils; /** @@ -62,13 +63,14 @@ public void elementAccess() { private void testWithTwoScopes(final String scriptScope1, final String scriptScope2) { Utils.runWithAllModes( cx -> { - final Scriptable scope1 = - cx.initStandardObjects(new MySimpleScriptableObject("scope1")); - final Scriptable scope2 = - cx.initStandardObjects(new MySimpleScriptableObject("scope2")); + final TopLevel scope1 = new TopLevel(new MySimpleScriptableObject("scope1")); + cx.initStandardObjects(scope1); + final TopLevel scope2 = new TopLevel(new MySimpleScriptableObject("scope2")); + cx.initStandardObjects(scope2); + cx.evaluateString(scope2, scriptScope2, "source2", 1, null); - scope1.put("scope2", scope1, scope2); + scope1.put("scope2", scope1, scope2.getGlobalThis()); return cx.evaluateString(scope1, scriptScope1, "source1", 1, null); }); @@ -123,17 +125,18 @@ public void functionObjectPrimitiveToObject() throws Exception { // define object with custom method final MyObject myObject = new MyObject(); final String[] functionNames = {"readPropFoo"}; - myObject.defineFunctionProperties(functionNames, MyObject.class, ScriptableObject.EMPTY); final String scriptScope1 = "String.prototype.foo = 'from 1'; scope2.f()"; Utils.runWithAllModes( cx -> { - final Scriptable scope1 = - cx.initStandardObjects(new MySimpleScriptableObject("scope1")); - final Scriptable scope2 = - cx.initStandardObjects(new MySimpleScriptableObject("scope2")); + final TopLevel scope1 = new TopLevel(new MySimpleScriptableObject("scope1")); + cx.initStandardObjects(scope1); + final TopLevel scope2 = new TopLevel(new MySimpleScriptableObject("scope2")); + cx.initStandardObjects(scope2); + myObject.defineFunctionProperties( + scope2, functionNames, MyObject.class, ScriptableObject.EMPTY); scope2.put("myObject", scope2, myObject); cx.evaluateString(scope2, scriptScope2, "source2", 1, null); diff --git a/tests/src/test/java/org/mozilla/javascript/drivers/ScriptTestsBase.java b/tests/src/test/java/org/mozilla/javascript/drivers/ScriptTestsBase.java index 3fe4666534a..8b0dde4c7ae 100644 --- a/tests/src/test/java/org/mozilla/javascript/drivers/ScriptTestsBase.java +++ b/tests/src/test/java/org/mozilla/javascript/drivers/ScriptTestsBase.java @@ -24,6 +24,7 @@ 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; import org.mozilla.javascript.tools.shell.Global; @@ -71,9 +72,7 @@ private Object executeRhinoScript(boolean interpretedMode) { Global global = new Global(cx); loadNatives(global); - Scriptable scope = cx.newObject(global); - scope.setPrototype(global); - scope.setParentScope(null); + var scope = TopLevel.createIsolate(global); return cx.evaluateReader(scope, script, suiteName, 1, null); } catch (JavaScriptException ex) { diff --git a/tests/src/test/java/org/mozilla/javascript/drivers/ShellTest.java b/tests/src/test/java/org/mozilla/javascript/drivers/ShellTest.java index 487f06371ec..eec8633de25 100644 --- a/tests/src/test/java/org/mozilla/javascript/drivers/ShellTest.java +++ b/tests/src/test/java/org/mozilla/javascript/drivers/ShellTest.java @@ -320,6 +320,7 @@ public static void run( // invoke after init(...) to make sure ClassCache is available for // FunctionObject global.defineFunctionProperties( + global, new String[] {"options"}, ShellTest.class, ScriptableObject.DONTENUM @@ -429,6 +430,7 @@ public static void runNoFork( // invoke after init(...) to make sure ClassCache is available for FunctionObject global.defineFunctionProperties( + global, new String[] {"options"}, ShellTest.class, ScriptableObject.DONTENUM diff --git a/tests/src/test/java/org/mozilla/javascript/tests/ExternalArrayTest.java b/tests/src/test/java/org/mozilla/javascript/tests/ExternalArrayTest.java index a17416d2e81..f6fcbba886d 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/ExternalArrayTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/ExternalArrayTest.java @@ -48,7 +48,7 @@ public void regularArray() { public void intArray() { ScriptableObject a = (ScriptableObject) cx.newObject(root); TestIntArray l = new TestIntArray(10); - a.setExternalArrayData(l); + a.setExternalArrayData(root, l); for (int i = 0; i < 10; i++) { l.setArrayElement(i, i); } @@ -63,7 +63,7 @@ public void intArrayThenRemove() { ScriptableObject a = (ScriptableObject) cx.newObject(root); // Set the external array data TestIntArray l = new TestIntArray(10); - a.setExternalArrayData(l); + a.setExternalArrayData(root, l); for (int i = 0; i < 10; i++) { l.setArrayElement(i, i); } @@ -76,7 +76,7 @@ public void intArrayThenRemove() { // regular JavaScript object. a.delete("stringField"); a.delete("intField"); - a.setExternalArrayData(null); + a.setExternalArrayData(root, null); for (int i = 0; i < 10; i++) { a.put(i, a, i); } @@ -89,7 +89,7 @@ public void intArrayThenRemove() { public void nativeIntArray() { ScriptableObject a = (ScriptableObject) cx.newObject(root); NativeInt32Array l = new NativeInt32Array(10); - a.setExternalArrayData(l); + a.setExternalArrayData(root, l); root.put("testArray", root, a); root.put("testArrayLength", root, 10); @@ -101,7 +101,7 @@ public void nativeIntArray() { public void nativeShortArray() { ScriptableObject a = (ScriptableObject) cx.newObject(root); NativeInt16Array l = new NativeInt16Array(10); - a.setExternalArrayData(l); + a.setExternalArrayData(root, l); root.put("testArray", root, a); root.put("testArrayLength", root, 10); @@ -113,7 +113,7 @@ public void nativeShortArray() { public void nativeDoubleArray() { ScriptableObject a = (ScriptableObject) cx.newObject(root); NativeFloat64Array l = new NativeFloat64Array(10); - a.setExternalArrayData(l); + a.setExternalArrayData(root, l); root.put("testArray", root, a); root.put("testArrayLength", root, 10); diff --git a/tests/src/test/java/org/mozilla/javascript/tests/ImportClassTest.java b/tests/src/test/java/org/mozilla/javascript/tests/ImportClassTest.java index e8a938cdbfb..3caa43a22f4 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/ImportClassTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/ImportClassTest.java @@ -17,8 +17,7 @@ import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.NativeJavaClass; import org.mozilla.javascript.Script; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; import org.mozilla.javascript.UniqueTag; import org.mozilla.javascript.drivers.TestUtils; import org.mozilla.javascript.testutils.Utils; @@ -80,7 +79,7 @@ public void importInSameContext() { public void importMultipleTimes() { Utils.runWithAllModes( cx -> { - ScriptableObject sharedScope = cx.initStandardObjects(); + TopLevel sharedScope = cx.initStandardObjects(); // sharedScope.sealObject(); // code below will try to modify sealed object Script script = @@ -88,10 +87,8 @@ public void importMultipleTimes() { "importClass(java.util.UUID);true", "TestScript", 1, null); for (int i = 0; i < 3; i++) { - Scriptable scope = new ImporterTopLevel(cx); - scope.setPrototype(sharedScope); - scope.setParentScope(null); - script.exec(cx, scope, scope); + var scope = ImporterTopLevel.createIsolate(cx, sharedScope); + script.exec(cx, scope, scope.getGlobalThis()); assertEquals(UniqueTag.NOT_FOUND, sharedScope.get("UUID", sharedScope)); assertTrue(scope.get("UUID", scope) instanceof NativeJavaClass); } diff --git a/tests/src/test/java/org/mozilla/javascript/tests/LambdaAccessorSlotTest.java b/tests/src/test/java/org/mozilla/javascript/tests/LambdaAccessorSlotTest.java index 749fcdcdb2f..fd551651882 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/LambdaAccessorSlotTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/LambdaAccessorSlotTest.java @@ -127,12 +127,14 @@ public void testRedefineExistingProperty() { sh.defineProperty("value", "oldValueOfValue", DONTENUM); - sh.defineProperty(cx, "value", (thisObj) -> "valueOfValue", null, DONTENUM); + sh.defineProperty( + cx, scope, "value", (thisObj) -> "valueOfValue", null, DONTENUM); - sh.defineProperty(cx, "status", (thisObj) -> 42, null, DONTENUM); + sh.defineProperty(cx, scope, "status", (thisObj) -> 42, null, DONTENUM); sh.defineProperty( cx, + scope, "status", (thisObj) -> self(thisObj).getStatus(), (thisObj, value) -> self(thisObj).setStatus(value), @@ -398,6 +400,7 @@ public void testRedefineExistingProperty_ChangingConfigurableAttr_ShouldFailVali () -> sh.defineProperty( cx, + scope, "status", (thisObj) -> self(thisObj).getStatus(), (thisObj, value) -> @@ -434,6 +437,7 @@ public void testRedefineExistingProperty_ChangingConfigurableAttr_ShouldFailVali () -> sh.defineProperty( cx, + scope, "status", (thisObj) -> self(thisObj).getStatus(), (thisObj, value) -> diff --git a/tests/src/test/java/org/mozilla/javascript/tests/NativeWrappedArrayTest.java b/tests/src/test/java/org/mozilla/javascript/tests/NativeWrappedArrayTest.java index 5c36b8f900d..7589af0ab39 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/NativeWrappedArrayTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/NativeWrappedArrayTest.java @@ -86,7 +86,7 @@ public void javaArray() throws IOException { public void customArray() throws IOException { ((ScriptableObject) global) .defineFunctionProperties( - new String[] {"makeCustomArray"}, NativeWrappedArrayTest.class, 0); + global, new String[] {"makeCustomArray"}, NativeWrappedArrayTest.class, 0); final String setFunc = "function makeTestArray() { return makeCustomArray(); }"; cx.evaluateString(global, setFunc, "setfunc.js", 1, null); @@ -108,7 +108,7 @@ public static Object makeCustomArray( a.add("two"); a.add("three"); a.add("four"); - return new WrappedArray(thisObj, a); + return new WrappedArray(fn.getDeclarationScope(), a); } static class WrappedArray extends ScriptableObject { diff --git a/tests/src/test/java/org/mozilla/javascript/tests/NestedContextPrototypeTest.java b/tests/src/test/java/org/mozilla/javascript/tests/NestedContextPrototypeTest.java index cfa775fc26b..fd4aa2cb119 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/NestedContextPrototypeTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/NestedContextPrototypeTest.java @@ -19,6 +19,7 @@ import org.mozilla.javascript.ContextFactory; import org.mozilla.javascript.EvaluatorException; import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.TopLevel; import org.mozilla.javascript.tools.shell.Global; /** @@ -105,14 +106,13 @@ private Object runScript(String scriptSourceText) { scope = context.newObject(global); break; case SEALED: - scope = context.newObject(global); - scope.setPrototype(global); - scope.setParentScope(null); + scope = TopLevel.createIsolate(global); break; case SEALED_OWN_OBJECTS: - scope = context.initStandardObjects(null); - scope.setPrototype(global); - scope.setParentScope(null); + scope = context.initStandardObjects(new TopLevel()); + ((TopLevel) scope) + .getGlobalThis() + .setPrototype(((TopLevel) global).getGlobalThis()); break; default: throw new UnsupportedOperationException(); diff --git a/tests/src/test/java/org/mozilla/javascript/tests/SealedSharedScopeTest.java b/tests/src/test/java/org/mozilla/javascript/tests/SealedSharedScopeTest.java index b2979157586..dbe44b2faef 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/SealedSharedScopeTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/SealedSharedScopeTest.java @@ -22,6 +22,7 @@ import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.JSFunction; import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.TopLevel; import org.mozilla.javascript.Wrapper; @RunWith(BlockJUnit4ClassRunner.class) @@ -41,12 +42,8 @@ public void setUp() throws Exception { ctx = Context.enter(); ctx.setLanguageVersion(Context.VERSION_DEFAULT); - scope1 = ctx.newObject(sharedScope); - scope1.setPrototype(sharedScope); - scope1.setParentScope(null); - scope2 = ctx.newObject(sharedScope); - scope2.setPrototype(sharedScope); - scope2.setParentScope(null); + scope1 = TopLevel.createIsolate(sharedScope); + scope2 = TopLevel.createIsolate(sharedScope); } @After diff --git a/tests/src/test/java/org/mozilla/javascript/tests/StrictModeApiTest.java b/tests/src/test/java/org/mozilla/javascript/tests/StrictModeApiTest.java index 0bec3fd7d04..193d01da757 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/StrictModeApiTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/StrictModeApiTest.java @@ -49,7 +49,12 @@ public void onlyGetterError() { ScriptableObject.defineClass(scope, MyHostObject.class); final Method readMethod = MyHostObject.class.getMethod("jsxGet_x"); prototype.defineProperty( - "readonlyProp", null, readMethod, null, ScriptableObject.EMPTY); + scope, + "readonlyProp", + null, + readMethod, + null, + ScriptableObject.EMPTY); ScriptableObject.defineProperty( scope, "o", prototype, ScriptableObject.DONTENUM); diff --git a/tests/src/test/java/org/mozilla/javascript/tests/Test262SuiteTest.java b/tests/src/test/java/org/mozilla/javascript/tests/Test262SuiteTest.java index 25a75e7151a..c6bea8c2d0c 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/Test262SuiteTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/Test262SuiteTest.java @@ -223,8 +223,8 @@ public static class $262 extends ScriptableObject { proto.defineProperty(scope, "evalScript", 1, $262::evalScript); proto.defineProperty(scope, "detachArrayBuffer", 0, $262::detachArrayBuffer); - proto.defineProperty(cx, "global", $262::getGlobal, null, DONTENUM | READONLY); - proto.defineProperty(cx, "agent", $262::getAgent, null, DONTENUM | READONLY); + proto.defineProperty(cx, scope, "global", $262::getGlobal, null, DONTENUM | READONLY); + proto.defineProperty(cx, scope, "agent", $262::getAgent, null, DONTENUM | READONLY); proto.defineProperty(SymbolKey.TO_STRING_TAG, "__262__", DONTENUM | READONLY); @@ -256,7 +256,7 @@ public static Object evalScript( } public static Object getGlobal(Scriptable scriptable) { - return scriptable.getParentScope(); + return ((TopLevel) scriptable.getParentScope()).getGlobalThis(); } public static $262 createRealm( diff --git a/tests/src/test/java/org/mozilla/javascript/tests/WriteReadOnlyPropertyTest.java b/tests/src/test/java/org/mozilla/javascript/tests/WriteReadOnlyPropertyTest.java index 366765c14c1..35fdfb7fd58 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/WriteReadOnlyPropertyTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/WriteReadOnlyPropertyTest.java @@ -49,8 +49,6 @@ public void writeReadOnly_throws() throws Exception { void testWriteReadOnly(final boolean acceptWriteReadOnly) throws Exception { final Method readMethod = Foo.class.getMethod("getMyProp", (Class[]) null); - final Foo foo = new Foo("hello"); - foo.defineProperty("myProp", null, readMethod, null, ScriptableObject.EMPTY); final String script = "foo.myProp = 123; foo.myProp"; @@ -67,6 +65,9 @@ protected boolean hasFeature(final Context cx, final int featureIndex) { contextFactory.call( cx -> { final ScriptableObject top = cx.initStandardObjects(); + final Foo foo = new Foo("hello"); + foo.defineProperty( + top, "myProp", null, readMethod, null, ScriptableObject.EMPTY); ScriptableObject.putProperty(top, "foo", foo); cx.evaluateString(top, script, "script", 0, null); diff --git a/tests/src/test/java/org/mozilla/javascript/tests/commonjs/module/ComplianceTest.java b/tests/src/test/java/org/mozilla/javascript/tests/commonjs/module/ComplianceTest.java index ecd86373675..cbbcb718ff4 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/commonjs/module/ComplianceTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/commonjs/module/ComplianceTest.java @@ -17,6 +17,7 @@ import org.mozilla.javascript.Function; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; import org.mozilla.javascript.commonjs.module.Require; import org.mozilla.javascript.commonjs.module.provider.StrongCachingModuleScriptProvider; import org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider; @@ -45,7 +46,7 @@ public static Collection data() { return retval; } - private static Require createRequire(File dir, Context cx, Scriptable scope) + private static Require createRequire(File dir, Context cx, TopLevel scope) throws URISyntaxException { return new Require( cx, @@ -68,7 +69,7 @@ private static Require createRequire(File dir, Context cx, Scriptable scope) public void require() throws Throwable { Utils.runWithAllModes( cx -> { - final Scriptable scope = cx.initStandardObjects(); + final TopLevel scope = cx.initStandardObjects(); ScriptableObject.putProperty(scope, "print", new Print(scope)); try { createRequire(testDir, cx, scope).requireMain(cx, "program"); diff --git a/tests/src/test/java/org/mozilla/javascript/tests/commonjs/module/RequireTest.java b/tests/src/test/java/org/mozilla/javascript/tests/commonjs/module/RequireTest.java index 1d961183ba0..9fd8b1f738d 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/commonjs/module/RequireTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/commonjs/module/RequireTest.java @@ -16,6 +16,7 @@ import org.mozilla.javascript.ScriptStackElement; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; import org.mozilla.javascript.commonjs.module.Require; import org.mozilla.javascript.commonjs.module.provider.StrongCachingModuleScriptProvider; import org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider; @@ -75,13 +76,13 @@ public String getClassName() { @Test public void customGlobal() throws Exception { try (Context cx = createContext()) { - final Scriptable scope = cx.initStandardObjects(); + final TopLevel scope = cx.initStandardObjects(); ScriptableObject.defineClass(scope, CustomGlobal.class); - final Scriptable global = cx.newObject(scope, "CustomGlobal", null); - - global.getPrototype().setPrototype(scope); - global.setParentScope(null); + var obj = cx.newObject(scope, "CustomGlobal", null); + obj.getPrototype().setPrototype(scope.getGlobalThis()); + final TopLevel global = + TopLevel.createIsolateCustomPrototypeChain(scope, (ScriptableObject) obj); final Require require = new Require( diff --git a/tests/src/test/java/org/mozilla/javascript/tests/es6/FunctionNullSetTest.java b/tests/src/test/java/org/mozilla/javascript/tests/es6/FunctionNullSetTest.java index 6ac3447ad48..8ae9c9d8c57 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/es6/FunctionNullSetTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/es6/FunctionNullSetTest.java @@ -38,6 +38,7 @@ public Object run(final Context cx) { final Method setterMethod = MyHostObject.class.getMethod("jsxSet_onclick", Object.class); prototype.defineProperty( + scope, "onclick", null, getterMethod, diff --git a/tests/src/test/java/org/mozilla/javascript/tests/es6/ParentPropertyTest.java b/tests/src/test/java/org/mozilla/javascript/tests/es6/ParentPropertyTest.java index 77ed228a90f..97123d3ce76 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/es6/ParentPropertyTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/es6/ParentPropertyTest.java @@ -18,7 +18,7 @@ public void parentGet() { // https://whereswalden.com/2010/05/07/spidermonkey-change-du-jour-the-special-__parent__-property-has-been-removed/ String script = "var a = {};" + "'' + a.__parent__;"; - Utils.assertWithAllModes_1_8("[object Object]", script); + Utils.assertWithAllModes_1_8("[object topLevel]", script); Utils.assertWithAllModes_ES6("undefined", script); } } diff --git a/tests/src/test/java/org/mozilla/javascript/tests/es6/PropertyTest.java b/tests/src/test/java/org/mozilla/javascript/tests/es6/PropertyTest.java index da233cb8470..e29ed61d9f1 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/es6/PropertyTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/es6/PropertyTest.java @@ -33,7 +33,7 @@ public void prototypeProperty() throws Exception { final Method getter = MyHostObject.class.getMethod("getFoo"); final Method setter = MyHostObject.class.getMethod("setFoo", String.class); myHostObject.defineProperty( - "foo", null, getter, setter, ScriptableObject.EMPTY); + scope, "foo", null, getter, setter, ScriptableObject.EMPTY); scope.put("MyHostObject", scope, myHostObject); } catch (Exception e) { } @@ -70,7 +70,7 @@ public void redefineGetterProperty() throws Exception { final Method getter = MyHostObject.class.getMethod("getFoo"); final Method setter = MyHostObject.class.getMethod("setFoo", String.class); myHostObject.defineProperty( - "foo", null, getter, setter, ScriptableObject.EMPTY); + scope, "foo", null, getter, setter, ScriptableObject.EMPTY); scope.put("MyHostObject", scope, myHostObject); } catch (Exception e) { } @@ -107,7 +107,7 @@ public void redefineSetterProperty() throws Exception { Method getter = MyHostObject.class.getMethod("getFoo"); final Method setter = MyHostObject.class.getMethod("setFoo", String.class); myHostObject.defineProperty( - "foo", null, getter, setter, ScriptableObject.EMPTY); + scope, "foo", null, getter, setter, ScriptableObject.EMPTY); scope.put("MyHostObject", scope, myHostObject); } catch (Exception e) { } @@ -146,7 +146,8 @@ public void redefinePropertyWithThreadSafeSlotMap() { // define custom getter method final Method getter = MyHostObject.class.getMethod("getFoo"); final Method setter = MyHostObject.class.getMethod("setFoo", String.class); - myHostObject.defineProperty("foo", null, getter, setter, ScriptableObject.EMPTY); + myHostObject.defineProperty( + scope, "foo", null, getter, setter, ScriptableObject.EMPTY); scope.put("MyHostObject", scope, myHostObject); } catch (Exception e) { } diff --git a/tests/src/test/java/org/mozilla/javascript/tests/type_info/CustomTypeInfoFactoryTest.java b/tests/src/test/java/org/mozilla/javascript/tests/type_info/CustomTypeInfoFactoryTest.java index 43ba811b639..c31dc2ceb2e 100644 --- a/tests/src/test/java/org/mozilla/javascript/tests/type_info/CustomTypeInfoFactoryTest.java +++ b/tests/src/test/java/org/mozilla/javascript/tests/type_info/CustomTypeInfoFactoryTest.java @@ -31,7 +31,7 @@ public void associate() throws Exception { var contextFactory = new ContextFactory(); try (var cx = contextFactory.enterContext()) { - var scope = new NativeObject(); + var scope = new TopLevel(); new NoGenericNoCacheFactory().associate(scope); cx.initStandardObjects(scope); @@ -59,7 +59,7 @@ public void serdeCustom() throws Exception { var contextFactory = new ContextFactory(); byte[] data; try (var cx = contextFactory.enterContext()) { - var scope = new NativeObject(); + var scope = new TopLevel(); new NoGenericNoCacheFactory().associate(scope); cx.initStandardObjects(scope); @@ -79,7 +79,7 @@ public void serdeGlobal() throws Exception { var contextFactory = new ContextFactory(); byte[] data; try (var cx = contextFactory.enterContext()) { - var scope = new NativeObject(); + var scope = new TopLevel(); TypeInfoFactory.GLOBAL.associate(scope); cx.initStandardObjects(scope); diff --git a/tests/testsrc/doctests/xmlOptions.doctest b/tests/testsrc/doctests/xmlOptions.doctest index bed5a3b5c62..bc9ce116e2c 100644 --- a/tests/testsrc/doctests/xmlOptions.doctest +++ b/tests/testsrc/doctests/xmlOptions.doctest @@ -9,11 +9,11 @@ js> x 1 -js> var xmlLib = org.mozilla.javascript.xml.XMLLib.extractFromScope(this); +js> var xmlLib = __xml_lib__; js> xmlLib.isPrettyPrinting(); true js> xmlLib.setPrettyPrinting(false); js> xmlLib.isPrettyPrinting(); false js> x -1 \ No newline at end of file +1