method.py 4.86 KB
Newer Older
Stefan Marr's avatar
Stefan Marr committed
1 2
from __future__ import absolute_import

3 4
from rpython.rlib import jit

5
from som.interpreter.control_flow import ReturnException
6

7
from som.vmobjects.abstract_object import AbstractObject
Stefan Marr's avatar
Stefan Marr committed
8

Stefan Marr's avatar
Stefan Marr committed
9

10
class Method(AbstractObject):
Stefan Marr's avatar
Stefan Marr committed
11
    
12
    _immutable_fields_ = ["_bytecodes[*]",
13
                          "_literals[*]",
14 15 16
                          "_inline_cache_class",
                          "_receiver_class_table",
                          "_number_of_locals",
17 18
                          "_maximum_number_of_stack_elements",
                          "_signature"]
19

Stefan Marr's avatar
Stefan Marr committed
20
    
21
    def __init__(self, literals, num_locals, max_stack_elements,
22
                 num_bytecodes, signature):
23
        AbstractObject.__init__(self)
24 25 26 27 28 29

        # Set the number of bytecodes in this method
        self._bytecodes              = ["\x00"] * num_bytecodes
        self._inline_cache_class     = [None]   * num_bytecodes
        self._inline_cache_invokable = [None]   * num_bytecodes
        
30 31
        self._literals               = literals
        
32 33
        self._number_of_locals       = num_locals
        self._maximum_number_of_stack_elements = max_stack_elements
34 35 36
        self._signature = signature
        
        self._holder = None
37
        
Stefan Marr's avatar
Stefan Marr committed
38 39 40
    
    def is_primitive(self):
        return False
41 42 43 44 45 46
    
    def is_invokable(self):
        """In the RPython version, we use this method to identify methods 
           and primitives
        """
        return True
Stefan Marr's avatar
Stefan Marr committed
47 48
  
    def get_number_of_locals(self):
49
        # Get the number of locals
50
        return self._number_of_locals
Stefan Marr's avatar
Stefan Marr committed
51 52 53

    def get_maximum_number_of_stack_elements(self):
        # Get the maximum number of stack elements
54
        return self._maximum_number_of_stack_elements
Stefan Marr's avatar
Stefan Marr committed
55

56 57
    # XXX this means that the JIT doesn't see changes to the method object
    @jit.elidable_promote('all')
Stefan Marr's avatar
Stefan Marr committed
58
    def get_signature(self):
59
        return self._signature
Stefan Marr's avatar
Stefan Marr committed
60 61

    def get_holder(self):
62
        return self._holder
Stefan Marr's avatar
Stefan Marr committed
63 64

    def set_holder(self, value):
65
        self._holder = value
Stefan Marr's avatar
Stefan Marr committed
66 67

        # Make sure all nested invokables have the same holder
68 69 70
        for i in range(0, len(self._literals)):
            if self._literals[i].is_invokable():
                self._literals[i].set_holder(value)
Stefan Marr's avatar
Stefan Marr committed
71

72 73
    # XXX this means that the JIT doesn't see changes to the constants
    @jit.elidable_promote('all')
Stefan Marr's avatar
Stefan Marr committed
74 75
    def get_constant(self, bytecode_index):
        # Get the constant associated to a given bytecode index
76
        return self._literals[self.get_bytecode(bytecode_index + 1)]
Stefan Marr's avatar
Stefan Marr committed
77 78 79 80

    def get_number_of_arguments(self):
        # Get the number of arguments of this method
        return self.get_signature().get_number_of_signature_arguments()
81
    
Stefan Marr's avatar
Stefan Marr committed
82 83 84 85
    def get_number_of_bytecodes(self):
        # Get the number of bytecodes in this method
        return len(self._bytecodes)

86
    @jit.elidable_promote('all')
Stefan Marr's avatar
Stefan Marr committed
87 88
    def get_bytecode(self, index):
        # Get the bytecode at the given index
89
        assert 0 <= index and index < len(self._bytecodes)
90
        return ord(self._bytecodes[index])
Stefan Marr's avatar
Stefan Marr committed
91 92 93

    def set_bytecode(self, index, value):
        # Set the bytecode at the given index to the given value
94 95
        assert 0 <= value and value <= 255
        self._bytecodes[index] = chr(value)
Stefan Marr's avatar
Stefan Marr committed
96 97 98

    def invoke(self, frame, interpreter):
        # Allocate and push a new frame on the interpreter stack
99
        new_frame = interpreter.new_frame(frame, self, None)
Stefan Marr's avatar
Stefan Marr committed
100
        new_frame.copy_arguments_from(frame)
101
        
102 103 104 105 106 107 108 109
        try:
            result = interpreter.interpret(self, new_frame)
            frame.pop_old_arguments_and_push_result(self, result)
            new_frame.clear_previous_frame()
            return
        except ReturnException as e:
            if e.has_reached_target(new_frame):
                frame.pop_old_arguments_and_push_result(self, e.get_result())
110
                return
111 112 113
            else:
                new_frame.clear_previous_frame()
                raise e
Stefan Marr's avatar
Stefan Marr committed
114 115 116

    def __str__(self):
        return "Method(" + self.get_holder().get_name().get_string() + ">>" + str(self.get_signature()) + ")"
117 118 119
    
    def get_class(self, universe):
        return universe.methodClass
Stefan Marr's avatar
Stefan Marr committed
120

121
    @jit.elidable
Stefan Marr's avatar
Stefan Marr committed
122
    def get_inline_cache_class(self, bytecode_index):
123
        assert 0 <= bytecode_index and bytecode_index < len(self._inline_cache_class)
Stefan Marr's avatar
Stefan Marr committed
124 125
        return self._inline_cache_class[bytecode_index]

126
    @jit.elidable
Stefan Marr's avatar
Stefan Marr committed
127
    def get_inline_cache_invokable(self, bytecode_index):
128
        assert 0 <= bytecode_index and bytecode_index < len(self._inline_cache_invokable)
Stefan Marr's avatar
Stefan Marr committed
129 130 131 132 133
        return self._inline_cache_invokable[bytecode_index]

    def set_inline_cache(self, bytecode_index, receiver_class, invokable):
        self._inline_cache_class[bytecode_index]    = receiver_class
        self._inline_cache_invokable[bytecode_index] = invokable
134 135 136 137 138

    def merge_point_string(self):
        """ debug info for the jit """
        return "%s>>%s" % (self.get_holder().get_name().get_string(),
                           self.get_signature().get_string())