def if_then_statement(subtree): condition_asm = subtree[2].assembly then_asm = subtree.find("then").assembly else_asm = subtree.find("else").assembly # Empty string if no else block condition_slot = subtree[2].slot label_no = new_label_no() top_of_else_label = "ELSE_" + str(label_no) + "_top" bottom_of_else_label = "ELSE_" + str(label_no) + "_bottom" subtree.assembly = """ ; begin if statement, test condition if ({dbg}) {condition_asm} cmp {condition_slot}, 0 jz .{top_of_else_label} ; end if ({dbg}) condition check, begin then block {then_asm} jmp .{bottom_of_else_label} ; end if ({dbg}) then block, begin else block .{top_of_else_label}: {else_asm} .{bottom_of_else_label}: ; end if ({dbg}) else block """.format( dbg=collect_debug_text(subtree[2]), condition_asm=condition_asm, condition_slot=stack_slot_to_operand(condition_slot), bottom_of_else_label=bottom_of_else_label, then_asm=then_asm, top_of_else_label=top_of_else_label, else_asm=else_asm, )
def class_instance_creation(subtree): subtree.slot = generate_new_stack_slot(subtree) declaration_site = typechecker.resolve_constructor_name(subtree) size = (declaration_site.env.findclass("this").num_fields + 1) * 4 # TODO: Initialize the vtable somehow constructor_name = mangle_fn_name(declaration_site) vtable_name = vtable_name_for_class(declaration_site.env.findclass("this")) pushes = push_arguments(subtree) return_slot = stack_slot_to_operand(subtree.slot) subtree.assembly = """ ; invoke constructor {dbg} mov eax, {size} call __malloc mov DWORD [eax], {vtable} {pushes} push eax call {constructor} mov {return_slot}, eax ; end invoke constructor """.format( dbg=collect_debug_text(subtree), size=size, constructor=constructor_name, pushes="\n".join(pushes), return_slot=return_slot, vtable=vtable_name, )
def array_access(subtree): subtree.slot = generate_new_stack_slot(subtree) subtree.memory_location = generate_new_stack_slot(subtree) subtree.assembly = """ ; array access {dbg} mov eax, {expression_value} mov ebx, {array_pointer} ; array bounds check mov edx, [ebx + 8] cmp edx, eax jle __exception mov ecx, 4 imul ecx add eax, 12 add eax, ebx mov {memory_location}, eax mov ebx, [eax] mov {destination}, ebx ; done array access """.format( dbg=collect_debug_text(subtree), expression_value=stack_slot_to_operand(subtree[2].slot), array_pointer=stack_slot_to_operand(subtree[0].slot), memory_location=stack_slot_to_operand(subtree.memory_location), destination=stack_slot_to_operand(subtree.slot), )
def unary_expression_not_plus_minus(subtree): if subtree[0].tag == "tok_complement": # Unary boolean complement subtree.slot = subtree[1].slot subtree.assembly = """ ; Unary complement {dbg} not {reg} """.format( dbg=collect_debug_text(subtree), reg=stack_slot_to_operand(subtree.slot) )
def unary_expression(subtree): if subtree[0].tag == "tok_minus": # Unary minus subtree.slot = subtree[1].slot subtree.assembly = """ ; Unary Minus {dbg} neg {reg} """.format( dbg=collect_debug_text(subtree), reg=stack_slot_to_operand(subtree.slot) )
def local_variable_declaration(subtree): subtree.slot = generate_new_stack_slot(subtree) subtree.assembly = """ ; local variable declaration {dbg} mov eax, {source} mov {dest}, eax ; end local variable declaration """.format( dbg=collect_debug_text(subtree), dest=stack_slot_to_operand(subtree.slot), source=stack_slot_to_operand(subtree.find("expression").slot), )
def multiplicative_expression(subtree): lhs_location = subtree[0].slot rhs_location = subtree[2].slot new_stack_slot = generate_new_stack_slot(subtree) operator_type = collect_token_text(subtree[1]) result = operator = "" if operator_type == "*": operator = "imul" result = "eax" check = "" elif operator_type == "/": operator = "idiv" result = "eax" label_no = new_label_no() check = """ sub ebx, 0 jne .{okay_label} call __exception .{okay_label}: """.format( okay_label="DIV0_CHECK_" + str(label_no) ) elif operator_type == "%": operator = "idiv" result = "edx" check = "" else: error_if(True, "Unknown argument to mulitplicative expression") subtree.assembly = """ ; multiplicative {dbg} mov edx, {lhs} mov eax, edx sar edx, 31 mov ebx, {rhs} {check} {op} ebx mov {nss}, {result} ; end multiplicative """.format( nss=stack_slot_to_operand(new_stack_slot), lhs=stack_slot_to_operand(lhs_location), rhs=stack_slot_to_operand(rhs_location), result=result, check=check, op=operator, imul_part=operator == "imul" and ", edx" or "", dbg=collect_debug_text(subtree), ) subtree.slot = new_stack_slot
def empty_expression(subtree): value = subtree.get("value") if value == "True": value = true elif value == "False": value = false error_if(value is None, "None in empty expression!") new_stack_slot = generate_new_stack_slot(subtree) subtree.assembly = """ ; empty expr {dbg} mov {nss}, {val} ; end empty expr """.format( nss=stack_slot_to_operand(new_stack_slot), val=value, dbg=collect_debug_text(subtree) ) subtree.slot = new_stack_slot
def cast_expression(subtree): if subtree[1].tag == "name": expression_being_cast = subtree.find("unary_expression_not_plus_minus") cast_tree = subtree[1] # if element.find("dims"): # cast_type += "[]" elif subtree[1].tag == "expression": # Expression case cast_tree = subtree[1] expression_being_cast = subtree[-1] elif subtree.find("dims") is not None: cast_tree = subtree[1] expression_being_cast = subtree[-1] else: # Primitive cast case subtree.slot = subtree[-1].slot if hasattr(subtree[-1], "memory_location"): subtree.memory_location = subtree[-1].memory_location return slot = generate_new_stack_slot(subtree) value_slot = expression_being_cast.slot debug_string = ( "ClassCastException check " + collect_debug_text(subtree) + " with result in " + stack_slot_to_operand(slot) ) subtree.assembly = instanceof_assembly( value_slot, slot, cast_tree, debug_string, isarray=subtree.find("dims") is not None ) valid_label = ".VALID_CAST_" + str(new_label_no()) subtree.assembly += """ ; Raise exception if instanceof check failed mov eax, {test_slot} sub eax, -1 jz {valid_label} ; check for null (can cast null to reference types) mov eax, {lhs_slot} sub eax, 0 jz {valid_label} call __exception {valid_label}: """.format( lhs_slot=stack_slot_to_operand(value_slot), valid_label=valid_label, test_slot=stack_slot_to_operand(slot) ) subtree.slot = subtree[-1].slot if hasattr(subtree[-1], "memory_location"): subtree.memory_location = subtree[-1].memory_location
def assignment(subtree): subtree.slot = generate_new_stack_slot(subtree) # subtree[0].slot if hasattr(subtree[0], "memory_location"): subtree.memory_location = subtree[0].memory_location subtree.assembly = """ ; assign {dbg} mov eax, {value} mov ebx, {memory_dst} mov DWORD [ebx], eax mov {value_dst}, eax mov {value_dst2}, eax ; end assign """.format( dbg=collect_debug_text(subtree), value=stack_slot_to_operand(subtree[-1].slot), memory_dst=stack_slot_to_operand(subtree.memory_location), value_dst=stack_slot_to_operand(subtree.slot), value_dst2=stack_slot_to_operand(subtree[0].slot), )
def for_statement(subtree): for_init_asm = subtree.find("for_init").assembly for_test_asm = subtree[3].assembly for_test_slot = subtree[3].slot for_update_asm = "" if subtree.find("for_update") is not None: for_update_asm = subtree.find("for_update").assembly body_asm = subtree[-1].assembly label_no = new_label_no() top_of_loop_label = "FOR_" + str(label_no) + "_top" bottom_of_loop_label = "FOR_" + str(label_no) + "_bottom" debug_string = collect_debug_text(subtree[0:6]) subtree.assembly = """ ; begin {dbg} init {for_init_asm} .{top_of_loop_label}: ; begin {dbg} test {for_test} ; end for statement test cmp {for_test_slot}, 0 jz .{bottom_of_loop_label} ; {dbg} body {body_asm} ; end for statement body, for statement update: {for_update_asm} jmp .{top_of_loop_label} .{bottom_of_loop_label}: ; end for statement {dbg} """.format( dbg=debug_string, for_init_asm=for_init_asm, top_of_loop_label=top_of_loop_label, for_test=for_test_asm, for_test_slot=stack_slot_to_operand(for_test_slot), bottom_of_loop_label=bottom_of_loop_label, body_asm=body_asm, for_update_asm=for_update_asm, )
def method_invocation(subtree): method = subtree.declaration subtree.slot = generate_new_stack_slot(subtree) pushes = push_arguments(subtree) if "static" not in modifiers(method): if subtree[0].tag == "name": name(subtree[0], args=argument_list(subtree)) pushes.append("push " + stack_slot_to_operand(subtree[0].slot)) return_slot = stack_slot_to_operand(subtree.slot) if "native" in modifiers(method): call = "call " + mangle_native_fn_name(subtree.declaration) argument_slot = subtree.find("./argument_list").slot operand = stack_slot_to_operand(argument_slot) pushes = ["mov eax, {slot}".format(slot=operand)] elif "static" in modifiers(method): call = "call " + mangle_fn_name(subtree.declaration) else: call = """ mov eax, {this_ptr} mov eax, [eax] add eax, {method_offset} mov eax, [eax] call eax """.format( this_ptr=stack_slot_to_operand(subtree[0].slot), method_offset=str(4 * method.mega_vtable_offset) ) subtree.assembly = """ ; method invocation {dbg} {push_arguments} {call} mov {return_slot}, eax ; end method invocation """.format( dbg=collect_debug_text(subtree), call=call, push_arguments="\n".join(pushes), return_slot=return_slot )
def eager_or_expression(subtree): error_if(subtree[1].tag != "tok_bit_or", "Unexpected structure to eager or expression") subtree.slot = generate_new_stack_slot(subtree) subtree.assembly = binary_operator_assembly( subtree[0].slot, subtree[2].slot, "or", subtree.slot, collect_debug_text(subtree) )
def additive_expression(subtree): lhs_slot = subtree[0].slot rhs_slot = subtree[2].slot result_slot = generate_new_stack_slot(subtree) lhs_type = subtree[0].get("type") rhs_type = subtree[2].get("type") if "java.lang.String" in [lhs_type, rhs_type]: (lhs_slot, lhs_assembly) = generate_promotion_to_string(subtree[0]) (rhs_slot, rhs_assembly) = generate_promotion_to_string(subtree[2]) assembly = """ ; string additive expression {lhs_assembly} {rhs_assembly} mov eax, {lhs_slot} mov ebx, {rhs_slot} push ebx push eax call java_lang_String_concat_java_lang_String_ mov {result_slot}, eax """.format( lhs_assembly=lhs_assembly, rhs_assembly=rhs_assembly, rhs_slot=stack_slot_to_operand(rhs_slot), lhs_slot=stack_slot_to_operand(lhs_slot), result_slot=stack_slot_to_operand(result_slot), ) subtree.assembly = assembly subtree.slot = result_slot return operator_type = collect_token_text(subtree[1]) operator = "" if operator_type == "+": operator = "add" elif operator_type == "-": operator = "sub" else: error_if(True, "Unknown additive_expression operator_type") subtree.assembly = binary_operator_assembly(lhs_slot, rhs_slot, operator, result_slot, collect_debug_text(subtree)) subtree.slot = result_slot
def instanceof_expression(subtree): lhs_location = subtree[0].slot subtree.slot = generate_new_stack_slot(subtree) subtree.assembly = instanceof_assembly(lhs_location, subtree.slot, subtree[2], collect_debug_text(subtree))
def name(subtree, args=None): # TODO: pathing # subtree.slot = subtree.declaration.slot try: path = subtree.env.get_declaration_path_for_name(name_to_str(subtree), args) if not path: return subtree.assembly = "; name {dbg}\n".format(dbg=collect_debug_text(subtree)) if path[0].tag == "method" or path[0].tag == "abstract_method": subtree.slot = this if path[0].tag == "class": subtree.slot = generate_new_stack_slot(subtree) subtree.memory_location = generate_new_stack_slot(subtree) mangled_name = mangle_field_name(path[1]) subtree.assembly += """ mov eax, {mangled_name} mov ebx, DWORD [eax] mov {memory_dst}, eax mov {value_dst}, ebx """.format( mangled_name=mangled_name, memory_dst=stack_slot_to_operand(subtree.memory_location), value_dst=stack_slot_to_operand(subtree.slot), ) path = path[1:] elif path[0].tag == "field": subtree.slot = generate_new_stack_slot(subtree) subtree.memory_location = generate_new_stack_slot(subtree) subtree.assembly += """ mov eax, DWORD [ebp + 8] ; this -> eax mov ebx, [eax + {field_location}] add eax, {field_location} mov {mem_loc}, eax mov {dest}, ebx """.format( field_location=path[0].field_offset * 4, dest=stack_slot_to_operand(subtree.slot), mem_loc=stack_slot_to_operand(subtree.memory_location), ) elif path[0].tag == "local_variable_declaration" or path[0].tag == "param": if not hasattr(path[0], "slot"): return subtree.slot = generate_new_stack_slot(subtree) subtree.memory_location = generate_new_stack_slot(subtree) subtree.assembly += """ mov eax, {source} mov {dest}, eax mov ebx, ebp sub ebx, {source_stack_slot} mov {mem_loc}, ebx """.format( source=stack_slot_to_operand(path[0].slot), source_stack_slot=path[0].slot * 4, mem_loc=stack_slot_to_operand(subtree.memory_location), dest=stack_slot_to_operand(subtree.slot), ) for child in path[1:]: if child.tag in ["method", "abstract_method"]: return former_slot = subtree.slot subtree.slot = generate_new_stack_slot(subtree) subtree.memory_location = generate_new_stack_slot(subtree) if not hasattr(subtree, "assembly"): subtree.assembly = "" subtree.assembly += """ mov eax, {former_location} mov ebx, [eax + {field_location}] add eax, {field_location} mov {mem_loc}, eax mov {dest}, ebx """.format( former_location=stack_slot_to_operand(former_slot), field_location=child.field_offset * 4, dest=stack_slot_to_operand(subtree.slot), mem_loc=stack_slot_to_operand(subtree.memory_location), ) except JoosSyntaxException: pass