Reusing compiled JS code keeping speed and thread-safety

yikes aroni yikesaroni at gmail.com
Thu Oct 30 14:24:18 UTC 2014


Thanks for the response Hannes. Is it possible to reuse a single
ScriptEngine without polluting its scopes/bindings? To be clear, consider
this process:

1) Get a ScriptEngine

2) Precompile a "library" script into ENGINE scope (or GLOBAL?). Do this
once and never again.

     This "library" script has functions, etc., that other, "local" scripts
need to run

3) Using the same (?) engine, eval() other scripts that use functions/vars
in the "library"

     Do (3) over and over and over with a wide variety of scripts without
polluting the scope in which the "library" lives with the variables of the
previous scripts that have run.

Is this possible? Again, my requirement (i.e., fond hope) is that a) i not
have to re-compile the "library" script; and that b) the scope not be
polluted with the local script's variables, etc.

Again, thanks!

On Thu, Oct 30, 2014 at 9:53 AM, Hannes Wallnoefer <
hannes.wallnoefer at oracle.com> wrote:

> Hi,
>
> The main requirement for reusing compiled scripts is to use a single
> script engine. You can use multiple JS environments/globals within a script
> engine by using multiple bindings/script contexts. The nashorn script
> engine implements javax.script.Compilable, so you can use the compile
> methods to get a CompiledScript that can be evaluated with multiple
> bindings or script contexts.
>
> http://docs.oracle.com/javase/7/docs/api/javax/script/Compilable.html
>
> Also, we have been improving reuse of compiled scripts since the initial
> JDK8 release, so later versions of Nashorn may work better. You probably
> should use JDK 8u20 or even a 8u40 preview release (avalable at <
> https://jdk8.java.net/>). In those releases, we have added caching of
> compiled scripts within the script engine, so even plain eval() should be
> faster as long as you use multiple globals/bindings within the same engine.
>
> I hope this helps. Let us know how it goes!
>
> Hannes
>
> Am 2014-10-30 um 14:09 schrieb yikes aroni:
>
>> Hi ... I’m using nashorn by embedding it in Java (not via command-line). I
>> can make it work, but I have a two primary challenges: 1) speed of
>> execution; and 2) thread safety.
>>
>>
>>
>> I have a “base” JS library that I compile more or less like this:
>>
>>
>>
>> ScriptEngineManager *factory* = *new* ScriptEngineManager();
>>
>>         ScriptEngine *baseEngine* = *factory*.getEngineByName("nashorn");
>>
>> Compilable *baseCompilable* = (Compilable) *baseEngine*;
>>
>> baseCompilable.compile(*new* java.io.FileReader(*pathDsBase*)).eval();
>>
>>
>>
>> where *pathDsBase* is a file system path to my javascript library. This
>> library isn’t huge, but it takes about 500+ ms to compile and eval().
>> That’s a long time for my purposes, so I want to do it only once.
>>
>>
>>
>> Other parts of my code then launch multiple Java threads that do various
>> work and occasionally invoke small, “temporary” Javascript scripts that
>> need to reference objects and functions in this “base” library. Since I
>> want these small scripts to run fast and thread-safe, I **could** simply
>> create a brand new ScriptEngine every time I want to run one of these
>> small, “temporary” scripts and recompile the base library into it. Problem
>> with that is that it takes too much time.
>>
>>
>>
>> I’ve tried a lot of approaches -- none have worked.
>>
>>
>>
>> My main approach (which has failed miserably at every turn) is to create a
>> “base” ScriptEngine, compile the “base” library into it, then create a
>> “temporary” ScriptEngine and attempt to set  the base bindings / context
>> to
>> it so that the temp ScriptEngine only eval()s the “temp” script, but has
>> the base library in scope. For example something like this  test code:
>>
>>
>>
>>         ScriptEngine tempEngine =  engineFactory.getScriptEngine(); // a
>> temporary engine. This is the one that will evaluate the “small” scripts
>> that reference the “base” script library.
>>
>> ScriptContext ctxBase = *new* SimpleScriptContext();
>>
>>         ctxBase.setBindings(baseEngine.createBindings(), ScriptContext.
>> *GLOBAL_SCOPE*);
>>
>>         // evaluate a script at add it to base’s context. This is where
>> the
>> “base” script libraries would be eval()-ed into the baseEngine context.
>>
>> baseEngine.eval("var y = 'hello';", ctxBase);
>>
>>
>>
>>                  // Now attempt to set the baseEngine’s bindings (which I
>> assume have y = “hello” in them (since I’m not clear where they end up,
>> I’ve tried every possible combination or ENGINE and GLOBAL scope.)
>>
>>         ScriptContext ctxTemp = *new* SimpleScriptContext();
>>
>>         ctxTemp.setBindings(baseEngine.createBindings(), ScriptContext.
>> *ENGINE_SCOPE*);
>>
>>
>>
>>         // Now for the temporary, “small” script. The print references a
>> variable (y) that I had hoped would be set to the temp engine’s scope from
>> the “base” engine’s context.
>>
>>         String script = "var x = 'world'; print(y + x);";
>>
>>         tempEngine.eval(script, ctxTemp);
>>
>>
>>
>> Exception is Exception in thread "main" *javax.script.ScriptException*:
>> ReferenceError: "y" is not defined in <eval> at line number 1
>>
>>
>>
>> I’ve also tried using loadWithNewGlobal, which solves the threading issue,
>> but doesn’t appear to solve the speed issue: the script has to be
>> recompiled every time.
>>
>>
>>
>> I am sure I am barking up the wrong tree. Can somebody help point me in
>> the
>> right direction for how to do this? Again, my two primary questions are:
>>
>>
>>
>> 1) (Speed) Generally, how do I make it so that I don’t have to re-eval() a
>> large library every time I want to run a script that references it? Or,
>> more specifically, how can I reuse code compiled (eval()ed) by one engine
>> (“base”) in another engine (“temp”)?
>>
>> 2) (Thread-safety) How do I reuse such a library in a way that running the
>> subsequent “temp” scripts doesn’t pollute the “base” bindings that I’m
>> reusing?
>>
>>
>>
>> I will be overjoyed if there is a clean solution to this. If not, I will
>> still be happy to clear up this mystery with a “can’t do that...” if that
>> is, in fact, the answer....
>>
>>
>>
>> thanks
>>
>
>


More information about the nashorn-dev mailing list