Beispiel #1
0
  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',
    ]
Beispiel #2
0
  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')