To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

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

3
from som.vmobjects.array import Array
Stefan Marr's avatar
Stefan Marr committed
4

5
from som.interpreter.bytecodes import bytecode_length
Stefan Marr's avatar
Stefan Marr committed
6

7
class Method(Array):
Stefan Marr's avatar
Stefan Marr committed
8
9
10
11
12
13
14
15
16
17
    
    # Static field indices and number of method fields
    NUMBER_OF_LOCALS_INDEX                 = 1 + Array.CLASS_INDEX
    MAXIMUM_NUMBER_OF_STACK_ELEMENTS_INDEX = 1 + NUMBER_OF_LOCALS_INDEX
    SIGNATURE_INDEX                        = 1 + MAXIMUM_NUMBER_OF_STACK_ELEMENTS_INDEX
    HOLDER_INDEX                           = 1 + SIGNATURE_INDEX
    NUMBER_OF_METHOD_FIELDS                = 1 + HOLDER_INDEX

    
    def __init__(self, nilObject):
18
        Array.__init__(self, nilObject)
Stefan Marr's avatar
Stefan Marr committed
19
20
21
22
23
24
25
26
27
28
29
30
31
        
        self._receiver_class_table   = []
        self._invoked_methods        = []
        self._receiver_class_index   = 0

        self._invocation_count       = 0

        self._bytecodes              = None
        self._inline_cache_class     = None
        self._inline_cache_invokable = None
    
    def is_primitive(self):
        return False
32
33
34
35
36
37
    
    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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  
    def get_number_of_locals(self):
        # Get the number of locals (converted to a Java integer)
        return self.get_field(self.NUMBER_OF_LOCALS_INDEX)

    def set_number_of_locals(self, value):
        # Set the number of locals
        self.set_field(self.NUMBER_OF_LOCALS_INDEX, value)

    def get_maximum_number_of_stack_elements(self):
        # Get the maximum number of stack elements
        return self.get_field(self.MAXIMUM_NUMBER_OF_STACK_ELEMENTS_INDEX)
  
    def set_maximum_number_of_stack_elements(self, value):
        # Set the maximum number of stack elements
        self.set_field(self.MAXIMUM_NUMBER_OF_STACK_ELEMENTS_INDEX, value)

    def get_signature(self):
        # Get the signature of this method by reading the field with signature
        # index
        return self.get_field(self.SIGNATURE_INDEX)

    def set_signature(self, value):
        # Set the signature of this method by writing to the field with
        # signature index
        self.set_field(self.SIGNATURE_INDEX, value)

    def get_holder(self):
        # Get the holder of this method by reading the field with holder index
        return self.get_field(self.HOLDER_INDEX)

    def set_holder(self, value):
        # Set the holder of this method by writing to the field with holder index
        self.set_field(self.HOLDER_INDEX, value)

        # Make sure all nested invokables have the same holder
        for i in range(0, self.get_number_of_indexable_fields()):
75
            if self.get_indexable_field(i).is_invokable():
Stefan Marr's avatar
Stefan Marr committed
76
77
78
79
80
81
82
83
84
85
                self.get_indexable_field(i).set_holder(value)

    def get_constant(self, bytecode_index):
        # Get the constant associated to a given bytecode index
        return self.get_indexable_field(self.get_bytecode(bytecode_index + 1))

    def get_number_of_arguments(self):
        # Get the number of arguments of this method
        return self.get_signature().get_number_of_signature_arguments()
  
86
    def _get_default_number_of_fields(self):
Stefan Marr's avatar
Stefan Marr committed
87
88
89
90
91
92
93
94
95
        # Return the default number of fields in a method
        return self.NUMBER_OF_METHOD_FIELDS
  
    def get_number_of_bytecodes(self):
        # Get the number of bytecodes in this method
        return len(self._bytecodes)

    def set_number_of_bytecodes(self, value):
        # Set the number of bytecodes in this method
96
        self._bytecodes              = ["\x00"] * value
Stefan Marr's avatar
Stefan Marr committed
97
98
99
100
101
        self._inline_cache_class     = [None] * value
        self._inline_cache_invokable = [None] * value

    def get_bytecode(self, index):
        # Get the bytecode at the given index
102
        return ord(self._bytecodes[index])
Stefan Marr's avatar
Stefan Marr committed
103
104
105

    def set_bytecode(self, index, value):
        # Set the bytecode at the given index to the given value
106
107
        assert 0 <= value and value <= 255
        self._bytecodes[index] = chr(value)
Stefan Marr's avatar
Stefan Marr committed
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

    # TODO: remove these things
    def increase_invocation_counter(self):
        self._invocation_count += 1

    # TODO: remove these things
    def get_invocation_count(self):
        return self._invocation_count

    def invoke(self, frame, interpreter):
        # Increase the invocation counter
        self._invocation_count += 1
    
        # Allocate and push a new frame on the interpreter stack
        new_frame = interpreter.push_new_frame(self)
        new_frame.copy_arguments_from(frame)

    def replace_bytecodes(self):
126
        newbc =  ["\x00"] * len(self._bytecodes)
Stefan Marr's avatar
Stefan Marr committed
127
128
129
130
131
        idx = 0

        i = 0
        while i < len(self._bytecodes):
            bc1 = self._bytecodes[i]
132
            len1 = bytecode_length(bc1)
Stefan Marr's avatar
Stefan Marr committed
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

            if i + len1 >= len(self._bytecodes):
                # we're over target, so just copy bc1
                for j in range(i, i + len1):
                    newbc[idx] = self._bytecodes[j]
                    idx += 1
                break
    

            newbc[idx] = bc1
            idx += 1

            # copy args to bc1
            for j in range(i + 1, i + len1):
                newbc[idx] = self._bytecodes[j]
                idx += 1

            i += len1 # update i to point on bc2
    

        # we copy the new array because it may be shorter, and we don't
        # want to upset whatever dependence there is on the length
155
        self._bytecodes = array('b', [0] * idx)
Stefan Marr's avatar
Stefan Marr committed
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
        for i in range(0, idx):
            self._bytecodes[i] = newbc[i]

    # TODO: remove these things
    def get_receiver_class(self, index):
        return self._receiver_class_table[index]

    # TODO: remove these things
    def get_invoked_method(self, index):
        # return the last invoked method for a particular send
        return self._invoked_methods[index]

    # TODO: remove these things
    def add_receiver_class_and_method(self, rcvr_class, invokable):
        self._receiver_class_table.append(self._receiver_class_index, rcvr_class)
        self._invoked_methods.append(self._receiver_class_index, invokable)
        self._receiver_class_index += 1

        return self._receiver_class_index - 1

    # TODO: remove these things
    def is_receiver_class_table_full(self):
        return self._receiver_class_index == 255

    def __str__(self):
        return "Method(" + self.get_holder().get_name().get_string() + ">>" + str(self.get_signature()) + ")"

    def get_inline_cache_class(self, bytecode_index):
        return self._inline_cache_class[bytecode_index]

    def get_inline_cache_invokable(self, bytecode_index):
        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