Transcript
Page 1: Nashorn: JavaScript that doesn’t suck (ILJUG)

Nashorn: JavaScript that doesn’t suck

Tomer Gabel, WixILJUG, April 2014

Page 2: Nashorn: JavaScript that doesn’t suck (ILJUG)

Agenda

• History• Features• Behind the

scenes• Performance• Juggling Act

Page 3: Nashorn: JavaScript that doesn’t suck (ILJUG)

History

• Existing Rhino engine:– Slow– Non-compliant– Did I mention slow?

• JavaScript since 1998:– Adoption went

through the roof– Technology advances

(V8, SpiderMonkey…)

Page 4: Nashorn: JavaScript that doesn’t suck (ILJUG)

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

Page 5: Nashorn: JavaScript that doesn’t suck (ILJUG)

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

Page 6: Nashorn: JavaScript that doesn’t suck (ILJUG)

Features

• Self-contained• Implements ECMAScript 5.1

– 100% compliant!• Runtime-compiled to bytecode

(no interpreted mode as with Rhino)

• Small: 1.5MB JAR• Fast!

Page 7: Nashorn: JavaScript that doesn’t suck (ILJUG)

JSR-223 at a glance

import javax.script.*;

ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine nashorn = manager.getEngineByName("nashorn");

nashorn.eval( "print(\"hello world!\");");

Page 8: Nashorn: JavaScript that doesn’t suck (ILJUG)

Integrating JSR-223

• Injecting state

nashorn.put("name", "Schnitzel McFry"); nashorn.eval( "print(\"hello \" + name + \"!\");");

Page 9: Nashorn: JavaScript that doesn’t suck (ILJUG)

Integrating JSR-223

• Invoking JavaScript from Java

nashorn.eval( "function hello(name) { " + " print(\"hello \" + name + \"!\");" + "} " );

Invocable context = (Invocable) nashorn; context.invokeFunction("hello", "world");

Page 10: Nashorn: JavaScript that doesn’t suck (ILJUG)

Nashorn Extensions

• Java object– Java.type– Java.extend– Java.from– Java.to– Java.super

• A bunch more

Page 11: Nashorn: JavaScript that doesn’t suck (ILJUG)

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");

Page 12: Nashorn: JavaScript that doesn’t suck (ILJUG)

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);

Page 13: Nashorn: JavaScript that doesn’t suck (ILJUG)

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();

Page 14: Nashorn: JavaScript that doesn’t suck (ILJUG)

Behind the Scenes

Page 15: Nashorn: JavaScript that doesn’t suck (ILJUG)

The challenge

• JavaScript is dynamic– Things can change at runtime– Optimization is all about

assumptions

Page 16: Nashorn: JavaScript that doesn’t suck (ILJUG)

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;

Page 17: Nashorn: JavaScript that doesn’t suck (ILJUG)

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?

Page 18: Nashorn: JavaScript that doesn’t suck (ILJUG)

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?

Page 19: Nashorn: JavaScript that doesn’t suck (ILJUG)

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

Page 20: Nashorn: JavaScript that doesn’t suck (ILJUG)

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

Page 21: Nashorn: JavaScript that doesn’t suck (ILJUG)

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

Page 22: Nashorn: JavaScript that doesn’t suck (ILJUG)

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!

Page 23: Nashorn: JavaScript that doesn’t suck (ILJUG)

invokedynamic

• The name is misleading

• It’s not about invocation

• … but about runtime linkage

Page 24: Nashorn: JavaScript that doesn’t suck (ILJUG)

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

Page 25: Nashorn: JavaScript that doesn’t suck (ILJUG)

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

Page 26: Nashorn: JavaScript that doesn’t suck (ILJUG)

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)

Page 27: Nashorn: JavaScript that doesn’t suck (ILJUG)

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)

Page 28: Nashorn: JavaScript that doesn’t suck (ILJUG)

So how does it perform?

Page 29: Nashorn: JavaScript that doesn’t suck (ILJUG)

Pretty damn good!

• 2-10 times faster than Rhino• ~60% percent of V8• Not much research out there

Page 30: Nashorn: JavaScript that doesn’t suck (ILJUG)

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

Page 31: Nashorn: JavaScript that doesn’t suck (ILJUG)

QUESTIONS?Thank you!


Top Related