Mastering Java Bytecode - JAX.de 2012

Post on 26-Jan-2015

119 views 3 download

Tags:

description

 

Transcript of Mastering Java Bytecode - JAX.de 2012

Mastering Java Bytecode

Anton Arhipov | ZeroTurnaround

whoami

• Anton Arhipov• Java Dev / Product Lead• ZeroTurnaround, JRebel

• @antonarhipov @javarebel

Today – Java Core

• Mastering Java Bytecode

• The Future of Java on Multi-Core, Lambdas, Spliterators and Methods

• OpenJDK JVM Internals

• Invokedynamic Deep Dive

Why Bytecode?

• Know your platform!• Create your own compiler?• Programming model (AOP, ORM)• Awesome tools (JRebel )

• … just bored?

THE INTRO

1 + 2

1 + 2

1 2 +

1 + 2

1 2 +

1 + 2

1 2 + PUSH 1 1

1 + 2

1 2 + PUSH 1PUSH 2

21

1 + 2

1 2 + PUSH 1PUSH 2ADD

3

1 + 2

1 2 + ICONST_1ICONST_2IADD

3

? = 1 + 2

TAXONOMY

Bytecode

• One-byte instructions• 256 possible opcodes• 200+ in use

TYPE OPERATION

• <TYPE> ::= b, s, c, i, l, f, d, a

OPERATIONTYPE

• <TYPE> ::= b, s, c, i, l, f, d, a• constant values (ldc, iconst_1)

OPERATIONTYPE

• <TYPE> ::= b, s, c, i, l, f, d, a• constant values (ldc, iconst_1)• Local variables and stack interaction (load/store)• Array operations (aload, astore)• Math (add, sub, mul, div)• Boolean/bitwise operations (iand, ixor)• Comparisons (cmpg, cmpl, ifne, ifeq)• Conversions (l2d, i2l)

OPERATIONTYPE

Bytecode Taxonomy

Bytecode Taxonomy

Stack Manipulation

Bytecode Taxonomy

Stack Manipulation

FlowControl

Bytecode Taxonomy

Stack Manipulation

FlowControl

Object Model

Bytecode Taxonomy

Stack Manipulation

FlowControl

ArithmeticsObject Model

Bytecode Taxonomy

Stack Manipulation

FlowControl

ArithmeticsObject Model

monitorentermonitorexit

TOOLING

javap

• Java class file disassembler• Used with no options shows class structure

only– Methods, superclass, interfaces, etc

• -c shows the bytecode• -private shows all methods and members• -s prints internal signatures• -l prints line numbers and local variable

tables

HELLO WORLD!

C:\work\geecon\classes>javap Hello -c

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

the default constructor

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

push this to stack

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

invoke <init> on this

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

get static field

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

load string to the stack

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

invoke method with parameter

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

