Download - goto java; (Jfokus)

Transcript
Page 1: goto java; (Jfokus)

@MSkarsaune

Martin SkarsauneJava Developer and Co-Owner

A peek into the OpenJDK compiler : goto java;

高馬丁

We’re

Hiring!

Page 2: goto java; (Jfokus)

@MSkarsaune

GOTO Statements in Java!

Page 3: goto java; (Jfokus)

@MSkarsaune

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.

Page 4: goto java; (Jfokus)

@MSkarsaune

GOTO Statement – Means• OpenJDK• Open source Java implementation• Javac is implemented in plain Java

• Modify compiler to support GOTO

Page 5: goto java; (Jfokus)

@MSkarsaune

public class GotoSuccess {

public static void main(String[] args) {one: System.out.print("goto ");two: System.out.print(”J");goto four;three: System.out.print(”2017");goto five;four: System.out.print(”Fokus ");goto three;five: System.out.print("!");

}}

Success Case

Page 6: goto java; (Jfokus)

@MSkarsaune

GOTOAHEAD

Dijkstra 1968:

Page 7: goto java; (Jfokus)

@MSkarsaune

What is a Compiler?

Compiler

Page 8: goto java; (Jfokus)

@MSkarsaune

What is a Compiler?

frontend

backend

Page 9: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))

Page 10: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))

Page 11: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

• Syntax: goto identifier;• First convert character stream to token stream

(Scanner.java)

GOTO IDENTIFIER SEMI

[g][o][t][o][ ][f][o][u][r][;]

Page 12: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

• 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!

Page 13: goto java; (Jfokus)

@MSkarsaune

...import com.sun.tools.javac.parser.Scanner;...

Parse Enter Process Attribute Flow Desugar Generat

e

final Scanner scanner=factory.newScanner(”goto identifier;”, false);

Page 14: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

final Scanner scanner=factory.newScanner(”goto identifier;”, false);

scanner.nextToken();

Page 15: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

final Scanner scanner=factory.newScanner(”goto identifier;”, false);

scanner.nextToken();assertThat(”First token is GOTO”, scanner.token().kind, is(GOTO));

Page 16: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

final Scanner scanner=factory.newScanner(”goto identifier;”, false);

scanner.nextToken();assertThat(”First token is GOTO”, scanner.token().kind, is(GOTO));

scanner.nextToken();

Page 17: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

final Scanner scanner=factory.newScanner(”goto identifier;”, false);

scanner.nextToken();assertThat(”First token is GOTO”, scanner.token().kind, is(GOTO));

scanner.nextToken();assertThat("Second token is IDENTIFIER", scanner.token().kind,

is(IDENTIFIER));

Page 18: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

final Scanner scanner=factory.newScanner(”goto identifier;”, false);

scanner.nextToken();assertThat(”First token is GOTO”, scanner.token().kind, is(GOTO));

scanner.nextToken();assertThat("Second token is IDENTIFIER", scanner.token().kind,

is(IDENTIFIER));

scanner.nextToken();

Page 19: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

final Scanner scanner=factory.newScanner(”goto identifier;”, false);

scanner.nextToken();assertThat(”First token is GOTO”, scanner.token().kind, is(GOTO));

scanner.nextToken();assertThat("Second token is IDENTIFIER", scanner.token().kind,

is(IDENTIFIER));

scanner.nextToken(); assertThat("Third token is SEMI", scanner.token().kind, is(SEMI));

Page 20: goto java; (Jfokus)

@MSkarsaune

CompilationUnit

ClassDefinitionFieldDefintion

MethodDefinition

Signature

BodyIfStatement

Goto

visitClassDef(..)

visitMethodDef(..)

visitIf(..)

Abstract Syntax Tree

[g][o][t][o][ ][f][o][u][r][;]

GOTO IDENTIFIER SEMIWikipedia: “the visitor design pattern is a way of separating an algorithm from an

object structure on which it operates”

Parse Enter Process Attribute Flow Desugar Generat

e

Page 21: goto java; (Jfokus)

@MSkarsaune

ClassInterface

Parse Enter Process Attribute Flow Desugar Generat

e

Page 22: goto java; (Jfokus)

@MSkarsaune

Interface based visitors

Parse Enter Process Attribute Flow Desugar Generat

e

Page 23: goto java; (Jfokus)

@MSkarsaune

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}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 24: goto java; (Jfokus)

@MSkarsaune

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; ...}

Helper object

Parse Enter Process Attribute Flow Desugar Generat

