def gen_creation_expr(info, node, method_obj): canon = node.find_child("Type").canon if canon.endswith('[]'): return gen_creation_expr_array(info, node, method_obj) output = ["; START gen_creation_expr"] # Number of bytes we will malloc (including metadata). num_bytes = info.get_size(canon) output.append("mov eax, %i" % num_bytes) output.append("push ebx") # Safety output.append("call __malloc") output.append("pop ebx") # Safety # Zero out fields. output.append('mov ebx, %d' % (num_bytes / 4)) output.extend(util.gen_zero_out(info)) output.append("mov dword [eax], SIT~%s" % canon) output.append("mov dword [eax+4], SBM~%s" % canon) output.append("mov dword [eax+8], 0") # Not an array, so 0. output.append("push eax ; this pointer") # calculate args, push args; left-to-right args = list(node.find_child("Arguments").children) num_args = len(args) arg_types = [] for arg in args: output.extend(gen_expr(info, arg, method_obj)) output.append("push eax") if typecheck.is_array_type(arg.typ) == True: # '[]'s replaced with '@', so that it can be accepted. arg_types.append(arg.typ[:-2] + '@') else: arg_types.append(arg.typ) constructor_name = canon.split(".")[-1] label = 'CONSTRUCTOR~%s.%s~%s' % (canon, constructor_name, '~'.join(arg_types)) output.append("call %s" % label) # pop args output.append("add esp, %i" % (num_args*4)) # put "this" on eax output.append("pop eax") output.append("; END gen_creation_expr") return output
def gen_field_access_addr(info, node, method_obj): output = [] # Gets the field receiver. obj_output = gen_expr(info, node.find_child("FieldReceiver")[0], method_obj) output.extend(obj_output) output.extend(util.gen_null_check()) if typecheck.is_array_type(node[1][0].typ) == True: # Array output.append('add eax, %d' % 12) else: # Object. offset = info.get_field_offset(node) output.append("add eax, %i" % (12 + offset)) return output
def get_method_label(node): assert node.name in ['MethodDeclaration', 'ConstructorDeclaration'] # Special case for native methods. # TODO: "in Joos 1W, all native methods must be static, must take a single # argument of type int, and must return a value of type int" should be # checked. class_name = node.obj.declared_in.name method_name = node.obj.name parameters = node.find_child('Parameters') param_types = [] for param in parameters: if typecheck.is_array_type(param[0].canon) == True: # '[]'s replaced with '@', so that it can be accepted. param_types.append(param[0].canon[:-2] + '@') else: param_types.append(param[0].canon) label = '' # Natives methods are of the form: # NATIVE<canonical_type>.<method_name> if 'native' in node.modifiers: label = 'NATIVE%s.%s' % (class_name, method_name) # Static methods are of the form: # STATICMETHOD~<canonical_type>.<method_name>~<param1>~<param2>... elif 'static' in node.modifiers: label = 'STATICMETHOD~%s.%s~%s' % (class_name, method_name, '~'.join(param_types)) # Constructors are of the form: # CONSTRUCTOR~<canonical_type>.<method_name>~<param1>~<param2>... elif node.name == 'ConstructorDeclaration': label = 'CONSTRUCTOR~%s.%s~%s' % (class_name, method_name, '~'.join(param_types)) # Instance methods are of the form: # METHOD~<canonical_type>.<method_name>~<param1>~<param2>... else: label = 'METHOD~%s.%s~%s' % (class_name, method_name, '~'.join(param_types)) return label
def gen_ambiguous_name_addr(info, node, method_obj): assert node.name == 'Name' output = ['; gen_ambiguous_name_addr'] # Loop through each identifier node, looking for a significant node. significant_node = None significant_index = -1 for i, id_node in enumerate(node.children): if hasattr(id_node, 'decl') or hasattr(id_node, 'canon'): significant_node = id_node significant_index = i break assert significant_index != -1 # Did not find anything, error. # We have Type.something, so there must be a next node. # This is a Static field access. id_node = significant_node i = significant_index prev_type = None if hasattr(id_node, 'canon') and id_node.canon != None: assert (i + 1) < len(node.children) # Return address of static field. next_node = node[i + 1].decl # decl should be static field ASTNode assert next_node.name == 'FieldDeclaration' assert 'static' in next_node.modifiers output.append('mov eax, %s' % next_node.label) i += 2 # Processed 2 nodes. prev_type = next_node[1].canon # Get type from Type node # We have local_var.something. Move its addr to eax. elif id_node.decl.name == 'LocalVariableDeclaration': assert i == 0 # Local variable must be first identifier. # Get the offset from the frame pointer. output.append('mov eax, ebp') local_var_offset = id_node.decl.frame_offset * 4 output.append('add eax, %d' % local_var_offset) i += 1 prev_type = id_node.decl[0].canon # Get type from Type node # We have a parameter.something. Move its addr to eax. elif id_node.decl.name == 'Parameter': assert i == 0 # Parameter must be first identifier. # Get the offset from the frame pointer. output.append('mov eax, ebp') param_offset = (id_node.decl.frame_offset * 4) output.append('add eax, %d' % param_offset) i += 1 prev_type = id_node.decl[0].canon # Get type from Type node # We have an implicit 'this' on an instance field. elif id_node.decl.name == 'FieldDeclaration': assert i == 0 # Field declaration must be first identifier. # Get this into eax. output.extend(gen_this(info, None, method_obj)) # If the field type is array, we must get the array field. offset = 0 receiver_type = info.class_obj.name field_name = id_node.decl.obj.name offset = info.get_field_offset_from_field_name(receiver_type, field_name) offset += 12 prev_type = id_node.decl[1].canon # Generic type. # Load the field address offset. output.append('add eax, %d' % offset) i += 1 # All the remaining things are instance fields. We have the address in eax # already, so we just keep going. while i < len(node.children): assert i >= 1 assert prev_type != None field_node = node[i] assert field_node.decl.name in ['FieldDeclaration', 'FakeFieldDeclaration'] # Nullcheck and dereference the previous result into eax. output.extend(util.gen_null_check()) output.append('mov eax, [eax]') # Calculate the offset of the field. offset = 0 # Array; length has type Int. if typecheck.is_array_type(prev_type): assert i == (len(node.children) - 1) # Must be last element. offset = 12 prev_type = 'Int' # Object. Must search up the object's type (in prev_type) in the field # index and get the offset. else: prev_type_field_list = info.field_index[prev_type] field_name = field_node.decl.obj.name temp = class_hierarchy.Temp_Field(field_name) offset = (prev_type_field_list.index(temp) * 4) + 12 # Keep the type. prev_type = field_node.decl[1].canon output.append('add eax, %d' % offset) i += 1 output.append('; end of gen_ambiguous_name_addr') return output