Commit 54182a5d authored by Stefan Marr's avatar Stefan Marr

Merge pull request #1 from cfbolz/master

Optimize low-hanging fruit in the jitted RPython version
parents 3558b9f8 18ad30f8
......@@ -15,113 +15,114 @@ class Interpreter(object):
def get_universe(self):
return self._universe
def _do_dup(self):
def _do_dup(self, frame, method):
# Handle the dup bytecode
self.get_frame().push(self.get_frame().get_stack_element(0))
frame.push(frame.get_stack_element(0))
def _do_push_local(self, bytecode_index):
def _do_push_local(self, bytecode_index, frame, method):
# Handle the push local bytecode
self.get_frame().push(
self.get_frame().get_local(self.get_method().get_bytecode(bytecode_index + 1),
self.get_method().get_bytecode(bytecode_index + 2)))
frame.push(
frame.get_local(method.get_bytecode(bytecode_index + 1),
method.get_bytecode(bytecode_index + 2)))
def _do_push_argument(self, bytecode_index):
def _do_push_argument(self, bytecode_index, frame, method):
# Handle the push argument bytecode
self.get_frame().push(
self.get_frame().get_argument(self.get_method().get_bytecode(bytecode_index + 1),
self.get_method().get_bytecode(bytecode_index + 2)))
frame.push(
frame.get_argument(method.get_bytecode(bytecode_index + 1),
method.get_bytecode(bytecode_index + 2)))
def _do_push_field(self, bytecode_index):
def _do_push_field(self, bytecode_index, frame, method):
# Handle the push field bytecode
field_index = self.get_method().get_bytecode(bytecode_index + 1)
field_index = method.get_bytecode(bytecode_index + 1)
# Push the field with the computed index onto the stack
self.get_frame().push(self.get_self().get_field(field_index))
frame.push(self.get_self().get_field(field_index))
def _do_push_block(self, bytecode_index):
def _do_push_block(self, bytecode_index, frame, method):
# Handle the push block bytecode
block_method = self.get_method().get_constant(bytecode_index)
block_method = method.get_constant(bytecode_index)
# Push a new block with the current self.get_frame() as context onto the
# Push a new block with the current frame as context onto the
# stack
self.get_frame().push(
self._universe.new_block(block_method, self.get_frame(),
frame.push(
self._universe.new_block(block_method, frame,
block_method.get_number_of_arguments()))
def _do_push_constant(self, bytecode_index):
def _do_push_constant(self, bytecode_index, frame, method):
# Handle the push constant bytecode
self.get_frame().push(self.get_method().get_constant(bytecode_index))
frame.push(method.get_constant(bytecode_index))
def _do_push_global(self, bytecode_index):
def _do_push_global(self, bytecode_index, frame, method):
# Handle the push global bytecode
global_name = self.get_method().get_constant(bytecode_index)
global_name = method.get_constant(bytecode_index)
# Get the global from the universe
glob = self._universe.get_global(global_name)
if glob:
# Push the global onto the stack
self.get_frame().push(glob)
frame.push(glob)
else:
# Send 'unknownGlobal:' to self
self.get_self().send_unknown_global(global_name, self._universe, self)
def _do_pop(self):
def _do_pop(self, frame, method):
# Handle the pop bytecode
self.get_frame().pop()
frame.pop()
def _do_pop_local(self, bytecode_index):
def _do_pop_local(self, bytecode_index, frame, method):
# Handle the pop local bytecode
self.get_frame().set_local(self.get_method().get_bytecode(bytecode_index + 1),
self.get_method().get_bytecode(bytecode_index + 2),
self.get_frame().pop())
frame.set_local(method.get_bytecode(bytecode_index + 1),
method.get_bytecode(bytecode_index + 2),
frame.pop())
def _do_pop_argument(self, bytecode_index):
def _do_pop_argument(self, bytecode_index, frame, method):
# Handle the pop argument bytecode
self.get_frame().set_argument(self.get_method().get_bytecode(bytecode_index + 1),
self.get_method().get_bytecode(bytecode_index + 2),
self.get_frame().pop())
frame.set_argument(method.get_bytecode(bytecode_index + 1),
method.get_bytecode(bytecode_index + 2),
frame.pop())
def _do_pop_field(self, bytecode_index):
def _do_pop_field(self, bytecode_index, frame, method):
# Handle the pop field bytecode
field_index = self.get_method().get_bytecode(bytecode_index + 1)
field_index = method.get_bytecode(bytecode_index + 1)
# Set the field with the computed index to the value popped from the stack
self.get_self().set_field(field_index, self.get_frame().pop())
self.get_self().set_field(field_index, frame.pop())
def _do_super_send(self, bytecode_index):
def _do_super_send(self, bytecode_index, frame, method):
# Handle the super send bytecode
signature = self.get_method().get_constant(bytecode_index)
signature = method.get_constant(bytecode_index)
# Send the message
# Lookup the invokable with the given signature
invokable = self.get_method().get_holder().get_super_class().lookup_invokable(signature)
invokable = method.get_holder().get_super_class().lookup_invokable(signature)
if invokable:
# Invoke the invokable in the current frame
invokable.invoke(self.get_frame(), self)
invokable.invoke(frame, self)
else:
# Compute the number of arguments
num_args = signature.get_number_of_signature_arguments()
# Compute the receiver
receiver = self.get_frame().get_stack_element(num_args - 1)
receiver = frame.get_stack_element(num_args - 1)
receiver.send_does_not_understand(signature, self._universe, self)
def _do_return_local(self):
def _do_return_local(self, frame, method):
# Handle the return local bytecode
result = self.get_frame().pop()
result = frame.pop()
# Pop the top frame and push the result
self._pop_frame_and_push_result(result)
def _do_return_non_local(self):
@jit.unroll_safe
def _do_return_non_local(self, frame, method):
# Handle the return non local bytecode
result = self.get_frame().pop()
result = frame.pop()
# Compute the context for the non-local return
context = self.get_frame().get_outer_context(self._universe.nilObject)
context = frame.get_outer_context(self._universe.nilObject)
# Make sure the block context is still on the stack
if not context.has_previous_frame(self._universe.nilObject):
......@@ -129,8 +130,8 @@ class Interpreter(object):
# this can get a bit nasty when using nested blocks. In this case
# the "sender" will be the surrounding block and not the object
# that actually sent the 'value' message.
block = self.get_frame().get_argument(0, 0)
sender = self.get_frame().get_previous_frame().get_outer_context(self._universe.nilObject).get_argument(0, 0)
block = frame.get_argument(0, 0)
sender = frame.get_previous_frame().get_outer_context(self._universe.nilObject).get_argument(0, 0)
# pop the frame of the currently executing block...
self._pop_frame()
......@@ -146,15 +147,15 @@ class Interpreter(object):
# Pop the top frame and push the result
self._pop_frame_and_push_result(result)
def _do_send(self, bytecode_index):
def _do_send(self, bytecode_index, frame, method):
# Handle the send bytecode
signature = self.get_method().get_constant(bytecode_index)
signature = method.get_constant(bytecode_index)
# Get the number of arguments from the signature
num_args = signature.get_number_of_signature_arguments()
# Get the receiver from the stack
receiver = self.get_frame().get_stack_element(num_args - 1)
receiver = frame.get_stack_element(num_args - 1)
# Send the message
self._send(signature, receiver.get_class(), bytecode_index)
......@@ -166,11 +167,12 @@ class Interpreter(object):
# Get the current bytecode
current_bc_idx = self._bytecode_index
method = self.get_method()
frame = self.get_frame()
jitdriver.jit_merge_point(bytecode_index=current_bc_idx,
interp=self,
method=method,
frame=self._frame)
frame=frame)
bytecode = method.get_bytecode(current_bc_idx)
......@@ -183,37 +185,37 @@ class Interpreter(object):
# Handle the current bytecode
if bytecode == Bytecodes.halt:
return self.get_frame().get_stack_element(0)
return frame.get_stack_element(0)
elif bytecode == Bytecodes.dup:
self._do_dup()
self._do_dup(frame, method)
elif bytecode == Bytecodes.push_local:
self._do_push_local(current_bc_idx)
self._do_push_local(current_bc_idx, frame, method)
elif bytecode == Bytecodes.push_argument:
self._do_push_argument(current_bc_idx)
self._do_push_argument(current_bc_idx, frame, method)
elif bytecode == Bytecodes.push_field:
self._do_push_field(current_bc_idx)
self._do_push_field(current_bc_idx, frame, method)
elif bytecode == Bytecodes.push_block:
self._do_push_block(current_bc_idx)
self._do_push_block(current_bc_idx, frame, method)
elif bytecode == Bytecodes.push_constant:
self._do_push_constant(current_bc_idx)
self._do_push_constant(current_bc_idx, frame, method)
elif bytecode == Bytecodes.push_global:
self._do_push_global(current_bc_idx)
self._do_push_global(current_bc_idx, frame, method)
elif bytecode == Bytecodes.pop:
self._do_pop()
self._do_pop(frame, method)
elif bytecode == Bytecodes.pop_local:
self._do_pop_local(current_bc_idx)
self._do_pop_local(current_bc_idx, frame, method)
elif bytecode == Bytecodes.pop_argument:
self._do_pop_argument(current_bc_idx)
self._do_pop_argument(current_bc_idx, frame, method)
elif bytecode == Bytecodes.pop_field:
self._do_pop_field(current_bc_idx)
self._do_pop_field(current_bc_idx, frame, method)
elif bytecode == Bytecodes.send:
self._do_send(current_bc_idx)
self._do_send(current_bc_idx, frame, method)
elif bytecode == Bytecodes.super_send:
self._do_super_send(current_bc_idx)
self._do_super_send(current_bc_idx, frame, method)
elif bytecode == Bytecodes.return_local:
self._do_return_local()
self._do_return_local(frame, method)
elif bytecode == Bytecodes.return_non_local:
self._do_return_non_local()
self._do_return_non_local(frame, method)
def push_new_frame(self, method, context):
# Allocate a new frame and make it the current one
......@@ -235,7 +237,7 @@ class Interpreter(object):
def get_method(self):
# Get the method from the interpreter
return self.get_frame().get_method()
return jit.promote(self.get_frame().get_method())
def get_self(self):
# Get the self object from the interpreter
......@@ -286,6 +288,7 @@ class Interpreter(object):
# Return the popped frame
return result
@jit.unroll_safe
def _pop_frame_and_push_result(self, result):
# Pop the top frame from the interpreter frame stack and compute the
# number of arguments
......
from rpython.rlib.rrandom import Random
from rpython.rlib import jit
from som.interpreter.interpreter import Interpreter
from som.interpreter.bytecodes import Bytecodes
......@@ -26,14 +27,29 @@ import time
from rlib.exit import Exit
from rlib.osext import path_split
class GlobalVersion(object):
pass
class Universe(object):
_immutable_fields_ = [
"nilObject",
"trueObject",
"falseObject",
"objectClass",
"integerClass",
"doubleClass",
"primitiveClass",
"_global_version?",
]
def __init__(self, avoid_exit = False):
self._interpreter = Interpreter(self)
self._symbol_table = SymbolTable()
self._globals = {}
self._global_version = GlobalVersion()
self.nilObject = None
self.trueObject = None
self.falseObject = None
......@@ -51,6 +67,7 @@ class Universe(object):
self.primitiveClass = None
self.systemClass = None
self.blockClass = None
self.blockClasses = None
self.stringClass = None
self.doubleClass = None
......@@ -279,7 +296,10 @@ class Universe(object):
self.set_global( trueClassName, trueClass)
self.set_global(falseClassName, falseClass)
self.blockClasses = [self.blockClass] + \
[self._make_block_class(i) for i in [1, 2, 3]]
return system_object
def symbol_for(self, string):
......@@ -474,35 +494,31 @@ class Universe(object):
def get_global(self, name):
# Return the global with the given name if it's in the dictionary of globals
if self.has_global(name):
return self._globals[name]
# if not, return None
jit.promote(self)
return self._get_global(name, self._global_version)
# Global not found
return None
@jit.elidable
def _get_global(self, name, version):
return self._globals.get(name, None)
def set_global(self, name, value):
# Insert the given value into the dictionary of globals
self._globals[name] = value
self._global_version = GlobalVersion()
def has_global(self, name):
# Returns if the universe has a value for the global of the given name
return name in self._globals
def _get_block_class(self, number_of_arguments = None):
if not number_of_arguments:
# Get the generic block class
return self.blockClass
def _get_block_class(self, number_of_arguments):
return self.blockClasses[number_of_arguments]
def _make_block_class(self, number_of_arguments):
# Compute the name of the block class with the given number of
# arguments
name = self.symbol_for("Block" + str(number_of_arguments))
# Lookup the specific block class in the dictionary of globals and
# return it
if self.has_global(name):
return self.get_global(name)
# Get the block class for blocks with the given number of arguments
result = self._load_class(name, None)
......@@ -517,8 +533,9 @@ class Universe(object):
def load_class(self, name):
# Check if the requested class is already in the dictionary of globals
if self.has_global(name):
return self.get_global(name)
result = self.get_global(name)
if result is not None:
return result
# Load the class
result = self._load_class(name, None)
......
from rpython.rlib import jit
from som.vmobjects.object import Object
from som.vmobjects.primitive import Primitive
......@@ -15,7 +17,7 @@ class Block(Object):
def get_method(self):
# Get the method of this block by reading the field with method index
return self._method
return jit.promote(self._method)
def get_context(self):
# Get the context of this block by reading the field with context index
......@@ -26,6 +28,7 @@ class Block(Object):
return self.NUMBER_OF_BLOCK_FIELDS
class Evaluation(Primitive):
_immutable_fields_ = ['_number_of_arguments']
def __init__(self, num_args, universe, invoke):
Primitive.__init__(self, self._compute_signature_string(num_args),
universe, invoke)
......
......@@ -17,13 +17,12 @@ class Frame(Array):
# Static field indices and number of frame fields
NUMBER_OF_FRAME_FIELDS = Array.NUMBER_OF_OBJECT_FIELDS
_immutable_fields_ = ["_method", "_context", "_previous_frame"]
_immutable_fields_ = ["_method", "_context"]
def __init__(self, nilObject, num_elements, method, context, previous_frame):
Array.__init__(self, nilObject, num_elements)
self._stack_pointer = 0
self._bytecode_index = 0
self._local_offset = 0
self._method = method
self._context = context
self._previous_frame = previous_frame if previous_frame else nilObject
......@@ -62,6 +61,7 @@ class Frame(Array):
# Return the found context
return frame
@jit.unroll_safe
def get_outer_context(self, nilObject):
# Compute the outer context of this frame
frame = self
......@@ -77,6 +77,9 @@ class Frame(Array):
# Get the method by reading the field with method index
return self._method
def get_number_of_arguments(self):
return self.get_method().get_number_of_arguments()
def _get_default_number_of_fields(self):
# Return the default number of fields in a frame
return self.NUMBER_OF_FRAME_FIELDS
......@@ -95,7 +98,7 @@ class Frame(Array):
def get_stack_pointer(self):
# Get the current stack pointer for this frame
return self._stack_pointer
return jit.promote(self._stack_pointer)
def set_stack_pointer(self, value):
# Set the current stack pointer for this frame
......@@ -103,10 +106,9 @@ class Frame(Array):
def reset_stack_pointer(self):
# arguments are stored in front of local variables
self._local_offset = self.get_method().get_number_of_arguments()
# Set the stack pointer to its initial value thereby clearing the stack
self.set_stack_pointer(self._local_offset +
self.set_stack_pointer(self.get_number_of_arguments() +
self.get_method().get_number_of_locals().get_embedded_integer() - 1)
def get_bytecode_index(self):
......@@ -128,10 +130,10 @@ class Frame(Array):
self.set_indexable_field(self.get_stack_pointer() - index, value)
def _get_local(self, index):
return self.get_indexable_field(self._local_offset + index)
return self.get_indexable_field(self.get_number_of_arguments() + index)
def _set_local(self, index, value):
self.set_indexable_field(self._local_offset + index, value)
self.set_indexable_field(self.get_number_of_arguments() + index, value)
def get_local(self, index, context_level):
# Get the local with the given index in the given context
......
......@@ -49,6 +49,8 @@ class Method(Array):
# Get the maximum number of stack elements
return self._maximum_number_of_stack_elements
# XXX this means that the JIT doesn't see changes to the method object
@jit.elidable_promote('all')
def get_signature(self):
# Get the signature of this method by reading the field with signature
# index
......@@ -72,6 +74,8 @@ class Method(Array):
if self.get_indexable_field(i).is_invokable():
self.get_indexable_field(i).set_holder(value)
# XXX this means that the JIT doesn't see changes to the constants
@jit.elidable_promote('all')
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))
......@@ -88,7 +92,7 @@ class Method(Array):
# Get the number of bytecodes in this method
return len(self._bytecodes)
@jit.elidable
@jit.elidable_promote('all')
def get_bytecode(self, index):
# Get the bytecode at the given index
assert 0 <= index and index < len(self._bytecodes)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment