def c_gen_code_get_array_pointer(self): '''Creates code that will store the array a reference to the array in ebx and the offset for the index in eax.''' array_check_pass = manager.CodeGenManager.get_label('array_check_pass') array_check_fail = manager.CodeGenManager.get_label('array_check_fail') # Assume that we're doing an array read. return [ self.array_expression.c_gen_code(), common.check_null('eax'), 'push eax', self.index.c_gen_code(), 'pop ebx ; restore the pointer to the array', common.unwrap_primitive('eax', 'eax'), '; check whether the index is out of bounds:', common.get_array_length('ecx', 'ebx'), common.unwrap_primitive('ecx', 'ecx'), 'cmp eax, ecx', 'jge {0}'.format(array_check_fail), 'cmp eax, 0', 'jl {0}'.format(array_check_fail), 'jmp {0}'.format(array_check_pass), '{0}:'.format(array_check_fail), 'call __exception', '{0}:'.format(array_check_pass), '; calculate the offset into the array:', 'imul eax, 4', 'add eax, 12', ]
def c_gen_code(self): import code_gen.access as access result = self.right.c_gen_code() # The left hand side is either an ASTArrayAccess, ASTFieldAccess or # ASTIdentifiers. if isinstance(self.left, ASTIdentifiers): # For assignment expressions, we evaluate the left hand side first. If # the left hand side is an ASTIdentifiers, the same ASTIdentifiers could # be used on the right hand side in an assignment. # Thus, we must store a reference to where the left hand side points # before evaluating the right hand side. if self.left.is_simple: # If the left hand side is simple, it is either a method parameter, # local variable or an instance field on the enclosing type. The # location for all of these cannot be altered by the right hand side, # so we can calculate the right hand side first. return [ result, access.set_simple_var(self.left.simple_decl, 'eax'), ] else: import code_gen.annotate_ids as annotate_ids annotations = annotate_ids.annotate_identifier(self.left) if len(annotations) == 0: # If we do not have any annotations then the left hand side is a # static field. This address cannot change. return [ result, access.set_simple_static_field(self.left, 'eax'), ] else: # _get_to_final provides code to store a pointer to the second last # part of the identifier in $eax. type_, code = access._get_to_final(self.left, annotations) env = type_.definition.environment final_part = str(self.left.parts[-1]) f, _ = env.lookup_field(final_part) return [ code, common.check_null('eax'), 'push eax ; save instance that we want to store a field on', result, 'pop ebx ; instance to store a field on', common.save_instance_field('ebx', f, 'eax'), ] elif isinstance(self.left, ASTFieldAccess): left_asm = self.left.left.c_gen_code() left_t = self.left.left.expr_type if left_t.is_array: raise Exception('Trying to write to array field') return [ '; FieldAccess assignment', access.get_field_from_parts( left_t, self.left.right, left_asm, get_addr=True), 'push eax ; Save field addr', result, '; RHS of assignment should be eax', 'pop ebx ; Pop addr of field', 'mov [ebx], eax ; Assign!' ] elif isinstance(self.left, ASTArrayAccess): array_soundness_pass = manager.CodeGenManager.get_label('array_soundness_pass') soundness_asm = [] if not self.left.array_expression.expr_type.is_primitive: soundness_asm = [ 'push eax', 'push ebx', 'push ecx', '; Get CIT of right side', 'mov ecx, [ecx]' '; Get subtype col of right side', 'mov ecx, [ecx + 4]', '; get subtype offset', 'mov ebx, [ebx + 4]', '; index into subtype col', 'mov ecx, [ecx + ebx]', 'cmp ecx, 1 ; 1 means that RHS is a subtype of LHS', 'je {0}'.format(array_soundness_pass), 'call __exception', '{0}:'.format(array_soundness_pass), 'pop ecx', 'pop ebx', 'pop eax', ] # The result is calculated after the array index offset. return [ self.left.c_gen_code_get_array_pointer(), 'push ebx ; save array pointer', 'push eax ; save array offset', result, 'mov ecx, eax ; move result', 'pop eax ; restore array offset', 'pop ebx ; restore array pointer', '; do array type soundness check', soundness_asm, 'mov [ebx + eax], ecx', 'mov eax, ecx ; result should be in eax', ] raise Exception('Programmer error: trying to assign to invalid AST')