invokedynamic: Evolution of a Language Feature

Post on 21-Jan-2017

408 views 0 download

Transcript of invokedynamic: Evolution of a Language Feature

Evolution of a Language Feature

Dan Heidinga, J9 VM Interpreter Lead

Daniel_Heidinga@ca.ibm.com

@DanHeidinga

26 October 2015

Invokedynamic

Brian Goetz, Java Language Architect

Oracle

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

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

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

Danger: highly technical talk!

This talk assumes you’re familiar with:

– JVM bytecode set

– java.lang.invoke.MethodHandle and related classes

– invokedynamic

5

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.

JVM Specification, first edition

7

JVM Specification, first edition

8

The JVM: a highly tuned performance machine

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

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

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

12

ResolutionAccess checkingType constraintsSelection

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

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

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

}

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

JVM Specification, first edition

17

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

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

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

From InvokeDynamic to target method

Invokedynamic Target method

21

User supplied

logic

Tell the VM what

method to link to

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

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

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

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

Anatomy of a CallSite

26

CallSite

type

target

MethodType

(String)V

MethodHandle

link(String)V

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

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

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

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

Interface injection: 3 Bootstrap Methods

31

Interface injection: 2 helpers

32

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

[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

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

Wait, what is a dyn language anyway?

Static Dynamic

36

Wait, what is a dyn language anyway?

Static Dynamic

37

Compile time

Runtime

Wait, what is a dyn language anyway?

Static Dynamic

38

Compile time

Runtime

Wait, what is a dyn language anyway?

Static

Typing

Dispatch

Dynamic

Binding

(Un)Loading

39

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;

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

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;

}

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

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

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.

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

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

48

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

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

51

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.