Slide 1

Slide 1 text

PPPJ 2013 Stuttgart, Germany — a Dynamic, Light and Efficient Language for Post-invokedynamic JVM Julien Ponge Frédéric Le Mouël Nicolas Stouls

Slide 2

Slide 2 text

A new language built with {invokedynamic}

Slide 3

Slide 3 text

DynaMid Middleware for dynamic environments APIs Languages Frameworks Runtimes

Slide 4

Slide 4 text

public static java.lang.Object main(java.lang.Object); Code: 0: ldc #19 2: invokedynamic #29, 0 7: pop 8: aconst_null 9: areturn runtime-bound call site method handles + combinators (type, logic, ...)

Slide 5

Slide 5 text

Hackable language implementation Humble approach to a new research field invokedynamic / JSR 292 for new languages? Disseminate experience outside of academia, F/OSS

Slide 6

Slide 6 text

Language quick, incomplete, Tour

Slide 7

Slide 7 text

module hello function main = |args| { let message = "Hello, PPPJ'13!" var a = 1 a = a + 1 display(message) display(">>> " + a) } local function display = |what| -> println(what)

Slide 8

Slide 8 text

module hello import java.util.LinkedList function main = |args| { let l = LinkedList() l: add(1) l: add(2) l: add(3) var sum = 0 foreach n in l { sum = sum + n } println(">>> " + sum) } constructors as functions calling an instance method

Slide 9

Slide 9 text

let list = LinkedList(): append(1, 2, 3, 4) let result = list: map(|x| -> x + 10): filter(|x| -> (x % 2) == 0): reduce(0, |acc, x| -> acc + x) # >>> 26 println(">>> " + result) append? map, filter, reduce?

Slide 10

Slide 10 text

function main = |args| { println("http://google.com": toURL(): getContent(): readFully()) } Augmentation on String Augmentation on InputStream

Slide 11

Slide 11 text

augment java.lang.String { function toURL = |this| -> java.net.URL(this) } augment java.io.InputStream { function readFully = |this| { let streamReader = java.io.InputStreamReader(this) let reader = java.io.BufferedReader(streamReader) let buffer = java.lang.StringBuilder() var line = 0 while line isnt null { line = reader: readLine() buffer: append(line orIfNull "") } reader: close() return buffer: toString() } }

Slide 12

Slide 12 text

let contacts = HashMap(): add("mrbean", HashMap(): add("email", "[email protected]"): add("url", "http://mrbean.com")): add("larry", HashMap(): add("email", "[email protected]")) # MrBean and Larry let mrbean = contacts: get("mrbean") let larry = contacts: get("larry") # Illustrates orIfNull println(mrbean: get("url") orIfNull "n/a") println(larry: get("url") orIfNull "n/a") # Querying a non-existent data model because there is no 'address' entry println(mrbean: get("address")?: street()?: number() orIfNull "n/a") dealing with null

Slide 13

Slide 13 text

let data = [ [1, 2, 3], tuple[1, 2, 3], array[1, 2, 3], set[1, 2, 3, 3, 1], map[ ["a", 10], ["b", 20] ], vector[1, 2, 3], list[1, 2, 3] ] Tuples Arrays (JVM) LinkedHashSet LinkedHashMap ArrayList LinkedList

Slide 14

Slide 14 text

let what = |item| -> match { when item: contains("@") then "an email?" when item: startsWith("+33") then "a French phone number?" when item: startsWith("http://") then "a website URL?" otherwise "I have no clue, mate!" } let func = what: andThen(|str| -> println(">>> " + str)) let data = ["http://golo-lang.org/", "+33.6.11.22.33", "[email protected]", "def foo = bar(_._) with :> T"] foreach item in data { func(item) }

Slide 15

Slide 15 text

let counter = DynamicObject(): define("value", 0): define("incr", |this| { this: value(this: value() + 1) return this }) # 0 println(counter: value()) # Increment twice counter: incr(): incr() # 2 println(counter: value())

Slide 16

Slide 16 text

struct Point = { x, y } augment hello.types.Point { function moveBy = |this, dx, dy| { this: x(this: x() + dx) this: y(this: y() + dy) return this } } # struct Point{x=11, y=-4} println(Point(1, 1): moveBy(10, -5)) + toString, equals, hashCode

Slide 17

Slide 17 text

$ du -hc lib/*.jar 48K lib/asm-4.1.jar 252K lib/golo-0-preview7-SNAPSHOT.jar 60K lib/jcommander-1.30.jar 360K total $ golo {compile, run, golo, version}

Slide 18

Slide 18 text

AOT, invokedynamic call sites polymorphic inline-cache, megamorphic inline-cache, null-safe dispatch, dynamic objects, operators, ...

Slide 19

Slide 19 text

invokedynamic toString (Object)Object MethodInvocationSupport.bootstrap(...) fallback initial state

Slide 20

Slide 20 text

invokedynamic toString (Object)Object MethodInvocationSupport.bootstrap(...) fallback guard asType SomeClass::toString()String monomorphic

Slide 21

Slide 21 text

fallback guard asType Foo::toString()String guard asType SomeClass::toString()String polymorphic (< n)

Slide 22

Slide 22 text

WeakHashMap { Foo::toString()String SomeClass::toString()String (...) } megamorphic (≥ n) foldArguments(target, combiner) exactInvoker(type) custom_vtable_lookup(callsite, args[]) + bind / asCollector / asType

Slide 23

Slide 23 text

How about performance? (take with a grain of salt)

Slide 24

Slide 24 text

Check specific runtime code Try to port to other JVM languages hard to be “fair” stay idiomatic no types, ever no tricks dispatch, mostly

Slide 25

Slide 25 text

*Groovy with invokedynamic is not included (very bad on polymorphic call sites) 0" 2" 4" 6" 8" 10" 12" Monomorphic" TriMorphic" MegaMorphic" JRuby" Clojure" Groovy" Java"reflec@on" Golo" Java" java version "1.7.0_17" Java(TM) SE Runtime Environment (build 1.7.0_17-b02) Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)

Slide 26

Slide 26 text

0" 5" 10" 15" 20" 25" 30" 35" 40" Java" Java" (boxing)" Golo" Groovy" (indy)" Java" reflec;on" Clojure" JRuby" Groovy" fib(40)' 0" 0.2" 0.4" 0.6" 0.8" 1" 1.2" 1.4" 1.6" Golo" Groovy" Groovy"(indy)" Clojure" JRuby" Filter,(map,(reduce(

Slide 27

Slide 27 text

Experience with invokedynamic Thin and reasonably efficient runtimes Frequent invalidations worse than reflection (e.g., Groovy-indy) Memory impact of many call sites? JVM support for boxing elimination? Faster vtable helpers for instance-based dispatch?

Slide 28

Slide 28 text

What’s next? Converge towards a proper v0 release Dynamic class adapters, proxies, etc Concurrency APIs Doc generation More performance + memory benchmarks (Debian shootout?) Runtime extensions (e.g., dynamic sandbox / monitoring) Type specialization mechanisms? Graal / Truffle interpreter?

Slide 29

Slide 29 text

Q+A @golo_lang - #gololang http://golo-lang.org/ http://dynamid.citi-lab.fr/ Julien Ponge Frédéric Le Mouël Nicolas Stouls