Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Golo, a Dynamic, Light and Efficient Language for Post-invokedynamic JVM

Julien Ponge
September 12, 2013

Golo, a Dynamic, Light and Efficient Language for Post-invokedynamic JVM

Julien Ponge

September 12, 2013
Tweet

More Decks by Julien Ponge

Other Decks in Research

Transcript

  1. PPPJ 2013 Stuttgart, Germany — a Dynamic, Light and Efficient

    Language for Post-invokedynamic JVM Julien Ponge Frédéric Le Mouël Nicolas Stouls
  2. 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, ...)
  3. Hackable language implementation Humble approach to a new research field

    invokedynamic / JSR 292 for new languages? Disseminate experience outside of academia, F/OSS
  4. 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)
  5. 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
  6. 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?
  7. 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() } }
  8. 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
  9. 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
  10. 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) }
  11. 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())
  12. 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
  13. WeakHashMap { Foo::toString()String SomeClass::toString()String (...) } megamorphic (≥ n) foldArguments(target,

    combiner) exactInvoker(type) custom_vtable_lookup(callsite, args[]) + bind / asCollector / asType
  14. Check specific runtime code Try to port to other JVM

    languages hard to be “fair” stay idiomatic no types, ever no tricks dispatch, mostly
  15. *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)
  16. 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(
  17. 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?
  18. 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?