e

Page 25: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

Page 26: goto java; (Jfokus)

@MSkarsaune

Demo

Page 27: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))✔

Page 28: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))

Page 29: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

• Basic sanity testing of compilation unit:

• File name and folder location• Duplicate class names

• Corrections• Add default constructor if no

constructors are declared

Page 30: goto java; (Jfokus)

@MSkarsaune

Default Constructorpublic class SimpleClass {

}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 31: goto java; (Jfokus)

@MSkarsaune

Default Constructorpublic class SimpleClass { public SimpleClass() { super(); }}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 32: goto java; (Jfokus)

@MSkarsaune

✔Parse Enter Process Attribut

e Flow Desugar Generate

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))

Page 33: goto java; (Jfokus)

@MSkarsaune

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))

Parse Enter Process Attribute Flow Desugar Generat

e

Page 34: goto java; (Jfokus)

@MSkarsaune

• Process Annitations• Annotation processing API• Part of ordinary javac process since Java

1.6• Plugin API (see javac documentation)

Parse Enter Process Attribute Flow Desugar Generat

e

Page 35: goto java; (Jfokus)

@MSkarsaune

• Output controlled by command line switches

@

- proc:only – only process annotations, do not compile- proc:none – do not process annotations

Parse Enter Process Attribute Flow Desugar Generat

e

Page 36: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))✔

Page 37: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))

Page 38: goto java; (Jfokus)

@MSkarsaune

• Attribution• Semantic checks

–Types–References

• Corrections–Add required calls to super constructor

Parse Enter Process Attribute Flow Desugar Generat

e

Page 39: goto java; (Jfokus)

@MSkarsaune

Ensure target label exists in current scopepublic class GotoMissingLabel {

public static void main(String[] args) {one: System.out.print("goto ");two: System.out.print(”Java");goto six;three: System.out.print(”2016");goto five;four: System.out.print(”One ");goto three;five: System.out.print("!");

}}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 40: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

Page 41: goto java; (Jfokus)

@MSkarsaune

Demo

Page 42: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))✔

Page 43: goto java; (Jfokus)

@MSkarsaune

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))

Parse Enter Process Attribute Flow Desugar Generat

e

Page 44: goto java; (Jfokus)

@MSkarsaune

Flow analysis• Detect unreachable code• Verify assignments• Ensure proper method return• Verify (effectively) final• Check exception flow

Parse Enter Process Attribute Flow Desugar Generat

e

Page 45: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

Detect circular gotospublic class GotoCircularWarning {

public static void main(String[] args) { one: System.out.print("goto "); two: System.out.print(”Java"); goto four; three: System.out.print(”2016"); goto five; four: System.out.print(”One "); goto three; five: System.out.println("!"); goto one;//forms infinite loop }}

Page 46: goto java; (Jfokus)

@MSkarsaune

Flow.FlowAnalyzer class:

compiler.properties:

@Override public void visitGoto(JCGoto tree) { if (tree.handler.detectCircularGotoPosition(tree))

log.warning(tree.pos, "circular.goto"); }

...compiler.warn.circular.goto=circular goto...

Parse Enter Process Attribute Flow Desugar Generat

e

Page 47: goto java; (Jfokus)

@MSkarsaune

Demo

Page 48: goto java; (Jfokus)

@MSkarsaune

✔processAnnotations(enterTrees(…

parseFiles(…))),…)…

generate(desugar(flow(attribute(…))))

Parse Enter Process Attribute Flow Desugar Generat

e

Page 49: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))

Page 50: goto java; (Jfokus)

@MSkarsaune

Erase generic types

public class Bridge implements Comparator {

}

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lowerpublic interface Comparator<T> {int compare(T o1, T o1);

}or<T> {

Page 51: goto java; (Jfokus)

@MSkarsaune

Erase generic types

public class Bridge implements Comparator<Integer> {

public int compare(Integer first, Integer second) {return first - second;

}

}

TransTypes Unlambda Lower

Parse Enter Process Attribute Flow Desugar Generat

e

public interface Comparator<T> {int compare(T o1, T o1);

} or<T> {

Page 52: goto java; (Jfokus)

@MSkarsaune

Erasure - Runtime

public class Bridge implements Comparator {

public int compare(Integer first, Integer second) {return first - second;

}

}

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 53: goto java; (Jfokus)

@MSkarsaune

Erasure - Bridge

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

}

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 54: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerExtract inner classpublic class Outer {

private void foo() { }

public Runnable fooRunner() {return new Runnable() {

public void run() {foo();

}};

}}

Page 55: goto java; (Jfokus)

@MSkarsaune

Extract inner class

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

public class Outer {private void foo() { }

public Runnable fooRunner() {return new Runnable() {

public void run() {foo();

}};

}}

Page 56: goto java; (Jfokus)

@MSkarsaune

Extract inner classpublic class Outer {

private void foo() { }

public Runnable fooRunner() {return new Outer$1(this);

}}

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

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$0.foo(); }}

