diff --git a/common/src/main/java/dev/latvian/mods/rhino/ArrowFunction.java b/common/src/main/java/dev/latvian/mods/rhino/ArrowFunction.java index 1a8b30ea..81e8ab5e 100644 --- a/common/src/main/java/dev/latvian/mods/rhino/ArrowFunction.java +++ b/common/src/main/java/dev/latvian/mods/rhino/ArrowFunction.java @@ -39,7 +39,7 @@ public ArrowFunction(Context cx, Scriptable scope, Callable targetFunction, Scri @Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { Scriptable callThis = boundThis != null ? boundThis : cx.getTopCallOrThrow(); - return targetFunction.call(cx, scope, callThis, args); + return cx.callSync(targetFunction, scope, callThis, args); } @Override diff --git a/common/src/main/java/dev/latvian/mods/rhino/Context.java b/common/src/main/java/dev/latvian/mods/rhino/Context.java index 5915054d..b025043d 100644 --- a/common/src/main/java/dev/latvian/mods/rhino/Context.java +++ b/common/src/main/java/dev/latvian/mods/rhino/Context.java @@ -21,10 +21,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.io.PrintWriter; import java.io.Reader; -import java.io.StringWriter; -import java.io.Writer; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; @@ -57,30 +54,10 @@ @SuppressWarnings("ThrowableNotThrown") public class Context { - public static final String errorReporterProperty = "error reporter"; - public static Context enter() { return new Context(); } - /** - * Call {@link - * Callable#call(Context cx, Scriptable scope, Scriptable thisObj, - * Object[] args)} - * using the Context instance associated with the current thread. - * If no Context is associated with the thread, then - * {@link ContextFactory#makeContext()} will be called to construct - * new Context instance. The instance will be temporary associated - * with the thread during call to {@link ContextAction#run(Context)}. - *

- * It is allowed but not advisable to use null for factory - * argument in which case the global static singleton ContextFactory - * instance will be used to create new context instances. - */ - public static Object call(Context cx, final Callable callable, final Scriptable scope, final Scriptable thisObj, final Object[] args) { - return callable.call(cx, scope, thisObj, args); - } - /** * Report a warning using the error reporter for the current thread. * @@ -108,17 +85,6 @@ public static void reportWarning(String message, Context cx) { Context.reportWarning(cx, message, filename, linep[0], null, 0); } - public static void reportWarning(Context cx, String message, Throwable t) { - int[] linep = {0}; - String filename = getSourcePositionFromStack(cx, linep); - Writer sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - pw.println(message); - t.printStackTrace(pw); - pw.flush(); - Context.reportWarning(cx, sw.toString(), filename, linep[0], null, 0); - } - /** * Report an error using the error reporter for the current thread. * @@ -336,6 +302,8 @@ public static String getSourcePositionFromStack(Context cx, int[] linep) { return null; } + public final Object lock = new Object(); + // Generate an observer count on compiled code public boolean generateObserverCount = false; private Scriptable topCallScope; @@ -631,95 +599,6 @@ public final Object evaluateReader(Scriptable scope, Reader in, String sourceNam return null; } - /** - * Execute script that may pause execution by capturing a continuation. - * Caller must be prepared to catch a ContinuationPending exception - * and resume execution by calling - * {@link #resumeContinuation(Object, Scriptable, Object)}. - * - * @param script The script to execute. Script must have been compiled - * with interpreted mode (optimization level -1) - * @param scope The scope to execute the script against - * @throws ContinuationPending if the script calls a function that results - * in a call to {@link #captureContinuation()} - * @since 1.7 Release 2 - */ - public Object executeScriptWithContinuations(Script script, Scriptable scope) throws ContinuationPending { - if (!(script instanceof InterpretedFunction) || !((InterpretedFunction) script).isScript()) { - // Can only be applied to scripts - throw new IllegalArgumentException("Script argument was not" + " a script or was not created by interpreted mode "); - } - return callFunctionWithContinuations((InterpretedFunction) script, scope, ScriptRuntime.EMPTY_OBJECTS); - } - - /** - * Call function that may pause execution by capturing a continuation. - * Caller must be prepared to catch a ContinuationPending exception - * and resume execution by calling - * {@link #resumeContinuation(Object, Scriptable, Object)}. - * - * @param function The function to call. The function must have been - * compiled with interpreted mode (optimization level -1) - * @param scope The scope to execute the script against - * @param args The arguments for the function - * @throws ContinuationPending if the script calls a function that results - * in a call to {@link #captureContinuation()} - * @since 1.7 Release 2 - */ - public Object callFunctionWithContinuations(Callable function, Scriptable scope, Object[] args) throws ContinuationPending { - if (!(function instanceof InterpretedFunction)) { - // Can only be applied to scripts - throw new IllegalArgumentException("Function argument was not" + " created by interpreted mode "); - } - if (hasTopCallScope()) { - throw new IllegalStateException("Cannot have any pending top " + "calls when executing a script with continuations"); - } - // Annotate so we can check later to ensure no java code in - // intervening frames - isContinuationsTopCall = true; - return ScriptRuntime.doTopCall(this, scope, function, scope, args, isTopLevelStrict); - } - - /** - * Capture a continuation from the current execution. The execution must - * have been started via a call to - * {@link #executeScriptWithContinuations(Script, Scriptable)} or - * {@link #callFunctionWithContinuations(Callable, Scriptable, Object[])}. - * This implies that the code calling - * this method must have been called as a function from the - * JavaScript script. Also, there cannot be any non-JavaScript code - * between the JavaScript frames (e.g., a call to eval()). The - * ContinuationPending exception returned must be thrown. - * - * @return A ContinuationPending exception that must be thrown - * @since 1.7 Release 2 - */ - public ContinuationPending captureContinuation() { - return new ContinuationPending(Interpreter.captureContinuation(this)); - } - - /** - * Restarts execution of the JavaScript suspended at the call - * to {@link #captureContinuation()}. Execution of the code will resume - * with the functionResult as the result of the call that captured the - * continuation. - * Execution of the script will either conclude normally and the - * result returned, another continuation will be captured and - * thrown, or the script will terminate abnormally and throw an exception. - * - * @param continuation The value returned by - * {@link ContinuationPending#getContinuation()} - * @param functionResult This value will appear to the code being resumed - * as the result of the function that captured the continuation - * @throws ContinuationPending if another continuation is captured before - * the code terminates - * @since 1.7 Release 2 - */ - public Object resumeContinuation(Object continuation, Scriptable scope, Object functionResult) throws ContinuationPending { - Object[] args = {functionResult}; - return Interpreter.restartContinuation((NativeContinuation) continuation, this, scope, args); - } - /** * Compiles the source in the given reader. *

@@ -1176,18 +1055,6 @@ public void addToScope(Scriptable scope, String name, Object value) { } } - /** - * Execute top call to script or function. - * When the runtime is about to execute a script or function that will - * create the first stack frame with scriptable code, it calls this method - * to perform the real call. In this way execution of any script - * happens inside this function. - */ - protected Object doTopCall(Callable callable, Scriptable scope, Scriptable thisObj, Object[] args) { - Object result = callable.call(this, scope, thisObj, args); - return result instanceof ConsString ? result.toString() : result; - } - // custom data /** @@ -1359,37 +1226,100 @@ public final void setWrapFactory(WrapFactory wrapFactory) { this.wrapFactory = wrapFactory; } - public synchronized boolean hasTopCallScope() { - return topCallScope != null; + public boolean hasTopCallScope() { + synchronized (lock) { + return topCallScope != null; + } } - public synchronized Scriptable getTopCallScope() { - return topCallScope; + public Scriptable getTopCallScope() { + synchronized (lock) { + return topCallScope; + } } - public synchronized Scriptable getTopCallOrThrow() { - if (topCallScope == null) { - throw new IllegalStateException(); + public Scriptable getTopCallOrThrow() { + synchronized (lock) { + if (topCallScope == null) { + throw new IllegalStateException(); + } + + return topCallScope; } + } - return topCallScope; + public void setTopCall(Scriptable scope) { + synchronized (lock) { + topCallScope = scope; + } } - public synchronized void setTopCall(Scriptable scope) { - topCallScope = scope; + public void storeScriptable(Scriptable value) { + synchronized (lock) { + // The previously stored scratchScriptable should be consumed + if (scratchScriptable != null) { + throw new IllegalStateException(); + } + scratchScriptable = value; + } } - public synchronized void storeScriptable(Scriptable value) { - // The previously stored scratchScriptable should be consumed - if (scratchScriptable != null) { - throw new IllegalStateException(); + public Scriptable lastStoredScriptable() { + synchronized (lock) { + Scriptable result = scratchScriptable; + scratchScriptable = null; + return result; + } + } + + /** + * Call {@link + * Callable#call(Context cx, Scriptable scope, Scriptable thisObj, + * Object[] args)} + * using the Context instance associated with the current thread. + * If no Context is associated with the thread, then makeContext() will be called to construct + * new Context instance. The instance will be temporary associated + * with the thread during call to {@link ContextAction#run(Context)}. + *

+ * It is allowed but not advisable to use null for factory + * argument in which case the global static singleton ContextFactory + * instance will be used to create new context instances. + */ + public Object callSync(Callable callable, Scriptable scope, Scriptable thisObj, Object[] args) { + synchronized (lock) { + return callable.call(this, scope, thisObj, args); } - scratchScriptable = value; } - public synchronized Scriptable lastStoredScriptable() { - Scriptable result = scratchScriptable; - scratchScriptable = null; + public Object doTopCall(Scriptable scope, Callable callable, Scriptable thisObj, Object[] args, boolean isTopLevelStrict) { + if (scope == null) { + throw new IllegalArgumentException(); + } + if (hasTopCallScope()) { + throw new IllegalStateException(); + } + + Object result; + setTopCall(ScriptableObject.getTopLevelScope(scope)); + boolean previousTopLevelStrict = this.isTopLevelStrict; + this.isTopLevelStrict = isTopLevelStrict; + try { + result = callSync(callable, scope, thisObj, args); + + if (result instanceof ConsString) { + result = result.toString(); + } + } finally { + setTopCall(null); + // Cleanup cached references + this.isTopLevelStrict = previousTopLevelStrict; + + if (currentActivationCall != null) { + // Function should always call exitActivationFunction + // if it creates activation record + throw new IllegalStateException(); + } + } return result; } } diff --git a/common/src/main/java/dev/latvian/mods/rhino/ContinuationPending.java b/common/src/main/java/dev/latvian/mods/rhino/ContinuationPending.java deleted file mode 100644 index 54b22ad5..00000000 --- a/common/src/main/java/dev/latvian/mods/rhino/ContinuationPending.java +++ /dev/null @@ -1,84 +0,0 @@ -/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package dev.latvian.mods.rhino; - -import java.io.Serial; - -/** - * Exception thrown by - * {@link Context#executeScriptWithContinuations(Script, Scriptable)} - * and {@link Context#callFunctionWithContinuations(Callable, Scriptable, Object[])} - * when execution encounters a continuation captured by - * {@link Context#captureContinuation()}. - * Exception will contain the captured state needed to restart the continuation - * with {@link Context#resumeContinuation(Object, Scriptable, Object)}. - * - * @author Norris Boyd - */ -public class ContinuationPending extends RuntimeException { - @Serial - private static final long serialVersionUID = 4956008116771118856L; - private NativeContinuation continuationState; - private Object applicationState; - - /** - * Construct a ContinuationPending exception. Internal call only; - * users of the API should get continuations created on their behalf by - * calling {@link Context#executeScriptWithContinuations(Script, Scriptable)} - * and {@link Context#callFunctionWithContinuations(Callable, Scriptable, Object[])} - * Creating subclasses allowed. - * - * @param continuationState Internal Continuation object - */ - protected ContinuationPending(NativeContinuation continuationState) { - this.continuationState = continuationState; - } - - /** - * Get continuation object. The only - * use for this object is to be passed to - * {@link Context#resumeContinuation(Object, Scriptable, Object)}. - * - * @return continuation object - */ - public Object getContinuation() { - return continuationState; - } - - /** - * Set continuation object. Allows subclasses to modify the internal state. - * - * @param continuation object - */ - public void setContinuation(NativeContinuation continuation) { - this.continuationState = continuation; - } - - /** - * @return internal continuation state - */ - NativeContinuation getContinuationState() { - return continuationState; - } - - /** - * @return arbitrary application state - */ - public Object getApplicationState() { - return applicationState; - } - - /** - * Store an arbitrary object that applications can use to associate - * their state with the continuation. - * - * @param applicationState arbitrary application state - */ - public void setApplicationState(Object applicationState) { - this.applicationState = applicationState; - } -} diff --git a/common/src/main/java/dev/latvian/mods/rhino/ES6Generator.java b/common/src/main/java/dev/latvian/mods/rhino/ES6Generator.java index fee11b17..b1ec0fe8 100644 --- a/common/src/main/java/dev/latvian/mods/rhino/ES6Generator.java +++ b/common/src/main/java/dev/latvian/mods/rhino/ES6Generator.java @@ -151,7 +151,7 @@ private Scriptable resumeDelegee(Context cx, Scriptable scope, Object value) { Callable nextFn = ScriptRuntime.getPropFunctionAndThis(cx, scope, delegee, ES6Iterator.NEXT_METHOD); Scriptable nextThis = cx.lastStoredScriptable(); - Object nr = nextFn.call(cx, scope, nextThis, nextArgs); + Object nr = cx.callSync(nextFn, scope, nextThis, nextArgs); Scriptable nextResult = ScriptableObject.ensureScriptable(nr, cx); if (ScriptRuntime.isIteratorDone(cx, nextResult)) { @@ -179,7 +179,7 @@ private Scriptable resumeDelegeeThrow(Context cx, Scriptable scope, Object value // Delegate to "throw" method. If it's not defined we'll get an error here. Callable throwFn = ScriptRuntime.getPropFunctionAndThis(cx, scope, delegee, "throw"); Scriptable nextThis = cx.lastStoredScriptable(); - Object throwResult = throwFn.call(cx, scope, nextThis, new Object[]{value}); + Object throwResult = cx.callSync(throwFn, scope, nextThis, new Object[]{value}); if (ScriptRuntime.isIteratorDone(cx, throwResult)) { // Iterator is "done". @@ -385,7 +385,7 @@ private Object callReturnOptionally(Context cx, Scriptable scope, Object value) if (!(retFnObj instanceof Callable)) { throw ScriptRuntime.typeError2(cx, "msg.isnt.function", ES6Iterator.RETURN_METHOD, ScriptRuntime.typeof(cx, retFnObj)); } - return ((Callable) retFnObj).call(cx, scope, ensureScriptable(delegee, cx), retArgs); + return cx.callSync((Callable) retFnObj, scope, ensureScriptable(delegee, cx), retArgs); } return null; } diff --git a/common/src/main/java/dev/latvian/mods/rhino/EqualObjectGraphs.java b/common/src/main/java/dev/latvian/mods/rhino/EqualObjectGraphs.java index ecde4ead..f58daa83 100644 --- a/common/src/main/java/dev/latvian/mods/rhino/EqualObjectGraphs.java +++ b/common/src/main/java/dev/latvian/mods/rhino/EqualObjectGraphs.java @@ -239,9 +239,7 @@ private boolean equalScriptables(Context cx, final Scriptable s1, final Scriptab } // Handle special Scriptable implementations - if (s1 instanceof NativeContinuation s3) { - return s2 instanceof NativeContinuation s4 && NativeContinuation.equalImplementations(s3, s4); - } else if (s1 instanceof IdFunctionObject s3) { + if (s1 instanceof IdFunctionObject s3) { return s2 instanceof IdFunctionObject s4 && IdFunctionObject.equalObjectGraphs(cx, s3, s4, this); } else if (s1 instanceof ArrowFunction s3) { return s2 instanceof ArrowFunction s4 && ArrowFunction.equalObjectGraphs(cx, s3, s4, this); diff --git a/common/src/main/java/dev/latvian/mods/rhino/InterfaceAdapter.java b/common/src/main/java/dev/latvian/mods/rhino/InterfaceAdapter.java index b5e7d179..9d4fe9e0 100644 --- a/common/src/main/java/dev/latvian/mods/rhino/InterfaceAdapter.java +++ b/common/src/main/java/dev/latvian/mods/rhino/InterfaceAdapter.java @@ -84,11 +84,7 @@ private InterfaceAdapter(Context cx, Class cl) { this.proxyHelper = VMBridge.getInterfaceProxyHelper(cx, new Class[]{cl}); } - public Object invoke(Context cx, final Object target, final Scriptable topScope, final Object thisObject, final Method method, final Object[] args) { - return invokeImpl(cx, target, topScope, thisObject, method, args); - } - - Object invokeImpl(Context cx, Object target, Scriptable topScope, Object thisObject, Method method, Object[] args) { + public Object invoke(Context cx, Object target, Scriptable topScope, Object thisObject, Method method, Object[] args) { Callable function; if (target instanceof Callable) { function = (Callable) target; @@ -126,7 +122,7 @@ Object invokeImpl(Context cx, Object target, Scriptable topScope, Object thisObj } Scriptable thisObj = wf.wrapAsJavaObject(cx, topScope, thisObject, null); - Object result = function.call(cx, topScope, thisObj, args); + Object result = cx.callSync(function, topScope, thisObj, args); Class javaResultType = method.getReturnType(); if (javaResultType == Void.TYPE) { result = null; diff --git a/common/src/main/java/dev/latvian/mods/rhino/InterpretedFunction.java b/common/src/main/java/dev/latvian/mods/rhino/InterpretedFunction.java index b40a4e69..3d3a7c4a 100644 --- a/common/src/main/java/dev/latvian/mods/rhino/InterpretedFunction.java +++ b/common/src/main/java/dev/latvian/mods/rhino/InterpretedFunction.java @@ -67,7 +67,7 @@ public String getFunctionName() { @Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!cx.hasTopCallScope()) { - return ScriptRuntime.doTopCall(cx, scope, this, thisObj, args, idata.isStrict); + return cx.doTopCall(scope, this, thisObj, args, idata.isStrict); } return Interpreter.interpret(this, cx, scope, thisObj, args); } @@ -80,7 +80,7 @@ public Object exec(Context cx, Scriptable scope) { } if (!cx.hasTopCallScope()) { // It will go through "call" path. but they are equivalent - return ScriptRuntime.doTopCall(cx, scope, this, scope, ScriptRuntime.EMPTY_OBJECTS, idata.isStrict); + return cx.doTopCall(scope, this, scope, ScriptRuntime.EMPTY_OBJECTS, idata.isStrict); } return Interpreter.interpret(this, cx, scope, scope, ScriptRuntime.EMPTY_OBJECTS); } diff --git a/common/src/main/java/dev/latvian/mods/rhino/Interpreter.java b/common/src/main/java/dev/latvian/mods/rhino/Interpreter.java index 1234e0a1..5522b5cb 100644 --- a/common/src/main/java/dev/latvian/mods/rhino/Interpreter.java +++ b/common/src/main/java/dev/latvian/mods/rhino/Interpreter.java @@ -235,7 +235,7 @@ public boolean equals(Object other) { return equalsInTopScope(otherCallFrame); } final Scriptable top = ScriptableObject.getTopLevelScope(scope); - return (Boolean) ScriptRuntime.doTopCall(localContext, top, (c, scope, thisObj, args) -> equalsInTopScope(otherCallFrame), top, ScriptRuntime.EMPTY_OBJECTS, isStrictTopFrame()); + return (Boolean) localContext.doTopCall(top, (c, scope, thisObj, args) -> equalsInTopScope(otherCallFrame), top, ScriptRuntime.EMPTY_OBJECTS, isStrictTopFrame()); //} finally { // Context.exit(); //} @@ -279,59 +279,6 @@ private boolean fieldsEqual(CallFrame other, EqualObjectGraphs equal, Context cx } } - private static final class ContinuationJump { - CallFrame capturedFrame; - CallFrame branchFrame; - Object result; - double resultDbl; - - ContinuationJump(NativeContinuation c, CallFrame current) { - this.capturedFrame = (CallFrame) c.getImplementation(); - if (this.capturedFrame == null || current == null) { - // Continuation and current execution does not share - // any frames if there is nothing to capture or - // if there is no currently executed frames - this.branchFrame = null; - } else { - // Search for branch frame where parent frame chains starting - // from captured and current meet. - CallFrame chain1 = this.capturedFrame; - CallFrame chain2 = current; - - // First work parents of chain1 or chain2 until the same - // frame depth. - int diff = chain1.frameIndex - chain2.frameIndex; - if (diff != 0) { - if (diff < 0) { - // swap to make sure that - // chain1.frameIndex > chain2.frameIndex and diff > 0 - chain1 = current; - chain2 = this.capturedFrame; - diff = -diff; - } - do { - chain1 = chain1.parentFrame; - } while (--diff != 0); - if (chain1.frameIndex != chain2.frameIndex) { - Kit.codeBug(); - } - } - - // Now walk parents in parallel until a shared frame is found - // or until the root is reached. - while (chain1 != chain2 && chain1 != null) { - chain1 = chain1.parentFrame; - chain2 = chain2.parentFrame; - } - - this.branchFrame = chain1; - if (this.branchFrame != null && !this.branchFrame.frozen) { - Kit.codeBug(); - } - } - } - } - private static boolean compareIdata(InterpreterData i1, InterpreterData i2) { return i1 == i2; } @@ -444,30 +391,6 @@ public static Object resumeGenerator(Context cx, Scriptable scope, int operation return result; } - public static Object restartContinuation(NativeContinuation c, Context cx, Scriptable scope, Object[] args) { - if (!cx.hasTopCallScope()) { - return ScriptRuntime.doTopCall(cx, scope, c, null, args, cx.isTopLevelStrict); - } - - Object arg; - if (args.length == 0) { - arg = Undefined.instance; - } else { - arg = args[0]; - } - - CallFrame capturedFrame = (CallFrame) c.getImplementation(); - if (capturedFrame == null) { - // No frames to restart - return arg; - } - - ContinuationJump cjump = new ContinuationJump(c, null); - - cjump.result = arg; - return interpretLoop(cx, null, cjump); - } - private static Object interpretLoop(Context cx, CallFrame frame, Object throwable) { // throwable holds exception object to rethrow or catch // It is also used for continuation restart in which case @@ -510,7 +433,7 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl // reestablish this call frame enterFrame(cx, frame, ScriptRuntime.EMPTY_OBJECTS, true); throwable = null; - } else if (!(throwable instanceof ContinuationJump)) { + } else { // It should be continuation Kit.codeBug(); } @@ -1033,30 +956,7 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl continue StateLoop; } - if (fun instanceof NativeContinuation) { - // Jump to the captured continuation - ContinuationJump cjump; - cjump = new ContinuationJump((NativeContinuation) fun, frame); - - // continuation result is the first argument if any - // of continuation call - if (indexReg == 0) { - cjump.result = undefined; - } else { - cjump.result = stack[stackTop + 2]; - cjump.resultDbl = sDbl[stackTop + 2]; - } - - // Start the real unwind job - throwable = cjump; - break withoutExceptions; - } - if (fun instanceof IdFunctionObject ifun) { - if (NativeContinuation.isContinuationConstructor(ifun)) { - frame.stack[stackTop] = captureContinuation(cx, frame.parentFrame, false); - continue; - } // Bug 405654 -- make best effort to keep Function.apply and // Function.call within this interpreter loop invocation if (BaseFunction.isApplyOrCall(ifun)) { @@ -1113,13 +1013,6 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl throw ScriptRuntime.notFunctionError(cx, lhs); } - if (fun instanceof IdFunctionObject ifun) { - if (NativeContinuation.isContinuationConstructor(ifun)) { - frame.stack[stackTop] = captureContinuation(cx, frame.parentFrame, false); - continue; - } - } - Object[] outArgs = getArgsArray(stack, sDbl, stackTop + 1, indexReg); stack[stackTop] = fun.construct(cx, frame.scope, outArgs); continue; @@ -1500,7 +1393,6 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl final int EX_NO_JS_STATE = 0; // Terminate JS execution int exState; - ContinuationJump cjump = null; if (generatorState != null && generatorState.operation == GeneratorState.GENERATOR_CLOSE && throwable == generatorState.value) { exState = EX_FINALLY_STATE; @@ -1511,16 +1403,10 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl exState = EX_CATCH_STATE; } else if (throwable instanceof EvaluatorException) { exState = EX_CATCH_STATE; - } else if (throwable instanceof ContinuationPending) { - exState = EX_NO_JS_STATE; } else if (throwable instanceof RuntimeException) { exState = EX_FINALLY_STATE; } else if (throwable instanceof Error) { exState = EX_NO_JS_STATE; - } else if (throwable instanceof ContinuationJump) { - // It must be ContinuationJump - exState = EX_FINALLY_STATE; - cjump = (ContinuationJump) throwable; } else { exState = EX_FINALLY_STATE; } @@ -1535,7 +1421,6 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl // Error from instruction counting // => unconditionally terminate JS throwable = ex; - cjump = null; exState = EX_NO_JS_STATE; } } @@ -1560,30 +1445,8 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl if (frame == null) { break; } - if (cjump != null && cjump.branchFrame == frame) { - // Continuation branch point was hit, - // restart the state loop to reenter continuation - indexReg = -1; - continue StateLoop; - } } - // No more frames, rethrow the exception or deal with continuation - if (cjump != null) { - if (cjump.branchFrame != null) { - // The above loop should locate the top frame - Kit.codeBug(); - } - if (cjump.capturedFrame != null) { - // Restarting detached continuation - indexReg = -1; - continue; - } - // Return continuation result to the caller - interpreterResult = cjump.result; - interpreterResultDbl = cjump.resultDbl; - throwable = null; - } break; } // end of StateLoop: for(;;) @@ -1997,68 +1860,6 @@ private static CallFrame processThrowable(Context cx, Object throwable, CallFram frame.stack[exLocal] = throwable; throwable = null; - } else { - // Continuation restoration - ContinuationJump cjump = (ContinuationJump) throwable; - - // Clear throwable to indicate that exceptions are OK - throwable = null; - - if (cjump.branchFrame != frame) { - Kit.codeBug(); - } - - // Check that we have at least one frozen frame - // in the case of detached continuation restoration: - // unwind code ensure that - if (cjump.capturedFrame == null) { - Kit.codeBug(); - } - - // Need to rewind branchFrame, capturedFrame - // and all frames in between - int rewindCount = cjump.capturedFrame.frameIndex + 1; - if (cjump.branchFrame != null) { - rewindCount -= cjump.branchFrame.frameIndex; - } - - int enterCount = 0; - CallFrame[] enterFrames = null; - - CallFrame x = cjump.capturedFrame; - for (int i = 0; i != rewindCount; ++i) { - if (!x.frozen) { - Kit.codeBug(); - } - if (x.useActivation) { - if (enterFrames == null) { - // Allocate enough space to store the rest - // of rewind frames in case all of them - // would require to enter - enterFrames = new CallFrame[rewindCount - i]; - } - enterFrames[enterCount] = x; - ++enterCount; - } - x = x.parentFrame; - } - - while (enterCount != 0) { - // execute enter: walk enterFrames in the reverse - // order since they were stored starting from - // the capturedFrame, not branchFrame - --enterCount; - x = enterFrames[enterCount]; - enterFrame(cx, x, ScriptRuntime.EMPTY_OBJECTS, true); - } - - // Continuation jump is almost done: capturedFrame - // points to the call to the function that captured - // continuation, so clone capturedFrame and - // emulate return that function with the suplied result - frame = cjump.capturedFrame.cloneFrozen(); - setCallResult(frame, cjump.result, cjump.resultDbl); - // restart the execution } frame.throwable = throwable; return frame; @@ -2214,57 +2015,6 @@ private static void setCallResult(CallFrame frame, Object callResult, double cal frame.savedCallOp = 0; } - public static NativeContinuation captureContinuation(Context cx) { - if (cx.lastInterpreterFrame == null || !(cx.lastInterpreterFrame instanceof CallFrame)) { - throw new IllegalStateException("Interpreter frames not found"); - } - return captureContinuation(cx, (CallFrame) cx.lastInterpreterFrame, true); - } - - private static NativeContinuation captureContinuation(Context cx, CallFrame frame, boolean requireContinuationsTopFrame) { - NativeContinuation c = new NativeContinuation(); - ScriptRuntime.setObjectProtoAndParent(cx, cx.getTopCallOrThrow(), c); - - // Make sure that all frames are frozen - CallFrame x = frame; - CallFrame outermost = frame; - while (x != null && !x.frozen) { - x.frozen = true; - // Allow to GC unused stack space - for (int i = x.savedStackTop + 1; i != x.stack.length; ++i) { - // Allow to GC unused stack space - x.stack[i] = null; - x.stackAttributes[i] = ScriptableObject.EMPTY; - } - if (x.savedCallOp == Token.CALL) { - // the call will always overwrite the stack top with the result - x.stack[x.savedStackTop] = null; - } else { - if (x.savedCallOp != Token.NEW) { - Kit.codeBug(); - } - // the new operator uses stack top to store the constructed - // object so it shall not be cleared: see comments in - // setCallResult - } - outermost = x; - x = x.parentFrame; - } - - if (requireContinuationsTopFrame) { - while (outermost.parentFrame != null) { - outermost = outermost.parentFrame; - } - - if (!outermost.isContinuationsTopFrame) { - throw new IllegalStateException("Cannot capture continuation " + "from JavaScript code not called directly by " + "executeScriptWithContinuations or " + "callFunctionWithContinuations"); - } - } - - c.initImplementation(frame); - return c; - } - private static int stack_int32(CallFrame frame, int i, Context cx) { Object x = frame.stack[i]; if (x == UniqueTag.DOUBLE_MARK) { diff --git a/common/src/main/java/dev/latvian/mods/rhino/JavaMembers.java b/common/src/main/java/dev/latvian/mods/rhino/JavaMembers.java index c4cd2a8e..062fdd8e 100644 --- a/common/src/main/java/dev/latvian/mods/rhino/JavaMembers.java +++ b/common/src/main/java/dev/latvian/mods/rhino/JavaMembers.java @@ -341,7 +341,7 @@ public void put(Scriptable scope, String name, Object javaObject, Object value, } } else { Object[] args = {value}; - bp.setters.call(cx, ScriptableObject.getTopLevelScope(scope), scope, args); + cx.callSync(bp.setters, ScriptableObject.getTopLevelScope(scope), scope, args); } } else { if (!(member instanceof Field field)) { diff --git a/common/src/main/java/dev/latvian/mods/rhino/LazilyLoadedCtor.java b/common/src/main/java/dev/latvian/mods/rhino/LazilyLoadedCtor.java deleted file mode 100644 index 1767419f..00000000 --- a/common/src/main/java/dev/latvian/mods/rhino/LazilyLoadedCtor.java +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package dev.latvian.mods.rhino; - -import java.lang.reflect.InvocationTargetException; - -/** - * Avoid loading classes unless they are used. - * - *

This improves startup time and average memory usage. - */ -public final class LazilyLoadedCtor { - private static final int STATE_BEFORE_INIT = 0; - private static final int STATE_INITIALIZING = 1; - private static final int STATE_WITH_VALUE = 2; - - @SuppressWarnings({"unchecked"}) - private static Class cast(Class cl) { - return (Class) cl; - } - - private final ScriptableObject scope; - private final String propertyName; - private final String className; - private final boolean sealed; - private final boolean privileged; - private Object initializedValue; - private int state; - - public LazilyLoadedCtor(ScriptableObject scope, String propertyName, String className, boolean sealed, Context cx) { - this(scope, propertyName, className, sealed, false, cx); - } - - LazilyLoadedCtor(ScriptableObject scope, String propertyName, String className, boolean sealed, boolean privileged, Context cx) { - - this.scope = scope; - this.propertyName = propertyName; - this.className = className; - this.sealed = sealed; - this.privileged = privileged; - this.state = STATE_BEFORE_INIT; - - scope.addLazilyInitializedValue(cx, propertyName, 0, this, ScriptableObject.DONTENUM); - } - - void init(Context cx) { - synchronized (this) { - if (state == STATE_INITIALIZING) { - throw new IllegalStateException("Recursive initialization for " + propertyName); - } - if (state == STATE_BEFORE_INIT) { - state = STATE_INITIALIZING; - // Set value now to have something to set in finally block if - // buildValue throws. - Object value = Scriptable.NOT_FOUND; - try { - value = buildValue(cx); - } finally { - initializedValue = value; - state = STATE_WITH_VALUE; - } - } - } - } - - Object getValue() { - if (state != STATE_WITH_VALUE) { - throw new IllegalStateException(propertyName); - } - return initializedValue; - } - - private Object buildValue(Context cx) { - //if (privileged) { - // return AccessController.doPrivileged((PrivilegedAction) () -> buildValue0()); - //} - return buildValue0(cx); - } - - private Object buildValue0(Context cx) { - Class cl = cast(Kit.classOrNull(className)); - if (cl != null) { - try { - Object value = ScriptableObject.buildClassCtor(scope, cl, sealed, false, cx); - if (value != null) { - return value; - } - // cl has own static initializer which is expected - // to set the property on its own. - value = scope.get(cx, propertyName, scope); - if (value != Scriptable.NOT_FOUND) { - return value; - } - } catch (InvocationTargetException ex) { - Throwable target = ex.getTargetException(); - if (target instanceof RuntimeException) { - throw (RuntimeException) target; - } - } catch (RhinoException | InstantiationException | IllegalAccessException | SecurityException ex) { - } - } - return Scriptable.NOT_FOUND; - } - -} diff --git a/common/src/main/java/dev/latvian/mods/rhino/MemberBox.java b/common/src/main/java/dev/latvian/mods/rhino/MemberBox.java index e9906fb0..b75232f3 100644 --- a/common/src/main/java/dev/latvian/mods/rhino/MemberBox.java +++ b/common/src/main/java/dev/latvian/mods/rhino/MemberBox.java @@ -177,9 +177,6 @@ Object invoke(Object target, Object[] args, Context cx, Scriptable scope) { do { e = ((InvocationTargetException) e).getTargetException(); } while ((e instanceof InvocationTargetException)); - if (e instanceof ContinuationPending) { - throw (ContinuationPending) e; - } throw Context.throwAsScriptRuntimeEx(e, cx); } catch (Exception ex) { throw Context.throwAsScriptRuntimeEx(ex, cx); diff --git a/common/src/main/java/dev/latvian/mods/rhino/NativeContinuation.java b/common/src/main/java/dev/latvian/mods/rhino/NativeContinuation.java deleted file mode 100644 index bc93da4c..00000000 --- a/common/src/main/java/dev/latvian/mods/rhino/NativeContinuation.java +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package dev.latvian.mods.rhino; - -import java.util.Objects; - -public final class NativeContinuation extends IdScriptableObject implements Function { - private static final Object FTAG = "Continuation"; - private static final int Id_constructor = 1; - private static final int MAX_PROTOTYPE_ID = 1; - - public static void init(Context cx, Scriptable scope, boolean sealed) { - NativeContinuation obj = new NativeContinuation(); - obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed, cx); - } - - public static boolean isContinuationConstructor(IdFunctionObject f) { - return f.hasTag(FTAG) && f.methodId() == Id_constructor; - } - - /** - * Returns true if both continuations have equal implementations. - * - * @param c1 one continuation - * @param c2 another continuation - * @return true if the implementations of both continuations are equal, or they are both null. - * @throws NullPointerException if either continuation is null - */ - public static boolean equalImplementations(NativeContinuation c1, NativeContinuation c2) { - return Objects.equals(c1.implementation, c2.implementation); - } - - private Object implementation; - - public Object getImplementation() { - return implementation; - } - - public void initImplementation(Object implementation) { - this.implementation = implementation; - } - - @Override - public String getClassName() { - return "Continuation"; - } - - @Override - public Scriptable construct(Context cx, Scriptable scope, Object[] args) { - throw Context.reportRuntimeError("Direct call is not supported", cx); - } - - @Override - public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { - return Interpreter.restartContinuation(this, cx, scope, args); - } - - // #string_id_map# - - @Override - protected void initPrototypeId(int id, Context cx) { - String s; - int arity; - if (id == Id_constructor) { - arity = 0; - s = "constructor"; - } else { - throw new IllegalArgumentException(String.valueOf(id)); - } - initPrototypeMethod(FTAG, id, s, arity, cx); - } - - @Override - public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { - if (!f.hasTag(FTAG)) { - return super.execIdCall(f, cx, scope, thisObj, args); - } - int id = f.methodId(); - if (id == Id_constructor) { - throw Context.reportRuntimeError("Direct call is not supported", cx); - } - throw new IllegalArgumentException(String.valueOf(id)); - } - - @Override - protected int findPrototypeId(String s) { - return switch (s) { - case "constructor" -> Id_constructor; - default -> 0; - }; - } - - // #/string_id_map# -} diff --git a/common/src/main/java/dev/latvian/mods/rhino/NativeScript.java b/common/src/main/java/dev/latvian/mods/rhino/NativeScript.java deleted file mode 100644 index fc696d5f..00000000 --- a/common/src/main/java/dev/latvian/mods/rhino/NativeScript.java +++ /dev/null @@ -1,163 +0,0 @@ -/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package dev.latvian.mods.rhino; - -/** - * The JavaScript Script object. - *

- * Note that the C version of the engine uses XDR as the format used - * by freeze and thaw. Since this depends on the internal format of - * structures in the C runtime, we cannot duplicate it. - *

- * Since we cannot replace 'this' as a result of the compile method, - * will forward requests to execute to the nonnull 'script' field. - * - * @author Norris Boyd - * @since 1.3 - */ - -class NativeScript extends BaseFunction { - private static final Object SCRIPT_TAG = "Script"; - private static final int Id_constructor = 1; - private static final int Id_toString = 2; - private static final int Id_compile = 3; - private static final int Id_exec = 4; - private static final int MAX_PROTOTYPE_ID = 4; - - static void init(Scriptable scope, boolean sealed, Context cx) { - NativeScript obj = new NativeScript(null); - obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed, cx); - } - - private static NativeScript realThis(Scriptable thisObj, IdFunctionObject f, Context cx) { - if (!(thisObj instanceof NativeScript)) { - throw incompatibleCallError(f, cx); - } - return (NativeScript) thisObj; - } - - private static Script compile(Context cx, String source) { - int[] linep = {0}; - String filename = Context.getSourcePositionFromStack(cx, linep); - if (filename == null) { - filename = "