Commit 91c4af20 authored by Stefan Marr's avatar Stefan Marr

Changing to new object model of core-lib

Introduction of AbstractObject without fields and classes.
Methods are not Arrays anymore to simplify and avoid use of 'object fields'.
Frames are not entirely implementation specific.

- clean out superficial comments
- added missing primitives
Signed-off-by: 's avatarStefan Marr <git@stefan-marr.de>
parent 9bd2c541
Subproject commit 555c692765b3853feb7fa3cdcd260440d9ec1422
Subproject commit b2d362a1f4ffdb6a2a6ad036eb8d582073ddad45
......@@ -67,7 +67,7 @@ class ClassGenerationContext(object):
result_class.set_instance_invokables(self._universe.new_array_from_list(self._class_methods))
result_class.set_name(self._universe.symbol_for(ccname))
super_mclass = super_class.get_class()
super_mclass = super_class.get_class(self._universe)
result_class.set_super_class(super_mclass)
# Allocate the resulting class
......@@ -86,6 +86,6 @@ class ClassGenerationContext(object):
system_class.set_instance_fields(self._universe.new_array_from_list(self._instance_fields))
# class-bound == class-instance-bound
super_mclass = system_class.get_class()
super_mclass = system_class.get_class(self._universe.nilObject)
super_mclass.set_instance_invokables(self._universe.new_array_from_list(self._class_methods))
super_mclass.set_instance_fields(self._universe.new_array_from_list(self._class_fields))
from som.vm.universe import error_print, error_println
from som.vm.universe import error_print, error_println, get_current
from som.interpreter.bytecodes import bytecode_as_str, bytecode_length, Bytecodes
def dump(clazz):
......@@ -61,7 +61,7 @@ def dump_method(m, indent):
constant = m.get_constant(b)
error_println("(index: " + str(m.get_bytecode(b + 1)) +
") value: (" +
str(constant.get_class().get_name()) +
str(constant.get_class(get_current()).get_name()) +
") " + str(constant))
elif bytecode == Bytecodes.push_global:
error_println("(index: " + str(m.get_bytecode(b + 1)) +
......
......@@ -29,21 +29,13 @@ class MethodGenerationContext(object):
return empty_primitive(self._signature.get_string(), universe)
def assemble(self, universe):
# create a method instance with the given number of bytecodes and literals
num_literals = len(self._literals)
num_locals = len(self._locals)
num_locals = len(self._locals)
meth = universe.new_method(self._signature,
len(self._bytecode),
num_literals,
self._literals,
universe.new_integer(num_locals),
universe.new_integer(self._compute_stack_depth()))
# copy literals into the method
i = 0
for l in self._literals:
meth.set_indexable_field(i, l)
i += 1
# copy bytecodes into method
i = 0
......
......@@ -89,7 +89,7 @@ class Parser(object):
if super_name.get_string() != "nil":
super_class = self._universe.load_class(super_name)
cgenc.set_instance_fields_of_super(super_class.get_instance_fields())
cgenc.set_class_fields_of_super(super_class.get_class().get_instance_fields())
cgenc.set_class_fields_of_super(super_class.get_class(self._universe).get_instance_fields())
else:
# WARNING:
# We hardcode here the field names for Class
......
from rpython.rlib import jit
from som.vmobjects.array import Array
# Frame layout:
#
......@@ -12,128 +11,105 @@ from som.vmobjects.array import Array
# | ... |
# +-----------------+
#
class Frame(Array):
# Static field indices and number of frame fields
NUMBER_OF_FRAME_FIELDS = Array.NUMBER_OF_OBJECT_FIELDS
_immutable_fields_ = ["_method", "_context"]
class Frame(object):
_immutable_fields_ = ["_method", "_context", "_stack"]
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._method = method
self._context = context
self._previous_frame = previous_frame if previous_frame else nilObject
self._stack = [nilObject] * num_elements
self._stack_pointer = 0
self._bytecode_index = 0
self._previous_frame = previous_frame
def get_previous_frame(self):
# Get the previous frame by reading the field with previous frame index
return self._previous_frame
def clear_previous_frame(self, nilObject):
# Set the previous frame to nil
self._previous_frame = nilObject
def clear_previous_frame(self):
self._previous_frame = None
def has_previous_frame(self, nilObject):
return self._previous_frame != nilObject
def has_previous_frame(self):
return self._previous_frame is not None
def is_bootstrap_frame(self, nilObject):
return not self.has_previous_frame(nilObject)
def is_bootstrap_frame(self):
return not self.has_previous_frame()
def get_context(self):
# Get the context by reading the field with context index
return self._context
def has_context(self, nilObject):
return self._context != nilObject
def has_context(self):
return self._context is not None
@jit.unroll_safe
def _get_context(self, level):
# Get the context frame at the given level
""" Get the context frame at the given level """
frame = self
# Iterate through the context chain until the given level is reached
for _ in range(level, 0, -1):
# Get the context of the current frame
frame = frame.get_context()
# Return the found context
return frame
@jit.unroll_safe
def get_outer_context(self, nilObject):
# Compute the outer context of this frame
def get_outer_context(self):
""" Compute the outer context of this frame """
frame = self
# Iterate through the context chain until null is reached
while frame.has_context(nilObject):
while frame.has_context():
frame = frame.get_context()
# Return the outer context
return frame
def get_method(self):
# 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
return self._method.get_number_of_arguments()
def pop(self):
# Pop an object from the expression stack and return it
stack_pointer = self.get_stack_pointer()
self.set_stack_pointer(stack_pointer - 1)
return self.get_indexable_field(stack_pointer)
""" Pop an object from the expression stack and return it """
stack_pointer = self._stack_pointer
self._stack_pointer = stack_pointer - 1
return self._stack[stack_pointer]
def push(self, value):
# Push an object onto the expression stack
stack_pointer = self.get_stack_pointer() + 1
self.set_indexable_field(stack_pointer, value)
self.set_stack_pointer(stack_pointer)
def get_stack_pointer(self):
# Get the current stack pointer for this frame
return jit.promote(self._stack_pointer)
def set_stack_pointer(self, value):
# Set the current stack pointer for this frame
self._stack_pointer = value
""" Push an object onto the expression stack """
stack_pointer = self._stack_pointer + 1
self._stack[stack_pointer] = value
self._stack_pointer = stack_pointer
def reset_stack_pointer(self):
""" Set the stack pointer to its initial value thereby clearing
the stack """
# arguments are stored in front of local variables
# Set the stack pointer to its initial value thereby clearing the stack
self.set_stack_pointer(self.get_number_of_arguments() +
self._stack_pointer = (self.get_number_of_arguments() +
self.get_method().get_number_of_locals().get_embedded_integer() - 1)
def get_bytecode_index(self):
# Get the current bytecode index for this frame
return self._bytecode_index
def set_bytecode_index(self, value):
# Set the current bytecode index for this frame
self._bytecode_index = value
def get_stack_element(self, index):
# Get the stack element with the given index
# (an index of zero yields the top element)
return self.get_indexable_field(self.get_stack_pointer() - index)
return self._stack[self._stack_pointer - index]
def set_stack_element(self, index, value):
# Set the stack element with the given index to the given value
# (an index of zero yields the top element)
self.set_indexable_field(self.get_stack_pointer() - index, value)
self._stack[self._stack_pointer - index] = value
def _get_local(self, index):
return self.get_indexable_field(self.get_number_of_arguments() + index)
return self._stack[self.get_number_of_arguments() + index]
def _set_local(self, index, value):
self.set_indexable_field(self.get_number_of_arguments() + index, value)
self._stack[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
......@@ -149,14 +125,14 @@ class Frame(Array):
context = self._get_context(context_level)
# Get the argument with the given index
return context.get_indexable_field(index)
return context._stack[index]
def set_argument(self, index, context_level, value):
# Get the context
context = self._get_context(context_level)
# Set the argument with the given index to the given value
context.set_indexable_field(index, value)
context._stack[index] = value
@jit.unroll_safe
def copy_arguments_from(self, frame):
......@@ -165,7 +141,7 @@ class Frame(Array):
# - copy them into the argument area of the current frame
num_args = self.get_method().get_number_of_arguments()
for i in range(0, num_args):
self.set_indexable_field(i, frame.get_stack_element(num_args - 1 - i))
self._stack[i] = frame.get_stack_element(num_args - 1 - i)
def print_stack_trace(self, nilObject):
# Print a stack trace starting in this frame
......@@ -174,5 +150,5 @@ class Frame(Array):
std_println(" %d @ %s" % (self.get_bytecode_index(),
self.get_method().get_signature().get_string()))
if self.has_previous_frame(nilObject):
self.get_previous_frame().print_stack_trace(nilObject)
if self.has_previous_frame():
self.get_previous_frame().print_stack_trace()
from som.interpreter.bytecodes import bytecode_length, Bytecodes
from som.vmobjects.clazz import Class
from rpython.rlib import jit
......@@ -122,16 +123,16 @@ class Interpreter(object):
result = frame.pop()
# Compute the context for the non-local return
context = frame.get_outer_context(self._universe.nilObject)
context = frame.get_outer_context()
# Make sure the block context is still on the stack
if not context.has_previous_frame(self._universe.nilObject):
if not context.has_previous_frame():
# Try to recover by sending 'escapedBlock:' to the sending 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 = frame.get_argument(0, 0)
sender = frame.get_previous_frame().get_outer_context(self._universe.nilObject).get_argument(0, 0)
sender = frame.get_previous_frame().get_outer_context().get_argument(0, 0)
# pop the frame of the currently executing block...
self._pop_frame()
......@@ -141,7 +142,7 @@ class Interpreter(object):
return
# Unwind the frames
while self.get_frame() != context:
while self.get_frame() is not context:
self._pop_frame()
# Pop the top frame and push the result
......@@ -158,7 +159,7 @@ class Interpreter(object):
receiver = frame.get_stack_element(num_args - 1)
# Send the message
self._send(signature, receiver.get_class(), bytecode_index)
self._send(signature, receiver.get_class(self._universe), bytecode_index)
def start(self):
......@@ -241,7 +242,7 @@ class Interpreter(object):
def get_self(self):
# Get the self object from the interpreter
return self.get_frame().get_outer_context(self._universe.nilObject).get_argument(0, 0)
return self.get_frame().get_outer_context().get_argument(0, 0)
def _send(self, selector, receiver_class, bytecode_index):
# First try the inline cache
......@@ -283,7 +284,7 @@ class Interpreter(object):
self.set_frame(self._frame.get_previous_frame())
# Destroy the previous pointer on the old top frame
result.clear_previous_frame(self._universe.nilObject)
result.clear_previous_frame()
# Return the popped frame
return result
......
......@@ -6,6 +6,26 @@ def _new(ivkbl, frame, interpreter):
rcvr = frame.pop()
frame.push(interpreter.get_universe().new_instance(rcvr))
def _name(ivkbl, frame, interpreter):
rcvr = frame.pop()
frame.push(rcvr.get_name())
def _super_class(ivkbl, frame, interpreter):
rcvr = frame.pop()
frame.push(rcvr.get_super_class())
def _methods(ivkbl, frame, interpreter):
rcvr = frame.pop()
frame.push(rcvr.get_instance_invokables())
def _fields(ivkbl, frame, interpreter):
rcvr = frame.pop()
frame.push(rcvr.get_instance_fields())
class ClassPrimitives(Primitives):
def install_primitives(self):
self._install_instance_primitive(Primitive("new", self._universe, _new))
\ No newline at end of file
self._install_instance_primitive(Primitive("new", self._universe, _new))
self._install_instance_primitive(Primitive("name", self._universe, _name))
self._install_instance_primitive(Primitive("superclass", self._universe, _super_class))
self._install_instance_primitive(Primitive("methods", self._universe, _methods))
self._install_instance_primitive(Primitive("fields", self._universe, _fields))
from som.primitives.primitives import Primitives
from som.vmobjects.primitive import Primitive
def _holder(ivkbl, frame, interpreter):
rcvr = frame.pop()
frame.push(rcvr.get_holder())
def _signature(ivkbl, frame, interpreter):
rcvr = frame.pop()
frame.push(rcvr.get_signature())
class MethodPrimitives(Primitives):
def install_primitives(self):
self._install_instance_primitive(Primitive("holder", self._universe, _holder))
self._install_instance_primitive(Primitive("signature", self._universe, _signature))
......@@ -2,6 +2,7 @@ from rpython.rlib.objectmodel import compute_identity_hash
from som.primitives.primitives import Primitives
from som.vmobjects.object import Object
from som.vmobjects.primitive import Primitive
from som.vmobjects.array import Array
......@@ -20,9 +21,12 @@ def _hashcode(ivkbl, frame, interpreter):
def _objectSize(ivkbl, frame, interpreter):
rcvr = frame.pop()
size = rcvr.get_number_of_fields()
if isinstance(rcvr, Array):
size += rcvr.get_number_of_indexable_fields()
size = 0
if isinstance(rcvr, Object):
size = rcvr.get_number_of_fields()
elif isinstance(rcvr, Array):
size = rcvr.get_number_of_indexable_fields()
frame.push(interpreter.get_universe().new_integer(size))
......@@ -30,7 +34,7 @@ def _perform(ivkbl, frame, interpreter):
selector = frame.pop()
rcvr = frame.get_stack_element(0)
invokable = rcvr.get_class().lookup_invokable(selector)
invokable = rcvr.get_class(interpreter.get_universe()).lookup_invokable(selector)
invokable.invoke(frame, interpreter)
def _performInSuperclass(ivkbl, frame, interpreter):
......@@ -49,7 +53,7 @@ def _performWithArguments(ivkbl, frame, interpreter):
for i in range(0, args.get_number_of_indexable_fields()):
frame.push(args.get_indexable_field(i))
invokable = rcvr.get_class().lookup_invokable(selector)
invokable = rcvr.get_class(interpreter.get_universe()).lookup_invokable(selector)
invokable.invoke(frame, interpreter)
def _instVarAt(ivkbl, frame, interpreter):
......@@ -71,7 +75,7 @@ def _halt(ivkbl, frame, interpreter):
def _class(ivkbl, frame, interpreter):
rcvr = frame.pop()
frame.push(rcvr.get_class())
frame.push(rcvr.get_class(interpreter.get_universe()))
......
from som.primitives.primitives import Primitives
from som.vmobjects.primitive import Primitive
def _holder(ivkbl, frame, interpreter):
rcvr = frame.pop()
frame.push(rcvr.get_holder())
def _signature(ivkbl, frame, interpreter):
rcvr = frame.pop()
frame.push(rcvr.get_signature())
class PrimitivePrimitives(Primitives):
def install_primitives(self):
self._install_instance_primitive(Primitive("holder", self._universe, _holder))
self._install_instance_primitive(Primitive("signature", self._universe, _signature))
......@@ -21,4 +21,4 @@ class Primitives(object):
def _install_class_primitive(self, primitive):
# Install the given primitive as an instance primitive in the class of
# the holder class
self._holder.get_class().add_instance_primitive(primitive)
self._holder.get_class(self._universe).add_instance_primitive(primitive)
......@@ -20,11 +20,12 @@ def _length(ivkbl, frame, interpreter):
def _equals(ivkbl, frame, interpreter):
op1 = frame.pop()
op2 = frame.pop() # rcvr
if op1.get_class() == interpreter.get_universe().stringClass:
universe = interpreter.get_universe()
if op1.get_class(universe) == universe.stringClass:
if op1.get_embedded_string() == op2.get_embedded_string():
frame.push(interpreter.get_universe().trueObject)
frame.push(universe.trueObject)
return
frame.push(interpreter.get_universe().falseObject)
frame.push(universe.falseObject)
def _substring(ivkbl, frame, interpreter):
end = frame.pop()
......
......@@ -20,7 +20,7 @@ class Shell(object):
std_println("SOM Shell. Type \"quit\" to exit.\n");
# Create a fake bootstrap frame
current_frame = self._interpreter.push_new_frame(self._bootstrap_method, self._universe.nilObject)
current_frame = self._interpreter.push_new_frame(self._bootstrap_method, None)
# Remember the first bytecode index, e.g. index of the halt instruction
bytecode_index = current_frame.get_bytecode_index()
......
This diff is collapsed.
class AbstractObject(object):
def send(self, selector_string, arguments, universe, interpreter):
# Turn the selector string into a selector
selector = universe.symbol_for(selector_string)
# Push the receiver onto the stack
interpreter.get_frame().push(self)
# Push the arguments onto the stack
for arg in arguments:
interpreter.get_frame().push(arg)
# Lookup the invokable
invokable = self.get_class(universe).lookup_invokable(selector)
# Invoke the invokable
invokable.invoke(interpreter.get_frame(), interpreter)
def send_does_not_understand(self, selector, universe, interpreter):
# Compute the number of arguments
number_of_arguments = selector.get_number_of_signature_arguments()
frame = interpreter.get_frame()
frame.print_stack_trace(universe.nilObject)
# Allocate an array with enough room to hold all arguments
arguments_array = universe.new_array_with_length(number_of_arguments)
# Remove all arguments and put them in the freshly allocated array
i = number_of_arguments - 1
while i >= 0:
arguments_array.set_indexable_field(i, frame.pop())
i -= 1
args = [selector, arguments_array]
self.send("doesNotUnderstand:arguments:", args, universe, interpreter)
def send_unknown_global(self, global_name, universe, interpreter):
arguments = [global_name]
self.send("unknownGlobal:", arguments, universe, interpreter)
def send_escaped_block(self, block, universe, interpreter):
arguments = [block]
self.send("escapedBlock:", arguments, universe, interpreter)
def get_class(self, universe):
raise NotImplementedError("Subclasses need to implement get_class(universe).")
def is_invokable(self):
return False
def __str__(self):
from som.vm.universe import get_current
return "a " + self.get_class(get_current()).get_name().get_string()
from som.vmobjects.object import Object
from som.vmobjects.abstract_object import AbstractObject
class Array(Object):
class Array(AbstractObject):
_immutable_fields_ = ["_indexable_fields"]
def __init__(self, nilObject, number_of_indexable_fields):
Object.__init__(self, nilObject)
AbstractObject.__init__(self)
# Private array of indexable fields
self._indexable_fields = [nilObject] * number_of_indexable_fields
......@@ -41,3 +41,6 @@ class Array(Object):
# Copy all indexable fields from this array to the destination array
for i in range(self.get_number_of_indexable_fields()):
destination.set_indexable_field(i, self.get_indexable_field(i))
def get_class(self, universe):
return universe.arrayClass
from som.vmobjects.object import Object
from som.vmobjects.abstract_object import AbstractObject
class BigInteger(Object):
class BigInteger(AbstractObject):
_immutable_fields_ = ["_embedded_biginteger"]
def __init__(self, nilObject, value):
Object.__init__(self, nilObject)
def __init__(self, value):
AbstractObject.__init__(self)
self._embedded_biginteger = value
def get_embedded_biginteger(self):
......@@ -14,3 +14,6 @@ class BigInteger(Object):
def get_embedded_value(self):
"""This Method is polymorphic with Integer"""
return self._embedded_biginteger
def get_class(self, universe):
return universe.bigintegerClass
from rpython.rlib import jit
from som.vmobjects.object import Object
from som.vmobjects.abstract_object import AbstractObject
from som.vmobjects.primitive import Primitive
class Block(Object):
NUMBER_OF_BLOCK_FIELDS = Object.NUMBER_OF_OBJECT_FIELDS
class Block(AbstractObject):
_immutable_fields_ = ["_method", "_context"]
def __init__(self, nilObject, method, context):
Object.__init__(self, nilObject)
self._number_of_arguments = 0
def __init__(self, method, context):
AbstractObject.__init__(self)
self._method = method
self._context = context
def get_method(self):
# Get the method of this block by reading the field with method index
return jit.promote(self._method)
def get_context(self):
# Get the context of this block by reading the field with context index
return self._context
def _get_default_number_of_fields(self):
# Return the default number of fields for a block
return self.NUMBER_OF_BLOCK_FIELDS
def get_class(self, universe):
return universe.blockClasses[self._method.get_number_of_arguments()]
class Evaluation(Primitive):
_immutable_fields_ = ['_number_of_arguments']
......
from som.vmobjects.object import Object
from som.primitives.primitives import Primitives
class Class(Object):
# Static field indices and number of class fields
SUPER_CLASS_INDEX = Object.NUMBER_OF_OBJECT_FIELDS
NAME_INDEX = 1 + SUPER_CLASS_INDEX
INSTANCE_FIELDS_INDEX = 1 + NAME_INDEX
INSTANCE_INVOKABLES_INDEX = 1 + INSTANCE_FIELDS_INDEX
NUMBER_OF_CLASS_FIELDS = 1 + INSTANCE_INVOKABLES_INDEX
_immutable_fields_ = ["_super_class"
"_name",
"_instance_fields"
"_instance_invokables"]
def __init__(self, universe, number_of_fields=-1):
Object.__init__(self, universe.nilObject, number_of_fields)
self._super_class = universe.nilObject
self._name = None
self._instance_fields = None
self._instance_invokables = None
self._invokables_table = {}
self._universe = universe
def get_super_class(self):
# Get the super class by reading the field with super class index
return self.get_field(self.SUPER_CLASS_INDEX)
return self._super_class
def set_super_class(self, value):
# Set the super class by writing to the field with super class index
self.set_field(self.SUPER_CLASS_INDEX, value)
self._super_class = value
def has_super_class(self):
# Check whether or not this class has a super class
return self.get_field(self.SUPER_CLASS_INDEX) != self._universe.nilObject
return self._super_class is not self._universe.nilObject
def get_name(self):
# Get the name of this class by reading the field with name index
return self.get_field(self.NAME_INDEX)
return self._name
def set_name(self, value):
# Set the name of this class by writing to the field with name index
self.set_field(self.NAME_INDEX, value)
self._name = value
def get_instance_fields(self):
# Get the instance fields by reading the field with the instance fields index
return self.get_field(self.INSTANCE_FIELDS_INDEX)
return self._instance_fields
def set_instance_fields(self, value):
# Set the instance fields by writing to the field with the instance fields index
self.set_field(self.INSTANCE_FIELDS_INDEX, value)
self._instance_fields = value
def get_instance_invokables(self):
# Get the instance invokables by reading the field with the instance
# invokables index
return self.get_field(self.INSTANCE_INVOKABLES_INDEX)
return self._instance_invokables
def set_instance_invokables(self, value):
# Set the instance invokables by writing to the field with the instance
# invokables index
self.set_field(self.INSTANCE_INVOKABLES_INDEX, value)
self._instance_invokables = value
# Make sure this class is the holder of all invokables in the array
for i in range(0, self.get_number_of_instance_invokables()):
......@@ -62,24 +50,18 @@ class Class(Object):
invokable.set_holder(self)
def get_number_of_instance_invokables(self):