Developer API docs

Sundararajan Athijegannathan sundararajan.athijegannathan at oracle.com
Fri Oct 16 02:56:49 UTC 2015


Hi Tal Liron,

Sorry about missing reply for this email. I somehow remember replying 
similar nashorn internal usage email.
It is difficult maintain all of jdk.nashorn.internal.* between versions. 
Also, with security manager around, jdk.nashorn.internal.* are not 
accessible without explicit 'package access' RuntimePermission. In 
addition, with jdk9, nashorn module exports only jdk.nashorn.api.* 
packages. i.e., even without any security manager, user code won't be 
able to access nashorn internal implementation classes. It is possible 
to use jdk.nashorn.api.scripting.JSObject to get constructors and create 
objecs.

JSObject numberConstructor = (JSObject) engine.eval("Number");
JSObject numberObj = numberConstructor.newObject();

Is it not possible to work with these? Please check out latest 8u-dev 
code. Mostly explicit wrap/unwrap won't be required from user's code.

Thanks,
-Sundar

On 10/15/2015 10:21 PM, Tal Liron wrote:
> Hey guys, nobody ever responded to my message...
>
> Do you really think that my usage of these internal Nashorn APIs is so 
> unwarranted?
>
> I tried to prove that some useful libraries need to use Nashorn APIs 
> that some of you insist should not be made public.
>
> On 07/06/2015 09:10 PM, Tal Liron wrote:
>> Hi Atilla (and Sundar and everyone else, really),
>>
>> You asked which Nashorn APIs I'm using that are not documented. I 
>> will reply in full detail.
>>
>> For the BSON/JSON codecs, the most important thing is to access the 
>> NativeBoolean, NativeNumber, NativeArray, ConsString, Undefined, 
>> etc., classes. This allows the codecs to check for these classes 
>> incoming, and also to easily create instances of them using their 
>> constructor() static method.
>>
>> ScriptObject has no constructor(), so I use 
>> Global.newEmptyInstance(). (By the way: NativeDate and NativeArray 
>> name the method construct() instead of constructor(). I assume this 
>> is a consistency mistake.)
>>
>> But I also need to access their data. This means get()/set() for 
>> NativeScriptObject and NativeArray, getOwnKeys(), getArray() (which 
>> means I need access to the ArrayData class), and also getTime() for 
>> NativeData. NativeRegExp is a bit harder, but I use get("source"), 
>> get("multiline"), etc.
>>
>> (In Rhino, some of these classes are actually private! This required 
>> an awkward workaround: I do a string equality check on the classname. 
>> That's neither efficient nor portable, though more "dynamic", I 
>> guess. Also, for these classes I can use Context.newObject() to 
>> create instances by JS name, for example "RegExp". Then I can do 
>> ScriptableObject.callMethod() to access their internals. So, there 
>> are workarounds to not being to able to access them.)
>>
>> ScriptObjectMirror is awkward. Though it's stable and documented, the 
>> issue with unwrap() is that it needs a global. Documented, but of 
>> course unclear what to do! For me, this actually means calling 
>> Context.getGlobal(), which is not publicly documented. (Another issue 
>> is that, of course, unwrap won't work for other globals. This has 
>> created difficulties in some threaded environments in which multiple 
>> globals are used intentionally. More on that below.)
>>
>> So much for BSON/JSON. The Scripturian implementation of Nashorn is 
>> much more complex. As you may know, Scripturian is a rethinking of 
>> and alternative to JSR-223, so it has to do much of the same work.
>>
>> Scripturian works by purposely creating different global instances 
>> for each "execution context" (which *can* be a thread, but doesn't 
>> have to be: it's an abstraction over, well, execution contexts). I 
>> use Context.createGlobal(), and set it via Context.setGlobal().
>>
>> We then need to compile scripts in the Context, so I use 
>> Source.sourceFor() and Context.compileScript(), which returns a 
>> ScriptFunction, so I also need access to that. Compilations errors 
>> are via Context.getErrorManager(), so I need access to ErrorManager. 
>> To run the scripts, I use ScriptRuntime.apply(). A small fix I need 
>> to add is that Nashorn's NativeArray does not support java.util.List, 
>> so if an array is returned from apply(), I call NativeJava.to() to 
>> get list access. Thats's just a bit friendlier for users of 
>> Scripturian, who are otherwise agnostic about implementation specifics.
>>
>> There's an important issue here: remember, there might be many 
>> different globals, but of course I want them all to use the same code 
>> cache, which is stored in the Context. So, I use one singleton 
>> Context and switch globals via Context.setGlobal(). To create a 
>> Context, I also need access to Options. A limitation in Nashorn is 
>> that I can't change stdout and stderr after I create the Context 
>> (Scripturian allows different onces per ExecutionContext), so my 
>> workaround is to use a custom Writer wrapper class that underneath 
>> delegates to the correct "real" Writers (I use the same mechanism for 
>> a few other Scripturian language engines, too).
>>
>> I grumbled here before that I have no programmatic access to the code 
>> cache. Behind the scenes, ScriptFunction might retrieve from the 
>> cache instead of being compiled. I can control the cache base 
>> location via the "nashorn.persistent.code.cache" system property, but 
>> it's unfortunate that I can't control the structure and naming the 
>> way I can with other languages supported by Scripturian. In 
>> particular, the problem is that it's a global property for the whole 
>> JVM, whereas compilation and caching location is ideally controlled 
>> per ExecutionContext in Scripturian. This makes Nashorn support in 
>> Scripturian a bit more limited.
>>
>> Finally, for errors during execution, I use NashornException 
>> (documented!) to extract specific information into Scripturian's more 
>> generic ExecutionException.
>>
>> Small extras: I use Version.version() and 
>> NashornScriptEngineFactory.getLanguageVersion() to get version data.
>>
>> I think that's everything! Of course, I also had to "reverse 
>> engineer" much of this (=read a lot of code) and work around many 
>> quirks (and big differences to Rhino's implementation) before 
>> streamlining it down to just these few classes. (I tried to work 
>> around the caching limitations, but gave up due to its complexity. 
>> Also, I think some of the key classes I would need are private.) I 
>> did my best not to delve to much into internals, but I hope I made it 
>> clear to you that it would have been impossible to achieve all the 
>> above goals without it.
>>
>> -Tal
>>
>> On 07/06/2015 04:18 AM, Attila Szegedi wrote:
>>> What APIs are you using, BTW? Just curious if I can suggest an 
>>> alternative approach, or even consider if something you use should 
>>> be publicly supported.
>>
>



More information about the nashorn-dev mailing list