invokedynamic: evolution of a language feature

52
Evolution of a Language Feature Dan Heidinga, J9 VM Interpreter Lead [email protected] @DanHeidinga 26 October 2015 Invokedynamic Brian Goetz, Java Language Architect Oracle

Upload: danheidinga

Post on 21-Jan-2017

409 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: invokedynamic: Evolution of a Language Feature

Evolution of a Language Feature

Dan Heidinga, J9 VM Interpreter Lead

[email protected]

@DanHeidinga

26 October 2015

Invokedynamic

Brian Goetz, Java Language Architect

Oracle

Page 2: invokedynamic: Evolution of a Language Feature

Who am I?

I've been involved with virtual machine development at IBM

since 2007 and am now the J9 Virtual Machine Team Lead.

J9 is IBM's independent implementation of the JVM.

I've represented IBM on both the JSR 292 ('invokedynamic')

and JSR 335 ('lambda') expert groups and lead J9's

implementation of both JSRs.

I’ve also maintain the bytecode verifier and deal with various

other parts of the runtime.

2

Page 3: invokedynamic: Evolution of a Language Feature

Who am I?

Brian Goetz is the Java Language Architect at Oracle, and is

one of the leading authorities on the Java platform.

He is the author of the very successful 'Java Concurrency in

Practice', and has published over 75 articles on software

development.

He was the specification lead for JSR-335 (Lambda

Expressions for the Java Language) and has served on

numerous other JCP Expert Groups.

3

Page 4: invokedynamic: Evolution of a Language Feature

Important disclaimers

THE INFORMATION CONTAINED IN THIS PRESENTATION IS PROVIDED FOR INFORMATIONAL PURPOSES ONLY.

WHILST EFFORTS WERE MADE TO VERIFY THE COMPLETENESS AND ACCURACY OF THE INFORMATION

CONTAINED IN THIS PRESENTATION, IT IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,

EXPRESS OR IMPLIED.

ALL PERFORMANCE DATA INCLUDED IN THIS PRESENTATION HAVE BEEN GATHERED IN A CONTROLLED

ENVIRONMENT. YOUR OWN TEST RESULTS MAY VARY BASED ON HARDWARE, SOFTWARE OR

INFRASTRUCTURE DIFFERENCES.

ALL DATA INCLUDED IN THIS PRESENTATION ARE MEANT TO BE USED ONLY AS A GUIDE.

IN ADDITION, THE INFORMATION CONTAINED IN THIS PRESENTATION IS BASED ON IBM’S CURRENT

PRODUCT PLANS AND STRATEGY, WHICH ARE SUBJECT TO CHANGE BY IBM, WITHOUT NOTICE.

IBM AND ITS AFFILIATED COMPANIES SHALL NOT BE RESPONSIBLE FOR ANY DAMAGES ARISING OUT

OF THE USE OF, OR OTHERWISE RELATED TO, THIS PRESENTATION OR ANY OTHER DOCUMENTATION.

NOTHING CONTAINED IN THIS PRESENTATION IS INTENDED TO, OR SHALL HAVE THE EFFECT OF:

– CREATING ANY WARRANT OR REPRESENTATION FROM IBM, ITS AFFILIATED COMPANIES OR ITS

OR THEIR SUPPLIERS AND/OR LICENSORS

4

Page 5: invokedynamic: Evolution of a Language Feature

Danger: highly technical talk!

This talk assumes you’re familiar with:

– JVM bytecode set

– java.lang.invoke.MethodHandle and related classes

– invokedynamic

5

Page 6: invokedynamic: Evolution of a Language Feature

Full bleed images preferredText over top of full bleed images would be in white or a color from the color palette that

would offer good contrast. Also, colored text in Arial Bold would have greater impact.

Page 7: invokedynamic: Evolution of a Language Feature

JVM Specification, first edition

7

Page 8: invokedynamic: Evolution of a Language Feature

JVM Specification, first edition

8

Page 9: invokedynamic: Evolution of a Language Feature

The JVM: a highly tuned performance machine

https://commons.wikimedia.org/wiki/File:Fernando_Alonso_2010_Jerez_test_14.jpg9

Page 10: invokedynamic: Evolution of a Language Feature

It’s fastest when you stay on the pathJVM optimized and tuned for the Java language.

As long as the language maps cleanly to Java’s semantics, good perf is likely

10

Page 11: invokedynamic: Evolution of a Language Feature

JVM invoke instructions

Prior to Java 7, there were 4 bytecodes to invoke methods:

– invokespecial: constructors, super calls, private methods

– invokevirtual: receiver based selection of instance methods

– invokestatic: static methods

