Author: Tobias Pape <tob...@netshed.de> Branch: Changeset: r76:77ba2d81ffc9 Date: 2013-02-20 16:09 +0100 http://bitbucket.org/pypy/lang-smalltalk/changeset/77ba2d81ffc9/
Log: merge diff --git a/spyvm/fixedstack.py b/spyvm/fixedstack.py deleted file mode 100644 --- a/spyvm/fixedstack.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -A Fixed stack for SPy. -""" - -import types - -from rpython.rlib import jit -from rpython.rlib.rarithmetic import r_uint - -class FixedStack(object): - # _annspecialcase_ = "specialize:ctr_location" # polymorphic - - def __init__(self): - pass - - def setup(self, stacksize): - self.ptr = r_uint(0) # we point after the last element - self.items = [None] * stacksize - - def clone(self): - # this is only needed if we support flow space - s = self.__class__() - s.setup(len(self.items)) - for item in self.items[:self.ptr]: - try: - item = item.clone() - except AttributeError: - pass - s.push(item) - return s - - def push(self, item): - ptr = jit.promote(self.ptr) - self.items[ptr] = item - self.ptr = ptr + 1 - - def pop(self): - ptr = jit.promote(self.ptr) - 1 - ret = self.items[ptr] # you get OverflowError if the stack is empty - self.items[ptr] = None - self.ptr = ptr - return ret - - @jit.unroll_safe - def drop(self, n): - jit.promote(self.ptr) - while n > 0: - n -= 1 - self.ptr -= 1 - self.items[self.ptr] = None - - def top(self, position=0): - # for a fixed stack, we assume correct indices - rpos = r_uint(position) - return self.items[self.ptr + ~rpos] - - def set_top(self, value, position=0): - # for a fixed stack, we assume correct indices - rpos = r_uint(position) - self.items[self.ptr + ~rpos] = value - - def depth(self): - return self.ptr - - def empty(self): - return not self.ptr - - diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -370,7 +370,7 @@ self.pop() # closure bytecodes - def pushNewArrayPopIntoArray(self, interp): + def pushNewArrayBytecode(self, interp): arraySize, popIntoArray = splitter[7, 1](self.getbytecode()) newArray = None if popIntoArray == 1: @@ -388,19 +388,19 @@ w_indirectTemps = self.gettemp(index_of_array) return index_in_array, w_indirectTemps - def pushTempAtInTempVectorAt(self, interp): + def pushRemoteTempLongBytecode(self, interp): index_in_array, w_indirectTemps = self._extract_index_and_temps() self.push(w_indirectTemps.at0(self.space, index_in_array)) - def storeTempAtInTempVectorAt(self, interp): + def storeRemoteTempLongBytecode(self, interp): index_in_array, w_indirectTemps = self._extract_index_and_temps() w_indirectTemps.atput0(self.space, index_in_array, self.top()) - def popAndStoreTempAtInTempVectorAt(self, interp): + def storeAndPopRemoteTempLongBytecode(self, interp): index_in_array, w_indirectTemps = self._extract_index_and_temps() w_indirectTemps.atput0(self.space, index_in_array, self.pop()) - def pushClosureNumCopiedNumArgsBlockSize(self, interp): + def pushClosureCopyCopiedValuesBytecode(self, interp): """ Copied from Blogpost: http://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/ ContextPart>>pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize "Simulate the action of a 'closure copy' bytecode whose result is the @@ -427,16 +427,8 @@ i = self.getbytecode() blockSize = (j << 8) | i #create new instance of BlockClosure - BlockClosureShadow = space.w_BlockClosure.as_class_get_shadow(space) - w_closure = BlockClosureShadow.new(numCopied) - closure = wrapper.BlockClosureWrapper(space, w_closure) - closure.store_outerContext(self._w_self) - closure.store_startpc(self.pc()) - closure.store_numArgs(numArgs) - if numCopied > 0: - copiedValues = self.pop_and_return_n(numCopied) - for i0 in range(numCopied): - closure.atput0(i0, copiedValues[i0]) + w_closure, closure = space.newClosure(self._w_self, self.pc(), numArgs, + self.pop_and_return_n(numCopied)) self.push(w_closure) self.jump(blockSize) @@ -572,12 +564,12 @@ (135, "popStackBytecode"), (136, "duplicateTopBytecode"), (137, "pushActiveContextBytecode"), - (138, "pushNewArrayPopIntoArray"), + (138, "pushNewArrayBytecode"), (139, "experimentalBytecode"), - (140, "pushTempAtInTempVectorAt"), - (141, "storeTempAtInTempVectorAt"), - (142, "popAndStoreTempAtInTempVectorAt"), - (143, "pushClosureNumCopiedNumArgsBlockSize"), + (140, "pushRemoteTempLongBytecode"), + (141, "storeRemoteTempLongBytecode"), + (142, "storeAndPopRemoteTempLongBytecode"), + (143, "pushClosureCopyCopiedValuesBytecode"), (144, 151, "shortUnconditionalJump"), (152, 159, "shortConditionalJump"), (160, 167, "longUnconditionalJump"), diff --git a/spyvm/model.py b/spyvm/model.py --- a/spyvm/model.py +++ b/spyvm/model.py @@ -308,10 +308,9 @@ @objectmodel.specialize.arg(2) def as_special_get_shadow(self, space, TheClass): shadow = self._shadow - if shadow is None: - shadow = self.attach_shadow_of_class(space, TheClass) - elif not isinstance(shadow, TheClass): - shadow.detach_shadow() + if not isinstance(shadow, TheClass): + if shadow is not None: + shadow.detach_shadow() shadow = self.attach_shadow_of_class(space, TheClass) shadow.sync_shadow() return shadow diff --git a/spyvm/objspace.py b/spyvm/objspace.py --- a/spyvm/objspace.py +++ b/spyvm/objspace.py @@ -1,6 +1,4 @@ -from spyvm import constants -from spyvm import model -from spyvm import shadow +from spyvm import constants, model, shadow, wrapper from spyvm.error import UnwrappingError, WrappingError from rpython.rlib.objectmodel import instantiate from rpython.rlib.rarithmetic import intmask, r_uint @@ -254,9 +252,27 @@ elif isinstance(w_v, model.W_SmallInteger): return float(w_v.value) raise UnwrappingError() + def unwrap_array(self, w_array): + # Check that our argument has pointers format and the class: + if not w_array.getclass(self).is_same_object(self.w_Array): + raise PrimitiveFailedError() + assert isinstance(w_array, model.W_PointersObject) + + return [w_array.at0(self, i) for i in range(w_array.size())] + def _freeze_(self): return True + def newClosure(self, outerContext, pc, numArgs, copiedValues): + BlockClosureShadow = self.w_BlockClosure.as_class_get_shadow(self) + w_closure = BlockClosureShadow.new(len(copiedValues)) + closure = wrapper.BlockClosureWrapper(self, w_closure) + closure.store_outerContext(outerContext) + closure.store_startpc(pc) + closure.store_numArgs(numArgs) + for i0 in range(len(copiedValues)): + closure.atput0(i0, copiedValues[i0]) + return w_closure, closure def bootstrap_class(space, instsize, w_superclass=None, w_metaclass=None, name='?', format=shadow.POINTERS, varsized=False): diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -97,6 +97,9 @@ elif spec is str: assert isinstance(w_arg, model.W_BytesObject) args += (w_arg.as_string(), ) + elif spec is list: + assert isinstance(w_arg, model.W_PointersObject) + args += (interp.space.unwrap_array(w_arg), ) elif spec is char: args += (unwrap_char(w_arg), ) else: @@ -829,25 +832,20 @@ frame.pop() finalize_block_ctx(interp, s_block_ctx, frame.w_self()) -@expose_primitive(VALUE_WITH_ARGS, unwrap_spec=[object, object], +@expose_primitive(VALUE_WITH_ARGS, unwrap_spec=[object, list], no_result=True) -def func(interp, w_block_ctx, w_args): +def func(interp, w_block_ctx, args_w): assert isinstance(w_block_ctx, model.W_PointersObject) s_block_ctx = w_block_ctx.as_blockcontext_get_shadow(interp.space) exp_arg_cnt = s_block_ctx.expected_argument_count() - # Check that our arguments have pointers format and the right size: - if not w_args.getclass(interp.space).is_same_object( - interp.space.w_Array): - raise PrimitiveFailedError() - if w_args.size() != exp_arg_cnt: + if len(args_w) != exp_arg_cnt: raise PrimitiveFailedError() - assert isinstance(w_args, model.W_PointersObject) # Push all the items from the array for i in range(exp_arg_cnt): - s_block_ctx.push(w_args.at0(interp.space, i)) + s_block_ctx.push(args_w[i]) # XXX Check original logic. Image does not test this anyway # because falls back to value + internal implementation @@ -913,6 +911,80 @@ return w_rcvr # ___________________________________________________________________________ +# BlockClosure Primitives + +CLOSURE_COPY_WITH_COPIED_VALUES = 200 +CLOSURE_VALUE = 201 +CLOSURE_VALUE_ = 202 +CLOSURE_VALUE_VALUE = 203 +CLOSURE_VALUE_VALUE_VALUE = 204 +CLOSURE_VALUE_VALUE_VALUE_VALUE = 205 +CLOSURE_VALUE_WITH_ARGS = 206 #valueWithArguments: +CLOSURE_VALUE_NO_CONTEXT_SWITCH = 221 +CLOSURE_VALUE_NO_CONTEXT_SWITCH_ = 222 + +@expose_primitive(CLOSURE_COPY_WITH_COPIED_VALUES, unwrap_spec=[object, int, list]) +def func(interp, outerContext, numArgs, copiedValues): + frame = interp.s_active_context() + w_context, s_context = interp.space.newClosure(outerContext, frame.pc(), + numArgs, copiedValues) + frame.push(w_context) + + +def activateClosure(w_block_closure, args_w, mayContextSwitch=True): + if not w_block_closure.getclass(interp.space).is_same_object( + interp.space.w_BlockClosure): + raise PrimitiveFailedError() + if not w_block_closure.numArgs == len(args_w): + raise PrimitiveFailedError() + if not w_block_closure.outerContext.getclass(interp.space).issubclass( + interp.space.w_ContextPart): + raise PrimitiveFailedError() + w_closureMethod = w_block_closure.w_method() + assert isinstance(w_closureMethod, W_CompiledMethod) + assert w_block_closure is not w_block_closure.outerContext + numCopied = w_block_closure.size() + + s_block_closure = w_block_closure.as_blockclosure_get_shadow(interp.space) + s_block_closure.push_all(args_w) + + s_block_closure.store_pc(s_block_closure.initialip()) + s_block_closure.store_w_sender(frame) + + +@expose_primitive(CLOSURE_VALUE, unwrap_spec=[object]) +def func(interp, w_block_closure): + activateClosure(w_block_closure, []) + +@expose_primitive(CLOSURE_VALUE_, unwrap_spec=[object, object]) +def func(interp, w_block_closure, w_a0): + activateClosure(w_block_closure, [w_a0]) + +@expose_primitive(CLOSURE_VALUE_VALUE, unwrap_spec=[object, object, object]) +def func(interp, w_block_closure, w_a0, w_a1): + activateClosure(w_block_closure, [w_a0, w_a1]) + +@expose_primitive(CLOSURE_VALUE_VALUE_VALUE, unwrap_spec=[object, object, object, object]) +def func(interp, w_block_closure, w_a0, w_a1, w_a2): + activateClosure(w_block_closure, [w_a0, w_a1, w_a2]) + +@expose_primitive(CLOSURE_VALUE_VALUE_VALUE_VALUE, unwrap_spec=[object, object, object, object, object]) +def func(interp, w_block_closure, w_a0, w_a1, w_a2, w_a3): + activateClosure(w_block_closure, [w_a0, w_a1, w_a2, w_a3]) + +@expose_primitive(CLOSURE_VALUE_WITH_ARGS, unwrap_spec=[object, list]) +def func(interp, w_block_closure, args_w): + activateClosure(w_block_closure, args_w) + +@expose_primitive(CLOSURE_VALUE_NO_CONTEXT_SWITCH, unwrap_spec=[object]) +def func(interp, w_block_closure): + activateClosure(w_block_closure, [], mayContextSwitch=False) + +@expose_primitive(CLOSURE_VALUE_NO_CONTEXT_SWITCH_, unwrap_spec=[object, object]) +def func(interp, w_block_closure, w_a0): + activateClosure(w_block_closure, [w_a0], mayContextSwitch=False) + +# ___________________________________________________________________________ # PrimitiveLoadInstVar # # These are some wacky bytecodes in squeak. They are defined to do diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -317,10 +317,8 @@ __metaclass__ = extendabletype def __init__(self, space, w_self): - from spyvm.fixedstack import FixedStack self._w_sender = space.w_nil - self._stack = FixedStack() self.currentBytecode = -1 AbstractRedirectingShadow.__init__(self, space, w_self) @@ -339,7 +337,7 @@ if n0 == constants.CTXPART_STACKP_INDEX: return self.wrap_stackpointer() if self.stackstart() <= n0 < self.external_stackpointer(): - return self._stack.top(self.stackdepth() - (n0-self.stackstart()) - 1) + return self.peek(self.stackdepth() - (n0-self.stackstart()) - 1) if self.external_stackpointer() <= n0 < self.stackend(): return self.space.w_nil else: @@ -354,7 +352,7 @@ if n0 == constants.CTXPART_STACKP_INDEX: return self.unwrap_store_stackpointer(w_value) if self.stackstart() <= n0 < self.external_stackpointer(): - return self._stack.set_top(w_value, + return self.set_top(w_value, self.stackdepth() - (n0-self.stackstart()) - 1) return if self.external_stackpointer() <= n0 < self.stackend(): @@ -375,10 +373,10 @@ if size < depth: # TODO Warn back to user assert size >= 0 - self._stack.drop(depth - size) + self.pop_n(depth - size) else: for i in range(depth, size): - self._stack.push(self.space.w_nil) + self.push(self.space.w_nil) def wrap_stackpointer(self): return self.space.wrap_int(self.stackdepth() + @@ -475,20 +473,32 @@ def settemp(self, index, w_value): self.s_home().settemp(index, w_value) + @jit.unroll_safe + def init_stack_and_temps(self): + stacksize = self.stackend() - self.stackstart() + tempsize = self.tempsize() + self._temps_and_stack = [None] * (stacksize + tempsize) + for i in range(tempsize): + self._temps_and_stack[i] = self.space.w_nil + self._stack_ptr = rarithmetic.r_uint(tempsize) # we point after the last element + # ______________________________________________________________________ # Stack Manipulation - def init_stack(self): - self._stack.setup(self.stackend() - self.stackstart()) - def stack(self): """NOT_RPYTHON""" # purely for testing - return self._stack.items[:self.stackdepth()] + return self._temps_and_stack[self.tempsize():self._stack_ptr] def pop(self): - return self._stack.pop() + ptr = jit.promote(self._stack_ptr) - 1 + ret = self._temps_and_stack[ptr] # you get OverflowError if the stack is empty + self._temps_and_stack[ptr] = None + self._stack_ptr = ptr + return ret def push(self, w_v): - self._stack.push(w_v) + ptr = jit.promote(self._stack_ptr) + self._temps_and_stack[ptr] = w_v + self._stack_ptr = ptr + 1 def push_all(self, lst): for elt in lst: @@ -496,18 +506,29 @@ def top(self): return self.peek(0) - + + def set_top(self, value, position=0): + rpos = rarithmetic.r_uint(position) + self._temps_and_stack[self._stack_ptr + ~rpos] = value + def peek(self, idx): - return self._stack.top(idx) + rpos = rarithmetic.r_uint(idx) + return self._temps_and_stack[self._stack_ptr + ~rpos] + @jit.unroll_safe def pop_n(self, n): - self._stack.drop(n) + jit.promote(self._stack_ptr) + while n > 0: + n -= 1 + self._stack_ptr -= 1 + self._temps_and_stack[self._stack_ptr] = None def stackdepth(self): - return rarithmetic.intmask(self._stack.depth()) + return rarithmetic.intmask(self._stack_ptr - self.tempsize()) + @jit.unroll_safe def pop_and_return_n(self, n): - result = [self._stack.top(i) for i in range(n - 1, -1, -1)] + result = [self.peek(i) for i in range(n - 1, -1, -1)] self.pop_n(n) return result @@ -533,7 +554,7 @@ s_result.store_initialip(initialip) s_result.store_w_home(w_home) s_result.store_pc(initialip) - s_result.init_stack() + s_result.init_stack_and_temps() return w_result def fetch(self, n0): @@ -559,7 +580,7 @@ def attach_shadow(self): # Make sure the home context is updated first self.copy_from_w_self(constants.BLKCTX_HOME_INDEX) - self.init_stack() + self.init_stack_and_temps() ContextPartShadow.attach_shadow(self) def unwrap_store_initialip(self, w_value): @@ -617,6 +638,7 @@ ContextPartShadow.__init__(self, space, w_self) @staticmethod + @jit.unroll_safe def make_context(space, w_method, w_receiver, arguments, w_sender=None): # From blue book: normal mc have place for 12 temps+maxstack @@ -634,10 +656,9 @@ s_result.store_w_sender(w_sender) s_result.store_w_receiver(w_receiver) s_result.store_pc(0) - s_result._temps = [space.w_nil] * w_method.tempsize + s_result.init_stack_and_temps() for i in range(len(arguments)): s_result.settemp(i, arguments[i]) - s_result.init_stack() return w_result def fetch(self, n0): @@ -672,9 +693,7 @@ def attach_shadow(self): # Make sure the method is updated first self.copy_from_w_self(constants.MTHDCTX_METHOD) - self.init_stack() - # And that there is space for the temps - self._temps = [self.space.w_nil] * self.tempsize() + self.init_stack_and_temps() ContextPartShadow.attach_shadow(self) def tempsize(self): @@ -694,10 +713,10 @@ self._w_receiver = w_receiver def gettemp(self, index0): - return self._temps[index0] + return self._temps_and_stack[index0] def settemp(self, index0, w_value): - self._temps[index0] = w_value + self._temps_and_stack[index0] = w_value def w_home(self): return self.w_self() diff --git a/spyvm/test/test_interpreter.py b/spyvm/test/test_interpreter.py --- a/spyvm/test/test_interpreter.py +++ b/spyvm/test/test_interpreter.py @@ -831,7 +831,7 @@ option.bc_trace = bc_trace # Closure Bytecodes -def test_bc_pushNewArrayPopIntoArray(bytecode=pushNewArrayPopIntoArray): +def test_bc_pushNewArrayBytecode(bytecode=pushNewArrayBytecode): interp = new_interpreter(bytecode + chr(0x83)) context = interp.s_active_context() context.push(fakeliterals(space, "egg")) @@ -843,7 +843,7 @@ assert array.at0(space, 1) == fakeliterals(space, "bar") assert array.at0(space, 2) == fakeliterals(space, "baz") -def test_bc_pushNewArray(bytecode=pushNewArrayPopIntoArray): +def test_bc_pushNewArray(bytecode=pushNewArrayBytecode): interp = new_interpreter(bytecode + chr(0x07)) context = interp.s_active_context() interp.step(interp.s_active_context()) @@ -851,7 +851,7 @@ assert array.size() == 7 assert array.at0(space, 0) == space.w_nil -def test_pushTempAt0InTempVectorAt0(bytecode = pushTempAtInTempVectorAt): +def test_bc_pushRemoteTempLongBytecode(bytecode = pushRemoteTempLongBytecode): interp = new_interpreter(bytecode + chr(0) + chr(0)) context = interp.s_active_context() context.push(fakeliterals(space, "jam")) @@ -871,21 +871,21 @@ interp.step(context) return context, temp_array -def test_pushTempAt3InTempVectorAt1(bytecode = pushTempAtInTempVectorAt): +def test_bc_pushRemoteTempLongBytecode2(bytecode = pushRemoteTempLongBytecode): context, _ = setupTempArrayAndContext(bytecode) assert context.top() == fakeliterals(space, "pub") -def test_storeTempAtInTempVectorAt(bytecode = storeTempAtInTempVectorAt): +def test_bc_storeRemoteTempLongBytecode(bytecode = storeRemoteTempLongBytecode): context, temp_array = setupTempArrayAndContext(bytecode) assert context.top() == fakeliterals(space, "bar") assert temp_array.at0(space, 2) == fakeliterals(space, "bar") -def test_popAndStoreTempAtInTempVectorAt(bytecode = popAndStoreTempAtInTempVectorAt): +def test_bc_storeAndPopRemoteTempLongBytecode(bytecode = storeAndPopRemoteTempLongBytecode): context, temp_array = setupTempArrayAndContext(bytecode) assert temp_array.at0(space, 2) == fakeliterals(space, "bar") assert context.top() == fakeliterals(space, "english") -def test_pushClosureNumCopied0NumArgsBlockSize(bytecode = pushClosureNumCopiedNumArgsBlockSize): +def test_bc_pushClosureCopyCopied0ValuesBytecode(bytecode = pushClosureCopyCopiedValuesBytecode): for i in (0, 0xF0, 0x0FF0, 0xFFF0): interp = new_interpreter(bytecode + chr(2) + chr(i >> 8) + chr(i & 0xFF)) context = interp.s_active_context() @@ -897,7 +897,7 @@ assert closure.startpc() == pc + 4 assert closure.outerContext() is context._w_self -def test_pushClosureNumCopied2NumArgsBlockSize(bytecode = pushClosureNumCopiedNumArgsBlockSize): +def test_bc_pushClosureCopyCopied2ValuesBytecode(bytecode = pushClosureCopyCopiedValuesBytecode): interp = new_interpreter(bytecode + chr(0x23) + chr(0) + chr(0)) context = interp.s_active_context() context.push("english") diff --git a/spyvm/test/test_primitives.py b/spyvm/test/test_primitives.py --- a/spyvm/test/test_primitives.py +++ b/spyvm/test/test_primitives.py @@ -16,7 +16,7 @@ def __init__(self, stack): self._vars = [None] * 6 + stack s_self = self.as_blockcontext_get_shadow() - s_self.init_stack() + s_self.init_stack_and_temps() s_self.reset_stack() s_self.push_all(stack) s_self.store_expected_argument_count(0) @@ -30,6 +30,7 @@ if isinstance(x, model.W_Object): return x if isinstance(x, str) and len(x) == 1: return space.wrap_char(x) if isinstance(x, str): return space.wrap_string(x) + if isinstance(x, list): return space.wrap_list(x) raise NotImplementedError def mock(stack): diff --git a/spyvm/todo.txt b/spyvm/todo.txt --- a/spyvm/todo.txt +++ b/spyvm/todo.txt @@ -22,5 +22,3 @@ Shadows: [ ] Fix invalidation of methoddictshadow when the w_self of its values array changes -Lars ToDo -[ ] different image with BlockClosure instead of BlockContext _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit