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