– invokeinterface: interface based selection of instance methods

The semantics are tightly defined by the JVM spec

11

Page 12: invokedynamic: Evolution of a Language Feature

12

ResolutionAccess checkingType constraintsSelection

Page 13: invokedynamic: Evolution of a Language Feature

Ruby fib

Show Ruby fib and outline why it’s not the same as the Java version

13

def fib(x)

if x < 2

return x

end

return fib(x-2) + fib(x-1)

end

Page 14: invokedynamic: Evolution of a Language Feature

Ruby fib

6 method sends for Ruby vs 2 for Java

14

def fib(x)

if x < 2

return x

end

return fib(x-2) + fib(x-1)

end

Page 15: invokedynamic: Evolution of a Language Feature

JRuby: ~1.6 implementation

15

CachingCallSite DynamicMethod

@JRubyMethod(name = "+")

public IRubyObject op_plus(ThreadContext ctx, IRubyObject other)

{

if (other instanceof RubyFixnum) {

return addFixnum(ctx, (RubyFixnum)other);

}

return addOther(ctx, other);

}

Page 16: invokedynamic: Evolution of a Language Feature

Second class performance citizen: Dynamic languages

Simulation overheads:

– Inlining depth limits

– Inlining bytecode size limits

– Reflection overhead

– Non-inlinable caching / Hashtable lookups

– Type mismatches: sharp types vs IRubyObject

Complexity

– Generating invokers at build time based on annotations

– Need to ensure the cache is correct

16

Page 17: invokedynamic: Evolution of a Language Feature

JVM Specification, first edition

17

Page 18: invokedynamic: Evolution of a Language Feature

Birth of JSR 292 EG

18

New JVM instruction, invokedynamic, designed to support the implementation of dynamically typed object oriented languages.

… investigate support for hotswapping

Page 19: invokedynamic: Evolution of a Language Feature

The problem: linkage + typing

JVM invoke instructions are tightly tied to Java

– Linkage must match the JVM rules

My language uses different dispatch rules

– Metaclass

– Multiple dispatch

– Mixins

User’s need to control the linkage

19https://en.wikipedia.org/wiki/Burr_puzzle#/media/File:SixPartWoodKnot.jpg

Page 20: invokedynamic: Evolution of a Language Feature

RestartMethodException & VM method cache

Invokedynamic

– like invokevirtual except:

arguments not required to match the method’s signature

support for “doesNotUnderstand” handler

– recursive lookup for method exactly matching descriptor

else call handler, which can:

implement the method & return result

pick a method and return it (via RestartMethodException)

> VM can cache the “restart” method

20

Page 21: invokedynamic: Evolution of a Language Feature

From InvokeDynamic to target method

Invokedynamic Target method

21

User supplied

logic

Tell the VM what

method to link to

Page 22: invokedynamic: Evolution of a Language Feature

From InvokeDynamic to target method

Invokedynamic

Static data:

Caller

Method name

Descriptor

Other data

Target method

22

User supplied

logic

Tell the VM what

method to link to

BootstrapMethod

Page 23: invokedynamic: Evolution of a Language Feature

From InvokeDynamic to target method

Invokedynamic

java.lang.invoke.CallSite

Target method

23

User supplied

logic

Tell the VM what

method to link to

BootstrapMethod

Page 24: invokedynamic: Evolution of a Language Feature

From InvokeDynamic to target method

Invokedynamic

java.lang.invoke.CallSite

Target method

24

User supplied

logic

Tell the VM what

method to link to

BootstrapMethod

Page 25: invokedynamic: Evolution of a Language Feature

From InvokeDynamic to target method

Invokedynamic Target method

25

java.lang.invoke.CallSite

Indy is permanently linked to the CallSite (1 time)

Invocation of target method can occur many times

Page 26: invokedynamic: Evolution of a Language Feature

Anatomy of a CallSite

26

CallSite

type

target

MethodType

(String)V

MethodHandle

link(String)V

Page 27: invokedynamic: Evolution of a Language Feature

Anatomy of a CallSite

27

CallSite

type

target

MethodType

(String)V

MethodHandle

link(String)V

The link() handle does two things:1. It sets CallSite target2. Completes the call

Page 28: invokedynamic: Evolution of a Language Feature

Anatomy of a CallSite

28

CallSite

type

target

MethodType

(String)V

MethodHandle

link(String)V

GuardWithTest

test

target

fallback

MethodHandle

Guard()boolean

MethodHandle

Method(String)V

Page 29: invokedynamic: Evolution of a Language Feature

Invokedynamic: bytecode factory

Lazy constants

New semantics

New bytecodes