Page 57: goto java; (Jfokus)

@MSkarsaune

Extract inner class

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

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$0.foo(); }}

Page 58: goto java; (Jfokus)

@MSkarsaune

TransTypes Unlambda Lower

Parse Enter Process Attribute Flow Desugar Generat

e

Extract inner classpublic class Outer {

private void foo() { }

public Runnable fooRunner() {return new Outer$1(this);

}/*synthetic*/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); }}

Page 59: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerBoxingList<Integer> list =

Arrays.asList(1, 2);for (Integer i : list) {

System.out.println(”Double: “ + i * 2);}

Page 60: goto java; (Jfokus)

@MSkarsaune

Boxing

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

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

Page 61: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerBoxingList<Integer> list =

Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));for (Integer i : list) {

System.out.println(”Double: “ + i * 2);}

Page 62: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerUnboxingList<Integer> list =

Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));for (Integer i : list) {

System.out.println(”Double: “ + i * 2);}

Page 63: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerUnboxingList<Integer> list =

Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));for (Integer i : list) {

System.out.println(”Double: “ + i.intValue() * 2);}

Page 64: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerVarargsList<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); }

Page 65: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerVarargsList<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);}

Page 66: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerVarargs - runtimeList<Integer> list =

Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});for (Integer i : list) {

System.out.println(”Double: “ + i.intValue() * 2);}

Page 67: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerFor each loopList<Integer> list =

Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});for (Integer i : list) {

System.out.println(”Double: “ + i.intValue() * 2);}

Page 68: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerFor each loopList<Integer> list =

Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});for (Integer i : list) {

System.out.println(”Double: “ + i.intValue() * 2);}

public interface Iterable<T> { Iterator<T> iterator();}

Page 69: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerFor each loopList<Integer> list =

Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});for (;;) {

System.out.println(”Double: “ + i.intValue() * 2);}

Page 70: goto java; (Jfokus)

@MSkarsaune

TransTypes Unlambda Lower

Parse Enter Process Attribute Flow Desugar Generat

e

For each loopList<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);

}

Page 71: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerFor each loopList<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);

}

Page 72: goto java; (Jfokus)

@MSkarsaune

TransTypes Unlambda Lower

Parse Enter Process Attribute Flow Desugar Generat

e

For each loopList<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);

}

Page 73: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerEnumspublic enum Status {

YES, NO, MAYBE}

Page 74: goto java; (Jfokus)

@MSkarsaune

TransTypes Unlambda Lower

Parse Enter Process Attribute Flow Desugar Generat

e

Enums - constructorpublic enum Status {

YES, NO, MAYBEprivate Status(String $enum$name, int $enum$ordinal) {

super($enum$name, $enum$ordinal); }}

public static final Status TRUE = new Status("TRUE", 0);public static final Status FALSE = new Status("FALSE", 1);public static final Status MAYBE = new Status("MAYBE", 2);

Page 75: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerEnums - valueOfpublic enum Status {

YES, NO, MAYBEprivate 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); }}

Page 76: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerEnums - valuespublic enum Status {

YES, NO, MAYBEprivate 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(); }}

Page 77: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerEnum switch statementpublic class SwitchStatus {

void switchStatus(Status status) {

switch (status) { case MAYBE: return;

default: break; } }}

Page 78: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerEnum switch statementpublic class SwitchStatus {

void switchStatus(Status status) {

switch (status) { case MAYBE: return;

default: break; } }}

Page 79: goto java; (Jfokus)

@MSkarsaune

TransTypes Unlambda Lower

Parse Enter Process Attribute Flow Desugar Generat

e

Enum switch statementpublic class SwitchStatus {

void switchStatus(Status status) {

switch (SwitchStatus$1.$SwitchMap$Status[(status).ordinal()]) { case 1: return;

default: break; } }}

class SwitchStatus$1 {

}

Page 80: goto java; (Jfokus)

@MSkarsaune

TransTypes Unlambda Lower

