nashorn: javascript that doesn’t suck (iljug)
Post on 10-May-2015
3.216 Views
Preview:
DESCRIPTION
TRANSCRIPT
Nashorn: JavaScript that doesn’t suck
Tomer Gabel, WixILJUG, April 2014
Agenda
• History• Features• Behind the
scenes• Performance• Juggling Act
History
• Existing Rhino engine:– Slow– Non-compliant– Did I mention slow?
• JavaScript since 1998:– Adoption went
through the roof– Technology advances
(V8, SpiderMonkey…)
Nashorn in a nutshell
• Project Nashorn– Started in July 2011– Integrates with JSR-
223– Reference use-case
for JSR-292
• Released with Java 8 in March 2014
Why bother?
Why you care
• Extensibility and scripting– Macro systems (a la
VBA)– Event hooks
• Server-side JavaScript – More on this later
• End-user programmability– Rule engines– Reporting engines/ETL– BPL and workflow
• … and more
Why Oracle cares
• Atwood’s law• Node.js
– A real threat to Java’s server-side growth
• Reference use-case for JSR-292– Drive innovation– Drive optimization– Reference
implementation
Features
• Self-contained• Implements ECMAScript 5.1
– 100% compliant!• Runtime-compiled to bytecode
(no interpreted mode as with Rhino)
• Small: 1.5MB JAR• Fast!
JSR-223 at a glance
import javax.script.*;
ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine nashorn = manager.getEngineByName("nashorn");
nashorn.eval( "print(\"hello world!\");");
Integrating JSR-223
• Injecting state
nashorn.put("name", "Schnitzel McFry"); nashorn.eval( "print(\"hello \" + name + \"!\");");
Integrating JSR-223
• Invoking JavaScript from Java
nashorn.eval( "function hello(name) { " + " print(\"hello \" + name + \"!\");" + "} " );
Invocable context = (Invocable) nashorn; context.invokeFunction("hello", "world");
Nashorn Extensions
• Java object– Java.type– Java.extend– Java.from– Java.to– Java.super
• A bunch more
Integrating JSR-223
• Invoking Java from JavaScript
nashorn.eval( "var HashMap = Java.type(\"java.util.HashMap\");" + "var map = new HashMap(); " + "map.put(\"name\", \"Schnitzel\"); " + "map.put(\"surname\", \"McFry\"); " );
HashMap<String, String> map = (HashMap<String, String>) nashorn.get("map");
Integrating JSR-223
• Implementing a Java interface
nashorn.eval( "var runnable = { " + " \"run\": function() { print(\"hello world\"); }" + "} " );
Invocable invocable = (Invocable) nashorn;Runnable runnable = invocable.getInterface( nashorn.get("runnable"), Runnable.class);
Integrating JSR-223
• Single Abstract Method (SAM) promotion:
nashorn.eval( "var Thread = Java.type(\"java.lang.Thread\");" + "var thread = new Thread(function() { " + " print(\"hello world\"); " + "} ); " );Thread thread = (Thread) nashorn.get("thread");thread.start();thread.join();
Behind the Scenes
The challenge
• JavaScript is dynamic– Things can change at runtime– Optimization is all about
assumptions
The challenge
• JavaScript is dynamic– Things can change at runtime– Optimization is all about
assumptions• For example, what is the type of:var x = 500000;
The challenge
• JavaScript is dynamic– Things can change at runtime– Optimization is all about
assumptions• For example, what is the type of:var x = 500000;x *= 500000; And now?
The challenge
• JavaScript is dynamic– Things can change at runtime– Optimization is all about
assumptions• For example, what is the type of:var x = 500000;x *= 500000; And now?
• How would you implement this?
The challenge
• Naïve multiplication operator:– Receive LHS and RHS as Objects– Unbox– Test for potential over/underflow– Add via appropriate codepath– Box and return
• You can specialize via static analysis• … but on-the-fly optimization is
better
The challenge
• That’s just one example.– Dynamic
dispatch– Type coercions – Primitive
widening– Prototype
mutation• All of these per
call site!
function square(x) { return x * x;}
square(10) //== 100square(3.14) //== 9.8596square("wat") //== NaN
The challenge
• Runtime code manipulation is not the JVM’s strong suite– Can only load entire classes– High overhead– Hard PermGen space limit– Class unloading issues
Enter JSR 292
• Based on an experimental project, the Da Vinci Machine
• Adds two new concepts to the JVM:– invokedynamic bytecode
instruction– MethodHandles
• The first bytecode extension since 1999!
invokedynamic
• The name is misleading
• It’s not about invocation
• … but about runtime linkage
java.lang.invoke
• MethodHandle– An immutable
function pointer– Composable:
• Guards• Exception
handlers• Argument
mutation– Typesafe andJIT-optimizable
• CallSite– Optionally
mutable wrapper– Binds an
invokedynamic callsite to a target MethodHandle
Why is this cool?
• Generated code is linked at runtime
• Code is hotswappable– Guards for branching
(over/underflow)– SwitchPoints for hotswap
(promotions)• Hotswapping is lightweight
– No class generation or loading• Resulting codepath can be JITted
Don’t forget JEP 122
• The PermGen space is no more– Now called “Metaspace”– Resides in native heap– Block allocator and classloader
isolation– Dynamic size (with bounds)
• Maximum size (hard)• Low/high watermark for GC
• This applies to all GCs (not just G1)
Dynalink
• An open-source library• Builds on top of invokedynamic:
– Metaobject protocol– Linkage model
• Enables cross-language interop (JRuby, Jython, Nashorn, plain Java)
• Open source (Apache-licensed)
So how does it perform?
Pretty damn good!
• 2-10 times faster than Rhino• ~60% percent of V8• Not much research out there
Avatar.js
• Implements the Node model and API on the JVM
• Supports most modules– Some natively– Some via JNI
• … and it does work!
Supported module highlights• mocha• coffee-script• uglify-js• underscore• request• async• jade• express• mongodb• Redis
Most popular per nodejsmodules.org
QUESTIONS?Thank you!
Thank you!Additional reading:• Nashorn war stories
(from a battle scarred veteran of invokedynamic)
• Dynalink
Contact me:• http://www.tomergabel.c
om• tomer@tomergabel.com• @tomerg
top related