C:\work\geecon\classes>javap Hello -cCompiled from "Hello.java"public class Hello extends java.lang.Object{public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return

public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

What’s #1,#2, etc ?

C:\work\geecon\classes>javap Hello -c -verbose

C:\work\geecon\classes>javap Hello -c -verbose

C:\work\geecon\classes>javap Hello -c -verboseCompiled from "Hello.java“public class Hello extends java.lang.Object SourceFile: "Hello.java" minor version: 0 major version: 50 Constant pool:const #1 = Method #6.#20; // java/lang/Object."<init>":()Vconst #2 = Field #21.#22; // java/lang/System.out:Ljava/io/PrintStream;const #3 = String #23; // Hello, World!const #4 = Method #24.#25; // java/io/PrintStream.println:(Ljava/lang/String;)Vconst #5 = class #26; // Helloconst #6 = class #27; // java/lang/Objectconst #7 = Asciz <init>;const #8 = Asciz ()V;

C:\work\geecon\classes>javap Hello -c -verboseCompiled from "Hello.java“public class Hello extends java.lang.Object SourceFile: "Hello.java" minor version: 0 major version: 50 Constant pool:const #1 = Method #6.#20; // java/lang/Object."<init>":()Vconst #2 = Field #21.#22; // java/lang/System.out:Ljava/io/PrintStream;const #3 = String #23; // Hello, World!const #4 = Method #24.#25; // java/io/PrintStream.println:(Ljava/lang/String;)Vconst #5 = class #26; // Helloconst #6 = class #27; // java/lang/Objectconst #7 = Asciz <init>;const #8 = Asciz ()V;

C:\work\geecon\classes>javap Hello -c -verbose…public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0

LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;

C:\work\geecon\classes>javap Hello -c -verbose…public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0

LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;

C:\work\geecon\classes>javap Hello -c -verbose…public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0

LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;

C:\work\geecon\classes>javap Hello -c -verbose…public static void main(java.lang.String[]); Code: Stack=2, Locals=1, Args_size=1 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 4: 0 line 5: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 args [Ljava/lang/String;

MODEL OF COMPUTATION

Stack Machine

Stack Machine

• JVM is a stack-based machine

Stack Machine

• JVM is a stack-based machine• Each thread has a stack

Stack Machine

• JVM is a stack-based machine• Each thread has a stack• Stack stores frames

Stack Machine

• JVM is a stack-based machine• Each thread has a stack• Stack stores frames• Frame is created on method invocation

Stack Machine

• JVM is a stack-based machine• Each thread has a stack• Stack stores frames• Frame is created on method invocation• Frame consists of:

– Operand stack– Array of local variables

The Frame

Operand stack

Local variables

20 1 N…

Constant Pool

#1

public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturnLocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;

public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturnLocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;

aload_0 getfield 00 02 areturn

0 1 2 3 4

public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturnLocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;

2A B4 00 02 B0

0 1 2 3 4

public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturnLocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;

STACK CRUNCHING

AB

duppopswapdup_x1dup2_x1

A

B

duppopswapdup_x1dup2_x1

A

duppopswapdup_x1dup2_x1

AB

duppopswapdup_x1dup2_x1

AB

duppopswapdup_x1dup2_x1

AB

B

duppopswapdup_x1dup2_x1

AB

BBA

dup2_x2

How do you swap doubles?

dup2_x2

dup2_x2dconst_0

0.0

dup2_x2dconst_0dconst_1 1.0

0.0

dup2_x2dconst_0dconst_1swap

1.0

0.0

dup2_x2dconst_0dconst_1swap

1.0

0.0

not allowed!

dup2_x2dconst_0dconst_1swap2

1.0

0.0

dup2_x2dconst_0dconst_1swap2

1.0

0.0

doesn’texist

dup2_x2dconst_0dconst_1dup2_x2

1.0

0.0

1.0

dup2_x2dconst_0dconst_1dup2_x2pop2

0.0

1.0

dup2_x2dconst_0dconst_1dup2_x2pop2

0.0

1.0

profit!

LOCAL VARIABLES

Local Variables

Local Variables

public int calculate(int); Code: Stack=2, Locals=2, Args_size=2 …

LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LLocalVariables; 0 5 1 value I

Local Variables

public int calculate(int); Code: Stack=2, Locals=2, Args_size=2 …

LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LLocalVariables; 0 5 1 value I

numbered

from 0

Local Variables

instance methodshave this at 0

public int calculate(int); Code: Stack=2, Locals=2, Args_size=2 …

LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LLocalVariables; 0 5 1 value I

public int calculate(int); Code: Stack=2, Locals=2, Args_size=2 …

LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LLocalVariables; 0 5 1 value I

Local Variables

The table maps

numbers to names

public int calculate(int); Code: Stack=2, Locals=2, Args_size=2 …

LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LLocalVariables; 0 5 1 value I

Sized explicitly

Local Variables

ldc "Hello"astore_0iconst_1astore_1aload_0

depth value

Stack

var value

Local Variables

0

1

2

3

4

0

1

2

3

4

ldc "Hello"astore_0iconst_1astore_1aload_0

depth value

Stack

var value

Local Variables

"Hello"0

1

2

3

4

0

1

2

3

4

ldc "Hello"astore_0iconst_1astore_1aload_0

depth valuevar value

Local Variables

"Hello"0

1

2

3

4

0

1

2

3

4

Stack

ldc "Hello"astore_0iconst_1astore_1aload_0

depth value

Stack

var value

Local Variables

"Hello"0

1

2

3

4

0

1

2

3

4

1

ldc "Hello"astore_0iconst_1astore_1aload_0

depth value

Stack

var value

Local Variables

"Hello"0

1

2

3

4

0

1

2

3

4

1

ldc "Hello"astore_0iconst_1astore_1aload_0

depth value

Stack

var value

Local Variables

"Hello"0

1

2

3

4

0

1

2

3

4

1

"Hello"

StackLocal

Variables Table

store

load

OBJECTS

new <init> <clinit>

Instance initialization method

Class and interface initialization method

Object Initialization

0xBB

Object Initialization: static {}

static {}; Code: 0: iconst_1 1: putstatic #2; //Field a:I 4: iconst_2 5: putstatic #3; //Field b:I 8: return

Object Initialization: static {}

static {}; Code: 0: iconst_1 1: putstatic #2; //Field a:I 4: iconst_2 5: putstatic #3; //Field b:I 8: return

<clinit>

Object Initialization: new

Object Initialization: new

Object Initialization: new

public Initializer(); Code:

Object Initialization: new

public Initializer(); Code: 0: aload_0

Object Initialization: new

public Initializer(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V

Object Initialization: new

public Initializer(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: aload_0

Object Initialization: new

public Initializer(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: aload_0 5: new #2; //class java/lang/Object 8: dup

Object Initialization: new

public Initializer(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: aload_0 5: new #2; //class java/lang/Object 8: dup 9: invokespecial #1; //Method java/lang/Object."<init>":()V 12: putfield #3; //Field o:Ljava/lang/Object;

Object Initialization: new

public Initializer(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: aload_0 5: new #2; //class java/lang/Object 8: dup 9: invokespecial #1; //Method java/lang/Object."<init>":()V 12: putfield #3; //Field o:Ljava/lang/Object; 15: return

Object Initialization: new

public Initializer(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: aload_0 5: new #2; //class java/lang/Object 8: dup 9: invokespecial #1; //Method java/lang/Object."<init>":()V 12: putfield #3; //Field o:Ljava/lang/Object; 15: return

Object Initialization: {}

Object Initialization: {}

?

Object Initialization: {}

public Initializer(int); Code: 0: aload_0 1: invokespecial #1; // ..<init> 4: aload_0 5: iconst_1 6: putfield #2; //Field a:I 9: aload_0 10: iconst_2 11: putfield #3; //Field c:I 14: aload_0 15: iload_1 16: putfield #4; //Field b:I 19: return

There’s no initializer

METHOD INVOCATION

invokeXXX

• invokestatic• invokespecial• invokevirtual• invokeinterface• invokedynamic

invokestatic

• invokestatic• invokespecial• invokevirtual• invokeinterface• invokedynamic

Integer.valueOf(“42”)

invokespecial

• invokestatic• invokespecial• invokevirtual• invokeinterface• invokedynamic

<init>

private void foo();

super.method();

invokevirtual

• invokestatic• invokespecial• invokevirtual• invokeinterface• invokedynamic

class AA/method1A/method2

invokevirtual

• invokestatic• invokespecial• invokevirtual• invokeinterface• invokedynamic

class A

class B

A/method1A/method2

invokevirtual

• invokestatic• invokespecial• invokevirtual• invokeinterface• invokedynamic

class A

class B

A/method1A/method2

A/method1B/method2B/method3

invokeinterface

• invokestatic• invokespecial• invokevirtual• invokeinterface• invokedynamic

class A

class B impl X

A/method1A/method2

A/method1B/method2B/method3X/methodX

invokeinterface

• invokestatic• invokespecial• invokevirtual• invokeinterface• invokedynamic

class A

class B impl X

A/method1A/method2

A/method1B/method2B/method3X/methodX

D impl XD/method1X/methodX

invokeinterface

• invokestatic• invokespecial• invokevirtual• invokeinterface• invokedynamic

class A

class B impl X

A/method1A/method2

A/method1B/method2B/method3X/methodX

D impl XD/method1X/methodX

invokeinterface

• invokestatic• invokespecial• invokevirtual• invokeinterface• invokedynamic

Efficient Implementation of Java Interfaces: Invokeinterface Considered Harmless,  Bowen Alpern, Anthony Cocchi, Stephen Fink, David Grove, and Derek Lieber, OOPSLA’01

class A

class B impl X

A/method1A/method2

A/method1B/method2B/method3X/methodX

D impl XD/method1X/methodX

Method Invocation

Method Invocation

obj.method(param1, param2);

Method Invocation

obj.method(param1, param2);

Method Invocation

obj.method(param1, param2);

push objpush param1push param2call method

Method Invocation

obj.method(param1, param2);

push objpush param1push param2call method

obj

Method Invocation

obj.method(param1, param2);

push objpush param1push param2call method

obj

param1

Method Invocation

obj.method(param1, param2);

push objpush param1push param2call method

obj

param1

param2

Method Invocation

obj.method(param1, param2);

push objpush param1push param2call method

obj?

Method Invocation

this.add(1, 2);

0: aload_01: iconst_12: iconst_23: invokevirtual #2; //Method add:(II)I

INNER CLASSES

Inner Classes

Inner Classes

Inner Classes

class Car$Engine extends j.l.Object{final Car this$0;

Car$Engine(Car); public void start(); Code: 0: aload_0 1: getfield #1; //Field this$0:LCar; 4: invokestatic #3; // Car.access$000:(LCar;)V 7: return

}

Inner Classespublic class Car extends j.l.Object{public Car();private void move();

static void access$000(Car); Code: 0: aload_0 1: invokespecial #1; // move: ()V; 4: return}

class Car$Engine extends j.l.Object{final Car this$0;

Car$Engine(Car); public void start(); Code: 0: aload_0 1: getfield #1; //Field this$0:LCar; 4: invokestatic #3; // Car.access$000:(LCar;)V 7: return

}

Inner Classespublic class Car extends j.l.Object{public Car();private void move();

static void access$000(Car); Code: 0: aload_0 1: invokespecial #1; // move: ()V; 4: return}

class Car$Engine extends j.l.Object{final Car this$0;

Car$Engine(Car); public void start(); Code: 0: aload_0 1: getfield #1; //Field this$0:LCar; 4: invokestatic #3; // Car.access$000:(LCar;)V 7: return

}

“HOW DO THEY DO THAT?”

object Singleton { def test={}}

object Singleton { def test={}}

$> scalac Singleton.scala

Singleton.class Singleton$.class

public final class Singleton extends java.lang.Object {public static final void test(); Code: 0: getstatic #11; //Field Singleton$.MODULE$:LSingleton$; 3: invokevirtual #13; //Method Singleton$.test:()V 6: return}

public final class Singleton extends java.lang.Object {public static final void test(); Code: 0: getstatic #11; //Field Singleton$.MODULE$:LSingleton$; 3: invokevirtual #13; //Method Singleton$.test:()V 6: return}

public final class Singleton extends java.lang.Object {public static final void test(); Code: 0: getstatic #11; //Field Singleton$.MODULE$:LSingleton$; 3: invokevirtual #13; //Method Singleton$.test:()V 6: return}

public final class Singleton extends java.lang.Object {public static final void test(); Code: 0: getstatic #11; //Field Singleton$.MODULE$:LSingleton$; 3: invokevirtual #13; //Method Singleton$.test:()V 6: return}

public final class Singleton$ extends java.lang.Object implements scala.ScalaObject {public static final Singleton$ MODULE$;

public static {}; Code: 0: new #9; //class Singleton$ 3: invokespecial #12; //Method "<init>":()V 6: return

public void test();private Singleton$();}

public final class Singleton extends java.lang.Object {public static final void test(); Code: 0: getstatic #11; //Field Singleton$.MODULE$:LSingleton$; 3: invokevirtual #13; //Method Singleton$.test:()V 6: return}

public final class Singleton$ extends java.lang.Object implements scala.ScalaObject {public static final Singleton$ MODULE$;

public static {}; Code: 0: new #9; //class Singleton$ 3: invokespecial #12; //Method "<init>":()V 6: return

public void test();private Singleton$();}

public final class Singleton extends java.lang.Object {public static final void test(); Code: 0: getstatic #11; //Field Singleton$.MODULE$:LSingleton$; 3: invokevirtual #13; //Method Singleton$.test:()V 6: return}

public final class Singleton$ extends java.lang.Object implements scala.ScalaObject {public static final Singleton$ MODULE$;

public static {}; Code: 0: new #9; //class Singleton$ 3: invokespecial #12; //Method "<init>":()V 6: return

public void test();private Singleton$();}

public final class Singleton extends java.lang.Object {public static final void test(); Code: 0: getstatic #11; //Field Singleton$.MODULE$:LSingleton$; 3: invokevirtual #13; //Method Singleton$.test:()V 6: return}

public final class Singleton$ extends java.lang.Object implements scala.ScalaObject {public static final Singleton$ MODULE$;

public static {};public void test();private Singleton$(); Code: 0: aload_0 1: invokespecial #17; //Method java/lang/Object."<init>":()V 4: aload_0 5: putstatic #19; //Field MODULE$:LSingleton$; 8: return

object Singleton { def test={}}

object Singleton { def test={}}

public class Singleton { public void test(){ Singleton$.MODULE$.test(); }}

object Singleton { def test={}}

public class Singleton { public void test(){ Singleton$.MODULE$.test(); }} public final class Singleton$ implements scala.ScalaObject { public static final Singleton$ MODULE$; static { new Singleton$(); }

private Singleton$(){ MODULE$ = this; }

public void test() { }}

class Groovy { }

class Groovy { }

$> groovyc Groovy.groovy$> javap –c –p Groovy

class Groovy { }

$> groovyc Groovy.groovy$> javap –c –p Groovypublic class Test extends java.lang.Object implements groovy.lang.GroovyObject{ private static org.codehaus.groovy.reflection.ClassInfo $staticClassInfo; private transient groovy.lang.MetaClass metaClass; public static java.lang.Long __timeStamp; public static java.lang.Long __timeStamp__239_neverHappen1304807931117; private static java.lang.ref.SoftReference $callSiteArray; private static java.lang.Class $class$groovy$lang$MetaClass; private static java.lang.Class $class$Test; private static java.lang.Class $class$java$lang$String; public java.lang.Object this$dist$invoke$2(java.lang.String, java.lang.Object); public void this$dist$set$2(java.lang.String, java.lang.Object); public java.lang.Object this$dist$get$2(java.lang.String); protected groovy.lang.MetaClass $getStaticMetaClass(); public groovy.lang.MetaClass getMetaClass(); public void setMetaClass(groovy.lang.MetaClass); public java.lang.Object invokeMethod(java.lang.String, java.lang.Object); public java.lang.Object getProperty(java.lang.String); public void setProperty(java.lang.String, java.lang.Object);

OBJECTWEB ASM

SLIDESGOTO IDESLIDESIDE: DEMO

https://github.com/antonarhipov

@antonarhipov

anton@zeroturnaround.com