Parse Enter Process Attribute Flow Desugar Generat

e

Enum switch statementpublic 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];

}

Page 81: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerEnum switch statementpublic 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]

}

Page 82: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerEnum switch statementpublic 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) { } }}

Page 83: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))✔

Page 84: goto java; (Jfokus)

@MSkarsaune

processAnnotations(enterTrees(… parseFiles(…))),…)

…generate(desugar(flow(attribute(…))))

Parse Enter Process Attribute Flow Desugar Generat

e

Page 85: goto java; (Jfokus)

@MSkarsaune

• Organize initializers• String concatenation• Generate bytecodes

Parse Enter Process Attribute Flow Desugar Generat

e

Page 86: goto java; (Jfokus)

@MSkarsaune

• Organize <init> (Constructor)public class InstanceInitialization { String key="key"; String value; public InstanceInitialization(String value) { this.value = value; }

}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 87: goto java; (Jfokus)

@MSkarsaune

• Organize <init> (Constructor)public class InstanceInitialization { String key="key"; String value; public InstanceInitialization(String value) {

super(); this.value = value; }

}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 88: goto java; (Jfokus)

@MSkarsaune

• Organize <init> (Constructor)public class InstanceInitialization { String key; String value; public InstanceInitialization(String value) {

super(); key = ”key”; this.value = value; }

}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 89: goto java; (Jfokus)

@MSkarsaune

• Organize <init> (Constructor)public class InstanceInitialization { String key; String value; public void <init> () {

super(); key = ”key”; this.value = value; }

}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 90: goto java; (Jfokus)

@MSkarsaune

• Organize <clinit> (static initialization)public class StaticInitialization { static String key="key"; static { init(); }}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 91: goto java; (Jfokus)

@MSkarsaune

• Organize <clinit> (static initialization)public class StaticInitialization { static String key; static { key="key"; init(); }}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 92: goto java; (Jfokus)

@MSkarsaune

• Organize <clinit> (static initialization)public class StaticInitialization { static String key; static void <clinit>() { key="key"; init(); }}

Parse Enter Process Attribute Flow Desugar Generat

e

Page 93: goto java; (Jfokus)

@MSkarsaune

String concatenationSource code “Generated code”

”string” + value

Parse Enter Process Attribute Flow Desugar Generat

e

Page 94: goto java; (Jfokus)

@MSkarsaune

String concatenationSource code “Generated code”

”string” + value new StringBuilder()

Parse Enter Process Attribute Flow Desugar Generat

e

Page 95: goto java; (Jfokus)

@MSkarsaune

String concatenationSource code “Generated code”

”string” + value new StringBuilder() .append(”string”)

Parse Enter Process Attribute Flow Desugar Generat

e

Page 96: goto java; (Jfokus)

@MSkarsaune

String concatenationSource code “Generated code”

”string” + value new StringBuilder() .append(”string”) .append(value)

Parse Enter Process Attribute Flow Desugar Generat

e

Page 97: goto java; (Jfokus)

@MSkarsaune

String concatenationSource code “Generated code”

”string” + value new StringBuilder() .append(”string”) .append(value) .toString()

Parse Enter Process Attribute Flow Desugar Generat

e

Page 98: goto java; (Jfokus)

@MSkarsaune

• Goto generation–Luckily for us there is a GOTO byte code–goto <addr>

Parse Enter Process Attribute Flow Desugar Generat

e

Page 99: goto java; (Jfokus)

@MSkarsaune

if (<test>) { <ifblock>} else { <elseblock>}<codeafter>

Source code Byte codeCI

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

Normal GOTO usage

Parse Enter Process Attribute Flow Desugar Generat

e

Page 100: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

Source code Byte codeCI…label: <somecode>…goto label;

…20

… goto 20

<stackmap><somecode>

Used by goto?Must emit stackmap

Emit goto to label and turn code generation on again

GOTO scenario 1 : jump back

Page 101: goto java; (Jfokus)

@MSkarsaune

Source code Byte codeCI

GOTO scenario 2 : jump forward…goto label; …label: <somecode>

……

29 <somecode>

goto<stackmap>

Label position not yet known?• emit goto• add to list of pending gotos• turn generation on again

29Label used? • emit stack frame • patch pending

gotos

Parse Enter Process Attribute Flow Desugar Generat

e

Page 102: goto java; (Jfokus)

@MSkarsaune

• Goto generation–Gen.java , visitor for code generation–Modify for LabelledStatement–Add implementation for Goto

