goto java; (jfokus)

Post on 14-Feb-2017

265 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

@MSkarsaune

Martin SkarsauneJava Developer and Co-Owner

A peek into the OpenJDK compiler : goto java;

高馬丁

We’re

Hiring!

@MSkarsaune

GOTO Statements in Java!

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

@MSkarsaune

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

• Modify compiler to support GOTO

@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

@MSkarsaune

GOTOAHEAD

Dijkstra 1968:

@MSkarsaune

What is a Compiler?

Compiler

@MSkarsaune

What is a Compiler?

frontend

backend

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

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

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

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

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

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

@MSkarsaune

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

Parse Enter Process Attribute Flow Desugar Generat

e

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

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

scanner.nextToken();

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

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

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

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

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

@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

@MSkarsaune

ClassInterface

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

Interface based visitors

Parse Enter Process Attribute Flow Desugar Generat

e

@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

@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

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

@MSkarsaune

Demo

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

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

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

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

@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

@MSkarsaune

Default Constructorpublic class SimpleClass {

}

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

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

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

✔Parse Enter Process Attribut

e Flow Desugar Generate

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

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

@MSkarsaune

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

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

Parse Enter Process Attribute Flow Desugar Generat

e

@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

@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

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

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

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

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

@MSkarsaune

• Attribution• Semantic checks

–Types–References

• Corrections–Add required calls to super constructor

Parse Enter Process Attribute Flow Desugar Generat

e

@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

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

@MSkarsaune

Demo

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

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

@MSkarsaune

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

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

Parse Enter Process Attribute Flow Desugar Generat

e

@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

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

@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

@MSkarsaune

Demo

@MSkarsaune

✔processAnnotations(enterTrees(…

parseFiles(…))),…)…

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

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

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

@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> {

@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> {

@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

@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

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

}};

}}

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

}};

}}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

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

}

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

}

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda LowerEnumspublic enum Status {

YES, NO, MAYBE}

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

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

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

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

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

@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 {

}

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

}

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

}

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

@MSkarsaune

Parse Enter Process Attribute Flow Desugar Generat

e

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

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

@MSkarsaune

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

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

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

• Organize initializers• String concatenation• Generate bytecodes

Parse Enter Process Attribute Flow Desugar Generat

e

@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

@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

@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

@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

@MSkarsaune

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

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

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

Parse Enter Process Attribute Flow Desugar Generat

e

@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

@MSkarsaune

String concatenationSource code “Generated code”

”string” + value

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

String concatenationSource code “Generated code”

”string” + value new StringBuilder()

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

String concatenationSource code “Generated code”

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

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

String concatenationSource code “Generated code”

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

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

String concatenationSource code “Generated code”

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

Parse Enter Process Attribute Flow Desugar Generat

e

@MSkarsaune

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

Parse Enter Process Attribute Flow Desugar Generat

e

@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

@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

@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

@MSkarsaune

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

Parse Enter Process Attribute Flow Desugar Generat

e

@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

@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

@MSkarsaune

Demo

@MSkarsaune

@MSkarsaune

ambdaλ

@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

@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

@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

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

@MSkarsaune

Runtime implementation

LambdaMetaFactory• metaFactory(…)• altMetaFactory(…)

InnerClassLambdaMetafactory

ASM

Lambda Class

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

@MSkarsaune

SerializationLambda Instance

Serialize

SerializedLambda

Deserialize

LambdaMeta

Factory

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

@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

@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

@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

@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

@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

@MSkarsaune

Example invokingpublic Comparator<String> lambdaExample() { }

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

Parse Enter Process Attribute Flow Desugar Generat

e

TransTypes Unlambda Lower

@MSkarsaune

Demo

@MSkarsaune

ambdaλ

@MSkarsaune

@MSkarsaune

Expe

ri

ment

@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

@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("...");

}

}

@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

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

}//...

@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 :

@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

@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:

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

@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

@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

@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

@MSkarsaune

Demo

@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

@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

@MSkarsaune

Questions or Comments?Martin Skarsaune

Java Developer and Co-Owner

@MSkarsaune

Thank You for Your Time!Martin Skarsaune

Java Developer and Co-Owner

top related