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

Merge branch 'master' into 'subtype-test'

# Conflicts:
#   AstBuilding.py
parents b66154a4 33e66800
No related branches found
No related tags found
2 merge requests!22Subtype test,!20Master
......@@ -28,6 +28,8 @@ def buildEnvAndLink(ASTs):
# print('\n\n\n', t[0])
# print("###################### Comp Unit Env ####################")
# t[1].recurseAction("printEnv")
# if t[0] == "./Tests/A5/J1_02_Array_Length.java":
# t[1].printTree()
# type Linking
......@@ -57,18 +59,62 @@ 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="dword I_SIT_spot_"+t+ "_array") + \
p(instruction="extern", arg1="I_SIT_Object") + \
p(instruction="mov", arg1="[eax]", arg2="dword 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="dword V_"+t+"_"+m+"_array") + \
p(instruction="mov", arg1="[eax]", arg2="dword "+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 = []
types = ['boolean', 'byte', 'char', 'int', 'short'] # All possible types
for t in ASTs:
classInterNode = t[1].typeDcl
types.append(classInterNode)
if classInterNode.__class__.__name__ == "ClassNode":
classInterNode.populateSizeAndFieldOffset()
types.append(classInterNode.name)
else: # interfaceNode, get their methods to prep for SIT
interM += classInterNode.methods
......@@ -88,10 +134,17 @@ def codeGenPrep(ASTs):
classInterNode.SITsize = len(interM)
classInterNode.subTypeSize = len(types)
return arrayClassMemory(types)
def codeGen(ASTs, output="output"):
codeGenPrep(ASTs)
ASTs = ASTs[:1] # TOREMOVE: don't compile stdlib for now
# rASTs = []
# for index,t in enumerate(ASTs):
# if index == 0 or t[0] == "stdlib/5.0/java/lang/Object.java":
# rASTs.append(t)
# ASTs = rASTs
arrayClassMemory = codeGenPrep(ASTs)
for t in ASTs:
t[1].codeGen()
# Outputting the generated code into className.s
......@@ -115,13 +168,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]
......@@ -132,16 +185,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") \
......
......@@ -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"
......@@ -134,6 +138,18 @@ def genericHelperFunctions():
p(instruction="cmp", arg1="eax", arg2="[G__Zero]") + \
p(instruction="jle", arg1="H__Throw_Exception") + \
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
......
......@@ -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):
......@@ -732,10 +806,13 @@ class FieldAccessNode(ASTNode):
self.env = None
self.children = []
self.typeName = typeName # the type (class/interface) this node belongs under
self.isLength = False
if not compid:
# input: fieldAccess primary PERIOD ID
self.primary = makeNodeFromAllPrimary(parseTree.children[0], typeName)
self.ID = NameNode(parseTree.children[2], False, typeName)
if self.ID.name == "length":
self.isLength = True
self.children.append(self.primary)
else:
# input: COMPID
......@@ -783,7 +860,10 @@ class FieldAccessNode(ASTNode):
# At this point, eax stores the address of the object
result += p(instruction="call", arg1="H__Null_Check", comment="calling null check function")
# 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")
if self.isLength:
result += p(instruction="add", arg1="eax", arg2=4, comment="calculating pointer to length")
else:
result += p(instruction="add", arg1="eax", arg2=self.ID.prefixLink.offset, comment="calculating pointer to the field")
result += "; End of calculating address for non-static field\n"
return result
......
......@@ -239,7 +239,9 @@ class NameNode(ASTNode):
if curType.myType and curType.myType.isArray and self.IDs[0] == 'length':
self.myType = TypeStruct("int", None)
# TODO: handle length at nameNode
cNameNode = genNameNode(self.typeName)
cNameNode.isLength = True
self.prefixNodes.append(cNameNode)
return
else:
if curType.__class__.__name__ in ['ParamNode', 'VarDclNode']:
......
public class J1_02_Array_Creation {
public int i = 5;
public J1_02_Array_Creation(){}
public static int test(){
J1_02_Array_Creation[] array = new J1_02_Array_Creation[10];
array[0] = new J1_02_Array_Creation();
array[9] = new J1_02_Array_Creation();
return array[0].i;
}
}
\ No newline at end of file
public class J1_02_Array_Length {
public J1_02_Array_Length(){}
public static int test(){
J1_02_Array_Length[] array = new J1_02_Array_Length[10];
return array.length;
}
}
\ No newline at end of file
public class J1_02_Array_Length_Primary {
public int[] arr = new int[10];
public J1_02_Array_Length_Primary(){}
public static int test(){
J1_02_Array_Length_Primary o = new J1_02_Array_Length_Primary();
return o.arr.length;
}
}
\ No newline at end of file
......@@ -4,7 +4,7 @@ class genNameNode():
def __init__(self, typeName):
self.isThis = False
self.isStatic = False
# self.isLength = False
self.isLength = False
self.nodeLink = None
self.typeName = typeName # which type this node resides in
self.code = ""
......@@ -13,6 +13,12 @@ class genNameNode():
def codeGen(self):
if self.isThis:
self.code = p("mov", "eax", "[ebp + 8]")
elif self.isLength:
# object will already be in eax
# Null check
self.code += p("call", "H__Null_Check")
self.code += p("add", "eax", 4)
self.code += p("mov", "eax", "[eax]")
elif self.nodeLink.__class__.__name__ == "VarDclNode":
self.code = p("mov", "eax", "[ebp - " + str(self.nodeLink.offset) + "]")
elif self.nodeLink.__class__.__name__ == "ParamNode":
......@@ -36,6 +42,10 @@ class genNameNode():
if self.isThis:
result = p("mov", "eax", "ebp")
result += p("add", "eax", "8")
# Object will already be in eax
elif self.isLength:
result += p("call", "H__Null_Check")
result += p("add", "eax", 4)
elif self.nodeLink.__class__.__name__ == "VarDclNode":
result = p("mov", "eax", "ebp")
result += p("sub", "eax", str(self.nodeLink.offset))
......
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