Slide pack for goto java; presentation at JavaZone 2014.
The talk looks into the Java compiler and adds support for goto statements.
Size: 27.43 MB
Language: en
Added: Sep 09, 2014
Slides: 123 pages
Slide Content
Martin Skarsaune Java Developer and Co- Owner A peek into the OpenJDK compiler : goto java ; 高馬丁
GOTO statements in Java!
GOTO Statement – Objective Syntax : goto identifier; Runtime Program control moves to target statement Other Semantics Target (statement label ) must be defined in same scope , compilation error if not Potential circular gotos should give compilation warning .
GOTO Statement – Means OpenJDK Open source Java implementation Compiler i mplemented in Java Modify compiler source to support goto statements
Syntax : goto identifier; First c onvert character stream to token stream ( Scanner.java ) [g][o][t][o][ ][f][o][u][r][;]
goto is already a reserved word in Java! Lucky for us , goto is therefore defined as a TokenKind . Tokens.java:141: GOTO ( " goto " ) The scanner therefore works out of the box !
Wikipedia: “ the visitor design pattern is a way of separating an algorithm from an object structure on which it operates ” visitClassDef (..) visitMethodDef (..) visitIf (..) Abstract Syntax Tree [g][o][t][o][ ][f][o][u][r][;]
Class Interface
Interface based visitors
Class based visitors public void visitGoto ( JCGoto tree ) { try { print( "goto " + tree . label + ";" ); } catch ( IOException e ) { throw new UncheckedIOException ( e ); } } public void visitGoto ( JCGoto tree ) { // TODO implement }
public static class JCLabeledStatement extends JCStatement implements LabeledStatementTree { … public GotoResolver handler ; … } public class GotoResolver { Map < GotoTree , Name> gotos ; Map <Name, LabeledStatementTree > targets; List < StatementTree > statementsInSequence ; ... }
JavacParser.parseStatement () case GOTO : { nextToken (); Name label = ident(); JCGoto t = to ( F .at ( pos ).Goto( label , getGotoResolver ())); accept ( SEMI ); return t ; } TreeMaker.java : public JCGoto Goto (Name label , GotoResolver resolver ) { JCGoto tree = new JCGoto ( label , resolver ); tree . pos = pos ; return tree ; }
Basic sanity testing of compilation unit File name and folder location Duplicate class names Corrections Add default constructor if no constructors are declared
public class SimpleClass { } Default constructor
public class SimpleClass { public SimpleClass () { super (); } } Default constructor
Semantic checks Types References Corrections Add required calls to super constructor
We want to verify that goto target exists in current scope public class GotoMissingLabel { public static void main(String[] args ) { one: System.out.print ( " goto " ); two: System.out.print ( "Java" ); goto six ; three: System.out.print ( "2014" ); goto five; four: System.out.print ( "Zone " ); goto three; five: System.out.print ( "!" ); } }
Attr.java : @Override public void visitGoto ( JCGoto that ) { that .findTarget (); if ( that . target == null ) log .error ( that .pos (), " undef.label " , that . label ); result = null ; } class JCGoto : … public void findTarget () { this . target = ( JCLabeledStatement ) this . handler .findTarget ( this ); }
Erase generic types public class Bridge implements Comparator { }
Erase generic types public class Bridge implements Comparator { } public interface Comparator< T > { t int compare( T o1 , T o2 ) ; } or <T> {
Erase generic types public class Bridge implements Comparator<Integer> { } public interface Comparator< T > { t int compare( T o1 , T o2 ) ; } or <T> {
Erase generic types public class Bridge implements Comparator< Integer > { public int compare( Integer first , Integer second ) { return first - second ; } } public interface Comparator< T > { t int compare( T o1 , T o2 ) ; } or <T> {
Erase generic types public class Bridge implements Comparator { public int compare( Integer first , Integer second ) { return first - second ; } }
Erase generic types public class Bridge implements Comparator { public int compare( Integer first , Integer second ) { return first - second ; } / *synthetic*/ public int compare (Object first , Object second ) { return this .compare ((Integer) first , (Integer) second ); } }
Extract Inner Class public class Outer { private void foo() { } public Runnable fooRunner ( ) { return new Runnable( ) { public void run() { foo (); } }; } }
Extract Inner Class public class Outer { private void foo() { } public Runnable fooRunner ( ) { return new Runnable( ) { public void run() { foo (); } }; } }
Extract Inner Class public class Outer { private void foo() { } public Runnable fooRunner ( ) { return new Outer$1( this ) ; } } class Outer$1 implements Runnable { final Outer this$0 ; public void run() { this $ .foo(); } }
Extract Inner Class public class Outer { private void foo() { } public Runnable fooRunner ( ) { return new Outer$1( this ) ; } } class Outer$1 implements Runnable { final Outer this$0 ; Outer$1( final Outer this$0 ) { this . this$0 = this$0 ; super (); } public void run() { this $ .foo(); } }
Extract Inner Class public class Outer { private void foo() { } public Runnable fooRunner ( ) { return new Outer$1( this ) ; } } class Outer$1 implements Runnable { final Outer this$0 ; Outer$1( final Outer this$0 ) { this . this$0 = this$0 ; super (); } public void run() { this $ . foo (); } }
Extract Inner Class public class Outer { private void foo() { } public Runnable fooRunner ( ) { return new Outer$1( this ) ; } static void access$000 ( Outer x0 ) { x0 .foo(); } } class Outer$1 implements Runnable { final Outer this$0 ; Outer$1( final Outer this$0 ) { this . this$0 = this$0 ; super (); } public void run() { Outer.access$000( this$0 ); } }
Boxing List <Integer> list = Arrays. asList (1, 2); for (Integer i : list ) { System. out .println ( "Double: " + i * 2) ; }
Boxing List <Integer> list = Arrays. asList ( 1 , 2 ); for (Integer i : list ) { System. out .println ( "Double: " + i * 2) ; } public static <T> List<T> asList (T... a) { return new ArrayList <>(a); } public static < T > List< T > asList ( T ... a ) { return new ArrayList <>( a ); }
Boxing List <Integer> list = Arrays. asList ( Integer.valueOf (1) , Integer.valueOf (2) ); for (Integer i : list ) { System. out .println ( "Double: " + i * 2) ; }
Unboxing List <Integer> list = Arrays. asList ( Integer.valueOf (1) , Integer.valueOf (2)); for ( Integer i : list ) { System. out .println ( "Double: " + i * 2 ) ; }
Unboxing List <Integer> list = Arrays. asList ( Integer.valueOf (1) , Integer.valueOf (2)); for ( Integer i : list ) { System. out .println ( "Double: " + i.intValue () * 2) ; }
Varargs List <Integer> list = Arrays. asList ( Integer.valueOf (1) , Integer.valueOf (2)); for ( Integer i : list ) { System. out .println ( "Double: " + i.intValue () * 2) ; }
Varargs List <Integer> list = Arrays. asList ( Integer.valueOf (1) , Integer.valueOf (2)); for ( Integer i : list ) { System. out .println ( "Double: " + i.intValue () * 2) ; } public static <T> List<T> asList (T... a) { return new ArrayList <>(a); } public static < T > List< T > asList ( T ... a ) { return new ArrayList <>( a ); }
Varargs List <Integer> list = Arrays. asList ( new Integer[]{ Integer.valueOf (1) , Integer.valueOf (2) } ); for ( Integer i : list ) { System. out .println ( "Double: " + i.intValue () * 2) ; }
For each loop List <Integer> list = Arrays. asList ( new Integer[]{ Integer.valueOf (1) , Integer.valueOf (2)}); for (Integer i : list) { System. out .println ( "Double: " + i.intValue () * 2) ; }
For each loop List <Integer> list = Arrays. asList ( new Integer[]{ Integer.valueOf (1) , Integer.valueOf (2)}); for ( Integer i : list ) { System. out .println ( "Double: " + i.intValue () * 2) ; } public static <T> List<T> asList (T... a) { return new ArrayList <>(a); } public interface Iterable <T> { Iterator<T> iterator () ; }
For each loop List <Integer> list = Arrays. asList ( new Integer[]{ Integer.valueOf (1) , Integer.valueOf (2)}); for (;;) { Integer i System. out .println ( "Double: " + i.intValue () * 2) ; }
For each loop List <Integer> list = Arrays. asList ( new Integer[]{ Integer.valueOf (1) , Integer.valueOf (2)}); for ( Iterator i $ = list.iterator () ;;) { Integer i System. out .println ( "Double: " + i.intValue () * 2) ; }
For each loop List <Integer> list = Arrays. asList ( new Integer[]{ Integer.valueOf (1) , Integer.valueOf (2)}); for ( Iterator i $ = list.iterator () ; i $ . hasNext () ;) { Integer i System. out .println ( "Double: " + i.intValue () * 2) ; }
For each loop List <Integer> list = Arrays. asList ( new Integer[]{ Integer.valueOf (1) , Integer.valueOf (2)}); for ( Iterator i $ = list.iterator () ; i $ . hasNext () ;) { Integer i = (Integer) i $ .next(); System. out .println ( "Double: " + i.intValue () * 2) ; }
Enums public enum Status { YES , NO , MAYBE }
Enums public enum Status { YES , NO , MAYBE private Status (String $ enum$name , int $ enum$ordinal ) { super ($ enum$name , $ enum$ordinal ); } }
Enums public enum Status { YES , NO , MAYBE private Status (String $ enum$name , int $ enum$ordinal ) { super ($ enum$name , $ enum$ordinal ); } public static Status valueOf (String name) { return (Status) Enum.valueOf ( Status. class , name); } }
Enums public enum Status { YES , NO , MAYBE private Status (String $ enum$name , int $ enum$ordinal ) { super ($ enum$name , $ enum$ordinal ); } public static Status valueOf (String name) { return (Status) Enum.valueOf ( Status. class , name); } private static final Status[] $VALUES = new Status[] { Status.YES , Status.NO , Status.MAYBE } ; public static Status[] values() { return (Status[])$ VALUES.clone (); } }
Enum based switch statements public class SwitchStatus { void switchStatus (Status status ) { switch ( status ) { case MAYBE : return ; default : break ; } } }
Enum based switch statements public class SwitchStatus { void switchStatus (Status status ) { switch ( status ) { case MAYBE : return ; default : break ; } } }
Enum based switch statements public class SwitchStatus { void switchStatus (Status status ) { switch ( SwitchStatus$1.$SwitchMap$Status[(status).ordinal()] ) { case 1 : return ; default : break ; } } }
Enum based switch statements public class SwitchStatus { void switchStatus (Status status ) { switch ( SwitchStatus$1.$SwitchMap$Status[ (status).ordinal() ] ) { case 1 : return ; default : break ; } } } class SwitchStatus$1 { }
Enum based switch statements public class SwitchStatus { void switchStatus (Status status ) { switch ( SwitchStatus$1.$SwitchMap$Status[ (status).ordinal() ] ) { case 1 : return ; default : break ; } } } class SwitchStatus$1 { static final int [] $ SwitchMap$Status = new int [ Status.values (). length ] ; }
Enum based switch statements public class SwitchStatus { void switchStatus (Status status ) { switch ( SwitchStatus$1.$SwitchMap$Status[ (status).ordinal() ] ) { case 1 : return ; default : break ; } } } class SwitchStatus$1 { static final int [] $ SwitchMap$Status = new int [ Status.values (). length ] ; [0][0][0] }
Enum based switch statements public class SwitchStatus { void switchStatus (Status status ) { switch ( SwitchStatus$1.$SwitchMap$Status[ (status).ordinal() ] ) { case 1 : return ; default : break ; } } } class SwitchStatus$1 { static final int [] $ SwitchMap$Status = new int [ Status.values (). length ]; [0][0] [1] static { try { SwitchStatus$1. $SwitchMap$Status [ Status.MAYBE.ordinal () ] = 1 ; } catch ( NoSuchFieldError ex ) { } } }
Enum based switch statements public class SwitchStatus { void switchStatus (Status status ) { switch ( SwitchStatus$1.$SwitchMap$Status[ (status).ordinal() ] ) { case 1 : return ; default : break ; } } } class SwitchStatus$1 { static final int [] $ SwitchMap$Status = new int [ Status.values (). length ]; [0][0][1 ] static { try { SwitchStatus$1. $SwitchMap$Status [ Status.MAYBE.ordinal () ] = 1 ; } catch ( NoSuchFieldError ex ) { } } }
Generate bytecodes Organize initializers String concatenation Some optimizations
Organize < init > (Constructor) public class InstanceInitialization { String key = "key" ; String value ; public InstanceInitialization (String value ) { this . value = value ; } }
Organize < init > (Constructor) public class InstanceInitialization { String key = "key" ; String value ; public InstanceInitialization (String value ) { super (); this . value = value ; } }
Organize < init > (Constructor) public class InstanceInitialization { String key ; String value ; public InstanceInitialization (String value ) { super () ; key = ”key”; this . value = value ; } }
Organize < init > (Constructor) public class InstanceInitialization { String key ; String value ; public < init >( String value ) { super () ; key = ”key”; this . value = value ; } }
Organize < clinit > (Static initialization) public class StaticInitialization { static String key = "key" ; static String value ; static { value = value ; } }
Organize < clinit > (Static initialization) public class StaticInitialization { static String key ; static String value ; static { key = " key ” ; value = value ; } }
Organize < clinit > (Static initialization) public class StaticInitialization { static String key ; static String value ; static void < clinit >{ key = " key” ; value = value ; } }
” string ” + value new StringBuilder () Source code “Generated code”
” string ” + value new StringBuilder () .append( ”string” ) Source code “Generated code”
” string ” + value new StringBuilder () . append( ”string” ) .append( value ) Source code “Generated code”
” string ” + value new StringBuilder () .append( ”string” ) .append( value ) . toString () Source code “Generated code”
Goto Generation Lucky for us there is a byte code for goto goto < addr >
… if (< test> ) { < ifblock > } else { < elseblock > } < codeafter > Source code Byte code PC … … 9 ifeq … < elseblock > … goto < stackmap > 22 < ifblock > 22 < stackmap > 29 < codeafter > 29 Java >= 1.6: Stack map frames must be embedded at target of jump instruction Code generator ( Code.java ) marked as not alive. Goto instruction added to list of pending jumps ( Chain.java ) Pending jumps processed
… label: < somecode > … g oto label ; Source code Byte code PC … 2 … goto 20 < stackmap > < somecode > Used by goto ? Must emit stackmap Scenario 1: go back Emit goto to label and turn code generation on again
… g oto label ; … label: < somecode > Source code Byte code PC … … 29 < somecode > goto < stackmap > Label position not yet known? emit goto add to list of pending gotos t urn generation on again Scenario 2: go forward Label used? emit stack frame patch pending gotos 29
Gen.java - Labelled public void visitLabelled ( JCLabeledStatement tree ) { // if the label is used from gotos , have to emit stack map if ( tree . handler .isUsed ( tree )) code .emitStackMap (); … }
Gen.java - Goto public void visitGoto ( JCGoto tree ) { tree . handler .addBranch ( new Chain( code .emitJump ( goto _ ), null , code . state .dup ()), tree . target ); / /normally goto marks code as not alive, turn generation on code .entryPoint (); } Target position known? Yes – patch immediately No – add to list of pending gotos
Mission Accomplished!
λ ambda
Lambda implementation in Java 8 Language change Compilation Runtime support Many interesting design considerations
Simple example public Comparator<String> lambdaExample ( ) { return (String a , String b ) -> a .compareTo ( b ); }
LambdaToMethod.java public Comparator<String> lambdaExample ( ) { return (String a , String b ) -> a .compareTo ( b ); } /*synthetic*/ private static int lambda $lambdaExample$0 ( , ) { return ; } final String a final String b a .compareTo ( b )
Runtime public Comparator<String> lambdaExample ( ) { return < invokedynamic > LambdaMetafactory.metafactory ( } /*synthetic*/ private static int lambda $lambdaExample$0 ( final String a , final String b ) { return a .compareTo ( b ); } public interface Comparator { / *erased* / int compare(Object o1 , Object o2 ); } Lookup( LambdaExample ) , / *caller* / "compare" , ()Comparator, /* MethodType */ ( Object,Object ) int , / * MethodType * / lambda$lambdaExample$0 , /* MethodHandle * / ( String,String ) int ); /* MethodType */ final class LambdaExample $$Lambda$1/1834188994 implements Comparator { private LambdaExample $$Lambda$1/1834188994() public int compare( Object,Object ) }
Runtime class generation Lambda Class
Serialization Lambda Instance Serialize Serialized Lambda Deserialize Lambda Meta Factory
Example with instance and local capture private int c = 3; public Comparator<String> withInstanceAndLocalCapture () { int a = 1, b = 2; return (String d , String e ) -> d .compareTo ( e ) + a + b - c ; }
Example with instance and local capture private int c = 3; public Comparator<String> withInstanceAndLocalCapture () { int a = 1, b = 2; return (String d , String e ) -> d .compareTo ( e ) + a + b - c ; } /*synthetic*/ private int lambda$withInstanceAndLocalCapture$1 ( final int cap$0 , final int cap$1 , final String d , final String e ) { return d .compareTo ( e ) + cap$0 + cap$1 - c ; }
Example with instance and local capture private int c = 3; public Comparator<String> withInstanceAndLocalCapture () { int a = 1, b = 2; return < invokedynamic > LambdaMetafactory.metafactory ( this ,a,b ); } / *synthetic*/ private int lambda$withInstanceAndLocalCapture$1 ( final int cap$0 , final int cap$1 , final String d , final String e ) { return d .compareTo ( e ) + cap$0 + cap$1 - c ; }
Example with instance and local capture final class LambdaExample $$Lambda$2/2117255219 extends Object implements Comparator { public int compare (Object, Object ) private final LambdaExample arg$ 1; private final int arg$ 2; private final int arg$ 3; private LambdaExample $$Lambda$2/2117255219( LambdaExample, int , int ) private static Comparator get$Lambda ( LambdaExample, int , int ) } .lambda $withInstanceAndLocalCapture$1 ( arg$2 , arg$3 ,(String) d ,(String) e ) a rg$1
Possible to back port ? Capture generated class ? Compile time generation of inner class!
Possible to back port ? Capture generated class ? Compile time generation of inner class!
Questions or Comments ? Martin Skarsaune Java Developer and Co- Owner
Thank You for Your Time! Martin Skarsaune Java Developer and Co- Owner if ( you.want ( nineBot )) goto K antega; Kantega: eat( bbq ); test( java.skills );