Sharing native JavaScript objects across contexts
Vivin Suresh Paliath
vivin.paliath at gmail.com
Tue Dec 8 16:04:10 UTC 2015
I have a Nashorn engine in which I evaluate some scripts that expose some
common utility functions and objects. I want custom scripts to run in their
own contexts and not step over each other, so I create new contexts for
them using engine.createBindings():
ScriptContext newContext = new SimpleScriptContext();
newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
newContext.getBindings(ScriptContext.ENGINE_SCOPE).putAll(engine.getBindings(ScriptContext.ENGINE_SCOPE));
Now I have access to everything that was created in the original scope, but
this also creates an entirely-new global-object for the new context, which
means that instances of native JS objects like Object, Number, etc. are
different from corresponding instances in the original context.
This leads to some strange behavior. For example, assume you have the
following code that was evaluated in the engine (i.e., the "parent"
context"):
function foo(obj) {
print(JSON.stringify(obj, null, 4));
print(Object.getPrototypeOf(obj) === Object.prototype);}
Now let's say your custom script is as follows:
function bar() {
foo({a: 10, b: 20});}
I evaluate this against newContext and then invoke the function:
engine.eval(source, newContext);ScriptObjectMirror foo =
newContext.getAttribute("foo", ScriptContext.ENGINE_SCOPE);
foo.call(null);
This returns:
undefinedfalse
This is expected behavior
<https://bugs.openjdk.java.net/browse/JDK-8067642> because
objects created in other contexts are treated as foreign objects.
What I'm trying to do is to expose a common library of functions and
maintain that within a single script-engine instance. I don't want to keep
recreating script-engine instances because I end up losing JIT
optimizations (I read this somewhere, but I can't find the link right now).
I do like the fact that objects "remember" their originating
global-context, but I'd like that not to happen in the case of native JS
objects.
Is there a way to create an entirely-new global context, while still
sharing JS global-object instances? I've tried manually copying over these
instances (enumerating the properties of this), but when I copy them over
to the new context, they are ScriptObjectMirror instances and not the
unwrapped versions. I assume this is because they were originally created
in a different context and therefore are considered to be "foreign".
I'm also open to doing this in a completely different manner. I looked at
using --global-per-engine, but I noticed that anything exposed by the
custom script seemed to end up in the main context instead of the new
context that I have created. In general I'm just looking for a way to have
isolated execution contexts while still sharing native JS object instances
across these contexts.
Thanks!
--
Ruin untold;
And thine own sadness,
Sing in the grass,
When eve has forgot, that no more hear common things that gleam and pass;
But seek alone to lip, sad Rose of love and ruin untold;
And thine own mother
Can know it as I know
More than another
What makes your own sadness,
Set in her eyes.
map{@n=split//;$j.=$n[0]x$n[1]}split/:/,"01:11:02".
":11:01:11:02:13:01:11:01:11:01:13:02:12:01:13:01".
":11:04:11:06:12:04:11:01:12:01:13:02:12:01:14:01".
":13:01:11:03:12:01:11:04:12:02:11:01:11:01:13:02".
":11:03:11:06:11:01:11:05:12:02:11:01:11:01:13:02".
":11:02:12:01:12:04:11:06:12:01:11:04:12:04:11:01".
":12:03:12:01:12:01:11:01:12:01:12:02:11:01:11:01".
":13:02:11:01:02:11:01:12:02";map{print chr unpack"
i",pack"B32",$_}$j=~m/.{8}/g
More information about the nashorn-dev
mailing list