WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

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

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