def c_gen_code(self): before_expr_label = CodeGenManager.get_label('for_loop_expr') done_for_label = CodeGenManager.get_label('for_loop_done') init_code = [] if self.init is not None: init_code = self.init.c_gen_code() expr_code = [] if self.expression is not None: expr_code = common.if_false(self.expression, done_for_label) update_code = [] if self.update is not None: update_code = self.update.c_gen_code() body_code = [] if self.statement is not None: body_code = self.statement.c_gen_code() return [ '; for loop', '; init code', init_code, '; expression', '{0}:'.format(before_expr_label), expr_code, '; body: ', body_code, '; update', update_code, 'jmp {0}'.format(before_expr_label), '{0}:'.format(done_for_label), ]
def _get_field_defns(t): '''Return stoarge locations for each of the static fields. Static fields are stored in the data segment with code.''' ret = [] for f in t.fields: if f.is_static: CodeGenManager.add_global_label(t.canonical_name, f.c_defn_label) ret.append([ 'global {0}'.format(f.c_defn_label), '{0}: ; Static field {1}'.format(f.c_defn_label, f.identifier), 'dd 0x0', ]) return ret
def _array_init_loop(is_primitive): ''' Code that loops through array elements to initialize them. This code does not save/restore registers, it should only be called from create_array() ''' # Code that will create the default value for a single array element: default_value_code = asm_object.create_default_value(is_primitive, False) loop_start, loop_end = CodeGenManager.get_labels( 'array_init_loop_start', 'array_init_loop_end') # eax gets set to the an element'ss default value # ebx stores the length of the array (number of elements) # ecx is the loop counter # edx is a pointer to the start of the array return [ 'mov ecx, 0 ; ecx is counter for which array index we\'re at', '{0}:'.format(loop_start), 'cmp ecx, ebx ; loop condition (check if done all array elements)', 'je {0}'.format(loop_end), '; init current array elem to default value:', 'push ebx', default_value_code, 'pop ebx', 'mov [edx + 12 + 4*ecx], eax', 'add ecx, 1 ; increment loop counter', 'jmp {0}'.format(loop_start), '{0}:'.format(loop_end), ]
def gen_code_sit_column(sit_column, label): '''Generates assembly for the SIT table for this type.''' table_entries = [] for ix, m in enumerate(sit_column): # Add an assembly comment to explain the row. selector = CodeGenManager.get_selector(ix) ret_type, (name, params) = selector param_strs = [str(t) for t in params] method_str = '{0} {1}({2})'.format(str(ret_type), name, ', '.join(param_strs)) table_entries.append('; {0}'.format(method_str)) entry = '' if m is None: entry = 'dd 0x0' else: entry = 'dd {0}'.format(m.c_defn_label) table_entries.append(entry) return [ 'global {0}'.format(label), '{0}:'.format(label), table_entries ]
def c_gen_code_create_array(self): from parser.ast.ast_type import ASTType type_ = ASTType.from_str(str(self.name), is_primitive=False) type_.definition = self offset = CodeGenManager.get_subtype_table_index(type_) return ASTClass.c_gen_code_create_array_helper( self.c_create_array_function_label, self.c_array_cit_label, offset)
def divide_int(): '''Divides one integer by another and returns the address of a new integer equal to the result. 2 Params: 1. The address of an integer (left operand - dividend) 2. The address of another integer (right operand - divisor)''' N_PARAMS = 2 div_not_zero = CodeGenManager.get_label('div_not_zero') return [ '_divide_int:', common.function_prologue(), '; get the value for the left operand and put it in eax', common.get_param('eax', 0, N_PARAMS), common.unwrap_primitive('eax', 'eax'), '; get the value for the right operand and put in in ebx', common.get_param('ebx', 1, N_PARAMS), common.unwrap_primitive('ebx', 'ebx'), '; check for division by zero:', 'cmp ebx, 0', 'jne {0}'.format(div_not_zero), 'call __exception', '{0}:'.format(div_not_zero), common.fill_high_order_bit('eax', 'edx'), 'idiv ebx ; sets eax to edx:eax/ebx', '; create an int with the result', 'push eax ; the result of div has to be in eax', 'call _create_int', 'pop ebx ; pop param', '; eax is an integer object with the old value of eax', common.function_epilogue() ]
def c_gen_code(self): before_expr_label = CodeGenManager.get_label('while_loop_expr') done_label = CodeGenManager.get_label('while_loop_done') body_code = [] if self.statement is not None: body_code = self.statement.c_gen_code() return [ '; while loop', '; expression', '{0}:'.format(before_expr_label), common.if_false(self.expression, done_label), body_code, 'jmp {0}'.format(before_expr_label), '{0}:'.format(done_label), ]
def check_null(src): '''Checks whether the value in src is null (0x0).''' from code_gen.manager import CodeGenManager check_pass = CodeGenManager.get_label('null_check_pass'); return [ 'cmp {0}, 0'.format(src), 'jne {0}'.format(check_pass), 'call __exception', '{0}:'.format(check_pass) ]
def c_gen_code(self): if_body_code = [] if self.if_statement is not None: if_body_code = self.if_statement.c_gen_code() else_body_code = [] if self.else_statement is not None: else_body_code = self.else_statement.c_gen_code() false_label = CodeGenManager.get_label('if_block_false') if_end_label = CodeGenManager.get_label('if_block_end') return [ '; if condition', common.if_false(self.expression, false_label), if_body_code, 'jmp {0}'.format(if_end_label), '{0}:'.format(false_label), else_body_code, '{0}:'.format(if_end_label), ]
def create_array(is_primitive, array_cit_label, subtype_offset = 0): ''' Returns code for a function that creates an array in memory. This function does NOT include a label, because each reference/primitive type will need their own version of this function. You should put your own label above this code. Structure of the created array object is as follows: 1. Pointer to Array CIT 2. The type's subtype column offset for reference types, 0 for primitives 3. Length (reference to a integer) 4. Array elements 1 Param: The length of the array (a reference to an integer)''' N_PARAMS = 1 # The first 12 bytes are for the pointer to the Array CIT, the subtype column # offset, and the length. Remaining bytes are for the array elements # (4 bytes each) array_length_pass = CodeGenManager.get_label('array_length_pass') return [ common.function_prologue(), common.get_param('ebx', 0, N_PARAMS), common.unwrap_primitive('ebx', 'ebx'), '; ebx now contains the length of the array', '; check that array length is not negative:', 'cmp ebx, 0', 'jge {0}'.format(array_length_pass), 'call __exception', '{0}:'.format(array_length_pass), 'push ebx ; store the array length (# elems)', '; calculate how much memory to allocate, based on length of array:', 'imul ebx, 4 ; 4 bytes for every element', 'add ebx, 12 ; add an extra 12 bytes for pointers/length field', common.malloc_reg('ebx'), 'pop ebx ; restore length (# elems)', 'mov edx, eax ; save pointer to array memory in edx', 'push eax', '; set array elems to their default values:', _array_init_loop(is_primitive), '; create an int to store the length of the array:', 'push ebx;', 'call _create_int', 'pop ecx; pop param to garbage', 'mov ebx, eax ; ebx has pointer to integer representing array length', 'pop eax ; eax now has pointer to memory from malloc call', 'mov dword [eax], {0}'.format(array_cit_label), 'mov dword [eax + 4], {0}'.format(subtype_offset*4), 'mov dword [eax + 8], ebx', common.function_epilogue() ]
def invoke_interface_method(this_reg, m, args_asm): '''Invokes an interface method m off this_reg using the SIT''' from code_gen.manager import CodeGenManager offset = CodeGenManager.get_sit_offset(m) n_params = len(m.params) pop_asm = ['pop ebx ; Pop param to garbage' for x in range(m.c_num_params)] return [ '; Invoke interface method: {0}'.format(m.name), check_null('eax'), 'push eax ; Push "this" as the first param', args_asm, 'mov dword eax, [esp + 4*{0}] ; Get to "this"'.format(n_params), 'mov dword eax, [eax] ; Get to CIT for T[]', 'mov eax, [eax] ; Get to SIT for T[]', 'mov eax, [eax + {0}] ; Get the method loc in the SIT'.format(offset), 'call eax ; Call the method', pop_asm, ]
def c_gen_code_subtype_column_helper(label, subtype_column): '''Generates the subtype column given the label and the values for the type subtype_column is a list of boolean values corresponding to whether the type is a subtype of the row type.''' subtype_cells = [] for ix, val in enumerate(subtype_column): # Add a comment for each subtype cell. type_ = CodeGenManager.get_subtype_table_type(ix) subtype_cells.append('; subtype = {0}'.format(str(type_))) if val: subtype_cells.append('dd 1') else: subtype_cells.append('dd 0') return [ '; EXAMPLE', '; subtype = X', '; dd 1', '; X is a subtype of the contained type', '{0}:'.format(label), subtype_cells ]
def c_gen_code(self): from ast_expression import ASTLiteral if self.type_node.is_primitive and not self.type_node.is_array: primitive_sizes = { 'boolean': 0x1, 'byte': 0xff, 'char': 0xff, 'int': 0xffffffff, 'null': 0x0, 'short': 0xffff, } expr_size = primitive_sizes[str(self.expressions[0].expr_type)] result_size = primitive_sizes[str(self.type_node)] # Widen all numeric types but chars. widen_code = [] if str(self.expressions[0].expr_type) in ['byte', 'short']: done_label = CodeGenManager.get_label('cast_widen_done') if expr_size == 0xff: widen_code = [ 'mov ebx, eax', 'and ebx, 0x80', 'cmp ebx, 0x80', 'jne {0}'.format(done_label), 'or eax, 0xffffff00', '{0}:'.format(done_label), ] elif expr_size == 0xffff: widen_code = [ 'mov ebx, eax', 'and ebx, 0x8000', 'cmp ebx, 0x8000', 'jne {0}'.format(done_label), 'or eax, 0xffff0000', '{0}:'.format(done_label), ] return [ self.expressions[0].c_gen_code(), common.unwrap_primitive('eax', 'eax'), widen_code, 'and eax, {0} ; narrow to {1}'.format(result_size, str(self.type_node)), 'push eax ; create new primitive with value', 'call _create_int', 'pop ebx ; pop param', ] else: subtype_offset = 4 * CodeGenManager.get_subtype_table_index( self.type_node) finished_label = CodeGenManager.get_label('cast_exp_finished') return [ self.expressions[0].c_gen_code(), # Null check. 'mov ebx, 0', 'cmp eax, ebx', 'je {0}'.format(finished_label), common.unwrap_subtype_col_from_object('ebx', 'eax'), 'mov ebx, [ebx + {0}]'.format(subtype_offset), 'mov ecx, 1', 'cmp ebx, ecx', 'je {0}'.format(finished_label), '; OH NO! CastException!', 'call __exception', '{0}:'.format(finished_label), ]
def c_add_static_to_init(self): '''Add static fields to the initializtion list in CodeGenManager''' for f in self.fields: if f.is_static: CodeGenManager.add_static_var_to_init(self, f) return
def c_create_array_function_label(self): label = 'create_array_{0}'.format(self.canonical_name) return CodeGenManager.memoize_label(self, label)
def c_array_cit_label(self): label = 'array_cit_{0}'.format(self.canonical_name) return CodeGenManager.memoize_label(self, label)
def c_cit_label(self): label = 'class_info_{0}'.format(self.canonical_name) return CodeGenManager.memoize_label(self, label)
def c_array_subtype_column_label(self): label = 'array_subtype_column_{0}'.format(self.canonical_name) return CodeGenManager.memoize_label(self, label)
def c_array_sit_column_label(self): label = 'sit_column_{0}'.format( CodeGenManager.java_lang_object_defn.canonical_name) return CodeGenManager.memoize_label(CodeGenManager.java_lang_object_defn, label)
def c_sit_column_label(self): label = 'sit_column_{0}'.format(self.canonical_name) return CodeGenManager.memoize_label(self, label)
def c_defn_label(self): label = 'method_defn_{0}'.format(str(self.name)) return CodeGenManager.memoize_label(self, label)
def c_defn_label(self): '''The label pointing to the field definition''' # NOTE: This is only for static fields! Instance fields can be obtained # by using the offset on the object. label = 'field_defn_{0}'.format(str(self.identifier)) return CodeGenManager.memoize_label(self, label)