Goto devoxx

Preview:

Citation preview

@MSkarsaune#GotoJava

goto java;- Java compilation under the hood

Martin Skarsaune@kantega.no

Kantega – Norwegian software craftsmanship since 2003

高馬丁

GOTO Statements in Java!

@MSkarsaune#GotoJava

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.

@MSkarsaune#GotoJava

GOTO Statement –Means

• OpenJDK• Open source Java implementation• Javac is implemented in plain Java

• Modify compiler to support GOTO

@MSkarsaune#GotoJava

public class GotoSuccess {

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

}}

Success Case

@MSkarsaune#GotoJava

GOTOAHEAD

Dijkstra 1968:

@MSkarsaune#GotoJava

What is a Compiler?

Compiler

@MSkarsaune#GotoJava

What is a Compiler?

frontend

backend

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

stream (Scanner.java)

GOTO IDENTIFIER SEMI

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

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!

@MSkarsaune#GotoJava

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

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

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

scanner.nextToken();

Parse Enter Process Attribute Flow Desuga

rGenerat

e

@MSkarsaune#GotoJava

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

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

Parse Enter Process Attribute Flow Desuga

rGenerat

e

@MSkarsaune#GotoJava

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

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

scanner.nextToken();

Parse Enter Process Attribute Flow Desuga

rGenerat

e

@MSkarsaune#GotoJava

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

Parse Enter Process Attribute Flow Desuga

rGenerat

e

@MSkarsaune#GotoJava

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

Parse Enter Process Attribute Flow Desuga

rGenerat

e

@MSkarsaune#GotoJava

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

Parse Enter Process Attribute Flow Desuga

rGenerat

e

@MSkarsaune#GotoJava

CompilationUnit

ClassDefinition

FieldDefintion

MethodDefinition

Signature

Body

IfStatement

Goto

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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”

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

ClassInterface

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

Interface based visitors

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

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

@YourTwitterHandle@MSkarsaune#GotoJava

Dem

o

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

• Basic sanity testing of compilation unit

• File name and folder location

• Duplicate class names• Corrections• Add default constructor if

no constructors are declared

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

Default Constructorpublic class SimpleClass {

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

• Plugin API (see javac documentation)

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

• Output controlled by command line switches

@

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

- proc:none – do not process annotations

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

Annotation processor Example• ensure that all fields with @Config

annotation are primitive or strings

@Configprivate String sender;//ok @Configprivate int retries;//ok @Configprivate String[] receivers;//not ok

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

META-INF/services/javax.annotation.processing.Processor:

org.kantega.reststop.apt.ConfigFieldProcessor

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

ConfigFieldProcessor.java :

@SupportedAnnotationTypes("org.kantega.reststop.api.Config")@SupportedSourceVersion(SourceVersion.RELEASE_7)public class ConfigFieldProcessor extends AbstractProcessor { //... public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

//... if(! isPrimitive(type) && ! isString(type) ) {

processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@Config annotated field must primitive, boxed or String”, element)

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

Simply add to compilation path:

<dependency> <groupId>org.kantega.reststop</groupId> <artifactId>reststop-annotation-processor</artifactId> <version>${reststop.version}</version> <scope>compile</scope></dependency>

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

• Devoxx BE 2014 : “Plugging into the Java Compiler” , •https://www.parleys.com/tutorial/plugging-java-compiler-1

•Google the session title for additional resources.

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

• Attribution• Semantic checks

–Types–References

• Corrections–Add required calls to super constructor

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

Ensure target label exists in current scopepublic class GotoMissingLabel {

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

}}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

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

@YourTwitterHandle@MSkarsaune#GotoJava

Dem

o

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

Detect circular gotospublic class GotoCircularWarning {

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@YourTwitterHandle@MSkarsaune#GotoJava

Dem

o

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerErase generic types

public class Bridge implements Comparator {

}

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

}or<T> {

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerErase generic types

public class Bridge implements Comparator<Integer> {

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

}

}

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

}or<T> {

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerErasure - Runtime

public class Bridge implements Comparator {

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

}

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerExtract inner class

public class Outer {private void foo() { }

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

public void run() {foo();

}};

}}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerExtract inner class

