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

Merge branch 'array-subtype' into 'master'

Array subtype

See merge request !26
parents 636e6cbb 07de14e0
No related branches found
No related tags found
2 merge requests!26Array subtype,!20Master
......@@ -17,6 +17,8 @@ class ASTNode():
# reachability: None = not set, True = maybe, False = no
self.outMaybe = None # either None or True/False
def getConstant(self):
return None
# Do certains actions on every node of the AST tree
# call the same method in each class and its children recursively
......
from CompNode import CompNode
from pprint import pprint
from Environment import GlobalEnv
from TypeNodes import getSupers
from CodeGenUtils import p, genProcedure, used_labels, local_labels, pLabel, genericHelperFunctions, globalImport
# tree: (filename, parseTree)
......@@ -62,23 +63,38 @@ def reachabilityChecking(ASTs):
# 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 = {}
primTypes = ['boolean', 'byte', 'char', 'int', 'short'] # All possible types
for t in types:
typeDict = {}
# assignable = dict({"java.lang.Object" : 0,
# "java.lang.Cloneable" : 4,
# "java.io.Serializable" : 8
# })
for tt 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"
if tt.__class__.__name__ == "ClassNode":
t = tt.name
else:
t = tt
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)
# point to subtype table
code += pLabel("subT_spot_" + t, "inter")
code += p("dd", "42")
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
......@@ -94,6 +110,12 @@ def arrayClassMemory(types):
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")
if tt.__class__.__name__ == "ClassNode":
code += p("extern", "A_subT_" + tt.name)
code += p("mov", "eax", "I_subT_spot_" + t)
code += p("mov", "[eax]", "dword A_subT_" + tt.name)
code += p(instruction="ret", arg1="")
code += "; End of function to initialize class memory layout\n"
if t in primTypes:
......@@ -113,21 +135,23 @@ def codeGenPrep(ASTs):
interM = []
types = ['boolean', 'byte', 'char', 'int', 'short'] # All possible types
classNodes = []
j = 0
for t in ASTs:
classInterNode = t[1].typeDcl
if classInterNode.__class__.__name__ == "ClassNode":
types.append(classInterNode.name)
types.append(classInterNode)
classNodes.append(classInterNode)
else: # interfaceNode, get their methods to prep for SIT
interM += classInterNode.methods
classInterNode.subTypeOffset = j * 4 # assign each type a position in the subtype testing table
j += 1
# store SIT and subtype table size
for i in range(len(classNodes)):
classNodes[i].SITsize = len(interM)
classNodes[i].subTypeSize = len(types) - 5 # no primitive types in subtype table
classNodes[i].subTypeOffset = i * 4 # assign each type a position in the subtype testing table
for c in classNodes:
c.SITsize = len(interM)
c.subTypeSize = j # no primitive types in subtype table
# prep SIT
for i in range(len(interM)):
......
......@@ -96,6 +96,7 @@ def genMethodInvoke(method):
# generates shorter code for constant value conditionals and comparison conditionals
# cond is either literalNode or ExprNode or NameNode
# cond could also be methodInvNode, arrayAccessNode or fieldAccessNode
def iffalse(cond, label):
result = ""
if cond.__class__.__name__ == "NameNode":
......
......@@ -163,6 +163,10 @@ class ArrayAccessNode(ASTNode):
if not self.index.myType.isNum():
raise Exception("ERROR: Array index must be a number.")
self.myType = TypeStruct(self.array.myType.name, self.array.myType.typePointer)
def getIfFalse(self, label):
self.codeGen()
return self.code + p("cmp", "eax", "[G__Zero]") + p("je", label)
def addr(self):
result = "; Start of calculating address for array access\n" + \
......@@ -327,6 +331,21 @@ class AssignNode(ASTNode):
self.code = self.right.code
self.code += p("push", "eax")
# array assign check
if self.left.__class__.__name__ == "ArrayAccessNode" and (not self.left.myType.isPrimitive):
self.code += "; array assign subtype check\n"
self.left.array.codeGen()
self.code += self.left.array.code
offset = self.right.myType.typePointer.subTypeOffset
self.code += p("mov", "ebx", "[eax]", "start subtype test") # access class tag of left object
self.code += p("mov", "ebx", "[ebx + 4]") # access subtype testing column
self.code += p("mov", "ebx", "[ebx + " + str(offset) + "]") # ebx has isSubtype
# exception if not subtype, else do nothing (object is already in eax)
self.code += p("cmp", "[G__Zero]", "ebx")
self.code += p("je", "H__Throw_Exception")
self.code +=("; Evaluate left of assignment\n")
self.code += self.left.addr()
......@@ -387,8 +406,9 @@ class CastNode(ASTNode):
self.code += self.right.code
# subtype test:
if not self.left.myType.isPrimitive:
# only test if right is not primitive (primitive types would be correctly static tested already)
if (not self.left.myType.isPrimitive) and self.right.myType.isArray == self.left.myType.isArray:
# only test if not primitive, both are array or both non array
# cast would've exception if array is casting to non-array and not Object
offset = self.left.myType.typePointer.subTypeOffset
self.code += p("mov", "ebx", "[eax]", "start subtype test") # access class tag of left object
self.code += p("mov", "ebx", "[ebx + 4]") # access subtype testing column
......@@ -578,8 +598,8 @@ class ExprNode(ASTNode):
self.left.codeGen()
self.code += self.left.code
# only test if non-primitive
if not self.right.myType.isPrimitive:
# only test if non-primitive, both arrays or both non arrays
if (not self.right.myType.isPrimitive) and self.right.myType.isArray == self.left.myType.isArray:
offset = self.right.myType.typePointer.subTypeOffset
self.code += p("mov", "eax", "[eax]") # access class tag of left object
self.code += p("mov", "eax", "[eax + 4]") # access subtype testing column
......@@ -856,6 +876,10 @@ class FieldAccessNode(ASTNode):
checkProtected(self.ID.prefixLink, self)
except: # where there are no mods
return
def getIfFalse(self, label):
self.codeGen()
return self.code + p("cmp", "eax", "[G__Zero]") + p("je", label)
# generates code that evaluates the address of field access
# result stored in eax (address)
......@@ -886,8 +910,7 @@ class FieldAccessNode(ASTNode):
return
fieldNode = self.ID.prefixLink
label = fieldNode.typeName + "_" + fieldNode.name
self.code = "; Accessing a field :" + label + "\n"
self.code = "; Accessing a field \n"
# Evaluating the address of the field we're trying to access
if self.primary:
self.code += self.addr()
......@@ -989,6 +1012,10 @@ class MethodInvNode(ASTNode):
self.args.codeGen()
self.code += self.args.code
def getIfFalse(self, label):
self.codeGen()
return self.code + p("cmp", "eax", "[G__Zero]") + p("je", label)
def codeGen(self):
if hasattr(self, "code"):
return
......
......@@ -19,7 +19,7 @@ class ClassInterNode(ASTNode):
self.SITsize = 0
self.subTypeSize = 0
self.subTypeOffset = 0
# sets
self.inherits = []
self.super = []
......@@ -331,7 +331,7 @@ class ClassNode(ClassInterNode):
####### ADDING METHODS TO CLASS MEMORY LAYOUT AND FIELDS TO FIELD OFFSET TABLE #########
# Copying over the offsets of methods from superclass and DECLARING memory segment for the methods
lastMethodOffset = 0 # stores the largest method offset in the superCalss
lastMethodOffset = 4 # stores the largest method offset in the superCalss
# TODO: set this to 4 after the implemntation of both the SIT and subtype testing table
# Note: This is 4 less than the offset of where the next method would be located
# This is to accomodate for the addition of 4 to lastMethodOffset in EVERY (including the first) iteration in the
......@@ -384,7 +384,7 @@ class ClassNode(ClassInterNode):
self.data += p("dd", "42")
# Layout subtype testing column
self.data += pLabel("subT_" + self.name, "inter")
self.data += pLabel("subT_" + self.name, "array")
for i in range(self.subTypeSize):
self.data += pLabel("subT_" + str(i), "inter")
self.data += p("dd", "0") # 0 for False, 1 for True
......@@ -443,7 +443,7 @@ class ClassNode(ClassInterNode):
# fill in subtype testing column
self.code += "\n; Filling in subtype testing\n"
self.code += p("mov", "eax", "I_subT_spot_" + self.name)
self.code += p("mov", "[eax]", "dword I_subT_" + self.name)
self.code += p("mov", "[eax]", "dword A_subT_" + self.name)
for t in getSupers(self): # getSupers includes self
dlabel = "I_subT_" + str(t.subTypeOffset // 4)
......
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