3. @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.
4. @MSkarsaune
GOTO Statement – Means
• OpenJDK
• Open source Java implementation
• Javac is implemented in plain Java
• Modify compiler to support GOTO
5. @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
9. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
processAnnotations(enterTrees(…
parseFiles(…))),…)
…
generate(desugar(flow(attribute(…))))
10. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
processAnnotations(enterTrees(…
parseFiles(…))),…)
…
generate(desugar(flow(attribute(…))))
11. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
• Syntax: goto identifier;
• First convert character stream to token stream
(Scanner.java)
GOTO IDENTIFIER SEMI
[g][o][t][o][ ][f][o][u][r][;]
12. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
• 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!
14. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
final Scanner scanner=factory.newScanner(”goto identifier;”, false);
scanner.nextToken();
15. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
final Scanner scanner=factory.newScanner(”goto identifier;”, false);
scanner.nextToken();
assertThat(”First token is GOTO”, scanner.token().kind, is(GOTO));
16. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
final Scanner scanner=factory.newScanner(”goto identifier;”, false);
scanner.nextToken();
assertThat(”First token is GOTO”, scanner.token().kind, is(GOTO));
scanner.nextToken();
17. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
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));
18. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
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();
19. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
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));
27. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
processAnnotations(enterTrees(…
parseFiles(…))),…)
…
generate(desugar(flow(attribute(…))))
28. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
processAnnotations(enterTrees(…
parseFiles(…))),…)
…
generate(desugar(flow(attribute(…))))
29. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
• Basic sanity testing of
compilation unit:
• File name and folder location
• Duplicate class names
• Corrections
• Add default constructor if no
constructors are declared
34. @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 Generate
35. @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 Generate
36. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
processAnnotations(enterTrees(…
parseFiles(…))),…)
…
generate(desugar(flow(attribute(…))))
37. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
processAnnotations(enterTrees(…
parseFiles(…))),…)
…
generate(desugar(flow(attribute(…))))
38. @MSkarsaune
• Attribution
• Semantic checks
–Types
–References
• Corrections
–Add required calls to super constructor
Parse Enter Process Attribute Flow Desugar Generate
39. @MSkarsaune
Ensure target label exists in current scope
public class GotoMissingLabel {
public static void main(String[] args) {
one: System.out.print("goto ");
two: System.out.print(”Java");
goto six;
three: System.out.print(”2016");
goto five;
four: System.out.print(”One ");
goto three;
five: System.out.print("!");
}
}
Parse Enter Process Attribute Flow Desugar Generate
40. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
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);
}
49. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
processAnnotations(enterTrees(…
parseFiles(…))),…)
…
generate(desugar(flow(attribute(…))))
50. @MSkarsaune
Erase generic types
public class Bridge implements Comparator {
}
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lowerpublic interface Comparator<T> {
int compare(T o1, T o1);
}or<T> {
51. @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 Generate
public interface Comparator<T> {
int compare(T o1, T o1);
} or<T> {
52. @MSkarsaune
Erasure - Runtime
public class Bridge implements Comparator {
public int compare(Integer first, Integer second) {
return first - second;
}
}
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
53. @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 Generate
TransTypes Unlambda Lower
54. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Extract inner class
public class Outer {
private void foo() { }
public Runnable fooRunner() {
return new Runnable() {
public void run() {
foo();
}
};
}
}
55. @MSkarsaune
Extract inner class
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
public class Outer {
private void foo() { }
public Runnable fooRunner() {
return new Runnable() {
public void run() {
foo();
}
};
}
}
56. @MSkarsaune
Extract inner class
public class Outer {
private void foo() { }
public Runnable fooRunner() {
return new Outer$1(this);
}
}
Parse Enter Process Attribute Flow Desugar Generate
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();
}
}
57. @MSkarsaune
Extract inner class
Parse Enter Process Attribute Flow Desugar Generate
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();
}
}
58. @MSkarsaune
TransTypes Unlambda Lower
Parse Enter Process Attribute Flow Desugar Generate
Extract 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);
}
}
59. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Boxing
List<Integer> list =
Arrays.asList(1, 2);
for (Integer i : list) {
System.out.println(”Double: “ + i * 2);
}
60. @MSkarsaune
Boxing
Parse Enter Process Attribute Flow Desugar Generate
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);
}
61. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Boxing
List<Integer> list =
Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));
for (Integer i : list) {
System.out.println(”Double: “ + i * 2);
}
62. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Unboxing
List<Integer> list =
Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));
for (Integer i : list) {
System.out.println(”Double: “ + i * 2);
}
63. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Unboxing
List<Integer> list =
Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));
for (Integer i : list) {
System.out.println(”Double: “ + i.intValue() * 2);
}
64. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Varargs
List<Integer> list =
Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));
for (Integer i : list) {
System.out.println(”Double: “ + i.intValue() * 2);
}
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
65. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Varargs
List<Integer> list =
Arrays.asList(Integer.valueOf(1), Integer.valueOf(2));
for (Integer i : list) {
System.out.println(”Double: “ + i.intValue() * 2);
}
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
66. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Varargs - 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);
}
67. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
For each loop
List<Integer> list =
Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});
for (Integer i : list) {
System.out.println(”Double: “ + i.intValue() * 2);
}
68. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
For each loop
List<Integer> list =
Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});
for (Integer i : list) {
System.out.println(”Double: “ + i.intValue() * 2);
}
public interface Iterable<T> {
Iterator<T> iterator();
}
69. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
For each loop
List<Integer> list =
Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});
for (;;) {
System.out.println(”Double: “ + i.intValue() * 2);
}
70. @MSkarsaune
TransTypes Unlambda Lower
Parse Enter Process Attribute Flow Desugar Generate
For each loop
List<Integer> list =
Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});
for (Iterator i$ = list.iterator();;) {
Integer i
System.out.println(”Double: “ + i.intValue() * 2);
}
71. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
For each loop
List<Integer> list =
Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});
for (Iterator i$ = list.iterator(); i$.hasNext();) {
Integer i
System.out.println(”Double: “ + i.intValue() * 2);
}
72. @MSkarsaune
TransTypes Unlambda Lower
Parse Enter Process Attribute Flow Desugar Generate
For each loop
List<Integer> list =
Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2)});
for (Iterator i$ = list.iterator(); i$.hasNext();) {
Integer i = (Integer)i$.next();
System.out.println(”Double: “ + i.intValue() * 2);
}
73. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Enums
public enum Status {
YES, NO, MAYBE
}
74. @MSkarsaune
TransTypes Unlambda Lower
Parse Enter Process Attribute Flow Desugar Generate
Enums - constructor
public enum Status {
YES, NO, MAYBE
private 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);
75. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Enums - valueOf
public enum Status {
YES, NO, MAYBE
private Status(String $enum$name, int $enum$ordinal) {
super($enum$name, $enum$ordinal);
}
public static Status valueOf(String name) {
return (Status)Enum.valueOf(Status.class, name);
}
}
76. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Enums - values
public enum Status {
YES, NO, MAYBE
private Status(String $enum$name, int $enum$ordinal) {
super($enum$name, $enum$ordinal);
}
public static Status valueOf(String name) {
return (Status)Enum.valueOf(Status.class, name);
}
private static final Status[] $VALUES = new Status[]{
Status.YES, Status.NO, Status.MAYBE};
public static Status[] values() {
return (Status[])$VALUES.clone();
}
}
77. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Enum switch statement
public class SwitchStatus {
void switchStatus(Status status) {
switch (status) {
case MAYBE:
return;
default:
break;
}
}
}
78. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Enum switch statement
public class SwitchStatus {
void switchStatus(Status status) {
switch (status) {
case MAYBE:
return;
default:
break;
}
}
}
79. @MSkarsaune
TransTypes Unlambda Lower
Parse Enter Process Attribute Flow Desugar Generate
Enum switch statement
public class SwitchStatus {
void switchStatus(Status status) {
switch (SwitchStatus$1.$SwitchMap$Status[(status).ordinal()]) {
case 1:
return;
default:
break;
}
}
}
class SwitchStatus$1 {
}
80. @MSkarsaune
TransTypes Unlambda Lower
Parse Enter Process Attribute Flow Desugar Generate
Enum 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];
}
81. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Enum 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]
}
82. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
Enum 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) { }
}
}
83. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
processAnnotations(enterTrees(…
parseFiles(…))),…)
…
generate(desugar(flow(attribute(…))))
86. @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 Generate
87. @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 Generate
88. @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 Generate
89. @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 Generate
90. @MSkarsaune
• Organize <clinit> (static initialization)
public class StaticInitialization {
static String key="key";
static {
init();
}
}
Parse Enter Process Attribute Flow Desugar Generate
91. @MSkarsaune
• Organize <clinit> (static initialization)
public class StaticInitialization {
static String key;
static {
key="key";
init();
}
}
Parse Enter Process Attribute Flow Desugar Generate
92. @MSkarsaune
• Organize <clinit> (static initialization)
public class StaticInitialization {
static String key;
static void <clinit>() {
key="key";
init();
}
}
Parse Enter Process Attribute Flow Desugar Generate
99. @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 Generate
100. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
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
101. @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
29
Label used?
• emit stack frame
• patch pending
gotos
Parse Enter Process Attribute Flow Desugar Generate
102. @MSkarsaune
• Goto generation
–Gen.java , visitor for code generation
–Modify for LabelledStatement
–Add implementation for Goto
Parse Enter Process Attribute Flow Desugar Generate
103. @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 Generate
104. @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 Generate
110. @MSkarsaune
LambdaToMethod.java
public Comparator<String> lambdaExample() {
return (String a, String b) -> a.compareTo(b);
}
/*synthetic*/
private static int
lambda$lambdaExample$0(
,
) {
return ;
}
final String a
final String b
a.compareTo(b)
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
111. @MSkarsaune
Runtime
public Comparator<String> lambdaExample() {
return <invokedynamic>LambdaMetafactory.metafactory(
}
/*synthetic*/
private static int
lambda$lambdaExample$0(
final String a,
final String b) {
return a.compareTo(b);
}
Parse Enter Process Attribute Flow Desugar Generate
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);
}
114. @MSkarsaune
• Possible to back port ?
–Capture generated class ?
–Compile time generation of inner class!
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
115. @MSkarsaune
Step 1: Source.java
public boolean allowLambda() {
return compareTo( ) >= 0;
}
JDK1_8JDK1_
5
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
116. @MSkarsaune
Step 2: Special handling
boolean mustBackportLambda() {
return this.target.compareTo(Target.JDK1_8) < 0;
}
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
117. @MSkarsaune
Step 3: Call backport
if(!this.attr.mustBackportLambda()) {
result = makeMetafactoryIndyCall(...);
}
else
{
result = new LambdaBackPorter(...).implementLambdaClass(...);
}
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
118. @MSkarsaune
Example 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);
}
}
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
119. @MSkarsaune
Example invoking
public Comparator<String> lambdaExample() {
}
return LambdaMetafactory.metafactory(...);return new Lambda$$2();
Parse Enter Process Attribute Flow Desugar Generate
TransTypes Unlambda Lower
124. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
• <invokedynamic> “playground”
1. @InvokeIndy annotation on method with
reference to boostrap method
2. Annotation processor that validates
reference
3. Compiler plugin that replaces method
invocation with invokedynamic
125. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
@IndyMethod
public 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("...");
}
}
127. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
Annotation processor: setup, compliance + mapping
@SupportedAnnotationTypes("no....IndyMethod")
@SupportedSourceVersion(SourceVersion.RELEASE_8)//Java version
public 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 plugin
IndyMethod indyMethodRef = element.getAnnotation(IndyMethod.class);
if (indyMethodRef != null) {
//...check existance of type and compliance of method ...
processingEnv.getMessager().printMessage(Kind.ERROR,"...", element);
}
}
//...
128. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
...
<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 :
129. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
• Compiler plugin
–Hook straight into the compilation process
–Respond to events from compilation process
–Make changes to AST
130. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
no.kantega.jvm.indy.compiler.plugin.IndyPlugin
Hooking in the plugin:
META-INF/services/com.sun.source.util.Plugin:
131. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
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)
132. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
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
133. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
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 it
MethodSymbol 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
134. @MSkarsaune
Parse Enter Process Attribute Flow Desugar Generate
<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
136. @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
Hello everyone.
My name is Martin Skarsaune, developer working for Kantega.
Today we are going to have a peek into the compiler. I assume everyone here rely on a Java compiler in their everyday work.
Just out of curiosity, have anyone had a look at the compiler source code ?
I guess a lot of clever developers out here have read articles, have debugged a lot of Java applications and disassempled class files to see what your Java code turns into on the other end.
So some of the stuff may be known to you, never the less I think it is worth while to look at the process step by step from the inside and see with out own eyes what goes on.
A compiler is a tool that accepts input in some sort of programming language and produces output targeted for another language or instruction set.
A common compiler architecture is to try to decouple the input from the output. The front end deals with specifics handling, checks and optimizations for the given programming language, and the back end deals with generation, dependencies and optimizations for a given target platform. This separation is an obvious choice for compilers that generate native code.
I was involved in a big project over several years, where we developed tools and routines for automated translation from Smalltalk to Java. In that project we did exactly this, we reused the parser and internal representation from the built in Smalltalk compiler, but instead of generating Smalltalk byte codes, we generated Java source code.