All these and more can be emulated using invokedynamic

– Bootstrap Method to link the CallSite

– Java code that implements the new operation

– Really the ultimate bytecode emulation tool

29

Page 30: invokedynamic: Evolution of a Language Feature

Interface injection

A Class implements all the methods for an interface

Doesn’t declare it implements it

– How can we allow the interface invocation to proceed?

30

Foo foo = new Foo();if (foo instanceof Injected) {

Injected i = (Injected) foo;System.out.println(i.m());

}

instanceof

checkcast

invokeinterface

Page 31: invokedynamic: Evolution of a Language Feature

Interface injection: 3 Bootstrap Methods

31

Page 32: invokedynamic: Evolution of a Language Feature

Interface injection: 2 helpers

32

Page 33: invokedynamic: Evolution of a Language Feature

Interface injection: bytecode

33

0: new #14 // class Foo

3: dup

4: invokespecial #15 // Method Foo."<init>":()V

7: astore_1

8: aload_1

9: invokedynamic #28, 0 // InvokeDynamic #0:instanceof:(LObject;)Z

14: ifeq 36

17: aload_1

18: invokedynamic #36, 0 // InvokeDynamic #1:checkcast:(LObject;)LInjected;

23: astore_2

24: getstatic #42 // Field System.out:LPrintStream;

27: aload_2

28: invokedynamic #50, 0 // InvokeDynamic #2:m:(LObject;)LString;

33: invokevirtual #56 // Method PrintStream.println:(LString;)V

36: return

BootstrapMethods:

0: #22 invokestatic Runtime.instanceOfBSM:(LLookup;LString;LMethodType;LClass;)LCallSite;

Method arguments:

#24 Injected

1: #32 invokestatic Runtime.checkcastBSM:(LLookup;LString;LMethodType;LClass;)LCallSite;

Method arguments:

#24 Injected

2: #46 invokestatic

Runtime.invokeinterfaceBSM:(LLookup;LString;LMethodType;Ljava/lang/Class;)LCallSite;

Method arguments:

#24 Injected

Page 34: invokedynamic: Evolution of a Language Feature

[jsr-292-eg] our package name 01/06/2011

Invokedynamic is more than dynamic languages!

Lambda can be built on top of invokedynamic and MethodHandles

(Painfully) renamed the package from java.dyn to java.lang.invoke at development cutoff

34

Page 35: invokedynamic: Evolution of a Language Feature

Birth of JSR 292 EG

35

New JVM instruction, invokedynamic, designed to support the implementation of dynamically typed object oriented languages.

… investigate support for hotswapping

Page 36: invokedynamic: Evolution of a Language Feature

Wait, what is a dyn language anyway?

Static Dynamic

36

Page 37: invokedynamic: Evolution of a Language Feature

Wait, what is a dyn language anyway?

Static Dynamic

37

Compile time

Runtime

Page 38: invokedynamic: Evolution of a Language Feature

Wait, what is a dyn language anyway?

Static Dynamic

38

Compile time

Runtime

Page 39: invokedynamic: Evolution of a Language Feature

Wait, what is a dyn language anyway?

Static

Typing

Dispatch

Dynamic

Binding

(Un)Loading

39

Page 40: invokedynamic: Evolution of a Language Feature

Its not just for dynamic languages anymore

Java 8 gave us Lambda expressions

– But how do we compile this lambda?

40

Predicate<Person> pred = p -> p.age < minAge;

Page 41: invokedynamic: Evolution of a Language Feature

Its not just for dynamic languages anymore

So, if indy is for dynamic languages, why is the Java compiler using it?

– All the types involved are static

– We can use indy to give us a dynamic code generation strategy

Generate inner classes?

Use method handles?

Use dynamic proxies?

Use VM-private APIs for constructing objects?

Indy lets us turn this choice into a pure implementation detail

– Separate from the binary representation

41

Page 42: invokedynamic: Evolution of a Language Feature

Desugaring lambdas to methods

First, we desugar the lambda to a method

– Signature matches functional interface method

– Plus captured arguments prepended

– Simplest lambdas desugar to static methods

But some need access to receiver, and so are instance methods

42

Predicate<Person> pred = p -> p.age < minAge;

private static boolean lambda$1(int minAge, Person p) {

return p.age < minAge;

}

Page 43: invokedynamic: Evolution of a Language Feature

Its not just for dynamic languages anymore

We use indy to embed a recipe for constructing a lambda, including

– The desugared implementation method (static)

– The functional interface we are converting to (static)

– Additional metadata, such as serialization information (static)

– Values captured from the lexical scope (dynamic)

