From 9b88df6fa776a8ef6ce3331fded538c353fbd779 Mon Sep 17 00:00:00 2001 From: pycsham <shampuiyanchloe@gmail.com> Date: Thu, 9 Apr 2020 21:52:02 -0400 Subject: [PATCH] Basic cases for static method invoke and static field access now works --- AstBuilding.py | 30 ++++++++--- CodeGenUtils.py | 24 ++++++--- ExprPrimaryNodes.py | 8 +-- MemberNodes.py | 11 ++-- NameNode.py | 3 +- Tests/A5/J1_00_Field_Basic_Empty.java | 4 ++ Tests/A5/J1_00_Field_Basic_Static_Fields.java | 6 ++- Tests/A5/J1_0X_Field_Basic_Empty.java | 4 -- TypeNodes.py | 53 ++++++++++++++----- 9 files changed, 102 insertions(+), 41 deletions(-) create mode 100644 Tests/A5/J1_00_Field_Basic_Empty.java delete mode 100644 Tests/A5/J1_0X_Field_Basic_Empty.java diff --git a/AstBuilding.py b/AstBuilding.py index f31e27b..c7b6dcd 100644 --- a/AstBuilding.py +++ b/AstBuilding.py @@ -1,7 +1,7 @@ from CompNode import CompNode from pprint import pprint from Environment import GlobalEnv -from CodeGenUtils import p, genProcedure, used_labels, local_labels, pLabel, genHelperFunctions, genGlobalImport +from CodeGenUtils import p, genProcedure, used_labels, local_labels, pLabel, genericHelperFunctions, globalImport # tree: (filename, parseTree) def astBuild(trees): @@ -79,28 +79,46 @@ def codeGen(ASTs, output="output"): if classInterNode and classInterNode.__class__.__name__ == "ClassNode": fileName = output + "/" + classInterNode.name + ".s" f = open(fileName, "w") + f.write("section .data\n") + f.write(classInterNode.data) + f.write("section .text\n") if not flagGlobalHelper: - f.write(genGlobalImport(True)) - f.write(genHelperFunctions()) + f.write(globalImport(True)) + f.write(genericHelperFunctions()) flagGlobalHelper = True else: - f.write(genGlobalImport()) + f.write(globalImport()) f.write(classInterNode.code) f.close() # ASTs[0][1].codeGen() - startGen(ASTs[0][1], output) # pass in the first AST that contains the test method + startGen(ASTs, output) # pass in the first AST that contains the test method # reset lables for running multiple testCases used_labels = set() local_labels = 0 -def startGen(ast, output): +def startGen(ASTs, output): + + # Test method lable + ast = ASTs[0][1] className = ast.typeDcl.name method_label = "M_" + className + "_test_" + + callInit = "; Start of calling each class's classAndStaticFieldInit \n" + for t in ASTs: + classInterNode = t[1].typeDcl + if classInterNode and classInterNode.__class__.__name__ == "ClassNode": + label = "H_" + classInterNode.name + "_" + "classAndStaticFieldInit \n" + callInit += p(instruction="extern", arg1=label) + \ + p(instruction="call", arg1=label) + callInit += "; End of calling each class's classAndStaticFieldInit \n" + + f = open( output + "/RunTest.s","w") result = " global _start\n_start:\n" \ + + callInit \ + 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 da0e5af..0b986e5 100644 --- a/CodeGenUtils.py +++ b/CodeGenUtils.py @@ -95,7 +95,8 @@ def iffalse(cond, label): return result -def genHelperFunctions(): +# Generates generic (not specific to class) helper functions +def genericHelperFunctions(): code = "" # The Zero constant @@ -110,15 +111,18 @@ def genHelperFunctions(): # Helper function to perform a null check # Note: using jle instead of calling the function since we don't need to preserve eip upon calling the exception function (?) + # saving and restoring ebx, a callee-save register code += pLabel(name="_Null_Check", type="helper", comment="helper function for null check") + \ - p(instruction="mov", arg1="ecx", arg2="[G__Zero]") + \ - p(instruction="cmp", arg1="eax", arg2="ecx") + \ + p(instruction="push", arg1="ebx", comment="saving ebx") + \ + p(instruction="mov", arg1="ebx", arg2="[G__Zero]") + \ + p(instruction="cmp", arg1="eax", arg2="ebx") + \ p(instruction="jle", arg1="H__Throw_Exception") + \ - ";End function for null checking\n" + p(instruction="pop", arg1="ebx", comment="restoring ebx") + \ + p(instruction="ret", arg1="") return code -# Generates code to import helper functions and constants -def genGlobalImport(genGlobalFunction=False): +# Generates code to import helper generic functions and global constants +def globalImport(genGlobalFunction=False): code = "; Importing helper functions and constants\n" + \ p(instruction="extern", arg1="__malloc") + \ p(instruction="extern", arg1="__exception") @@ -131,12 +135,18 @@ def genGlobalImport(genGlobalFunction=False): code += "; End of importing helper functions and constants\n" return code -# Helper function for importation of label +# Helper function for importation of label (only import if it's not already inside the same .s file) def importHelper(targetClass, ownClass, labelName): if targetClass != ownClass: return p(instruction="extern", arg1=labelName, comment="importing label") return "" +# Helper function for allocating space on the heap +def heapAllocate(size): + code = p(instruction="mov", arg1="eax", arg2=size, comment="size of field in bytes") + \ + p(instruction="call", arg1="__malloc", comment="allocating space on heap for the field") + return code + #################################################### class codeSectionUtil(): diff --git a/ExprPrimaryNodes.py b/ExprPrimaryNodes.py index 4cf2e64..f175856 100644 --- a/ExprPrimaryNodes.py +++ b/ExprPrimaryNodes.py @@ -368,7 +368,7 @@ class ClassCreateNode(ASTNode): self.code += importHelper(classDef.name, self.typeName, "C_"+classDef.name) self.code += p(instruction="mov", arg1="[eax]", arg2="[C_"+classDef.name+"]", comment="first item is vtable pointer") - # 4. Calling constructor + # 3. Calling constructor self.code += "; Calling constructor for object\n" self.code += p(instruction="push", arg1="eax", comment="pushing object as first argument") # Evaluate arguments and pushing parameters @@ -380,7 +380,7 @@ class ClassCreateNode(ASTNode): self.code += importHelper(classDef.name, self.typeName, label) self.code += p(instruction="call", arg1=label, comment="Calling constructor") - # 5. Popping parameters and pointer to object + # 4. Popping parameters and pointer to object self.code += p(instruction="add", arg1="esp", arg2=len(self.args.exprs)*4, comment="Popping parameters") + \ p(instruction="pop", arg1="eax", comment="eax now contains pointer to newly created object") self.code += ";End of object creation\n" @@ -683,10 +683,10 @@ class FieldAccessNode(ASTNode): def addr(self): result = "" fieldNode = self.ID.prefixLink + if fieldNode.__class__.__name__ == "VarDclNode": + fieldNode = self.ID.staticField if "static" in fieldNode.mods: - if fieldNode.__class__.__name__ == "VarDclNode": - fieldNode = self.ID.staticField label = fieldNode.typeName + "_" + fieldNode.name result += "; Start of calculating address for static field: " + label + "\n" + \ importHelper(fieldNode.typeName, self.typeName, "S_"+label) + \ diff --git a/MemberNodes.py b/MemberNodes.py index 928a38b..dfeed75 100644 --- a/MemberNodes.py +++ b/MemberNodes.py @@ -60,19 +60,22 @@ class FieldNode(ASTNode): if hasattr(self, "code"): return self.code = "" + self.data = "" label = self.typeName + "_" + self.name # static fields: the pointer lives in assembly if "static" in self.mods: - self.code += ";Declaring a static field: " + label + "\n" - self.code += pLabel(name=label, type="static") + \ - p(instruction="dd", arg1="64", comment="Declaring space on assembly for a static field") + self.data += ";Declaring a static field: " + label + "\n" + self.data += pLabel(name=label, type="static") + \ + p(instruction="dd", arg1=0, comment="Declaring space on assembly for a static field") + self.data += ";End of declaration of static field\n" # Initializing static fields # static fields are intialized in the order of declaration within the class and has to be intialized # before the test() method is being called initNode = self.variableDcl.variableInit if initNode: + self.code += ";Start of initialization of static field\n" initNode.codeGen() self.code += "; Calculating the initial value of declared field: " + label + "\n" @@ -81,7 +84,7 @@ class FieldNode(ASTNode): self.code += p(instruction="mov", arg1="ebx", arg2="dword S_"+label) + \ p(instruction="mov", arg1="[ebx]", arg2="eax", comment="eax is a pointer to field value in heap") - self.code += ";End of declaration of static field\n" + self.code += ";End of initialization of static field\n" ########################################################### diff --git a/NameNode.py b/NameNode.py index 62acb8e..b413c69 100644 --- a/NameNode.py +++ b/NameNode.py @@ -36,6 +36,7 @@ class NameNode(ASTNode): self.myType = None # will become TypeStruct to tell us what the whole is/returns self.shouldBeStatic = False self.pointToThis = False + self.staticField = None self.name = getParseTreeNodes(["ID", "COMPID"], parseTree)[0].lex @@ -130,7 +131,7 @@ class NameNode(ASTNode): typeFieldNode = typeNode.env.getNode(staticFieldName, "fieldDcl") if "static" in typeFieldNode.mods: self.prefixLink = typeFieldNode.variableDcl - + self.staticField = typeFieldNode # if it is primitive, then we leave it as a VarDclNode if not self.prefixLink.dclType.myType.isPrimitive: self.prefixLink = self.prefixLink.dclType.myType.typePointer diff --git a/Tests/A5/J1_00_Field_Basic_Empty.java b/Tests/A5/J1_00_Field_Basic_Empty.java new file mode 100644 index 0000000..204244c --- /dev/null +++ b/Tests/A5/J1_00_Field_Basic_Empty.java @@ -0,0 +1,4 @@ +public class J1_00_Field_Basic_Empty { + public J1_00_Field_Basic_Empty(){} + public static void test(){} +} \ No newline at end of file diff --git a/Tests/A5/J1_00_Field_Basic_Static_Fields.java b/Tests/A5/J1_00_Field_Basic_Static_Fields.java index 6e353aa..9982649 100644 --- a/Tests/A5/J1_00_Field_Basic_Static_Fields.java +++ b/Tests/A5/J1_00_Field_Basic_Static_Fields.java @@ -3,7 +3,11 @@ public class J1_00_Field_Basic_Static_Fields { public static int f2; public static int f3 = 4; public J1_00_Field_Basic_Static_Fields(){} - public int test(){ + public static int test() { + return J1_00_Field_Basic_Static_Fields.test2(); + } + + public static int test2(){ return J1_00_Field_Basic_Static_Fields.f3; } } \ No newline at end of file diff --git a/Tests/A5/J1_0X_Field_Basic_Empty.java b/Tests/A5/J1_0X_Field_Basic_Empty.java deleted file mode 100644 index dcc9b9c..0000000 --- a/Tests/A5/J1_0X_Field_Basic_Empty.java +++ /dev/null @@ -1,4 +0,0 @@ -public class J1_0X_Field_Basic_Empty { - public J1_0X_Field_Basic_Empty(){} - public static void test(){} -} \ No newline at end of file diff --git a/TypeNodes.py b/TypeNodes.py index 241d4a8..860ca7a 100644 --- a/TypeNodes.py +++ b/TypeNodes.py @@ -304,13 +304,15 @@ class ClassNode(ClassInterNode): return - self.code = "" + self.code = "" # For read-only section + self.data = "" # For writeable data section # print("This is the super class: {}".format(self.superClass)) # Generate class label self.label = pLabel(name=self.name, type="class") - self.code += ";START OF CLASS MEMORY LAYOUT FOR CLASS: " + self.canonName + "\n" - self.code += self.label + self.data += ";START OF CLASS MEMORY LAYOUT FOR CLASS: " + self.canonName + "\n" + self.data += self.label + # TODO: SIT and subtype testing tables @@ -328,8 +330,8 @@ class ClassNode(ClassInterNode): # Iterating through method offset table sorted by offset for key,value in sorted(self.superClass.methodOffset.items(), key=lambda item: item[1]): self.methodOffset[key] = value - self.code += pLabel(name=self.name + "_" + key[0] + "_" + key[1], type="vtable") - self.code += p(instruction="dd", arg1=64) # just declaring a memory segment with a random number + self.data += pLabel(name=self.name + "_" + key[0] + "_" + key[1], type="vtable") + self.data += p(instruction="dd", arg1=64) # just declaring a memory segment with a random number lastMethodOffset = max(value, lastMethodOffset) @@ -338,8 +340,8 @@ class ClassNode(ClassInterNode): lastMethodOffset += 4 self.methodOffset[(method.name, method.paramTypes)] = lastMethodOffset method.offset = lastMethodOffset - self.code += pLabel(name=self.name + "_" + method.name + "_" + method.paramTypes, type="vtable") - self.code += p(instruction="dd", arg1=64) # just declaring a memory segment with a random number + self.data += pLabel(name=self.name + "_" + method.name + "_" + method.paramTypes, type="vtable") + self.data += p(instruction="dd", arg1=64) # just declaring a memory segment with a random number # 3. Assigning offsets to methods that aren't in the super class, DECLARING memory segment for the methods # Also simultaneosly creating a dictionary of methods for easier lookup @@ -350,8 +352,8 @@ class ClassNode(ClassInterNode): lastMethodOffset += 4 method.methodOffset = lastMethodOffset self.methodOffset[(method.name, method.paramTypes)] = lastMethodOffset - self.code += pLabel(name=self.name + "_" + method.name + "_" + method.paramTypes, type="vtable") - self.code += p(instruction="dd", arg1=64) # just declaring a memory segment with a random number + self.data += pLabel(name=self.name + "_" + method.name + "_" + method.paramTypes, type="vtable") + self.data += p(instruction="dd", arg1=64) # just declaring a memory segment with a random number # Adding inherited method to the methodDict for i in self.inherits: @@ -361,11 +363,12 @@ class ClassNode(ClassInterNode): methodDict[(i.name, i.paramTypes)] = i # print(self.methodOffset) - self.code += ";END OF CLASS MEMORY LAYOUT FOR CLASS " + self.name + "\n" + self.data += ";END OF CLASS MEMORY LAYOUT FOR CLASS " + self.name + "\n" # 4. Fill in the memory segment declared in step 1 and 2 with the addresses of the method implementations - self.code += "; Filling in class memory layout for class " + self.name + "\n" + self.code += "; Function for filling in class memory layout for class " + self.name + "\n" + self.code += pLabel(name=self.name + "_"+ "classMemoryInit", type="helper") for key,value in self.methodOffset.items(): vLabel = "V_" + self.name + "_" + key[0] + "_" + key[1]+"" # method at class's vtable @@ -381,7 +384,8 @@ class ClassNode(ClassInterNode): self.code += p(instruction="extern", arg1=mLabel, comment="importing method implementation label") self.code += p(instruction="mov", arg1="eax", arg2=vLabel, comment="Filling in class memory segment for method " + mLabel) self.code += p(instruction="mov", arg1="[eax]", arg2="dword " + mLabel) - self.code += "; End of filling in class memory layout\n" + self.code += p(instruction="ret", arg1="") + self.code += "; End of function for filling in class memory layout\n" # print(self.name) # print(self.fieldOffset) @@ -390,13 +394,34 @@ class ClassNode(ClassInterNode): ########################################################### - + # Generating a function that allocates and initializes all static fields + # Note: 1. saving and restoring ebx, a callee-save register + # 2. static fields are intialized in the order of declaration within the class and has to be intialized + # before the test() method is being called + self.code += "; Function for filling allocating space and initializing static fields for class " + self.name + "\n" + self.code += pLabel(name=self.name + "_" + "staticFieldMemoryInit", type="helper") + self.code += p(instruction="push", arg1="ebx", comment="saving ebx") + for field in self.fields: + if not hasattr(field, "code"): + field.codeGen() + self.code += field.code + self.data += field.data + self.code += p(instruction="pop", arg1="ebx", comment="restoring ebx") + self.code += p(instruction="ret", arg1="") + self.code += "; End of function for filling allocating space and initializing static fields for class " + self.name + "\n" + + # Generating a function that calls both the class memory init and static field init functions + self.code += "; Function that calls staticFieldMemoryInit and classMemoryInit \n" + self.code += pLabel(name=self.name + "_" + "classAndStaticFieldInit", type="helper") + self.code += p(instruction="call", arg1="H_"+self.name+"_"+"classMemoryInit") + \ + p(instruction="call", arg1="H_"+self.name+"_"+ "staticFieldMemoryInit") + \ + p(instruction="ret", arg1="") for c in self.children: if c and hasattr(c, "codeGen"): if not hasattr(c, "code"): # children hasn't generated code yet c.codeGen() - self.code += c.code + self.code += c.code # don't want to repeat field code ##################################################################### -- GitLab