Attila,
On 11/12/13 11:30, Attila Szegedi wrote:
Admittedly, I've not been working a lot with the scoping/multiple
globals/javax.script API side of the project; Sundar is probably the
one with best insight here (I've mostly worked on dynamic linking and
Java platform APIs, and am lately focused on bytecode compiler and
performance improvements targetted for the first post-8.0 update).
Having said that, I think it should be fairly easy to implement a
CommonJS require() function within a single ScriptEngine instance,
using separate ENGINE_SCOPE level bindings for loading each module and
having them use a single global (setting the "--global-per-engine"
flag that you can pass to one of NashornScriptEngine.getEngine()
overloads that takes a String[] args).
As far as I know, when multiple engine scopes in a single ScriptEngine
are sharing a single Global (effectively recreating the "MGN" model
from <http://wiki.commonjs.org/wiki/Modules/ProposalForNativeExtension>),
Confused...
I assumed that if two scripts where run with their own script context,
then they would already have separate globals, i.e. if I do
myglobal = 1
in module 1 that won't be visible in module 2.
So I'm not sure really what --global-per-engine really means, if the
modules have their own globals anyway. I guess my understanding must be
wrong somewhere.
those scopes can accept each others' objects without
ScriptObjectMirror wrapping. (ScriptObject-> ScriptObjectMirror
wrapping only happens for scopes that don't share the Global object).
You could execute every module with separate engine scope bindings
(setting those bindings up with "require", "export", "module"
variables for that module.) thus achieving isolation of their
namespaces except for the built-in globals.
The obvious limitation of the approach is that execution within a
single ScriptEngine is not threadsafe. In a multithreaded system you'd
have to make sure they're either thread local, or access to them is
synchronized. And you'd have your modules be loaded separately into
every ScriptEngine. I'm not familiar with Vert.x architecture; I know
folks working on Avatar.js didn't have problems with implementing
require() in their system, but their system is single-threaded.
ScriptObjectMirror is obviously not as capable as ScriptObject. Mind
you, I'm not using "obviously" meaning "it should've been obvious to
everyone" but rather in the sense of "obvious now that you have
stumbled across it". The reality of product development scheduling is
that we can't address it in the current phase (see
<http://openjdk.java.net/projects/jdk8/milestones>) even if we decided
that it should be addressed. In ideal world, a mirror wouldn't be
needed, but due to JavaScript's inherent entanglement of execution
semantics with a set of highly mutable built-ins (Function, String,
Array, etc.) they currently seem like a necessity when crossing Global
boundaries.
I'd suggest you try to work with an approach that avoids creation of
mirrors - where each ScriptEngine instance is an isolated execution
context organized around a Global (this is true for JavaScript
runtimes in general). Mirrors are an attempt on our part to provide
cross-Global usage of JS objects, but as you have found out, they
aren't complete first-class citizens when they end up in a different
Global environments.
The abovementioned approach with "--global-per-engine",
single-threaded usage of every engine instance, and use of separate
ENGINE_SCOPE bindings in the engine using ScriptEngine.setBindings()
is the best I can recommend at the moment.
Attila.
On Dec 10, 2013, at 9:16 PM, Tim Fox <[email protected]
<mailto:[email protected]>> wrote:
Attila-
Perhaps a more fundamental question is, is what I am trying to do
(implement commonJS require) really possible in Vanilla Nashorn?
I did notice this post by you in December 2012:
http://mail.openjdk.java.net/pipermail/nashorn-dev/2012-December/000014.html
I understand there is no intention to implement require() directly in
Nashorn, but my previous understanding was that it should be possible
to implement it myself on top of Nashorn given that I can create
different scopes and pass JS objects between them. After my recent
experiments I'm not sure that understanding is really correct!
What's your view on this?
On 10/12/13 19:49, Tim Fox wrote:
Sorry for the deluge of posts, but I think I've found another issue
with scopes/ScriptObjectMirror.
Consider this case: https://gist.github.com/purplefox/7896892
I have a simple JS object which contains a function 'setCallback'
which simply delegates to a Java object which also has a setCallback
method.
Calling this method works fine from within the same scope that it
was created in.
However, if I export the object to another scope - wrapping in
ScriptObjectMirror as advised (and this is exactly the kind of thing
I would need to do to implement CommonJS require in Nashorn), and
then try to call the setCallback method from there, it yields the
following exception:
java.lang.ClassCastException: Cannot cast
jdk.nashorn.api.scripting.ScriptObjectMirror to java.lang.Runnable
at
sun.invoke.util.ValueConversions.newClassCastException(ValueConversions.java:461)
at
sun.invoke.util.ValueConversions.castReference(ValueConversions.java:456)
at jdk.nashorn.internal.scripts.Script$\^eval\_._L2(<eval>:3)
at
jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:500)
at
jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:207)
at
jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:378)
at
jdk.nashorn.api.scripting.ScriptObjectMirror.call(ScriptObjectMirror.java:107)
at jdk.nashorn.internal.scripts.Script$\^eval\_.runScript(<eval>:1)
at
jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:498)
at
jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:207)
at
jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:378)
at
jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:544)
at
jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:526)
at
jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:522)
at
jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:193)
at
org.vertx.java.platform.impl.HandlerScopeTest.run(HandlerScopeTest.java:48)
at
org.vertx.java.platform.impl.HandlerScopeTest.main(HandlerScopeTest.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at
com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)