Skip to content

Commit 810ccbc

Browse files
authored
Refactor global.spawn method
* Add testcase for global.spawn method * Simplified the spawn function and added a submit function
1 parent 8e69a72 commit 810ccbc

File tree

2 files changed

+87
-51
lines changed

2 files changed

+87
-51
lines changed

rhino-tools/src/main/java/org/mozilla/javascript/tools/shell/Global.java

Lines changed: 37 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -519,39 +519,56 @@ private boolean doctestOutputMatches(String expected, String actual) {
519519
/**
520520
* The spawn function runs a given function or script in a different thread.
521521
*
522-
* <p>js&gt; function g() { a = 7; } js&gt; a = 3; 3 js&gt; spawn(g) Thread[Thread-1,5,main]
523-
* js&gt; a 3
522+
* <pre>
523+
* js&gt; function g() { a = 7; }
524+
* js&gt; a = 3; 3
525+
* js&gt; spawn(g) Thread[Thread-1,5,main]
526+
* js&gt; a 7
527+
* </pre>
524528
*/
525529
public static Object spawn(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
526530
Scriptable scope = funObj.getParentScope();
527-
Runner runner;
531+
ContextAction<?> action = getAsyncAction(cx, args, scope);
532+
ContextFactory factory = cx.getFactory();
533+
Thread thread = new Thread(() -> factory.call(action));
534+
thread.start();
535+
return cx.getWrapFactory().wrap(cx, scope, thread, Thread.class);
536+
}
537+
538+
private static ContextAction<Object> getAsyncAction(
539+
Context cx, Object[] args, Scriptable scope) {
540+
ContextAction<Object> action;
528541
if (args.length != 0 && args[0] instanceof Function) {
529-
Object[] newArgs = null;
530-
if (args.length > 1 && args[1] instanceof Scriptable) {
531-
newArgs = cx.getElements((Scriptable) args[1]);
532-
}
533-
if (newArgs == null) {
534-
newArgs = ScriptRuntime.emptyArgs;
535-
}
536-
runner = new Runner(scope, (Function) args[0], newArgs);
542+
Function f = (Function) args[0];
543+
Object[] newArgs =
544+
args.length > 1 && args[1] instanceof Scriptable
545+
? cx.getElements((Scriptable) args[1])
546+
: ScriptRuntime.emptyArgs;
547+
action = cx2 -> f.call(cx2, scope, scope, newArgs);
537548
} else if (args.length != 0 && args[0] instanceof Script) {
538-
runner = new Runner(scope, (Script) args[0]);
549+
Script s = (Script) args[0];
550+
action = cx2 -> s.exec(cx2, scope, scope);
539551
} else {
540552
throw reportRuntimeError("msg.spawn.args");
541553
}
542-
runner.factory = cx.getFactory();
543-
Thread thread = new Thread(runner);
544-
thread.start();
545-
return thread;
554+
return action;
546555
}
547556

548557
/**
549558
* The sync function creates a synchronized function (in the sense of a Java synchronized
550559
* method) from an existing function. The new function synchronizes on the the second argument
551-
* if it is defined, or otherwise the <code>this</code> object of its invocation. js&gt; var o =
552-
* { f : sync(function(x) { print("entry"); Packages.java.lang.Thread.sleep(x*1000);
553-
* print("exit"); })}; js&gt; spawn(function() {o.f(5);}); Thread[Thread-0,5,main] entry js&gt;
554-
* spawn(function() {o.f(5);}); Thread[Thread-1,5,main] js&gt; exit entry exit
560+
* if it is defined, or otherwise the <code>this</code> object of its invocation.
561+
*
562+
* <pre>
563+
* js&gt; var o = { f : sync(function(x) {
564+
* print("entry");
565+
* Packages.java.lang.Thread.sleep(x*1000);
566+
* print("exit");
567+
* })};
568+
* js&gt; spawn(function() {o.f(5);}); Thread[Thread-0,5,main] entry
569+
* js&gt; spawn(function() {o.f(5);}); Thread[Thread-1,5,main]
570+
* js&gt; exit entry exit
571+
* </pre>
555572
*/
556573
public static Object sync(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
557574
if (args.length >= 1 && args.length <= 2 && args[0] instanceof Function) {
@@ -885,34 +902,3 @@ public interface CommandExecutor {
885902
Process exec(String[] cmdarray, String[] envp, File dir) throws IOException;
886903
}
887904
}
888-
889-
class Runner implements Runnable, ContextAction<Object> {
890-
891-
Runner(Scriptable scope, Function func, Object[] args) {
892-
this.scope = scope;
893-
f = func;
894-
this.args = args;
895-
}
896-
897-
Runner(Scriptable scope, Script script) {
898-
this.scope = scope;
899-
s = script;
900-
}
901-
902-
@Override
903-
public void run() {
904-
factory.call(this);
905-
}
906-
907-
@Override
908-
public Object run(Context cx) {
909-
if (f != null) return f.call(cx, scope, scope, args);
910-
else return s.exec(cx, scope, scope);
911-
}
912-
913-
ContextFactory factory;
914-
private Scriptable scope;
915-
private Function f;
916-
private Script s;
917-
private Object[] args;
918-
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.mozilla.javascript.tools.tests;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
7+
import org.junit.jupiter.api.Test;
8+
import org.mozilla.javascript.Context;
9+
import org.mozilla.javascript.Script;
10+
import org.mozilla.javascript.testutils.Utils;
11+
import org.mozilla.javascript.tools.shell.Global;
12+
13+
/**
14+
* Testcases for <code>global.spawn</code>.
15+
*
16+
* @author Roland Praml, Foconis Analytics GmbH
17+
*/
18+
public class GlobalSpawnTest {
19+
20+
@Test
21+
public void testSpawnFunction() {
22+
String cmd = "function g(f) { a = a * f }; a = 5; var t = spawn(g, [2]); t.join(); a";
23+
Utils.runWithAllModes(
24+
cx -> {
25+
cx.setLanguageVersion(Context.VERSION_ES6);
26+
var g = new Global(cx);
27+
var result = cx.evaluateString(g, cmd, "test.js", 1, null);
28+
assertInstanceOf(Number.class, result);
29+
assertEquals(10, ((Number) result).intValue());
30+
return null;
31+
});
32+
}
33+
34+
@Test
35+
public void testSpawnScript() {
36+
String cmd = "a = 5; var t = spawn(script); t.join(); a";
37+
Utils.runWithAllModes(
38+
cx -> {
39+
cx.setLanguageVersion(Context.VERSION_ES6);
40+
var g = new Global(cx);
41+
var script = cx.compileString("a *= 2", "script.js", 1, null);
42+
assertTrue(script instanceof Script);
43+
g.put("script", g, script);
44+
var result = cx.evaluateString(g, cmd, "test.js", 1, null);
45+
assertInstanceOf(Number.class, result);
46+
assertEquals(10, ((Number) result).intValue());
47+
return null;
48+
});
49+
}
50+
}

0 commit comments

Comments
 (0)