diff --git a/AstBuilding.py b/AstBuilding.py index b67b81eb775d763a9a8e4d7dac4e91d09dab6682..25a7d0491409385d80ac71e056d5c040af5f7cc3 100644 --- a/AstBuilding.py +++ b/AstBuilding.py @@ -57,15 +57,61 @@ def reachabilityChecking(ASTs): t[1].reachCheck() #################################################### +# Returns a dictionary (type e.g. "boolean") -> str (the assembly code generated) +def arrayClassMemory(types): + # All method labels from java.lang.Object + # TODO: add subtype testing table + methods = ["M_Object_Object_", "M_Object_equals_Object", "M_Object_toString_", "M_Object_hashCode_", "M_Object_clone_", "M_Object_getClass_"] + typeDict = {} + for t in types: + # Class memory layout + # Label: "A_type" + # Label for SIT pointer: "I_SIT_spot_typeName_array" + # Label for method pointers: "V_typeName_methodName_param_array" + code = "section .data\n" + code += "; Start of class memory layout\n" + code += pLabel(name=t, type="array") + \ + pLabel("SIT_spot_"+ t + "_array", "inter") + \ + p(instruction="dd", arg1=64) + for m in methods: + code += pLabel(name=t+"_"+m+"_array", type="vtable") + \ + p(instruction="dd", arg1=64) + code += "; End of class memory layout\n" + + # Creating a function to initialize class memory layout + # Function label: H_typeName_arrayMemoryInitialize + code += "section .text\n" + \ + "; Function to initialize class memory layout\n" + \ + pLabel(name=t+"_arrayMemoryInitialize", type="helper") + \ + p(instruction="mov", arg1="eax", arg2="I_SIT_spot_"+t+ "_array") + \ + p(instruction="extern", arg1="I_SIT_Object") + \ + p(instruction="mov", arg1="[eax]", arg2="I_SIT_Object", comment="Points to the SIT column of java.lang.Object") + + for m in methods: + code += p(instruction="extern", arg1=m) + \ + p(instruction="mov", arg1="eax", arg2="V_"+t+"_"+m+"_array") + \ + p(instruction="mov", arg1="[eax]", arg2=m, comment="points to method implementation") + code += p(instruction="ret", arg1="") + code += "; End of function to initialize class memory layout\n" + + typeDict[t] = code + + return typeDict + + # Preparation before code Gen: # 1. Calculating the size of the object from each class # (also simultaneosly creating fieldOffset because fieldOffset table is required to generate size) +# 2. SIT building +# 3. Creating class memory layout for every possible array types def codeGenPrep(ASTs): interM = [] + types = ['boolean', 'byte', 'char', 'int', 'short'] # All possible types for t in ASTs: classInterNode = t[1].typeDcl if classInterNode and classInterNode.__class__.__name__ == "ClassNode": classInterNode.populateSizeAndFieldOffset() + types.append(classInterNode.name) else: # interfaceNode, get their methods to prep for SIT interM += classInterNode.methods @@ -78,10 +124,12 @@ def codeGenPrep(ASTs): if classInterNode and classInterNode.__class__.__name__ == "ClassNode": classInterNode.SITsize = len(interM) + return arrayClassMemory(types) + def codeGen(ASTs, output="output"): - ASTs = ASTs[:10] # TOREMOVE: don't compile stdlib for now - codeGenPrep(ASTs) + ASTs = ASTs[:1] # TOREMOVE: don't compile stdlib for now + arrayClassMemory = codeGenPrep(ASTs) for t in ASTs: t[1].codeGen() # Outputting the generated code into className.s @@ -105,13 +153,13 @@ def codeGen(ASTs, output="output"): f.close() # ASTs[0][1].codeGen() - startGen(ASTs, output) # pass in the first AST that contains the test method + startGen(ASTs, output, arrayClassMemory) # pass in the first AST that contains the test method # reset lables for running multiple testCases used_labels = set() local_labels = 0 -def startGen(ASTs, output): +def startGen(ASTs, output, arrayClassMemory): # Test method lable ast = ASTs[0][1] @@ -122,16 +170,29 @@ def startGen(ASTs, output): for t in ASTs: classInterNode = t[1].typeDcl if classInterNode and classInterNode.__class__.__name__ == "ClassNode": - label = "H_" + classInterNode.name + "_" + "classAndStaticFieldInit \n" + label = "H_" + classInterNode.name + "_" + "classAndStaticFieldInit" callInit += p(instruction="extern", arg1=label) + \ p(instruction="call", arg1=label) callInit += "; End of calling each class's classAndStaticFieldInit \n" + callArrayInit = "; Start of calling each array type's arrayMemoryInitialize\n" + for t, code in arrayClassMemory.items(): + label = "H_" + t + "_arrayMemoryInitialize" + callArrayInit += p(instruction="extern", arg1=label) + \ + p(instruction="call", arg1=label) + # Creating .s files for each array type to store the class memory layout + fileName = output + "/" + t + "_arrayClass" + ".s" + f = open(fileName, "w") + f.write(code) + f.close() + callArrayInit += "; End of calling each array type's arrayMemoryInitialize\n" + f = open( output + "/RunTest.s","w") result = " global _start\n_start:\n" \ + callInit \ + + callArrayInit \ + p("extern", method_label, None, None) \ + p("call", method_label, None, None) \ + p("mov", "ebx", "eax", " move eax to exit code") \ diff --git a/CodeGenUtils.py b/CodeGenUtils.py index febb4f6dc7b947d8ec1de229aa99be1798764b7d..dce2f92e46660a556aecf67947d5985e0125e185 100644 --- a/CodeGenUtils.py +++ b/CodeGenUtils.py @@ -10,7 +10,7 @@ def p(instruction, arg1, arg2="", comment=""): return result + "\n" # format a string that represents label -# String, "class"/"method"/"field"/"constant"/"local/vtable/"srarix"/"helper","globalConstant" +# String, "class"/"method"/"field"/"constant"/"local/vtable/"srarix"/"helper","globalConstant", "array" # helper: useful helper functions (these ARE NOT METHODS) # (label list to be extended) # (local label are just for local running of the code) @@ -32,20 +32,24 @@ def getLStringLabel(): def pLabel(name, type, comment=""): global local_labels global used_labels + C = "" # Used for checking if lable is used + l = "" # The result label if type == "local": - l = "_" + str(local_labels) + C = "_" + str(local_labels) local_labels += 1 + l = type[0].upper() + "_" + name else: if type == "constant": l = "cc_" + name else : l = type[0].upper() + "_" + name + C = l # if l in used_labels: # raise("ERROR: Generated repeated label " + l) - used_labels.add(l) + used_labels.add(C) result = "" - if type in ["class", "method", "static", "helper", "globalConstant"]: # make global + if type in ["class", "method", "static", "helper", "globalConstant", "array"]: # make global result += "global " + l + "\n" if comment: result += l + ": ;" + comment + "\n" @@ -137,6 +141,18 @@ def genericHelperFunctions(): p(instruction="jle", arg1="H__Throw_Exception") + \ p(instruction="pop", arg1="ebx", comment="restoring ebx") + \ p(instruction="ret", arg1="") + + # Helper function to perform bounds check on array + # eax = pointer to array + # ecx = index i + code += pLabel(name="_Bounds_Check", type="helper", comment="helper function to check array bounds") + \ + p(instruction="push", arg1="ebx", comment="saving ebx") + \ + p(instruction="mov", arg1="ebx", arg2="[eax+4]", comment="ebx stores length of array") + \ + p(instruction="cmp", arg1="ecx", arg2="ebx") + \ + p(instruction="jge", arg1="H__Throw_Exception") + \ + p(instruction="pop", arg1="ebx", comment="restoring ebx") + \ + p(instruction="ret", arg1="") + return code # Generates code to import helper generic functions and global constants diff --git a/ExprPrimaryNodes.py b/ExprPrimaryNodes.py index 6f74859265df44da6d8b094cde36a89bd8a739b9..11e60a14358f53136253c264466655cc48e32fd3 100644 --- a/ExprPrimaryNodes.py +++ b/ExprPrimaryNodes.py @@ -164,13 +164,52 @@ class ArrayAccessNode(ASTNode): raise Exception("ERROR: Array index must be a number.") self.myType = TypeStruct(self.array.myType.name, self.array.myType.typePointer) + def addr(self): + result = "; Start of calculating address for array access\n" + \ + p(instruction="push", arg1="ecx", comment="saving register ecx") + # 1. Generating code for a + if not hasattr(self.array, "code"): + self.array.codeGen() + result += "; Evaluating pointer to array\n" + \ + self.array.code + \ + p(instruction="push", arg1="eax", comment="push arrray pointer") + + # 2. Evaluating i + if not hasattr(self.index, "code"): + self.index.codeGen() + result += "; Evaluating index i\n"+ \ + self.index.code + \ + p(instruction="mov", arg1="ecx", arg2="eax", comment="ecx stores index i") + + # 3. Runtime checks + result += p(instruction="pop", arg1="eax", comment="eax is pointer to array") + \ + p(instruction="call", arg1="H__Null_Check") + \ + p(instruction="call", arg1="H__Bounds_Check") + + # 4. Make eax store the address to the item we're accessing + result += p(instruction="add", arg1="eax", arg2=8, comment="eax points at a[0]") + \ + p(instruction="imul", arg1="ecx", arg2=4, comment="ecx contains the number of bytes to shift according to i") + \ + p(instruction="add", arg1="eax", arg2="ecx", comment="eax now points at a[i]") + \ + p(instruction="pop", arg1="ecx", comment="restoring ecx") + + result += "; End of calculating address for array access\n" + + return result + + def codeGen(self): + if hasattr(self, "code"): + return + self.code = "; Array access\n" + \ + self.addr + \ + p(instruction="mov", arg1="eax", arg2="[eax]", comment="eax now contains a[i]") +\ + "; End of array access\n" + + ################################################################################### # arrayCreationExpr # arrayCreationExpr NEW primitiveType LSQRBRACK expr RSQRBRACK # arrayCreationExpr NEW name LSQRBRACK expr RSQRBRACK -# arrayCreationExpr NEW primitiveType LSQRBRACK RSQRBRACK -# arrayCreationExpr NEW name LSQRBRACK RSQRBRACK class ArrayCreateNode(ASTNode): # always list all fields in the init method to show the class structure def __init__(self, parseTree, typeName): @@ -203,6 +242,41 @@ class ArrayCreateNode(ASTNode): self.myType = TypeStruct(self.arrayType.myType.name, self.arrayType.myType.typePointer) self.myType.isArray = True + def codeGen(self): + if hasattr(self, "code"): + return + self.code = "; Creating an array\n" + + # 1. Allocating space for the array in heap + # Note: uses ecx to temporarily store the array length + if not hasattr(self.arraySize, "code"): + self.arraySize.codeGen() + self.code += "; Evaluating array length\n" + \ + self.arraySize.code + \ + " ; End of evaluating array length\n" + \ + p(instruction="push", arg1="ecx", comment="saving ecx's value") + \ + p(instruction="mov", arg1="ecx", arg2="eax", comment="ecx now stroes the array's length") + \ + p(instruction="add", arg1="eax", arg2=2, comment="number of items to allocate on heap") + \ + p(instruction="imul", arg1="eax", arg2=4, comment="number of bytes to allocate on heap") + \ + p(instruction="call", arg1="__malloc", comment="allocating memory for array on heap") + + # 2. Pointing first item to vtable + aLabel = "A_" + if self.arrayType.myType.isPrimitive: + aLabel += self.arrayType.myType.name + else: + aLabel += self.arrayType.myType.typePointer.name + + self.code += p(instruction="extern", arg1=aLabel) + \ + p(instruction="mov", arg1="[eax]", arg2="dword "+aLabel, comment="first item is vtable pointer") + + # 3. Storing length in the second slot + self.code += p(instruction="mov", arg1="[eax+4]", arg2="ecx", comment="storing array length in second slot") + + # 4. Restoring ecx + self.code += p(instruction="pop", arg1="ecx", comment="restoring register ecx") + self.code += ";End of array creation\n" + ################################################################################### # assignment leftHandSide ASSIGN expr class AssignNode(ASTNode): diff --git a/Tests/A5/J1_02_Array_Creation.java b/Tests/A5/J1_02_Array_Creation.java new file mode 100644 index 0000000000000000000000000000000000000000..ebe3645284308d4536858bfd6f1db7baa741bb08 --- /dev/null +++ b/Tests/A5/J1_02_Array_Creation.java @@ -0,0 +1,7 @@ +public class J1_02_Array_Creation { + public J1_02_Array_Creation(){} + public static void test(){ + int[] array = new int[10]; + return; + } +} \ No newline at end of file