The capture site is called the lambda factory

– Invoked with indy, returns an instance of the desired functional interface

– Subsequent captures bypass the (slow) linkage path

43

Page 44: invokedynamic: Evolution of a Language Feature

Factories and metafactories

We generate an indy call site which, when called, returns the lambda

– This is the lambda factory

– Bootstrap for the lambda factory

selects the translation strategy

Bootstrap is called the lambda metafactory

Part of Java runtime

– Captured args passed

to lambda factory

44

list.removeIf(p -> p.age < minAge);

private static boolean lambda$1(int minAge, Person p) {

return p.getAge() >= minAge;

}

Predicate $p = indy[bootstrap=LambdaMetafactory,

staticargs=[Predicate, lambda$1],

dynargs=[minAge])

list.removeIf($p);

Page 45: invokedynamic: Evolution of a Language Feature

Full bleed images preferredText over top of full bleed images would be in white or a color from the color palette that

would offer good contrast. Also, colored text in Arial Bold would have greater impact.

Page 46: invokedynamic: Evolution of a Language Feature

Optimized String concat (JEP tbd)

46

String m(String a, int b) {

return a + "(" + b + ")";

}

java.lang.String m(java.lang.String, int);

0: new #2 // class StringBuilder

3: dup

4: invokespecial #3 // Method StringBuilder.<init>:()V

7: aload_1

8: invokevirtual #4 // Method StringBuilder.append:(LString;)LStringBuilder;

11: ldc #5 // String (

13: invokevirtual #4 // Method StringBuilder.append:(LString;)LStringBuilder;

16: iload_2

17: invokevirtual #6 // Method StringBuilder.append:(I)LStringBuilder;

20: ldc #7 // String )

22: invokevirtual #4 // Method StringBuilder.append:(LString;)LStringBuilder;

25: invokevirtual #8 // Method StringBuilder.toString:()LString;

28: areturn

http://openjdk.java.net/jeps/8085796

Page 47: invokedynamic: Evolution of a Language Feature

Optimized String concat (JEP tbd)

47

String m(String a, int b) {

return a + "(" + b + ")";

}

java.lang.String m(java.lang.String, int);

0: aload_1

1: ldc #2 // String (

3: iload_2

4: ldc #3 // String )

6: invokedynamic #4, 0

// InvokeDynamic #0:stringConcat:(LString;LString;ILString;)LString;

11: areturn

BootstrapMethods:

0: #19 invokestatic StringConcatFactory.stringConcat:

(LMethodHandles$Lookup;LString;LMethodType;LString;[LObject;)LCallSite;

http://openjdk.java.net/jeps/8085796

Page 48: invokedynamic: Evolution of a Language Feature

48

Page 49: invokedynamic: Evolution of a Language Feature

Invoking Specialized Generic Static Methods

We need to capture the type argument at the callsite.

How does m access the type information at run-time?

class C {

static <any T> T m(T i) {…}

}

int i = C.<int>m(3);

Page 50: invokedynamic: Evolution of a Language Feature

Embed specialized type information in the invokedynamic Callsite

Invoking Specialized Static Methods (cont’d)

7: iconst_38: invokedynamic #4, 0 // InvokeDynamic #0:m:(LFoo;I)V

BootstrapMethods:0: #26 invokestatic GenericMethodSpecializer.metafactory:

(LMethodHandles$Lookup;LString;LMethodType;[LObject;)LCallSite;Method arguments:#27 LC;#28 invokevirtual C.m:(LObject;)V#29 I

Page 51: invokedynamic: Evolution of a Language Feature

51

Page 52: invokedynamic: Evolution of a Language Feature

52

Legal Notice

IBM and the IBM logo are trademarks or registered trademarks of IBM Corporation, in the United States, other

countries or both.

Java and all Java-based marks, among others, are trademarks or registered trademarks of Oracle in the United

States, other countries or both.

Other company, product and service names may be trademarks or service marks of others.

THE INFORMATION DISCUSSED IN THIS PRESENTATION IS PROVIDED FOR INFORMATIONAL

PURPOSES ONLY. WHILE EFFORTS WERE MADE TO VERIFY THE COMPLETENESS AND

ACCURACY OF THE INFORMATION, IT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,

EXPRESS OR IMPLIED, AND IBM SHALL NOT BE RESPONSIBLE FOR ANY DAMAGES ARISING OUT

OF THE USE OF, OR OTHERWISE RELATED TO, SUCH INFORMATION. ANY INFORMATION

CONCERNING IBM'S PRODUCT PLANS OR STRATEGY IS SUBJECT TO CHANGE BY IBM WITHOUT

NOTICE.