CS453 Colorado State University ============================================== Memory Model: Code Generation for Classes ============================================== ------------------------ Outline for today - step through a multi-scope symbol table build and use from previous notes - Type data structure example - questions about symbol tables or representing types? - implementing classes - memory layout for an example - dynamically allocating objects - the implicit "this" parameter and expression - uses and defines of class member variables - memory layout examples ------------------------- Type data structure What are the ways we can use and construct types in MeggyJava? VarDecl -> Type id ; Type -> byte | boolean | int | Meggy.Color | Meggy.Tone | Meggy.Button | id ClassDecl -> class id { VarDecl* } MethodDecl -> public Type id ( FormalList ) Discussion of the Type data structure usage for following example: class C { int i; C c; public int foo( boolean p ) { B b; -> write these down in any order and ask around the room as to the correctness // correct in terms of typing p = true; c = this; // legal? b = new B(); // incorrect c = new B(); i = x; } } class B { } Representing types in the symbol table. - AST has nodes IntType, ClassType, BoolType, etc. that derive from IType. Probably want a helper method that can convert one of those instances into the appropriate symtable.Type instance. Other information to maintain in the symbol table - for each VarSTE, is it a local variable or a member variable - for each class, what will the object size be? - for each method, - a VarSTE for "this" parameter - how many parameters including the implicit "this" parameter? - how many local variables - mangled method name, e.g. classname_method --------------------------- Possible Type Errors in PA6 - see slide 5 ---------------------------------- Class example (bring up in editor) import meggy.Meggy; class ClassRef { public static void main(String[] a){ Meggy.setPixel((byte)7, (byte)(new Foo().testing()), Meggy.Color.RED); } } class Foo { Bar b; public int testing() { int a; b = new Bar(); a = b.changeY(2); return b.getY() + a; } } class Bar { boolean x; int y; public int changeY(int p) { y = p; return this.getY(); } public int getY() { return y; } } -> show run-time stack and heap right before the epilogue for the changeY(2) call executes Suggested Exercise: - show run-time stack and heap right before the return instruction in getY at the b.getY() call ------------------------- dynamically allocating objects outNewExp 1) push size of class instance onto stack ldi r24, lo8(OBJSIZEINBYTES) ldi r25, hi8(OBJSIZEINBYTES) 2) allocate that space on the heap call malloc 3) push return from malloc on stack push r25 push r24 ------------------------- Method calls Now you will need to pass in the receiver reference as the first parameter. outCallExp 1) Using the mapping of expression nodes to types in the symbol table, look up the ClassSTE from the receiver type. Then lookup the MethodSTE from the ClassSTE scope. 2) Generate code that pops parameters off the stack and into the appropriate registers from right to left. Don't forget the "this" parameter. 3) Generate code that calls the mangled method name. 4) Generate code that pushes the return value back on the stack. outThisExp 1) push the value of the "this" parameter onto the run-time stack Recall that the "this" parameter is stored in r31:r30. ------------------------- uses and defines of class member variables outIdExp 1) Lookup id in symbol table to get VarSTE 2) If the VarSTE is a member variable 2a) Look up VarSTE for "this" and generate code that loads the value of "this" into registers r31:r30. 3) load variable into a register(s) using the base+offset stored in the VarSTE. 4) Push the variable value on the stack. outAssignStatement 1) Lookup id in symbol table to get VarSTE 2) If the VarSTE is a member variable 2a) Look up VarSTE for "this" and generate code that loads the value of "this" into registers r31:r30. 3) store value of expression on top of run-time stack into base+offset for VarSTE ------------------------ Memory Layout Examples (1) Show run-time stack and heap before the return from printCount(0). /* Output should be: Setting pixel (3,3) to BLUE Setting pixel (2,2) to BLUE Setting pixel (1,1) to BLUE Setting pixel (0,0) to BLUE Setting pixel (3,7) to WHITE */ import meggy.Meggy; class CountDown { public static void main(String[] a){ Meggy.setPixel((byte)(new Recurse().printCount(3)), (byte)7, Meggy.Color.WHITE); } } class Recurse { public int printCount(int i) { int x; x = i + 3; Meggy.setPixel( (byte)i, (byte)i, Meggy.Color.BLUE ); if ( i < 1 ) { } else { x = this.printCount(i-1); } return x; } } (2) Suggested Exercise: Show the run-time stack and heap after the while loop. import meggy.Meggy; class ListCountDown { public static void main(String[] a){ new List().runProgram(3); } } class List { Node head; public void runProgram( int p ) { int x; Node iter; Node prev; /* create count down list */ head = new Node(); prev = head; x = p; while ( 0 < x ) { iter = new Node(); prev = prev.init( x, iter); iter = iter.initLast( x - 1 ); prev = iter; x = x-1; } /* print list */ iter = head; while ( ! iter.isLast() ) { Meggy.setPixel( (byte)(iter.getValue()), (byte)(iter.getValue()), Meggy.Color.BLUE); iter = iter.getNext(); } Meggy.setPixel( (byte)(iter.getValue()), (byte)(iter.getValue()), Meggy.Color.VIOLET); } } /* Nodes in a singly-linked list. */ class Node { int value; Node next; boolean last; /* is this the last node in the list? */ public Node init(int p, Node node) { value = p; next = node; last = false; return this; } public Node initLast(int p) { value = p; last = true; return this; } public boolean isLast() { return last; } public int getValue() { return value; } public Node getNext() { return next; } } ------------------------ mstrout@cs.colostate.edu, 4/11/11