Call functions from cached scripts from few threads

143 views
Skip to first unread message

Александр Макаров

unread,
Jun 1, 2015, 8:29:03 AM6/1/15
to mozill...@googlegroups.com
I have using Rhino to call JS function from few files from few threads (any file from any thread).
For example I have few scripts with various implementations of "findResponse" method. And I want to call "findResponse" from script "1_handler" or "2_handler" relatively to response.
Also I have separate script with data to share to other "findResponse" implementors.
I have created:
1) `Scriptable` "globalScope": Used as common scope. Created one time with:

context = Context.enter();
globalScope = (Scriptable) context.initStandardObjects();
... (ScriptableObject.putProperty(globalScope, ...)

2) `HashMap<String, Scriptable>` "scopesCache". Used to store scriptable-per-file. Each `Scriptable` cached on first call (of function from file, in `cacheScript`):

Scriptable scriptScope = context.newObject(globalScope);
scriptScope.setParentScope(globalScope);
script.exec(context, scriptScope);
scopesCache.put("xxx", scriptScope);

Used as (`callFunctionInGlobalScope`):

Scriptable thisScope = scopesCache.get(...);
Object calledFunction = thisScope.get(funcName, thisScope);
((Function) calledFunction).call(context, globalScope, thisScope, funcArgs);


On last line I catch:

java.lang.IllegalStateException: null
at org.mozilla.javascript.ScriptRuntime.storeScriptable(ScriptRuntime.java:4197) ~[runner.jar:2.7.0-SNAPSHOT]
at org.mozilla.javascript.ScriptRuntime.getPropFunctionAndThisHelper(ScriptRuntime.java:2426) ~[runner.jar:2.7.0-SNAPSHOT]
at org.mozilla.javascript.ScriptRuntime.getPropFunctionAndThis(ScriptRuntime.java:2405) ~[runner.jar:2.7.0-SNAPSHOT]
at xxx ~[na:na]
at xxx ~[na:na]
at xxx callFunctionInGlobalScope(JavaScriptManager.java:170) ~[runner.jar:2.7.0-SNAPSHOT]

As I see it related to [`scratchScriptable` in context](https://github.com/mozilla/rhino/blob/master/src/org/mozilla/javascript/ScriptRuntime.java#L4202)
Repro is not 100%. If try to run it manually not reproduced at all. But on intensive using it reproduced oftenly.

--

[In Issue 195 on GitHub](https://github.com/mozilla/rhino/issues/195) **eshepelyuk** proposed to catch scripts instead of scopes. I have tried to implement it with changing:

`scopesCache` changed to `HashMap<String, Script>`,

`cacheScript` changed to `scopesCache.put("xxx", script);`

`callFunctionInGlobalScope` changed to:

Scriptable thisScope = context.newObject(globalScope);
thisScope.setParentScope(globalScope);
script.exec(context, thisScope);
Object calledFunction = thisScope.get(funcName, thisScope);
((Function) calledFunction).call(context, globalScope, thisScope, funcArgs);

But in this case I see performance degradation (about 5-10 times), seems like it related to `script.exec` in `callFunctionInGlobalScope`.

Can you have any ideas - how to fix issue or implement first varaiant (cache scopes) thread-safe?

Evgeny Shepelyuk

unread,
Jun 1, 2015, 2:47:56 PM6/1/15
to mozill...@googlegroups.com
Hello

1. I would also recommend to carefully read Rhino scopes tutorial
2. With this code it's not clear why do you want to execute all functions in global scope instead of calling them on each scope.
3, From the presented code it is not clear about exact usage scenario, so it really hard to provide proper answers.

понеділок, 1 червня 2015 р. 15:29:03 UTC+3 користувач Александр Макаров написав:

Александр Макаров

unread,
Jun 2, 2015, 4:56:31 AM6/2/15
to mozill...@googlegroups.com
1. Thank you. I will read it one more time.
2, 3) You can see full code here: https://drive.google.com/folderview?id=0BwTbzXydRX2RfjlrM3JJY19QbUdIeG1XWWtWY2pBUDV4dUp3QUh2UmJNb01CdVk3dFJpYnc&usp=sharing
It is first variant from init post (caching scopes).

JavaScriptManager.java:
- `callFunctionInScript` called from few threads.
localeData.js:
- `setLocale` called on start to set locale (with `callFunctionInScript`).
- `Global.getString` and `Global.getLocale` used in `meHandler.js`. `Global` here - see JavaScriptManager:30.
meHandler.js:
- `findResponse` example of `findResponse`. Called many times from various threads (with `callFunctionInScript`). There are few scripts with `findResponse` implementation.

Note: correction with cahing `Script`-s instead of `Scope`-s is worse solution - IllegalStateException still here plus it worked in 5-10 times slowly.


Александр Макаров

unread,
Jun 2, 2015, 5:14:31 AM6/2/15
to mozill...@googlegroups.com
Some words about chosen structure: I want to move out whole `findResponse`-s logic from Java code to JavaScript. But locale in this case should be specified for each `findResponse` and one time - on initialization. I won't execute all functions in global scope directly but I need in shared JavaScript data storage.

Evgeny Shepelyuk

unread,
Jun 2, 2015, 5:16:56 AM6/2/15
to mozill...@googlegroups.com
Is it possible to put this code as GitHub Project ?

вівторок, 2 червня 2015 р. 11:56:31 UTC+3 користувач Александр Макаров написав:

Александр Макаров

unread,
Jun 2, 2015, 5:26:29 AM6/2/15
to mozill...@googlegroups.com
Seems like no. Because project is big and private. I only can say that `findResponse`-s used by HTTP server to handle responses from single client.

Evgeny Shepelyuk

unread,
Jun 2, 2015, 6:52:41 AM6/2/15
to mozill...@googlegroups.com
Well, sorry, I can't get the idea of this code and what problem it tries to solve, So unfortunately I will be unable to advice anything useful on Rhino scope usage setup :(

вівторок, 2 червня 2015 р. 12:26:29 UTC+3 користувач Александр Макаров написав:

Александр Макаров

unread,
Jun 2, 2015, 7:10:27 AM6/2/15
to mozill...@googlegroups.com
Emm... Idea - execute JS function with same name from few files and from few threads.

Result - "IllegalStateException: null" inside Rhino here https://github.com/mozilla/rhino/blob/master/src/org/mozilla/javascript/ScriptRuntime.java#L4202
It looks like bug, because has not any description and has not 100% repro (reproduced on heavy load, seems like).

In "Scopes And Contests" tutorial, "Scopes" article I see:
It's important to understand that a scope is independent of the Context that created it. You can create a scope using one Context and then evaluate a script using that scope and another Context (either by exiting the current context and entering another, or by executing on a different thread). You can even execute scripts on multiple threads simultaneously in the same scope. Rhino guarantees that accesses to properties of JavaScript objects are atomic across threads, but doesn't make any more guarantees for scripts executing in the same scope at the same time.

I can guarantee that few threads not used same scope at the same time.

Александр Макаров

unread,
Jun 8, 2015, 5:01:53 AM6/8/15
to mozill...@googlegroups.com

I can guarantee that few threads not used same scope at the same time.

After detailed investigation (and "script-to-repro-issue-in-few-seconds") exactly this has been wrong. Sorry for wrong information.
Due investigation I get described above and other exceptions with error message "null" but seems like all of them related to concurrently using 'callFunctionInGlobalScope' by few threads.

Fix is "synchronized" modifier for 'callFunctionInGlobalScope' (1 variant of code described in inital post and in attached class JavaScriptManager).

Evgeny - thank you for "vector to check".
Reply all
Reply to author
Forward
0 new messages