Parse Enter Process Attribute Flow Desugar Generat

e

Page 103: goto java; (Jfokus)

@MSkarsaune

• Gen.java – Labelled Statement

public void visitLabelled(JCLabeledStatement tree) { // if the label is used from gotos, have to emit stack map if (tree.handler.isUsed(tree)) code.emitStackMap(); … }

Parse Enter Process Attribute Flow Desugar Generat

e

Page 104: goto java; (Jfokus)

@MSkarsaune

• 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

Parse Enter Process Attribute Flow Desugar Generat

e

Page 105: goto java; (Jfokus)

@MSkarsaune

Demo

Page 106: goto java; (Jfokus)

@MSkarsaune

Page 107: goto java; (Jfokus)

@MSkarsaune

ambdaλ

Page 108: goto java; (Jfokus)

@MSkarsaune

• Lambda implementation in Java 8–Language change–Compilation–Runtime support

• Many interesting design considerations

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 109: goto java; (Jfokus)

@MSkarsaune

Simple Examplepublic Comparator<String> lambdaExample() { return (String a, String b) -> a.compareTo(b);}

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 110: goto java; (Jfokus)

@MSkarsaune

LambdaToMethod.javapublic Comparator<String> lambdaExample() { return (String a, String b) -> a.compareTo(b);}

/*synthetic*/ private static int lambda$lambdaExample$0( , ) { return ;}

final String afinal String b

a.compareTo(b)

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 111: goto java; (Jfokus)

@MSkarsaune

Runtimepublic Comparator<String> lambdaExample() { return <invokedynamic>LambdaMetafactory.metafactory(}

/*synthetic*/ private static int lambda$lambdaExample$0( final String a, final String b) { return a.compareTo(b);}

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

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

public interface Comparator {/*erased*/ int compare(Object o1, Object o2);}

Page 112: goto java; (Jfokus)

@MSkarsaune

Runtime implementation

LambdaMetaFactory• metaFactory(…)• altMetaFactory(…)

InnerClassLambdaMetafactory

ASM

Lambda Class

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 113: goto java; (Jfokus)

@MSkarsaune

SerializationLambda Instance

Serialize

SerializedLambda

Deserialize

LambdaMeta

Factory

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 114: goto java; (Jfokus)

@MSkarsaune

• Possible to back port ?–Capture generated class ?–Compile time generation of inner class!

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 115: goto java; (Jfokus)

@MSkarsaune

Step 1: Source.java

public boolean allowLambda() { return compareTo( ) >= 0;}

JDK1_8JDK1_5

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 116: goto java; (Jfokus)

@MSkarsaune

Step 2: Special handling

boolean mustBackportLambda() { return this.target.compareTo(Target.JDK1_8) < 0;}

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 117: goto java; (Jfokus)

@MSkarsaune

Step 3: Call backport

if(!this.attr.mustBackportLambda()) { result = makeMetafactoryIndyCall(...);}else{ result = new LambdaBackPorter(...).implementLambdaClass(...);}

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 118: goto java; (Jfokus)

@MSkarsaune

Example implementationprivate static final class Lambda$$2 implements Comparator<String> {

Lambda$$2 { super(); } public int compare(String arg0, String arg1) { return LambdaExample.lambda$lambdaExample$0(arg0, arg1); } public int compare(Object o1, Object o2) { return this.compare((String)o1, (String)o2); }}

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 119: goto java; (Jfokus)

@MSkarsaune

Example invokingpublic Comparator<String> lambdaExample() { }

return LambdaMetafactory.metafactory(...);return new Lambda$$2();

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

Page 120: goto java; (Jfokus)

@MSkarsaune

Demo

Page 121: goto java; (Jfokus)

@MSkarsaune

ambdaλ

Page 122: goto java; (Jfokus)

@MSkarsaune

Page 123: goto java; (Jfokus)

@MSkarsaune

Expe

ri

ment

Page 124: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

• <invokedynamic> “playground”1. @InvokeIndy annotation on method with

reference to boostrap method2. Annotation processor that validates

reference3. Compiler plugin that replaces method

invocation with invokedynamic

Page 125: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

@IndyMethodpublic class SomeService {

//must refer to a valid public static method //with certain characteristics

@IndyMethod(implementation="no.kantega.jvm.indy.example.SomeProvider", method= "dummyMethod")

public static void doStuff() {throw new UnsupportedOperationException("...");

}

}

Page 126: goto java; (Jfokus)

@MSkarsaune

no.kantega.jvm.indy.compiler.plugin.IndyAnnotationChecker

Hooking in the processor:META-INF/services/javax.annotation.processing.Processor:

Parse Enter Process Attribute Flow Desugar Generat

e

Page 127: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

Annotation processor: setup, compliance + mapping@SupportedAnnotationTypes("no....IndyMethod")

@SupportedSourceVersion(SourceVersion.RELEASE_8)//Java versionpublic class IndyAnnotationChecker extends AbstractProcessor {

//...public boolean process(Set<...> annotations, RoundEnvironment roundEnv) {

for (TypeElement annotation : annotations) {for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {

//...raise error if earlier than Java 7 or missing pluginIndyMethod indyMethodRef = element.getAnnotation(IndyMethod.class);if (indyMethodRef != null) {

//...check existance of type and compliance of method ...processingEnv.getMessager().printMessage(Kind.ERROR,"...", element);}

}//...

Page 128: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

...<build>

<plugins><plugin>

<artifactId>maven-compiler-plugin</artifactId><configuration>

<!-- Disable annotation processing for ourselves. --><compilerArgument>-proc:none</compilerArgument>

</configuration></plugin>

</plugins></build>

...

Disable annotation processing in the project that implements the plugin (!): pom.xml :

Page 129: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

• Compiler plugin–Hook straight into the compilation process–Respond to events from compilation process–Make changes to AST

Page 130: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

no.kantega.jvm.indy.compiler.plugin.IndyPlugin

Hooking in the plugin:META-INF/services/com.sun.source.util.Plugin:

Page 131: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

public class IndyPlugin implements Plugin {public String getName() {

return "IndyPlugin";}public void init(JavacTask paramJavacTask,

String... paramArrayOfString) {paramJavacTask.addTaskListener(

new GenerateInvokeDynamicHandler());}

}

Typical plugin definition:• Unique name• Delegate to task listener(s)

Page 132: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

public class GenerateInvokeDynamicHandler implements TaskListener {

public void started(TaskEvent start) {if(start.getKind() == Kind.GENERATE) {

for (Tree tree : start.getCompilationUnit().getTypeDecls()) {tree.accept(new IndyMethodInvocationReplacer(), tree);

}}

}

Task listener:• Receive callback, check stage• Insert visitor to process ASTs

Page 133: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

public class IndyMethodInvocationReplacer extends TreeScanner {public Object visitMethodInvocation(MethodInvocationTree node, Tree p) {{//...various checks on the method call//...see if annotation processor has created mapping for itMethodSymbol replacementMethod = IndyMethodMappings.getInstance().

mappingFor((MethodSymbol) identifier.sym);if(replacementMethod!= null) {//insert reference to bootstrap

identifier.sym=new Symbol.DynamicMethodSymbol(...); }

}}

}return super.visitMethodInvocation(node, p);

}}

Visitor:• Make modifications

Page 134: goto java; (Jfokus)

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

<build><plugins>

<plugin><artifactId>maven-compiler-plugin</artifactId><configuration>

<compilerArgs><arg>-Xplugin:IndyPlugin</arg>

</compilerArgs><source>1.8</source><target>1.8</target>

</configuration></plugin>

</plugins></build>

Users:• Enable plugin in compilation

Page 135: goto java; (Jfokus)

@MSkarsaune

Demo

Page 136: goto java; (Jfokus)

@MSkarsaune

Wrap Up• The Java compiler is written in pure Java• Compilation is done in phases• Programming language advances (syntactic sugar)

require good compiler support• Lambdas are compiled in a forward compatible manner• Annotation processors and compiler plugins may be

used to tailor the compilation process to specific needs

Page 137: goto java; (Jfokus)

@MSkarsaune

Resources• OpenJDK

• Source: http://hg.openjdk.java.net/• Compiler hacking tutorial

• http://www.ahristov.com/tutorial/java-compiler.html• Sample code:

• https://github.com/skarsaune/goto• https://github.com/skarsaune/indy-plugin

• Slide pack:• http://www.slideshare.net/MartinSkarsaune

• 60 minute video (Devoxx) :• https://youtu.be/gGTDQq6ZjIk

Page 138: goto java; (Jfokus)

@MSkarsaune

Questions or Comments?Martin Skarsaune

Java Developer and Co-Owner

Page 139: goto java; (Jfokus)

@MSkarsaune

Thank You for Your Time!Martin Skarsaune

Java Developer and Co-Owner