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

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: default 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()
......
......@@ -3,7 +3,9 @@ from rpython.rlib import jit
from som.interpreter.interpreter import Interpreter
from som.interpreter.bytecodes import Bytecodes
from som.interpreter.frame import Frame
from som.vm.symbol_table import SymbolTable
from som.vmobjects.abstract_object import AbstractObject
from som.vmobjects.object import Object
from som.vmobjects.clazz import Class
from som.vmobjects.array import Array
......@@ -12,7 +14,6 @@ from som.vmobjects.method import Method
from som.vmobjects.integer import Integer
from som.vmobjects.string import String
from som.vmobjects.block import Block, block_evaluation_primitive
from som.vmobjects.frame import Frame
from som.vmobjects.biginteger import BigInteger
from som.vmobjects.double import Double
......@@ -63,7 +64,6 @@ class Universe(object):
self.arrayClass = None
self.methodClass = None
self.symbolClass = None
self.frameClass = None
self.primitiveClass = None
self.systemClass = None
self.blockClass = None
......@@ -97,7 +97,7 @@ class Universe(object):
clazz = self.load_class(self.symbol_for(class_name))
# Lookup the invokable on class
invokable = clazz.get_class().lookup_invokable(self.symbol_for(selector))
invokable = clazz.get_class(self).lookup_invokable(self.symbol_for(selector))
bootstrap_method = self._create_bootstrap_method()
bootstrap_frame = self._create_bootstrap_frame(bootstrap_method, clazz)
......@@ -106,7 +106,7 @@ class Universe(object):
def _create_bootstrap_method(self):
# Create a fake bootstrap method to simplify later frame traversal
bootstrap_method = self.new_method(self.symbol_for("bootstrap"), 1, 0,
bootstrap_method = self.new_method(self.symbol_for("bootstrap"), 1, [],
self.new_integer(0),
self.new_integer(2))
bootstrap_method.set_bytecode(0, Bytecodes.halt)
......@@ -115,7 +115,7 @@ class Universe(object):
def _create_bootstrap_frame(self, bootstrap_method, receiver, arguments = None):
# Create a fake bootstrap frame with the system object on the stack
bootstrap_frame = self._interpreter.push_new_frame(bootstrap_method, self.nilObject)
bootstrap_frame = self._interpreter.push_new_frame(bootstrap_method, None)
bootstrap_frame.push(receiver)
if arguments:
......@@ -230,7 +230,6 @@ class Universe(object):
self.methodClass = self.new_system_class()
self.integerClass = self.new_system_class()
self.bigintegerClass = self.new_system_class()
self.frameClass = self.new_system_class()
self.primitiveClass = self.new_system_class()
self.stringClass = self.new_system_class()
self.doubleClass = self.new_system_class()
......@@ -248,7 +247,6 @@ class Universe(object):
self._initialize_system_class(self.symbolClass, self.objectClass, "Symbol")
self._initialize_system_class(self.integerClass, self.objectClass, "Integer")
self._initialize_system_class(self.bigintegerClass, self.objectClass, "BigInteger")
self._initialize_system_class(self.frameClass, self.arrayClass, "Frame")
self._initialize_system_class(self.primitiveClass, self.objectClass, "Primitive")
self._initialize_system_class(self.stringClass, self.objectClass, "String")
self._initialize_system_class(self.doubleClass, self.objectClass, "Double")
......@@ -263,7 +261,6 @@ class Universe(object):
self._load_system_class(self.symbolClass)
self._load_system_class(self.integerClass)
self._load_system_class(self.bigintegerClass)
self._load_system_class(self.frameClass)
self._load_system_class(self.primitiveClass)
self._load_system_class(self.stringClass)
self._load_system_class(self.doubleClass)
......@@ -313,12 +310,7 @@ class Universe(object):
return result
def new_array_with_length(self, length):
# Allocate a new array and set its class to be the array class
result = Array(self.nilObject, length)
result.set_class(self.arrayClass)
# Return the freshly allocated array
return result
return Array(self.nilObject, length)
def new_array_from_list(self, values):
# Allocate a new array with the same length as the list
......@@ -327,8 +319,7 @@ class Universe(object):
# Copy all elements from the list into the array
for i in range(len(values)):
result.set_indexable_field(i, values[i])
# Return the allocated and initialized array
return result
def new_array_with_strings(self, strings):
......@@ -339,23 +330,15 @@ class Universe(object):
for i in range(len(strings)):
result.set_indexable_field(i, self.new_string(strings[i]))
# Return the allocated and initialized array
return result
def new_block(self, method, context_frame, arguments):
# Allocate a new block and set its class to be the block class
result = Block(self.nilObject, method, context_frame)
result.set_class(self._get_block_class(arguments))
# Return the freshly allocated block
return result
return Block(method, context_frame)
def new_class(self, class_class):
# Allocate a new class and set its class to be the given class class
result = Class(self, class_class.get_number_of_instance_fields())
result.set_class(class_class)
# Return the freshly allocated class
return result
def new_frame(self, previous_frame, method, context):
......@@ -366,65 +349,31 @@ class Universe(object):
method.get_number_of_locals().get_embedded_integer() +