Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
CS 432: Compiler Construction Lecture 16 Department of Computer Science Salisbury University Fall 2016 Instructor: Dr. Sophie Wang http://faculty.salisbury.edu/~xswang 5/4/2017 1 Java Virtual Machine (JVM) Architecture Java stack Heap area code for methods constants pool Native method stacks 5/4/2017 dynamically allocated objects automatic garbage collection Class area runtime stack support native methods, e.g., written in C (not shown) 2 Java Virtual Machine Architecture, cont’d The runtime stack contains stack frames. Each stack frame contains 5/4/2017 Stack frame = activation record. local variables array operand stack program counter (PC) 3 The JVM’s Java Runtime Stack Each method invocation pushes a stack frame. The stack frame currently on top of the runtime stack is the active stack frame. A stack frame is popped off when the method returns, possibly leaving behind a return value on top of the stack. Contents of a stack frame: Operand stack Local variables array 5/4/2017 equivalent to the memory map in our Pascal interpreter’s activation record Program counter (PC) for doing computations keeps track of the currently executing instruction Pointers to method area and heap 4 JVM Instructions Load and store values Arithmetic operations Type conversions Object creation and management Runtime stack management (push/pop values) Branching Method call and return Throwing exceptions Concurrency _ 5/4/2017 5 JASMIN JASMIN is an assembler for the JVM Takes an ASCII description of a Java class Input written in a simple assembler like syntax Outputs binary class file Suitable for loading by the JVM Running JASMIN Using the JVM instruction set jasmin myfile.j Produces a .class file with the name specified by the .class directive in myfile.j 6 5/4/2017 Jasmin file format Directives Instructions .catch .class .end .field .implements .interface .limit .line .method .source .super .throws .var JVM instructions Labels Any name followed by : Foo: 7 5/4/2017 Cannot start with = : . * Labels can only be used within method definitions Jasmin Assembler Download from: http://jasmin.sourceforge.net/ Site also includes: 5/4/2017 User Guide Instruction set Sample programs _ 8 Example Jasmin Program .class public HelloWorld .super java/lang/Object hello.j .method public static main([Ljava/lang/String;)V .limit stack 2 .limit locals 1 getstatic java/lang/System/out Ljava/io/PrintStream; ldc " Hello World." invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V return .end method Assemble: java –jar jasmin.jar hello.j Execute: 5/4/2017 java HelloWorld 9 Jasmin Assembly Instructions An Jasmin instruction consists of a mnemonic optionally followed by arguments. aload 5 fstore 5 ; Push a reference to local variable #5 ; pop off the floating-point value at the ; top of the stack and store it to ; local variable #5 getstatic Newton/number I ; push integer value of the static field ; number of class Newton to operand stack Some instructions require operands on the operand stack. iadd _ 5/4/2017 ; Pop the two integer values on top of the ; stack, add them, and push the result on ; the top of the stack 10 Jasmin Assembly Directives Directive statements provide info to Jasmin assembler. They begins with a period immediately followed by the reserved directive word. For example, the main method of a Java program public static void main(String args[]) would have the following equivalent Jasmin directive .method public static main([Ljava/lang/String;)V 5/4/2017 11 Jasmin Type Descriptors Java Scalar type 5/4/2017 Jasmin Type Descriptor int I float F boolean Z char C Java Class Jasmin Type Descriptor java.lang.String Ljava/lang/String; java.util.HashMap Ljava/util/HashMap; Newton LNewton; Java Array type Jasmin Type Descriptor java.lang.String[] [Ljava/lang/String; Newton[][] [[LNewton; int[][][] [[[I; 12 Compilation Strategy A Pascal program is compiled as if it were a public Java class. The Pascal program name becomes the Java class name. The main program becomes the main method of the class. Each program variable is compiled as if it were a field of the class. Fields do have names in a Jasmin program. A Pascal procedure or function is compiled as if it were a private static method of the Java class. 5/4/2017 Local variables and formal parameters of the method do not have names in a Jasmin program. Jasmin instructions refer to local variables and parameters by their slot numbers of the local variables array. 13 Pascal, Java and Jasmin Code Example 1. PROGRAM HelloOnce; 2. 3. BEGIN 4. writeln('Hello, world.') 5. END. public class HelloOnce { private static RunTimer _runTimer; private static PascalTextIn _standardIn; public static void main(String[] args) { _runTimer = new RunTimer(); _standardIn = new PascalTextIn(); System.out.println("Hello, world."); _runTimer.printElapsedTime(); } 14 5/4/2017 } .class public helloonce .super java/lang/Object .field private static _runTimer LRunTimer; .field private static _standardIn LPascalTextIn; .method public <init>()V aload_0 invokenonvirtual java/lang/Object/<init>()V return .limit locals 1 .limit stack 1 .end method 5/4/2017 .method public static main([Ljava/lang/String;)V new RunTimer dup invokenonvirtual RunTimer/<init>()V putstatic helloonce/_runTimer LRunTimer; new PascalTextIn dup invokenonvirtual PascalTextIn/<init>()V putstatic helloonce/_standardIn LPascalTextIn; .line 4 getstatic java/lang/System/out Ljava/io/PrintStream; ldc "Hello, world.\n" invokevirtual java/io/PrintStream.print(Ljava/lang/String;)V getstatic helloonce/_runTimer LRunTimer; invokevirtual RunTimer.printElapsedTime()V return .limit locals 1 .limit stack 3 .end method 15 Code Templates Syntax diagrams Specify the source language grammar Help us write the parsers Code templates 5/4/2017 Specify what object code to generate Help us write the code emitters _ 16 Code Template for a Pascal Program 5/4/2017 Translate a Pascal program into a public class. Program variables become class fields. Must have a default constructor. Each procedure or function becomes a private static method. The main program code becomes the public static main method. 17 Program Header The program header consists of .class public hellomany .super java/lang/Object 5/4/2017 18 Class Constructor The Pascal compiler always generates the same default constructor <init>. When the constructor executes, slot 0 of local variables array contains the address of the class instance (this). To create an instance of the program class, the ALOAD_0 instruction pushes this address onto the operand stack and the instruction invokenonvirtual passes it to the constructor of java.lang.Object .method public <init>()V aload_0 invokenonvirtual java/lang/Object/<init>()V return .limit locals 1 .limit stack 1 .end method 5/4/2017 19 Instruction-set … Method invocation: invokevirtual usual instruction for calling a method on an object. invokespecial/invokenonvirtual for calling things such as constructors. These are not dynamically dispatched invokestatic for calling methods that have the “static” modifier (these methods “belong” to a class, rather an object) 20 invokevirtual Object x; ... x.equals("hello"); aload_1 ldc "hello" ; push local variable 1 (i.e. 'x') onto stack ; push the string "hello" onto stack ; invoke the equals method invokevirtual java/lang/Object/equals(Ljava/lang/Object;)Z ; the boolean result is now on the stack -the actual method run depends on the runtime type of the object invokevirtual is used with. -if x is an instance of a class that overrides Object's equal method, then the subclasses' overridden version of the equals method will be used. 21 Invokespecial/invokenonvirtual -invoke an object's instance initialization method, <init>, during the construction phase for a new object. new StringBuffer(); == new java/lang/StringBuffer ; create a new StringBuffer dup ; make an extra reference to the new instance ; now call an instance initialization method invokespecial java/lang/StringBuffer/<init>()V ; stack now contains an initialized StringBuffer. 22 Invokespecial/invokenonvirtual class Example { // override equals public boolean equals(Object x) { // call Object's version of // equals return return super.equals(x); } } -also used to access a superclass's version of a method. return super.equals(x); === aload_0 aload_1 invokespecial 23 ; push 'this' onto the stack ; push the first argument (i.e. x) onto the stack ; now invoke Object's equals() method. java/lang/Object/equals(Ljava/lang/Object;)Z Program Fields For example: PROGRAM test; VAR i, j, k : x, y : p, q : ch : index : integer; real; boolean; char; 1..10; Pascal program variables Compiles to: .field .field .field .field .field .field .field .field .field .field .field 5/4/2017 private private private private private private private private private private private static static static static static static static static static static static _runTimer LRunTimer; _standardIn LPascalTextIn; ch C i I Classes RunTimer and PascalTextIn index I are defined in the Pascal Runtime Library j I PascalRTL.jar containing runtime routines k I written in Java. p Z q Z x F y F 24 Code Template for the Main Method The main method prologue initializes the runtime timer _runTimer and the standard input _standardIn fields. The main method epilogue prints the elapsed run time. 5/4/2017 .limit locals .limit stack specify the size of the local variables array and the maximum size of the operand stack, respectively. 25 Loading a Program Variable’s Value To load (push) a program variable’s value onto the operand stack: getstatic program-name/variable-name type-descriptor Examples: getstatic getstatic Test/count I Test/radius F Java Scalar type 5/4/2017 Jasmin Type Descriptor int I float F boolean Z char C 26 Storing a Program Variable’s Value To store (pop) a value from the operand stack into program variable: putstatic program-name/variable-name type-descriptor Examples: putstatic putstatic Test/count I Test/radius F Java Scalar type 5/4/2017 Jasmin Type Descriptor int I float F boolean Z char C 27 Tips Write special code emitters for loading (pushing) values onto the operand stack. If loading constants: If loading variables, Determine whether to you can emit a shortcut instruction. Determine whether it’s a program variable (emit a getstatic instruction with the field name) or a local variable (emit a load instruction with the slot number). Determine whether you can emit a shortcut instruction for a local variable. Similarly, write special code emitters for storing (popping) values off the operand stack into variables. 5/4/2017 28 Code for Procedures and Functions Each a private static method. Method signature: Routine’s name Type descriptors of the formal parameters. Type descriptors of the return type 5/4/2017 29 Compiling Local Variables FUNCTION func(i, j : integer; x, y : real; p : boolean; ch : char; vector : arr; length : integer) : real; VAR n : integer; z : real; w : arr; • • • Compiles to: .method private static func(IIFFZC[FI)F .var 5 is ch C .var 0 is i I .var 1 is j I .var 7 is length I .var 8 is n I .var 4 is p Z .var 6 is vector [F .var 10 is w [F .var 2 is x F .var 3 is y F .var 9 is z F .var 11 is func F SymTabImpl - add a slot number to each variable’s the symbol table entry for the local variables array. DeclaredRoutineParser – parse() VariableDeclarationParser – parseIdentifier() 5/4/2017 30 Generating Code for Expressions alpha + 3/(beta - gamma) + 5 Recall that in our Pascal interpreter, the expression executor does a postorder traversal of the expression parse tree. 5/4/2017 Pascal’s operator precedence rules are encoded in the structure of the parse tree. 31 Generating Code for Expressions, cont’d A compiler’s expression code generator also does a postorder traversal to generate code. Assume that alpha, beta, and gamma are local real variables alpha local variable slot #0 beta local variable slot #1 gamma local variable slot #2 Generated code: 1 2 3 4 5 6 7 8 9 5/4/2017 fload_0 ldc 3.0 fload_1 fload_2 fsub fdiv fadd ldc 5.0 fadd alpha + 3/(beta - gamma) + 5 32 Comparing Integer Values Jasmin has a set of instructions each of which compares the top two integer values on the operand stack and then branches if the comparison is true. Instruction Action if_icmpeq label Branch to label if [TOS-1] == [TOS] if_icmpne label Branch to label if [TOS-1] != [TOS] if_icmpgt label Branch to label if [TOS-1] > [TOS] if_icmpge label Branch to label if [TOS-1] >= [TOS] if_icmplt label Branch to label if [TOS-1] < [TOS] if_icmple label Branch to label if [TOS-1] <= [TOS] The two values are popped off the operand stack. 5/4/2017 [TOS] is the value at the top of the stack. [TOS-1] is the value just under the one at the top of the stack. 33 Comparing Integer Values, cont’d You can also simply compare the single integer value at the top of the operand stack to 0 and then branch if the comparison is true. Instruction Action ifeq label Branch to label if [TOS] == 0 ifne label Branch to label if [TOS] != 0 ifgt label Branch to label if [TOS] > 0 ifge label Branch to label if [TOS] >= 0 iflt label Branch to label if [TOS1] < 0 ifle label Branch to label if [TOS] <= 0 The top value is popped off the stack. _ 5/4/2017 34 Comparing Other Values Instructions lcmp, fcmp, and dcmp compare two long, float, or double values at the top of the operand stack. Each pops the top two values off the operand stack and then pushes the integer value -1, 0, or 1 onto the stack. If [TOS-1] < [TOS], push -1 onto the stack. If [TOS-1] = [TOS], push 0 onto the stack. If [TOS-1] > [TOS], push 1 onto the stack. Use instructions iflt, ifeq, or ifgt to test for the -1, 0, or 1. _ 5/4/2017 35 Relational Expressions Suppose i and j are local integer variables, and that: i slot #0 j slot #1 0 represents false and 1 represents true. For the expression i < j leave either 0 or 1 on top of the operand stack: The code in red are the only parts that change based on the expression. 5/4/2017 iload_0 iload_1 if_icmplt L003 iconst_0 goto L004 L003: iconst_1 L004: ; ; ; ; ; push the value of i (slot #0) push the value of j (slot #1) branch if i < j push false go to next statement ; push true Your code generator also needs to emit labels. 36 Relational Expression Code Template iload_0 iload_1 if_icmplt L003 iconst_0 goto L004 L003: iconst_1 L004: 5/4/2017 37 Assignment Statement Code Template The code template for an assignment statement to a local variable <variable> := <expression> code for <expression> xstore n Where x is i, l, f, or d depending on the type of the computed value of <expression>. You can generate a shortcut store instruction such as istore_3 (3 is a slot number) whenever possible. _ 5/4/2017 38 Pascal Procedures and Functions Analogous to Java methods. Two major simplifications for our Pascal compiler: Standard Pascal is not object-oriented. Java does not have nested methods. 5/4/2017 Therefore, Pascal procedures and functions are more like the private static methods of a Java class. The JVM does not easily implement nested methods. Therefore, we will compile only “top level” (level 1) Pascal procedures and functions. _ 39 Procedures and Functions, cont’d A Pascal program: The roughly equivalent Java class: Fields and methods are private static. PROGRAM ADDER; VAR i, j, sum : integer; FUNCTION add(n1, n2 : integer) : integer; public class Adder { private static int i, j, sum; private static int add(int n1, int n2) { int s = i + j + n1 + n2; return s; } VAR s : integer; BEGIN s := i + j + n1 + n2; add := s; END; public static void main(String args[]) { i = 10; j = 20; BEGIN i := 10; j := 20; sum := add(100, 200); writeln('Sum = ', sum) END. 5/4/2017 sum = add(100, 200); System.out.println("Sum = " + sum); } } 40 Code for a Pascal Main Program PROGRAM ADDER; .class public super Adder .super java/lang/Object VAR i, j, sum : integer; FUNCTION add(n1, n2 : integer) : integer; VAR s : integer; .private field static i I .private field static j I .private field static sum I .method public <init>()V BEGIN s := i + j + n1 + n2; add := s; END; Private static class fields. Void method. No parameters. aload_0 invokenonvirtual java/lang/Object/<init>()V return .limit stack 1 .limit locals 1 .end method BEGIN i := 10; j := 20; ... sum := add(100, 200); writeln('Sum = ', sum) END. Each Jasmin class must have a constructor named <init>. 5/4/2017 The local variable in slot #0 contains the value of “this”. Each constructor must call the superclass constructor. 41 Code for a Pascal Function PROGRAM ADDER; VAR i, j, sum : integer; FUNCTION add(n1, n2 : integer) : integer; VAR s : integer; BEGIN s := i + j + n1 + n2; add := s; END; BEGIN i := 10; j := 20; iload_2 ireturn sum := add(100, 200); writeln('Sum = ', sum) END. 5/4/2017 .method static add(II)I .var 0 is n1 I .var 1 is n2 I .var 2 is s I .var 3 is add I getstatic Adder/i I getstatic Adder/j I iadd iload_0 ; n1 (slot #0) iadd iload_1 ; n2 (slot #1) iadd istore_2 ; s (slot #2) ; load s to stack top ; (see below) .limit stack 2 .limit locals 3 .end method getstatic with a fully qualified name and type to push the value of a static field onto the operand stack. ireturn pops an integer from the top of the callee’s stack and pushes it onto the caller’s stack 42 Code to Call a Function (Static Method) PROGRAM ADDER; .method public static main([Ljava/lang/String;)V .limit stack 4 .limit locals 1 VAR i, j, sum : integer; FUNCTION add(n1, n2 : integer) : integer; bipush 10 putstatic Adder/i I VAR s : integer; bipush 20 putstatic Adder/j I BEGIN s := i + j + n1 + n2; add := s; END; bipush 100 sipush 200 invokestatic Adder/add(II)I putstatic Adder/sum I BEGIN i := 10; j := 20; sum := add(100, 200); writeln('Sum = ', sum) END. ... 5/4/2017 A function call leaves its return value on top of the operand stack of the caller. Use putstatic with a fully qualified field name and type signature to pop a value off the operand stack and store it into a static field. Use invokestatic with a fully-qualified method name and a type signature to call a static method. 43 Code to Call a Function (Static Method) PROGRAM ADDER; .method public static main([Ljava/lang/String;)V .limit stack 4 .limit locals 1 VAR i, j, sum : integer; FUNCTION add(n1, n2 : integer) : integer; bipush 10 putstatic Adder/i I VAR s : integer; bipush 20 putstatic Adder/j I BEGIN s := i + j + n1 + n2; add := s; END; bipush 100 sipush 200 invokestatic Adder/add(II)I putstatic Adder/sum I BEGIN i := 10; j := 20; sum := add(100, 200); writeln('Sum = ', sum) END. ... 5/4/2017 Use putstatic with a fully qualified field name and type signature to pop a value off the operand stack and store it into a static field. Use invokestatic with a fully-qualified method name and a type signature to call a static method. 44 Code to Call System.out.println() What does the method call System.out.println("Hello, world!") require on the operand stack? A reference to the java.io.PrintStream object System.out. A reference to the java.lang.String object "Hello, world!" object type descriptor of object getstatic java/lang/System/out Ljava/io/PrintStream; ldc "Hello, world!" invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V method parm type descriptor no return type (void) 5/4/2017 45 System.out.println(), cont’d Compile the Pascal call writeln('Sum = ', sum) as if it were the Java System.out.println( new StringBuilder(" Sum = ") .append(sum) .toString() ); Each call to invokevirtual requires an object reference and then any required actual parameter values on the operand stack. getstatic java/lang/System/out Ljava/io/PrintStream; new java/lang/StringBuilder Why do we need this dup instruction? dup ldc "Sum = " invokenonvirtual java/lang/StringBuilder/<init>(Ljava/lang/String;)V getstatic Adder/sum I invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder; invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String; invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V 5/4/2017 46 A call to the static format() method of the Java String class has two parameters, the format string and an array of object values and it returns a string value String.format(“The square root of %4d is %8.4f”, n, root) would compile to the Jasmin instruction invokestatic java/lang/String/format(Ljava/lang/String; [Ljava/lang/Object;)Ljava/lang/String; This instruction requires that the address of the string constant “The square …. “ and the address of the array containing the values of n, root be at the top of the operand stack. It pops off the string and array addresses to be used as parameters of the call and the call pushes the string value result onto the operand stack 5/4/2017 47 String.format() A more elegant way to compile a call to Pascal’s standard writeln() procedure is to use Java’s String.format() method. Compile Pascal writeln('The square root of ', n:4, ' is ', root:8:4); as if it were the Java System.out.print( String.format( "The square root of %4d is %8.4f\n", n, root) ); 5/4/2017 48 String.format(), cont’d The Java String.format() method has a variable-length parameter list. The first parameter is the format string. Similar to C’s format strings for printf(). The code generator must construct the format string. Pascal: ('The square root of ', n:4, ' is ', root:8:4) Equivalent Java: ("The square root of %4d is %8.4f\n", n, root) The remaining parameters are the values to be formatted, one for each format specification in the format string. 5/4/2017 Jasmin passes these remaining parameters as a one-dimensional array of objects. Therefore, we must emit code to create and initialize the array and leave its reference on the operand stack. 49 String.format(), cont’d s = String.format( "The square root of %4d is %8.4f\n", n, root); Instruction aastore operands on the stack: ldc iconst_2 anewarray dup iconst_0 getstatic invokestatic aastore dup iconst_1 getstatic invokestatic aastore invokestatic putstatic 5/4/2017 Array reference Index value Element value (object reference) "The square root of %4d is %8.4f\n" java/lang/Object Create an array of size 2 and leave the array reference on the operand stack. FormatTest/n I java/lang/Integer.valueOf(I)Ljava/lang/Integer; Store element 0: The value of n. Why the dup instructions? FormatTest/root F java/lang/Float.valueOf(F)Ljava/lang/Float; Store element 1: The value of root. java/lang/String.format(Ljava/lang/String;[Ljava/lang/Object;) Ljava/lang/String; FormatTest/s Ljava/lang/String; 50 String.format(), cont’d System.out.print( String.format("The square root of %4d is 8.4f\n", n, root); ); getstatic java/lang/System/out Ljava/io/PrintStream; ldc "The square root of %4d is %8.4f\n" iconst_2 anewarray java/lang/Object dup iconst_0 getstatic FormatTest/n I invokestatic java/lang/Integer.valueOf(I)Ljava/lang/Integer; aastore dup iconst_1 getstatic FormatTest/root F invokestatic java/lang/Float.valueOf(F)Ljava/lang/Float; aastore invokestatic java/lang/String.format(Ljava/lang/String; [Ljava/lang/Object;)Ljava/lang/String; invokevirtual java/io/PrintStream.print(Ljava/lang/String;)V 5/4/2017 51 Parameter Passing Java (and Jasmin) always passes parameters by value. For scalar data type, they are passed by value. For structured data types (string, array, object), their address are passed by value (hence indirectly by reference) Strategies for compiling Pascal parameter passing 5/4/2017 If a parameter is scalar (integer, real, bool, subrange, enum) without VAR, follow default rule for Java parameter passing. If a parameter is structured data type with VAR, follow default rule for Java parameter passing. If a parameter is scalar (integer, real, bool, subrange, enum) with VAR, convert this into a wrapper class object. If a parameter is structured data type without VAR, we create a clone of the parameter object and pass the clone at the actual parameter _ 52 Passing Parameters Pascal can pass parameters by value and by reference. VAR parameters = pass by reference Java and Jasmin pass scalar values by value. To pass a scalar value by reference, you must first wrap the value inside an object. 5/4/2017 Pass the object reference (by value) to the routine. The routine can modify the wrapped value. Upon return, the caller must unwrap the changed value. _ 53 Passing Parameters, cont’d Java and Jasmin pass references to objects by value. When a formal parameter to a method is a reference to an object, the method can change the value of the object (such as by modifying the values of the object fields). But the method cannot change the parameter’s value to refer to another object and have the method’s caller see that change. 5/4/2017 To pass an array or record by value as in Pascal, first clone the array or record value and then pass the reference to the clone. 54 Passing Parameters, cont’d The Pascal Runtime Library contains classes for passing parameters by value or by reference. Classes BWrap, CWrap, IWrap, and RWrap wrap a boolean, character, integer, and real scalar value, respectively, to be passed by reference. Class Cloner clones an array or reference to be passed by value. public class IWrap { public int value; public IWrap(int value) { this.value = value; } _ 5/4/2017 } 55 Example: Passing Scalars by Reference PROGRAM parmswrap; .method public static main([Ljava/lang/String;)V ... VAR new IWrap Wrap i. i, j : integer; dup getstatic parmswrap/i I PROCEDURE swap(VAR parm1, parm2 invokenonvirtual IWrap/<init>(I)V : integer); dup Allocate slots #1 and #2 VAR astore_1 as temporaries to store the temp : integer; new IWrap Wrap j. wrapped i and j. dup BEGIN getstatic parmswrap/j I temp := parm1; invokenonvirtual IWrap/<init>(I)V parm1 := parm2; dup parm2 := temp; astore_2 Call method. END; invokestatic parmswrap/swap(LIWrap;LIWrap;)V BEGIN i := 10; aload_1 j := 20; getfield IWrap/value I Unwrap i. swap(i, j); putstatic parmswrap/i I writeln('Result: i = ', i:0, aload_2 ', j = ', j:0); getfield IWrap/value I Unwrap j. END. putstatic parmswrap/j I 5/4/2017 56 Example: Passing Scalars by Reference, cont’d PROGRAM parmswrap; .method private static swap(LIWrap;LIWrap;)V VAR i, j : integer; #0 #1 PROCEDURE swap(VAR parm1, parm2 : integer); VAR #2 temp : integer; BEGIN temp := parm1; parm1 := parm2; parm2 := temp; END; BEGIN i := 10; j := 20; swap(i, j); writeln('Result: i = ', i:0, ', j = ', j:0); END. 5/4/2017 .var 2 is temp I .var 0 is parm1 LIWrap; .var 1 is parm2 LIWrap; aload_0 getfield istore_2 IWrap/value I Access the wrapped values of aload_0 parm1 and parm2 and swap them. aload_1 getfield IWrap/value I putfield IWrap/value I aload_1 iload_2 putfield IWrap/value I return .limit locals 3 .limit stack 2 .end method 57 Example: Passing an Array by Value PROGRAM parmsclone; TYPE cube = ARRAY [0..1, 0..2, 0..3] OF integer; VAR vvv : cube; PROCEDURE printCube(VAR c : cube); ... PROCEDURE doCubeValue(c : cube); VAR i, j, k : integer; 5/4/2017 BEGIN doCubeRef(vvv); writeln('In main:'); printCube(vvv); BEGIN FOR i := 0 TO 1 DO BEGIN FOR j := 0 TO 2 DO BEGIN FOR k := 0 TO 3 DO BEGIN c[i,j][k] := 200*i + 10*j +k; END; END; getstatic END; invokestatic writeln('In doCubeValue:'); printCube(c); END; PROCEDURE doCubeRef(VAR c : cube); ... BEGIN ... c[i,j][k] := 100*i + 10*j +k; ... END; checkcast invokestatic doCubeValue(vvv); writeln('In main:'); printCube(vvv); END. parmsclone/vvv [[[I Cloner.deepClone(Ljava/lang/Object;) Ljava/lang/Object; [[[I parmsclone/docubevalue([[[I)V 58 Class Cloner In the Pascal Runtime Library: public class Cloner { public static Object deepClone(Object original) throws PascalRuntimeException { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); Write the original object to a byte ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(original); array stream. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return ois.readObject(); Construct a copy from the stream. Return the copy as the deep clone. } catch (Exception ex) { throw new PascalRuntimeException("Deep clone failed."); } } } 5/4/2017 59 Arrays and Subscripted Variables Code generation for arrays: Allocate memory for single-dimensional arrays Code to allocate memory for an array variable. Code to allocate memory for each non-scalar array element. Code for a subscripted variable in an expression. Code for a subscripted variable that is an assignment target. Instruction newarray for scalar elements. Instruction anewarray for non-scalar elements. Allocate memory for multidimensional arrays. 5/4/2017 Instruction multianewarray. _ 60 Allocating Memory for Arrays Recall the code template for a Jasmin method. Code to allocate arrays here! Pascal automatically allocates memory for arrays declared in the main program or locally in a procedure or function. The memory allocation occurs whenever the routine is called. This is separate from dynamically allocated data Therefore, our generated Jasmin code using pointers and new. must implement this automatic runtime behavior. 5/4/2017 61 Example: Allocate Memory for Scalar Arrays PROGRAM ArrayTest; TYPE vector = ARRAY[0..9] OF integer; matrix = ARRAY[0..4, 0..4] OF integer; cube = ARRAY[0..1, 0..2, 0..3] OF integer; VAR i, j, k, n : integer; a1 : vector; a2 : matrix; a3 : cube; BEGIN ... END. 5/4/2017 bipush 10 newarray int putstatic arraytest/a1 [I iconst_5 iconst_5 multianewarray putstatic [[I 2 arraytest/a2 [[I iconst_2 iconst_3 iconst_4 multianewarray putstatic [[[I 3 arraytest/a3 [[[I 62 Access an Array Element of a 2-D Array PROGRAM ArrayTest; a2 TYPE matrix = ARRAY[0..2, 0..3] OF integer; 0 0 VAR i, j, k : integer; a2 : matrix; 1 BEGIN ... i := 1; j := 2; k := a2[i, j]; ... END. k 1 2 3 1 2 3 4 5 6 7 8 2 9 10 11 12 1 2 3 4 5 6 7 8 7 getstatic getstatic aaload getstatic iaload putstatic arraytest/a2 [[I arraytest/i I arraytest/j I arraytest/k I 9 10 11 12 5/4/2017 63 Subscripted Variables in Expressions PROGRAM ArrayTest; TYPE vector = ARRAY[0..9] OF integer; matrix = ARRAY[0..4, 0..4] OF integer; cube = ARRAY[0..1, 0..2, 0..3] OF integer; VAR i, j, k, n : integer; a1 : vector; a2 : matrix; a3 : cube; BEGIN ... j := a1[i]; k := a2[i, j]; n := a3[i, j, k]; ... END. getstatic getstatic iaload putstatic arraytest/a1 [I arraytest/i I getstatic getstatic aaload getstatic iaload putstatic arraytest/a2 [[I arraytest/i I getstatic getstatic aaload getstatic aaload getstatic iaload putstatic arraytest/a3 [[[I arraytest/i I arraytest/j I arraytest/j I arraytest/k I arraytest/j I arraytest/k I arraytest/n I Instructions iaload (push a scalar value from an array element value) and aaload (push an array element address) 5/4/2017 64 Set an Array Element of a 2-D Array PROGRAM ArrayTest; a2 TYPE matrix = ARRAY[0..2, 0..3] OF integer; 0 0 VAR i, j, k : integer; a2 : matrix; 1 BEGIN ... i := 1; j := 2; k := 0; a2[i, j] := k; ... END. k 1 2 3 1 2 3 4 5 6 7 0 8 2 9 10 11 12 1 2 3 4 5 6 7 8 0 getstatic getstatic aaload getstatic getstatic iastore arraytest/a2 [[I arraytest/i I arraytest/j I arraytest/k I 9 10 11 12 5/4/2017 65 Subscripted Variables as Assignment Targets PROGRAM ArrayTest; TYPE vector = ARRAY[0..9] OF integer; matrix = ARRAY[0..4, 0..4] OF integer; cube = ARRAY[0..1, 0..2, 0..3] OF integer; VAR i, j, k, n : integer; a1 : vector; a2 : matrix; a3 : cube; BEGIN ... a1[i] := j; a2[i, j] := k; a3[i, j, k] := n; ... END. getstatic getstatic getstatic iastore arraytest/a1 [I arraytest/i I arraytest/j I getstatic getstatic aaload getstatic getstatic iastore arraytest/a2 [[I arraytest/i I getstatic getstatic aaload getstatic aaload getstatic getstatic iastore arraytest/a3 [[[I arraytest/i I arraytest/j I arraytest/k I arraytest/j I arraytest/k I arraytest/n I Instructions iastore (pop and store a scalar value into an array element) and aaload (push an array element address) 5/4/2017 66 More Subscripted Variables PROGRAM ArrayTest; TYPE vector = ARRAY[0..9] OF integer; matrix = ARRAY[0..4, 0..4] OF integer; cube = ARRAY[0..1, 0..2, 0..3] OF integer; VAR i, j, k, n : integer; a1 : vector; a2 : matrix; a3 : cube; BEGIN ... a3[i][a1[j]][k] := a2[i][j] - a3[k, 2*n][k+1]; ... END. Instruction aaload pushes the address of one dimension of an array. Instruction iaload pushes the integer value of an array element. 5/4/2017 getstatic getstatic aaload getstatic getstatic iaload aaload getstatic arraytest/a3 [[[I arraytest/i I arraytest/a1 [I arraytest/j I arraytest/k I getstatic arraytest/a2 [[I getstatic arraytest/i I aaload getstatic arraytest/j I iaload getstatic getstatic aaload iconst_2 getstatic imul aaload getstatic iconst_1 iadd iaload isub iastore arraytest/a3 [[[I arraytest/k I arraytest/n I arraytest/k I What’s on the stack after this instruction? 67 Allocate Memory for Non-Scalar Arrays For a non-scalar array, we must generate code to : Allocate memory for the array itself. 5/4/2017 Similar to a scalar array, except that each element will contain a reference to its data. Allocate memory for the data of each array element and initialize each element. _ 68 Allocate Memory for a 1-D String Array PROGRAM AllocArrayTest2; TYPE string = ARRAY[1..5] OF char; vector = ARRAY[0..9] OF string; a1 " " " " " " " " " " " " " " " " " " " " VAR a1 : vector; BEGIN END. Each array element should contain a reference to a string object. _ 5/4/2017 69 Memory for a 1-D String Array, con’d PROGRAM AllocArrayTest2; a1 " " " " " " " " " " " " " " " " " " " " TYPE string = ARRAY[1..5] OF char; vector = ARRAY[0..9] OF string; VAR a1 : vector; bipush anewarray BEGIN END. 10 java/lang/StringBuilder iconst_0 istore_1 Allocate slot #1 as the temporary variable i. L001: iload_1 bipush if_icmpge Like the Java code: for (int i = 0; i < 10; ++i) { a1[i] = PaddedString.create(5); } PaddedString is a class in the Pascal Runtime Library. 10 L002 dup What are we duplicating? iload_1 iconst_5 invokestatic PaddedString.create(I) Ljava/lang/StringBuilder; aastore iinc goto 1 1 L001 L002: 5/4/2017 putstatic allocarraytest2/a1 [Ljava/lang/StringBuilder; 70 Code Template: 1-D Non-Scalar Array bipush 10 anewarray java/lang/StringBuilder iconst_0 istore_1 L001: iload_1 bipush 10 if_icmpge dup iload_1 L002 iconst_5 invokestatic PaddedString.create(I)Ljava/lang/StringBuilder; aastore iinc 1 1 goto L001 L002: putstatic 5/4/2017 allocarraytest2/a1 [Ljava/lang/StringBuilder; 71 Allocate Memory for a 2-D String Array a2 PROGRAM AllocArrayTest2; " " " " " " " " " " " " " " " " " " " " " " " " TYPE string = ARRAY[1..5] OF char; matrix = ARRAY[0..2, 0..3] OF string; VAR a2 : matrix; BEGIN END. 5/4/2017 72 Memory for a 2-D String Array, cont’d iconst_3 iconst_4 multianewarray PROGRAM AllocArrayTest2; TYPE string = ARRAY[1..5] OF char; matrix = ARRAY[0..2, 0..3] OF string; VAR a2 : matrix; BEGIN END. Allocate slots #1 and #2 as the temporary variables i and j. 5/4/2017 iconst_0 istore_1 " " iload_1 iconst_3 if_icmpge " " " " " " L003: L004 dup iload_1 aaload a2 iconst_0 istore_2 ditto iload_2 iconst_4 if_icmpge ditto L005: Like the Java code: for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { a2[i][j] = PaddedString.create(5); } } [[Ljava/lang/StringBuilder; 2 L006 dup iload_2 iconst_5 invokestatic aastore iinc goto 2 1 L005 pop iinc goto 1 1 L003 PaddedString.create(I)Ljava/lang/StringBuilder; L006: L004: putstatic allocarraytest2/a2 [[Ljava/lang/StringBuilder; 73 Code Template: n-D Non-Scalar Array iconst_5 iconst_4 multianewarray [[Ljava/lang/StringBuilder; 2 iconst_0 istore_1 L003: iload_1 iconst_3 if_icmpge L004 dup iload_1 aaload iconst_0 istore_2 L005: iload_2 iconst_4 if_icmpge L006 dup iload_2 iconst_5 invokestatic aastore iinc goto 2 1 L005 pop iinc goto 1 1 L003 PaddedString.create(I)Ljava/lang/StringBuilder; L006: 5/4/2017 L004: putstatic 74 allocarraytest2/a2 [[Ljava/lang/StringBuilder; Records and Fields Recall the code template for a Jasmin method. Code to allocate records here! Implement the value of each Pascal record variable as a java.util.HashMap object. 5/4/2017 Keys: Field names (as strings) Values: Field values (as objects) _ 75 Pascal Records in the JVM Each record value is a separate hash table. Keys: field names Values: field values PROGRAM RecordTest2; TYPE String16 = ARRAY [1..16] OF char; PersonRec = RECORD firstName : String16; age : integer; END; VAR john : PersonRec; BEGIN ... END. 5/4/2017 john Allocate and initialize each value. "age" 0 "firstname" " " new java/util/HashMap dup invokenonvirtual java/util/HashMap/<init>()V dup ldc "age" Convert the int value 0 to an Integer object. iconst_0 invokestatic java/lang/Integer.valueOf(I)Ljava/lang/Integer; invokevirtual java/util/HashMap.put(Ljava/lang/Object; Ljava/lang/Object;)Ljava/lang/Object; pop Why pop? dup ldc "firstname" bipush 16 invokestatic PaddedString.create(I)Ljava/lang/StringBuilder; invokevirtual java/util/HashMap.put(Ljava/lang/Object; Ljava/lang/Object;)Ljava/lang/Object; pop putstatic recordtest2/john Ljava/util/HashMap; 76 Set the Values of Record Fields john "age" "firstname" 240 " "" "John "John" "" PROGRAM RecordTest2; TYPE String16 = ARRAY [1..16] OF char; PersonRec = RECORD firstName : String16; age : integer; END; VAR john : PersonRec; age : integer; BEGIN john.age := 24; john.firstName := 'John'; age := john.age; END. 5/4/2017 getstatic ldc bipush invokestatic invokevirtual recordtest2/john Ljava/util/HashMap; "age" 24 java/lang/Integer.valueOf(I)Ljava/lang/Integer; java/util/HashMap.put(Ljava/lang/Object; Ljava/lang/Object;)Ljava/lang/Object; pop getstatic ldc invokevirtual checkcast dup iconst_0 invokevirtual ldc invokevirtual bipush iconst_4 invokestatic invokevirtual recordtest2/john Ljava/util/HashMap; "firstname" java/util/HashMap.get(Ljava/lang/Object;)Ljava/lang/Object; java/lang/StringBuilder java/lang/StringBuilder.setLength(I)V "John" java/lang/StringBuilder.append( Ljava/lang/String;)Ljava/lang/StringBuilder; 16 PaddedString.blanks(II)Ljava/lang/StringBuilder; java/lang/StringBuilder.append( Ljava/lang/CharSequence;)Ljava/lang/StringBuilder; pop 77 Access Values of Record Fields PROGRAM RecordTest2; john TYPE String16 = ARRAY [1..16] OF char; PersonRec = RECORD firstName : String16; age : integer; END; VAR john : PersonRec; age : integer; "age" "firstname" age 24 "John " 24 getstatic ldc invokevirtual checkcast invokevirtual putstatic recordtest2/john Ljava/util/HashMap; "age" java/util/HashMap.get(Ljava/lang/Object;) Ljava/lang/Object; java/lang/Integer java/lang/Integer.intValue()I recordtest2/age I BEGIN john.age := 24; john.firstName := 'John'; age := john.age; END. 5/4/2017 78 IF Statement Code Templates The code that evaluates the boolean expression leaves either 0 (false) or 1 (true) on top of the operand stack. 5/4/2017 ifeq branches if [TOS] is 0 (the expression is false) 79 Example: IF Statement getstatic getstatic if_icmplt iconst_0 goto PROGRAM IfTest; VAR i, j, t, f : integer; iftest/i I iftest/j I L002 L003 L002: BEGIN {IF statements} ... IF i < j THEN t := 300; iconst_1 L003: ifeq sipush putstatic L001 300 iftest/t I getstatic getstatic if_icmpeq iconst_0 goto iftest/i I iftest/j I L005 L001: IF i = j THEN t := 200 ELSE f := -200; ... END. L006 L005: iconst_1 L006: ifeq sipush putstatic goto L007 200 iftest/t I L004 sipush ineg putstatic 200 L007: iftest/f I L004: 5/4/2017 80 Looping Statement Code Template The code that evaluates the boolean expression leaves either 0 (false) or 1 (true) on top of the operand stack. 5/4/2017 ifne branches if [TOS] is not 0 (the expression value is true) There might not be any code before or after the test. _ 81 Example: Newton’s Square Root Function #0 FUNCTION sqrt(x : real) : real; VAR #1 #2 i : integer; root : real; BEGIN i := 0; root := x; REPEAT root := (x/root + root)/2; i := i + 1; UNTIL i > 10; sqrt := root; END; 5/4/2017 iconst_0 istore_1 ; i := 0 fload_0 fstore_2 ; root := x L000: fload_0 ; x fload_2 ; root fdiv ; / fload_2 ; root fadd ; + fconst_2 ; 2.0 fdiv ; / fstore_2 ; ==> root iinc 1 1 ; i := i + 1; iload_1 ; i bipush 10 ; 10 if_icmpgt L001 ; if i > 10 goto L001 iconst_0 ; false goto L002 L001: iconst_1 ; true L002: ifne L001 ; if true goto L003 goto L000 L003: fload_2 82 freturn ; return root Example: FOR Statement PROGRAM ForTest; VAR j, k, n : integer; fortest/j I fortest/k I getstatic iconst_5 if_icmpgt iconst_0 goto L004 fortest/k I L001: BEGIN {FOR statements} ... FOR k := j TO 5 DO BEGIN n := k; END; getstatic putstatic L003: iconst_1 L004: ifne ... END. Remember that program variables are translated into Jasmin static fields, and so they have names, not slot numbers. L002 L003 This is code emitted for a general > test. It can be improved! getstatic putstatic fortest/k I fortest/n I getstatic iconst_1 iadd putstatic goto L001 fortest/k I fortest/k I L002: 5/4/2017 83 SELECT Statement 5/4/2017 84 Example: CASE Statement #0 #1 VAR i, j : integer; ... CASE i OF 100,105: j := 1000; 200,256,282: j := 2000; END 5/4/2017 iload_0 ; i lookupswitch 100: L010 105: L010 200: L020 256: L020 282: L020 default: L099 L010: sipush 1000 istore_1 ; j := 1000 goto L099 L020: sipush 2000 istore_1 ; j := 2000 goto L099 L099: 85 Using Java Because your compilers will generate .class files to run on the Java Virtual Machine (JVM) … You can write Java classes whose methods invoke methods in your compiled code. Your compiled code can invoke methods in classes that you write in Java. 5/4/2017 Create a runtime library. Example: You invent a new source language with statements that do regular expression searches on strings. You can write the RE algorithms in Java and call them from your compiled code. 86 The Pascal Runtime Library Useful utility classes written in Java that contain methods your compiled Jasmin code can call. Create an archive file PascalRTL.jar. Some utility classes: PascalTextIn RunTimer Error exception thrown while executing compiled code. PaddedString 5/4/2017 Perform runtime range checking. PascalRuntimeException Time the execution of compiled programs and print the elapsed run time. RangeChecker Runtime text input based on the scanner. Pascal string implementation with blank-padding 87 The Pascal Runtime Library, cont’d The Pascal Runtime Library can reuse some classes from the front end. When a Pascal program calls the standard procedure read to input values at run time, read must scan the input text for values of various data types (integer, real, string, etc.). Therefore, reuse the scanner and token classes by including them in the library. Include the runtime library on your class path when you run your compiled program. java –cp .;PascalRTL.jar ... Your generated code can call routines in the library. 5/4/2017 88 The Pascal Runtime Library, cont’d Cloner.class PaddedString.class PascalRuntimeException.class PascalTextIn.class RangeChecker.class RunTimer.class BWrap.class CWrap.class IWrap.class RWrap.class 5/4/2017 89 The Pascal Runtime Library, cont’d wci/frontend/EofToken.class wci/frontend/Scanner.class wci/frontend/Source.class wci/frontend/Token.class wci/frontend/TokenType.class wci/frontend/pascal/PascalScanner.class wci/frontend/pascal/PascalToken.class wci/frontend/pascal/PascalTokenType.class wci/frontend/pascal/tokens/PascalErrorToken.class wci/frontend/pascal/tokens/PascalNumberToken.class wci/frontend/pascal/tokens/PascalSpecialSymbolToken.class wci/frontend/pascal/tokens/PascalStringToken.class wci/frontend/pascal/tokens/PascalWordToken.class wci/message/Message.class wci/message/MessageHandler.class wci/message/MessageListener.class wci/message/MessageProducer.class wci/message/MessageType.class 5/4/2017 90