public class Outer {private void foo() { }

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

public void run() {foo();

}};

}}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerExtract inner class

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerBoxing

List<Integer> list = Arrays.asList(1, 2);

for (Integer i : list) {System.out.println("Double: " + i * 2);

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerBoxing

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerBoxing

List<Integer> list = Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));

for (Integer i : list) {System.out.println("Double: " + i * 2);

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerUnboxing

List<Integer> list = Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));

for (Integer i : list) {System.out.println("Double: " + i * 2);

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerUnboxing

List<Integer> list = Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));

for (Integer i : list) {System.out.println("Double: " + i.intValue() * 2);

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerVarargs

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerVarargs

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerVarargs - runtime

List<Integer> list = Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});

for (Integer i : list) {System.out.println("Double: " + i.intValue() * 2);

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerFor 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 interface Iterable<T> { Iterator<T> iterator();}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerEnums

public enum Status {YES, NO, MAYBE

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerEnums - constructor

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerEnums - valueOf

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerEnums - values

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerEnum switch statement

public class SwitchStatus {

void switchStatus(Status status) {

switch (status) { case MAYBE: return;

default: break; } }}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerEnum switch statement

public class SwitchStatus {

void switchStatus(Status status) {

switch (status) { case MAYBE: return;

default: break; } }}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerEnum switch statement

public class SwitchStatus {

void switchStatus(Status status) {

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

default: break; } }}

class SwitchStatus$1 {

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerEnum switch statement

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerEnum switch statement

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]

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerEnum switch statement

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

• Organize initializers• String concatenation• Generate bytecodes

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

super(); this.value = value; }

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

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

}

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

String concatenationSource code “Generated code”

”string” + value

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

String concatenationSource code “Generated code”

”string” + value new StringBuilder()

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

String concatenationSource code “Generated code”

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

String concatenationSource code “Generated code”

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

String concatenationSource code “Generated code”

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

• 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(); … }

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

• 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

@YourTwitterHandle@MSkarsaune#GotoJava

Dem

o

@YourTwitterHandle@MSkarsaune#GotoJava

@YourTwitterHandle@MSkarsaune#GotoJava

ambdaλ

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda Lower

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

• Many interesting design considerations

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerSimple Example

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerLambdaToMethod.java

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerRuntime

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda Lower

Runtime implementation

LambdaMetaFactory• metaFactory(…)• altMetaFactory(…)

InnerClassLambdaMetafactory

ASM

Lambda Class

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda Lower

SerializationLambda Instance

Serialize

SerializedLambda

Deserialize

LambdaMeta

Factory

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda Lower

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerStep 1: Source.java

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

JDK1_8JDK1_5

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerStep 2: Special handling

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerStep 3: Call backport

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerExample implementation

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

@MSkarsaune#GotoJava

Parse Enter Process Attribute Flow Desuga

rGenerat

e

TransTypes Unlambda LowerExample invoking

public Comparator<String> lambdaExample() { }

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

@YourTwitterHandle@MSkarsaune#GotoJava

ambdaλ

@YourTwitterHandle#DVXFR14{session hashtag} @MSkarsaune#GotoJava

Sum

mar

y

@MSkarsaune#GotoJava

Wrap Up

• The Java compiler is written in Java• Compilation is done in phases• Programming language advances (syntactic

sugar) require good compiler support• Lambdas are compiled in a forward compatible

manner

@MSkarsaune#GotoJava

Resources• OpenJDK

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

• http://www.ahristov.com/tutorial/java-compiler.html• Lambda design discussion

• http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html

• Sample code:• https://github.com/skarsaune/goto

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

@YourTwitterHandle#DVXFR14{session hashtag} @MSkarsaune#GotoJava

Q &

A

https://wall-simple.sli.do/#/event/cmnxxfl0/section/18316/questions

@YourTwitterHandle#DVXFR14{session hashtag} @MSkarsaune#GotoJava

Than

k yo

u

for yo

ur

time!

http://lanyrd.com/profile/martinskarsaune/