Skip to content
Snippets Groups Projects
Commit 670a7643 authored by Xun Yang's avatar Xun Yang
Browse files

Merge branch 'CodeGenField' into 'insta-field'

merge Code gen field

See merge request !13
parents 98330d70 9271c23b
No related branches found
No related tags found
2 merge requests!14Insta field,!13merge Code gen field
from CompNode import CompNode from CompNode import CompNode
from pprint import pprint from pprint import pprint
from Environment import GlobalEnv 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) # tree: (filename, parseTree)
def astBuild(trees): def astBuild(trees):
...@@ -79,28 +79,46 @@ def codeGen(ASTs, output="output"): ...@@ -79,28 +79,46 @@ def codeGen(ASTs, output="output"):
if classInterNode and classInterNode.__class__.__name__ == "ClassNode": if classInterNode and classInterNode.__class__.__name__ == "ClassNode":
fileName = output + "/" + classInterNode.name + ".s" fileName = output + "/" + classInterNode.name + ".s"
f = open(fileName, "w") f = open(fileName, "w")
f.write("section .data\n")
f.write(classInterNode.data)
f.write("section .text\n")
if not flagGlobalHelper: if not flagGlobalHelper:
f.write(genGlobalImport(True)) f.write(globalImport(True))
f.write(genHelperFunctions()) f.write(genericHelperFunctions())
flagGlobalHelper = True flagGlobalHelper = True
else: else:
f.write(genGlobalImport()) f.write(globalImport())
f.write(classInterNode.code) f.write(classInterNode.code)
f.close() f.close()
# ASTs[0][1].codeGen() # 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 # reset lables for running multiple testCases
used_labels = set() used_labels = set()
local_labels = 0 local_labels = 0
def startGen(ast, output): def startGen(ASTs, output):
# Test method lable
ast = ASTs[0][1]
className = ast.typeDcl.name className = ast.typeDcl.name
method_label = "M_" + className + "_test_" 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") f = open( output + "/RunTest.s","w")
result = " global _start\n_start:\n" \ result = " global _start\n_start:\n" \
+ callInit \
+ p("extern", method_label, None, None) \ + p("extern", method_label, None, None) \
+ p("call", method_label, None, None) \ + p("call", method_label, None, None) \
+ p("mov", "ebx", "eax", " move eax to exit code") \ + p("mov", "ebx", "eax", " move eax to exit code") \
......
...@@ -95,7 +95,8 @@ def iffalse(cond, label): ...@@ -95,7 +95,8 @@ def iffalse(cond, label):
return result return result
def genHelperFunctions(): # Generates generic (not specific to class) helper functions
def genericHelperFunctions():
code = "" code = ""
# The Zero constant # The Zero constant
...@@ -110,15 +111,18 @@ def genHelperFunctions(): ...@@ -110,15 +111,18 @@ def genHelperFunctions():
# Helper function to perform a null check # 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 (?) # 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") + \ code += pLabel(name="_Null_Check", type="helper", comment="helper function for null check") + \
p(instruction="mov", arg1="ecx", arg2="[G__Zero]") + \ p(instruction="push", arg1="ebx", comment="saving ebx") + \
p(instruction="cmp", arg1="eax", arg2="ecx") + \ p(instruction="mov", arg1="ebx", arg2="[G__Zero]") + \
p(instruction="cmp", arg1="eax", arg2="ebx") + \
p(instruction="jle", arg1="H__Throw_Exception") + \ 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 return code
# Generates code to import helper functions and constants # Generates code to import helper generic functions and global constants
def genGlobalImport(genGlobalFunction=False): def globalImport(genGlobalFunction=False):
code = "; Importing helper functions and constants\n" + \ code = "; Importing helper functions and constants\n" + \
p(instruction="extern", arg1="__malloc") + \ p(instruction="extern", arg1="__malloc") + \
p(instruction="extern", arg1="__exception") p(instruction="extern", arg1="__exception")
...@@ -131,12 +135,18 @@ def genGlobalImport(genGlobalFunction=False): ...@@ -131,12 +135,18 @@ def genGlobalImport(genGlobalFunction=False):
code += "; End of importing helper functions and constants\n" code += "; End of importing helper functions and constants\n"
return code 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): def importHelper(targetClass, ownClass, labelName):
if targetClass != ownClass: if targetClass != ownClass:
return p(instruction="extern", arg1=labelName, comment="importing label") return p(instruction="extern", arg1=labelName, comment="importing label")
return "" 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(): class codeSectionUtil():
......
...@@ -368,7 +368,7 @@ class ClassCreateNode(ASTNode): ...@@ -368,7 +368,7 @@ class ClassCreateNode(ASTNode):
self.code += importHelper(classDef.name, self.typeName, "C_"+classDef.name) 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") 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 += "; Calling constructor for object\n"
self.code += p(instruction="push", arg1="eax", comment="pushing object as first argument") self.code += p(instruction="push", arg1="eax", comment="pushing object as first argument")
# Evaluate arguments and pushing parameters # Evaluate arguments and pushing parameters
...@@ -379,7 +379,7 @@ class ClassCreateNode(ASTNode): ...@@ -379,7 +379,7 @@ class ClassCreateNode(ASTNode):
self.code += importHelper(classDef.name, self.typeName, label) self.code += importHelper(classDef.name, self.typeName, label)
self.code += p(instruction="call", arg1=label, comment="Calling constructor") 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") + \ 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") p(instruction="pop", arg1="eax", comment="eax now contains pointer to newly created object")
self.code += ";End of object creation\n" self.code += ";End of object creation\n"
...@@ -680,28 +680,30 @@ class FieldAccessNode(ASTNode): ...@@ -680,28 +680,30 @@ class FieldAccessNode(ASTNode):
# result stored in eax (address) # result stored in eax (address)
# NOTE: this is always called by codeGen, so self.code is already intialized to "" # NOTE: this is always called by codeGen, so self.code is already intialized to ""
def addr(self): def addr(self):
result = "" result = ""
fieldNode = self.ID.prefixLink fieldNode = self.ID.prefixLink
if fieldNode.__class__.__name__ == "VarDclNode":
if "static" in fieldNode.mods: fieldNode = self.ID.staticField
label = fieldNode.typeName + "_" + fieldNode.name
result += "; Start of calculating address for static field: " + label + "\n" + \ if "static" in fieldNode.mods:
importHelper(fieldNode.typeName, self.typeName, "S_"+label) + \ label = fieldNode.typeName + "_" + fieldNode.name
p(instruction="mov", arg1="eax", arg2="dword S_"+label, comment="getting address to static field") + \ result += "; Start of calculating address for static field: " + label + "\n" + \
"; End of field access\n" importHelper(fieldNode.typeName, self.typeName, "S_"+label) + \
p(instruction="mov", arg1="eax", arg2="dword S_"+label, comment="getting address to static field") + \
else: "; End of field access\n"
result += "; Start of calculating address for non-static field\n"
self.primary.codeGen() else:
result += self.primary.code result += "; Start of calculating address for non-static field\n"
# Null check self.primary.codeGen()
# At this point, eax stores the address of the object result += self.primary.code
result += p(instruction="call", arg1="H__Null_Check", comment="calling null check function") # Null check
# Make eax store the address to the field we're accessing # At this point, eax stores the address of the object
result += p(instruction="add", arg1="eax", arg2=self.ID.prefixLink.offset, comment="calculating pointer to the field") result += p(instruction="call", arg1="H__Null_Check", comment="calling null check function")
result += "; End of calculating address for non-static field\n" # Make eax store the address to the field we're accessing
result += p(instruction="add", arg1="eax", arg2=self.ID.prefixLink.offset, comment="calculating pointer to the field")
return result result += "; End of calculating address for non-static field\n"
return result
def codeGen(self): def codeGen(self):
...@@ -828,7 +830,7 @@ class MethodInvNode(ASTNode): ...@@ -828,7 +830,7 @@ class MethodInvNode(ASTNode):
if self.args: if self.args:
toPop = len(self.args.exprs) toPop = len(self.args.exprs)
self.code += p(instruction="add", arg1="esp", arg2=toPop, comment="popping off all arguments off stack") self.code += p(instruction="add", arg1="esp", arg2=toPop*4, comment="popping off all arguments off stack")
# Epilogue # Epilogue
self.code += epi self.code += epi
......
...@@ -60,19 +60,22 @@ class FieldNode(ASTNode): ...@@ -60,19 +60,22 @@ class FieldNode(ASTNode):
if hasattr(self, "code"): if hasattr(self, "code"):
return return
self.code = "" self.code = ""
self.data = ""
label = self.typeName + "_" + self.name label = self.typeName + "_" + self.name
# static fields: the pointer lives in assembly # static fields: the pointer lives in assembly
if "static" in self.mods: if "static" in self.mods:
self.code += ";Declaring a static field: " + label + "\n" self.data += ";Declaring a static field: " + label + "\n"
self.code += pLabel(name=label, type="static") + \ self.data += pLabel(name=label, type="static") + \
p(instruction="dd", arg1="64", comment="Declaring space on assembly for a static field") 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 # Initializing static fields
# static fields are intialized in the order of declaration within the class and has to be intialized # static fields are intialized in the order of declaration within the class and has to be intialized
# before the test() method is being called # before the test() method is being called
initNode = self.variableDcl.variableInit initNode = self.variableDcl.variableInit
if initNode: if initNode:
self.code += ";Start of initialization of static field\n"
initNode.codeGen() initNode.codeGen()
self.code += "; Calculating the initial value of declared field: " + label + "\n" self.code += "; Calculating the initial value of declared field: " + label + "\n"
...@@ -81,8 +84,8 @@ class FieldNode(ASTNode): ...@@ -81,8 +84,8 @@ class FieldNode(ASTNode):
self.code += p(instruction="mov", arg1="ebx", arg2="dword S_"+label) + \ 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") 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"
########################################################### ###########################################################
......
...@@ -36,6 +36,7 @@ class NameNode(ASTNode): ...@@ -36,6 +36,7 @@ class NameNode(ASTNode):
self.myType = None # will become TypeStruct to tell us what the whole is/returns self.myType = None # will become TypeStruct to tell us what the whole is/returns
self.shouldBeStatic = False self.shouldBeStatic = False
self.pointToThis = False self.pointToThis = False
self.staticField = None
self.name = getParseTreeNodes(["ID", "COMPID"], parseTree)[0].lex self.name = getParseTreeNodes(["ID", "COMPID"], parseTree)[0].lex
...@@ -130,7 +131,7 @@ class NameNode(ASTNode): ...@@ -130,7 +131,7 @@ class NameNode(ASTNode):
typeFieldNode = typeNode.env.getNode(staticFieldName, "fieldDcl") typeFieldNode = typeNode.env.getNode(staticFieldName, "fieldDcl")
if "static" in typeFieldNode.mods: if "static" in typeFieldNode.mods:
self.prefixLink = typeFieldNode.variableDcl self.prefixLink = typeFieldNode.variableDcl
self.staticField = typeFieldNode
# if it is primitive, then we leave it as a VarDclNode # if it is primitive, then we leave it as a VarDclNode
if not self.prefixLink.dclType.myType.isPrimitive: if not self.prefixLink.dclType.myType.isPrimitive:
self.prefixLink = self.prefixLink.dclType.myType.typePointer self.prefixLink = self.prefixLink.dclType.myType.typePointer
......
public class J1_00_Field_Basic_Empty {
public J1_00_Field_Basic_Empty(){}
public static void test(){}
}
\ No newline at end of file
...@@ -3,7 +3,11 @@ public class J1_00_Field_Basic_Static_Fields { ...@@ -3,7 +3,11 @@ public class J1_00_Field_Basic_Static_Fields {
public static int f2; public static int f2;
public static int f3 = 4; public static int f3 = 4;
public J1_00_Field_Basic_Static_Fields(){} 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; return J1_00_Field_Basic_Static_Fields.f3;
} }
} }
\ No newline at end of file
...@@ -3,12 +3,12 @@ public class J1_01_basicTest { ...@@ -3,12 +3,12 @@ public class J1_01_basicTest {
public J1_01_basicTest() {} public J1_01_basicTest() {}
public static int test() { public static int test() {
return J1_01_basicTest.test2(); return J1_01_basicTest.test2(4,5);
} }
public static int test2(){ public static int test2(int i, int j){
if (true) if (true)
return 123; return i;
return 7; return j;
} }
} }
public class J1_0X_Field_Basic_Empty {
public J1_0X_Field_Basic_Empty(){}
public static void test(){}
}
\ No newline at end of file
...@@ -305,13 +305,15 @@ class ClassNode(ClassInterNode): ...@@ -305,13 +305,15 @@ class ClassNode(ClassInterNode):
return return
self.code = "" self.code = "" # For read-only section
self.data = "" # For writeable data section
# print("This is the super class: {}".format(self.superClass)) # print("This is the super class: {}".format(self.superClass))
# Generate class label # Generate class label
self.label = pLabel(name=self.name, type="class") self.label = pLabel(name=self.name, type="class")
self.code += ";START OF CLASS MEMORY LAYOUT FOR CLASS: " + self.canonName + "\n" self.data += ";START OF CLASS MEMORY LAYOUT FOR CLASS: " + self.canonName + "\n"
self.code += self.label self.data += self.label
# TODO: SIT and subtype testing tables # TODO: SIT and subtype testing tables
...@@ -329,8 +331,8 @@ class ClassNode(ClassInterNode): ...@@ -329,8 +331,8 @@ class ClassNode(ClassInterNode):
# Iterating through method offset table sorted by offset # Iterating through method offset table sorted by offset
for key,value in sorted(self.superClass.methodOffset.items(), key=lambda item: item[1]): for key,value in sorted(self.superClass.methodOffset.items(), key=lambda item: item[1]):
self.methodOffset[key] = value self.methodOffset[key] = value
self.code += pLabel(name=self.name + "_" + key[0] + "_" + key[1], type="vtable") self.data += 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 += p(instruction="dd", arg1=64) # just declaring a memory segment with a random number
lastMethodOffset = max(value, lastMethodOffset) lastMethodOffset = max(value, lastMethodOffset)
...@@ -339,8 +341,8 @@ class ClassNode(ClassInterNode): ...@@ -339,8 +341,8 @@ class ClassNode(ClassInterNode):
lastMethodOffset += 4 lastMethodOffset += 4
self.methodOffset[(method.name, method.paramTypes)] = lastMethodOffset self.methodOffset[(method.name, method.paramTypes)] = lastMethodOffset
method.offset = lastMethodOffset method.offset = lastMethodOffset
self.code += pLabel(name=self.name + "_" + method.name + "_" + method.paramTypes, type="vtable") self.data += 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 += 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 # 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 # Also simultaneosly creating a dictionary of methods for easier lookup
...@@ -351,10 +353,10 @@ class ClassNode(ClassInterNode): ...@@ -351,10 +353,10 @@ class ClassNode(ClassInterNode):
lastMethodOffset += 4 lastMethodOffset += 4
method.methodOffset = lastMethodOffset method.methodOffset = lastMethodOffset
self.methodOffset[(method.name, method.paramTypes)] = lastMethodOffset self.methodOffset[(method.name, method.paramTypes)] = lastMethodOffset
self.code += pLabel(name=self.name + "_" + method.name + "_" + method.paramTypes, type="vtable") self.data += 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 += p(instruction="dd", arg1=64) # just declaring a memory segment with a random number
# Adding inherited method to the methodDict # Adding inherited method to the methodDict
for i in self.inherits: for i in self.inherits:
if isinstance(i, MethodNode): if isinstance(i, MethodNode):
key = (i.name, i.paramTypes) key = (i.name, i.paramTypes)
...@@ -362,11 +364,12 @@ class ClassNode(ClassInterNode): ...@@ -362,11 +364,12 @@ class ClassNode(ClassInterNode):
methodDict[(i.name, i.paramTypes)] = i methodDict[(i.name, i.paramTypes)] = i
# print(self.methodOffset) # 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 # 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(): for key,value in self.methodOffset.items():
vLabel = "V_" + self.name + "_" + key[0] + "_" + key[1]+"" # method at class's vtable vLabel = "V_" + self.name + "_" + key[0] + "_" + key[1]+"" # method at class's vtable
...@@ -382,7 +385,8 @@ class ClassNode(ClassInterNode): ...@@ -382,7 +385,8 @@ class ClassNode(ClassInterNode):
self.code += p(instruction="extern", arg1=mLabel, comment="importing method implementation label") 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=vLabel, comment="Filling in class memory segment for method " + mLabel)
self.code += p(instruction="mov", arg1="[eax]", arg2="dword " + 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.name)
# print(self.fieldOffset) # print(self.fieldOffset)
...@@ -391,7 +395,28 @@ class ClassNode(ClassInterNode): ...@@ -391,7 +395,28 @@ 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.fields + self.methods: for c in self.fields + self.methods:
c.codeGen() c.codeGen()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment