Author: Carl Friedrich Bolz <[email protected]>
Branch: 
Changeset: r87:2ece4888b751
Date: 2013-02-22 11:50 +0100
http://bitbucket.org/pypy/lang-smalltalk/changeset/2ece4888b751/

Log:    merge

diff --git a/spyvm/constants.py b/spyvm/constants.py
--- a/spyvm/constants.py
+++ b/spyvm/constants.py
@@ -38,12 +38,15 @@
 
 # MethodContext < ContextPart
 MTHDCTX_METHOD = 3
-MTHDCTX_RECEIVER_MAP = 4
+MTHDCTX_CLOSURE_OR_NIL = 4
 MTHDCTX_RECEIVER = 5
 MTHDCTX_TEMP_FRAME_START = 6
 
 # BlockClosure < Object
-BLOCKCLOSURE_SIZE = 3
+BLKCLSR_OUTER_CONTEXT = 0
+BLKCLSR_STARTPC = 1
+BLKCLSR_NUMARGS = 2
+BLKCLSR_SIZE = 3
 
 # ___________________________________________________________________________
 # Miscellaneous constants
diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -445,7 +445,7 @@
         i = self.getbytecode()
         blockSize = (j << 8) | i
         #create new instance of BlockClosure
-        w_closure, closure = space.newClosure(self._w_self, self.pc(), 
numArgs, 
+        w_closure = space.newClosure(self._w_self, self.pc(), numArgs, 
                                             self.pop_and_return_n(numCopied))
         self.push(w_closure)
         self.jump(blockSize)
diff --git a/spyvm/objspace.py b/spyvm/objspace.py
--- a/spyvm/objspace.py
+++ b/spyvm/objspace.py
@@ -112,7 +112,7 @@
         define_cls("w_BlockContext", "w_ContextPart",
                    instvarsize=constants.BLKCTX_STACK_START)
         define_cls("w_BlockClosure", "w_Object",
-                   instvarsize=constants.BLOCKCLOSURE_SIZE,
+                   instvarsize=constants.BLKCLSR_SIZE,
                    varsized=True)
         # make better accessors for classes that can be found in special object
         # table
@@ -273,14 +273,15 @@
 
     def newClosure(self, outerContext, pc, numArgs, copiedValues):
         BlockClosureShadow = self.w_BlockClosure.as_class_get_shadow(self)
-        w_closure = BlockClosureShadow.new(len(copiedValues))
+        numCopied = len(copiedValues)
+        w_closure = BlockClosureShadow.new(numCopied)
         closure = wrapper.BlockClosureWrapper(self, w_closure)
         closure.store_outerContext(outerContext)
         closure.store_startpc(pc)
         closure.store_numArgs(numArgs)
-        for i0 in range(len(copiedValues)):
+        for i0 in range(numCopied):
             closure.atput0(i0, copiedValues[i0])
-        return w_closure, closure
+        return w_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
@@ -926,63 +926,66 @@
 @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(), 
+    w_context = interp.space.newClosure(outerContext, frame.pc(), 
                                                         numArgs, copiedValues)
-    frame.push(w_context)
+    return w_context
 
 
-def activateClosure(interp, w_block_closure, args_w, mayContextSwitch=True):
-    raise PrimitiveFailedError
-    if not w_block_closure.getclass(interp.space).is_same_object(
-            interp.space.w_BlockClosure):
+def activateClosure(interp, w_block, args_w, mayContextSwitch=True):
+    space = interp.space
+    if not w_block.getclass(space).is_same_object(
+            space.w_BlockClosure):
         raise PrimitiveFailedError()
-    if not w_block_closure.numArgs == len(args_w):
+    block = wrapper.BlockClosureWrapper(space, w_block)
+    if not block.numArgs() == len(args_w):
         raise PrimitiveFailedError()
-    if not w_block_closure.outerContext.getclass(interp.space).issubclass(
-            interp.space.w_ContextPart):
+    outer_ctxt_class = block.outerContext().getclass(space)
+    if not (outer_ctxt_class is space.w_MethodContext
+                or outer_ctxt_class is space.w_BlockContext
+                or outer_ctxt_class is space.w_BlockClosure):
         raise PrimitiveFailedError()
-    w_closureMethod = w_block_closure.w_method()
+    
+    # additionally to the smalltalk implementation, this also pushes
+    # args and copiedValues
+    w_new_frame = block.asContextWithSender(
+                            interp.w_active_context(), args_w)
+    w_closureMethod = w_new_frame.get_shadow(space).w_method()
+
     assert isinstance(w_closureMethod, model.W_CompiledMethod)
-    assert w_block_closure is not w_block_closure.outerContext
-    numCopied = w_block_closure.size()
+    assert w_block is not block.outerContext()
 
-    s_block_closure = w_block_closure.as_blockclosure_get_shadow(interp.space)
-    s_block_closure.push_all(args_w)
+    interp.store_w_active_context(w_new_frame)
 
-    s_block_closure.store_pc(s_block_closure.initialip())
-    frame = interp.s_active_context()
-    s_block_closure.store_w_sender(frame)
 
-
-@expose_primitive(CLOSURE_VALUE, unwrap_spec=[object])
+@expose_primitive(CLOSURE_VALUE, unwrap_spec=[object], no_result=True)
 def func(interp, w_block_closure):
     activateClosure(interp, w_block_closure, [])
 
-@expose_primitive(CLOSURE_VALUE_, unwrap_spec=[object, object])
+@expose_primitive(CLOSURE_VALUE_, unwrap_spec=[object, object], no_result=True)
 def func(interp, w_block_closure, w_a0):
     activateClosure(interp, w_block_closure, [w_a0])
 
-@expose_primitive(CLOSURE_VALUE_VALUE, unwrap_spec=[object, object, object])
+@expose_primitive(CLOSURE_VALUE_VALUE, unwrap_spec=[object, object, object], 
no_result=True)
 def func(interp, w_block_closure, w_a0, w_a1):
     activateClosure(interp, w_block_closure, [w_a0, w_a1])
 
-@expose_primitive(CLOSURE_VALUE_VALUE_VALUE, unwrap_spec=[object, object, 
object, object])
+@expose_primitive(CLOSURE_VALUE_VALUE_VALUE, unwrap_spec=[object, object, 
object, object], no_result=True)
 def func(interp, w_block_closure, w_a0, w_a1, w_a2):
     activateClosure(interp, w_block_closure, [w_a0, w_a1, w_a2])
 
-@expose_primitive(CLOSURE_VALUE_VALUE_VALUE_VALUE, unwrap_spec=[object, 
object, object, object, object])
+@expose_primitive(CLOSURE_VALUE_VALUE_VALUE_VALUE, unwrap_spec=[object, 
object, object, object, object], no_result=True)
 def func(interp, w_block_closure, w_a0, w_a1, w_a2, w_a3):
     activateClosure(interp, w_block_closure, [w_a0, w_a1, w_a2, w_a3])
 
-@expose_primitive(CLOSURE_VALUE_WITH_ARGS, unwrap_spec=[object, list])
+@expose_primitive(CLOSURE_VALUE_WITH_ARGS, unwrap_spec=[object, list], 
no_result=True)
 def func(interp, w_block_closure, args_w):
     activateClosure(interp, w_block_closure, args_w)
 
-@expose_primitive(CLOSURE_VALUE_NO_CONTEXT_SWITCH, unwrap_spec=[object])
+@expose_primitive(CLOSURE_VALUE_NO_CONTEXT_SWITCH, unwrap_spec=[object], 
no_result=True)
 def func(interp, w_block_closure):
     activateClosure(interp, w_block_closure, [], mayContextSwitch=False)
 
-@expose_primitive(CLOSURE_VALUE_NO_CONTEXT_SWITCH_, unwrap_spec=[object, 
object])
+@expose_primitive(CLOSURE_VALUE_NO_CONTEXT_SWITCH_, unwrap_spec=[object, 
object], no_result=True)
 def func(interp, w_block_closure, w_a0):
     activateClosure(interp, w_block_closure, [w_a0], mayContextSwitch=False)
 
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -634,14 +634,14 @@
 
 class MethodContextShadow(ContextPartShadow):
     def __init__(self, space, w_self):
-        self.w_receiver_map = space.w_nil
+        self.w_closure_or_nil = space.w_nil
         self._w_receiver = None
         ContextPartShadow.__init__(self, space, w_self)
 
     @staticmethod
     @jit.unroll_safe
     def make_context(space, w_method, w_receiver,
-                     arguments, w_sender=None):
+                     arguments, w_sender=None, closure=None, pc=0):
         # From blue book: normal mc have place for 12 temps+maxstack
         # mc for methods with islarge flag turned on 32
         size = 12 + w_method.islarge * 20 + w_method.argsize
@@ -652,25 +652,32 @@
         # XXX could hack some more to never have to create the _vars of 
w_result
         s_result = MethodContextShadow(space, w_result)
         w_result.store_shadow(s_result)
+        if closure is not None: 
+            s_result.w_closure_or_nil = closure._w_self
+        
         s_result.store_w_method(w_method)
         if w_sender:
             s_result.store_w_sender(w_sender)
         s_result.store_w_receiver(w_receiver)
-        s_result.store_pc(0)
+        s_result.store_pc(pc)
         s_result.init_stack_and_temps()
-        for i in range(len(arguments)):
-            s_result.settemp(i, arguments[i])
+        
+        argc = len(arguments)
+        for i0 in range(argc):
+            s_result.settemp(i0, arguments[i0])
+        if closure is not None: 
+            for i0 in range(closure.size()):
+                s_result.settemp(i0+argc, closure.at0(i0))
         return w_result
 
     def fetch(self, n0):
         if n0 == constants.MTHDCTX_METHOD:
             return self.w_method()
-        if n0 == constants.MTHDCTX_RECEIVER_MAP:
-            return self.w_receiver_map
+        if n0 == constants.MTHDCTX_CLOSURE_OR_NIL:
+            return self.w_closure_or_nil
         if n0 == constants.MTHDCTX_RECEIVER:
             return self.w_receiver()
-        if (0 <= n0-constants.MTHDCTX_TEMP_FRAME_START <
-                 self.tempsize()):
+        if (0 <= n0-constants.MTHDCTX_TEMP_FRAME_START < self.tempsize()):
             return self.gettemp(n0-constants.MTHDCTX_TEMP_FRAME_START)
         else:
             return ContextPartShadow.fetch(self, n0)
@@ -678,8 +685,8 @@
     def store(self, n0, w_value):
         if n0 == constants.MTHDCTX_METHOD:
             return self.store_w_method(w_value)
-        if n0 == constants.MTHDCTX_RECEIVER_MAP:
-            self.w_receiver_map = w_value
+        if n0 == constants.MTHDCTX_CLOSURE_OR_NIL:
+            self.w_closure_or_nil = w_value
             return
         if n0 == constants.MTHDCTX_RECEIVER:
             self.store_w_receiver(w_value)
@@ -698,7 +705,11 @@
         ContextPartShadow.attach_shadow(self)
 
     def tempsize(self):
-        return self.method().tempsize
+        if self.w_closure_or_nil == self.space.w_nil:
+            return self.method().tempsize
+        else:
+            return wrapper.BlockClosureWrapper(self.space, 
+                                self.w_closure_or_nil).tempsize()
 
     def w_method(self):
         return self._w_method
diff --git a/spyvm/squeakimage.py b/spyvm/squeakimage.py
--- a/spyvm/squeakimage.py
+++ b/spyvm/squeakimage.py
@@ -11,14 +11,30 @@
     first = ord(b[0]) # big endian
     if first & 0x80 != 0:
         first = first - 0x100
-    return first << 24 | ord(b[1]) << 16 | ord(b[2]) << 8 | ord(b[3])
+    return (first << 24 | ord(b[1]) << 16 | ord(b[2]) << 8 | ord(b[3]))
 
 def swapped_chrs2int(b):
     assert len(b) == 4
     first = ord(b[3]) # little endian
     if first & 0x80 != 0:
         first = first - 0x100
-    return first << 24 | ord(b[2]) << 16 | ord(b[1]) << 8 | ord(b[0])
+    return (first << 24 | ord(b[2]) << 16 | ord(b[1]) << 8 | ord(b[0]))
+
+def chrs2long(b):
+    assert len(b) == 8
+    first = ord(b[0]) # big endian
+    if first & 0x80 != 0:
+        first = first - 0x100
+    return (      first << 56 | ord(b[1]) << 48 | ord(b[2]) << 40 | ord(b[3]) 
<< 32
+            | ord(b[4]) << 24 | ord(b[5]) << 16 | ord(b[6]) <<  8 | ord(b[7])  
    )
+
+def swapped_chrs2long(b):
+    assert len(b) == 8
+    first = ord(b[7]) # little endian
+    if first & 0x80 != 0:
+        first = first - 0x100
+    return (      first << 56 | ord(b[6]) << 48 | ord(b[5]) << 40 | ord(b[4]) 
<< 32
+            | ord(b[3]) << 24 | ord(b[2]) << 16 | ord(b[1]) <<  8 | ord(b[0])  
    )
 
 
 # ____________________________________________________________
@@ -32,24 +48,36 @@
             self.data = inputfile.read()
         finally:
             inputfile.close()
-        self.swap = False
-        self.pos = 0
-        self.count = 0
+        self.reset()
 
     def peek(self):
         if self.pos >= len(self.data):
             raise IndexError
-        if self.swap:
-            return swapped_chrs2int( self.data[self.pos:self.pos+4] )
+        data_peek = self.data[self.pos:self.pos + self.word_size]
+        if self.use_long_read:
+            if self.swap:
+                return swapped_chrs2long(data_peek)
+            else:
+                return chrs2long(data_peek)
         else:
-            return chrs2int( self.data[self.pos:self.pos+4] )
+            if self.swap:
+                return swapped_chrs2int(data_peek)
+            else:
+                return chrs2int(data_peek)
+    
 
     def next(self):
         integer = self.peek()
-        self.pos += 4
-        self.count += 4
+        self.pos += self.word_size
+        self.count += self.word_size
         return integer
 
+    def reset(self):
+        self.swap = False
+        self.pos = 0
+        self.count = 0
+        self.be_32bit()
+
     def reset_count(self):
         self.count = 0
 
@@ -59,25 +87,120 @@
         self.pos += jump
         self.count += jump
 
+    def skipwords(self, jump):
+        self.skipbytes(jump * self.word_size)
+        assert (self.pos + jump) <= len(self.data)
+        self.pos += jump
+        self.count += jump
+
+
+    def length(self):
+        return len(self.data)
+
     def close(self):
         pass # already closed
 
+    def be_64bit(self):
+        self.word_size = 8
+        self.use_long_read = True
+
+    def be_32bit(self):
+        self.word_size = 4
+        self.use_long_read = False
 
 
 class CorruptImageError(Exception):
     pass
 
+class UnsupportedImageError(Exception):
+    pass
+
 # ____________________________________________________________
 
-# XXX hack to read Cog images.
-# TODO implement Cog float byte reversal
-SUPPORTED_VERSIONS = [6502, 6505]
+class ImageVersion(object):
+
+    def __init__(self, magic, is_big_endian, is_64bit, has_closures, 
has_floats_reversed):
+        self.magic = magic
+        self.is_big_endian = is_big_endian
+        self.is_64bit = is_64bit
+        self.has_closures = has_closures
+        self.has_floats_reversed = has_floats_reversed
+
+image_versions = {
+    0x00001966:         ImageVersion(6502,  True,  False, False, False),
+    0x66190000:         ImageVersion(6502,  False, False, False, False),
+    0x00001968:         ImageVersion(6504,  True,  False, True,  False),
+    0x68190000:         ImageVersion(6504,  False, False, True,  False),
+    0x00001969:         ImageVersion(6505,  True,  False, True,  True ),
+    0x69190000:         ImageVersion(6505,  False, False, True,  True ),
+    0x00000000000109A0: ImageVersion(68000, True,  True,  False, False),
+   -0x5ff6ff0000000000:
+    # signed version of 0xA009010000000000: 
+                        ImageVersion(68000, False, True,  False, False),
+    0x00000000000109A2: ImageVersion(68002, True,  True,  True,  False),
+   -0x5df6ff0000000000:
+    # signed version of 0xA209010000000000: 
+                       ImageVersion(68002, False, True,  True,  False),
+    0x00000000000109A3: ImageVersion(68003, True,  True,  True,  True ),
+   -0x5cf6ff0000000000:
+    # signed version of 0xA309010000000000: 
+                       ImageVersion(68003, False, True,  True,  True ),
+}
+
+    
+def version(magic):
+    ver = image_versions.get(magic, None)
+    if ver is None:
+        raise CorruptImageError
+    # if ver.is_64bit or ver.has_floats_reversed:
+    #     raise UnsupportedImageError
+    return ver
+
+possible_image_offset = 512
+
+def version_from_stream(stream):
+    # 32 bit
+    try:
+        return version(stream.peek())
+    except CorruptImageError as e:
+        if stream.length() > possible_image_offset + 4:
+            stream.skipbytes(possible_image_offset)
+            try:
+                return version(stream.peek())
+            except CorruptImageError:
+                pass # raise original error
+        # 64 bit
+        stream.reset()
+        stream.be_64bit()
+        try:
+            v = version(stream.peek())
+            assert v.is_64bit
+            return v
+        except CorruptImageError as e:
+            if stream.length() > possible_image_offset + 4:
+                stream.skipbytes(possible_image_offset)
+                try:
+                    v = version(stream.peek())
+                    assert v.is_64bit
+                    return v
+                except CorruptImageError:
+                    pass # raise original error
+        raise
+
+    
+    
+def reader_for_image(space, stream):
+    ver = version_from_stream(stream)
+    if not ver.is_big_endian:
+        stream.swap = True
+    return ImageReader(space, stream, ver)
 
 class ImageReader(object):
     
-    def __init__(self, space, stream):
+    def __init__(self, space, stream, version):
         self.space = space
         self.stream = stream
+        self.version = version
         # dictionary mapping old address to chunk object
         self.chunks = {}
         self.chunklist = []
@@ -94,15 +217,13 @@
         self.init_w_objects()
         self.fillin_w_objects()
 
+    def read_version(self):
+        # 1 word version
+        magic = self.stream.next()
+        assert self.version.magic == magic
+
     def read_header(self):
-        # 1 word version
-        version = self.stream.peek()
-        if version not in SUPPORTED_VERSIONS:
-            self.stream.swap = True
-            version = self.stream.peek()
-            if version not in SUPPORTED_VERSIONS:
-                raise CorruptImageError
-        version = self.stream.next()
+        self.read_version()
         #------
         # 1 word headersize
         headersize = self.stream.next()
@@ -118,8 +239,7 @@
         print "savedwindowssize", savedwindowssize
         fullscreenflag = self.stream.next()
         extravmmemory = self.stream.next()
-        # we called 9 times next, 1 word = 4 byte
-        self.stream.skipbytes(headersize - (9 * 4))
+        self.stream.skipbytes(headersize - self.stream.pos)
 
     def read_body(self):
         import sys
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
@@ -76,7 +76,7 @@
         return lit
     return [fakeliteral(lit) for lit in literals]
 
-def new_interpreter(bytes, receiver=space.w_nil):
+def new_interpreter(bytes, receiver=space.w_nil, space=space):
     assert isinstance(bytes, str)
     w_method = model.W_CompiledMethod(len(bytes))
     w_method.islarge = 1
diff --git a/spyvm/test/test_miniimage.py b/spyvm/test/test_miniimage.py
--- a/spyvm/test/test_miniimage.py
+++ b/spyvm/test/test_miniimage.py
@@ -27,7 +27,7 @@
     return perform(space.wrap_string(name), "asSymbol")
 
 def open_miniimage(space):
-    return squeakimage.ImageReader(space, 
squeakimage.Stream(mini_image.open()))
+    return squeakimage.reader_for_image(space, 
squeakimage.Stream(mini_image.open()))
 
 def get_reader():
     return reader
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
@@ -2,9 +2,7 @@
 import math
 from spyvm.primitives import prim_table, PrimitiveFailedError
 from spyvm import model, shadow, interpreter
-from spyvm import constants
-from spyvm import primitives
-from spyvm import objspace
+from spyvm import constants, primitives, objspace, wrapper
 
 from rpython.rlib.rfloat import INFINITY, NAN, isinf, isnan
 
@@ -20,6 +18,7 @@
         s_self.reset_stack()
         s_self.push_all(stack)
         s_self.store_expected_argument_count(0)
+    
     def as_blockcontext_get_shadow(self):
         self._shadow = shadow.BlockContextShadow(space, self)
         return self._shadow
@@ -33,15 +32,20 @@
     if isinstance(x, list): return space.wrap_list(x)
     raise NotImplementedError
     
-def mock(stack):
+def mock(stack, context = None):
     mapped_stack = [wrap(x) for x in stack]
-    frame = MockFrame(mapped_stack)
+    if context is None:
+        frame = MockFrame(mapped_stack)
+    else:
+        frame = context
+        for i in range(len(stack)):
+            frame.as_context_get_shadow(space).push(stack[i])
     interp = interpreter.Interpreter(space)
     interp.store_w_active_context(frame)
     return (interp, len(stack))
 
-def prim(code, stack):
-    interp, argument_count = mock(stack)
+def prim(code, stack, context = None):
+    interp, argument_count = mock(stack, context)
     prim_table[code](interp, argument_count-1)
     res = interp.s_active_context().pop()
     assert not interp.s_active_context().stackdepth() # check args are consumed
@@ -439,6 +443,57 @@
     assert space.unwrap_char(w_c) == os.path.sep
 
 
+def test_primitive_closure_copyClosure():
+    from test_interpreter import new_interpreter
+    interp = new_interpreter("<never called, but used for method generation>")
+    w_block = prim(200, map(wrap, ["anActiveContext", 2, [wrap(1), wrap(2)]]), 
+            interp.w_active_context())
+    assert w_block is not space.w_nil
+    w_w_block = wrapper.BlockClosureWrapper(space, w_block)
+    assert w_w_block.startpc() is 0
+    assert w_w_block.at0(0) == wrap(1)
+    assert w_w_block.at0(1) == wrap(2)
+    assert w_w_block.numArgs() is 2
+
+def build_up_closure_environment(args, copiedValues=[]):
+    from test_interpreter import new_interpreter
+    interp = new_interpreter("<never called, but used for method generation>",
+        space=space)
+    s_initial_context = interp.s_active_context()
+    
+    size_arguments = len(args)
+    closure = space.newClosure(interp.w_active_context(), 4, #pc 
+                                size_arguments, copiedValues)
+    s_initial_context.push_all([closure] + args)
+    prim_table[201 + size_arguments](interp, size_arguments)
+    return interp, s_initial_context, closure, interp.s_active_context()
+
+def test_primitive_closure_value():
+    interp, s_initial_context, closure, s_new_context = 
build_up_closure_environment([])
+
+    assert s_new_context.w_closure_or_nil is closure
+    assert s_new_context.s_sender() is s_initial_context
+    assert s_new_context.w_receiver() is space.w_nil
+
+def test_primitive_closure_value_value():
+    interp, s_initial_context, closure, s_new_context = 
build_up_closure_environment(["first arg", "second arg"])
+
+    assert s_new_context.w_closure_or_nil is closure
+    assert s_new_context.s_sender() is s_initial_context
+    assert s_new_context.w_receiver() is space.w_nil
+    assert s_new_context.gettemp(0) == "first arg"
+    assert s_new_context.gettemp(1) == "second arg"
+
+def test_primitive_closure_value_value_with_temps():
+    interp, s_initial_context, closure, s_new_context = 
build_up_closure_environment(["first arg", "second arg"],
+        copiedValues=['some value'])
+
+    assert s_new_context.w_closure_or_nil is closure
+    assert s_new_context.s_sender() is s_initial_context
+    assert s_new_context.w_receiver() is space.w_nil
+    assert s_new_context.gettemp(0) == "first arg"
+    assert s_new_context.gettemp(1) == "second arg"
+    assert s_new_context.gettemp(2) == "some value"
 
 # Note:
 #   primitives.NEXT is unimplemented as it is a performance optimization
diff --git a/spyvm/test/test_shadow.py b/spyvm/test/test_shadow.py
--- a/spyvm/test/test_shadow.py
+++ b/spyvm/test/test_shadow.py
@@ -90,7 +90,7 @@
     w_object.store(space, constants.CTXPART_STACKP_INDEX, 
space.wrap_int(method.tempsize+stackpointer))
     w_object.store(space, constants.MTHDCTX_METHOD, method)
     # XXX
-    w_object.store(space, constants.MTHDCTX_RECEIVER_MAP, '???')
+    w_object.store(space, constants.MTHDCTX_CLOSURE_OR_NIL, space.w_nil)
     w_object.store(space, constants.MTHDCTX_RECEIVER, 'receiver')
 
     w_object.store(space, constants.MTHDCTX_TEMP_FRAME_START, 'el')
diff --git a/spyvm/test/test_squeakimage.py b/spyvm/test/test_squeakimage.py
--- a/spyvm/test/test_squeakimage.py
+++ b/spyvm/test/test_squeakimage.py
@@ -1,15 +1,16 @@
 import py
 from spyvm import squeakimage
-from spyvm.squeakimage import chrs2int
+from spyvm.squeakimage import chrs2int, chrs2long, swapped_chrs2long
 from spyvm import objspace
 
+from struct import pack
+
 space = objspace.ObjSpace()
 
 # ----- helpers ----------------------------------------------
 
 def ints2str(*ints):
-    import struct
-    return struct.pack(">" + "i" * len(ints), *ints)
+    return pack(">" + "i" * len(ints), *ints)
 
 def joinbits(values, lengths):
     result = 0
@@ -18,12 +19,18 @@
         result += each
     return result   
 
-def imagereader_mock(string):
+def imagestream_mock(string):
     import StringIO
     f = StringIO.StringIO(string)
-    stream = squeakimage.Stream(f)
-    return squeakimage.ImageReader(space, stream)
+    return squeakimage.Stream(f)
 
+def imagereader_mock(string):
+    stream = imagestream_mock(string)
+    return squeakimage.reader_for_image(space, stream)
+
+
+SIMPLE_VERSION_HEADER = pack(">i", 6502)
+SIMPLE_VERSION_HEADER_LE = pack("<i", 6502)
 
 # ----- tests ------------------------------------------------
 
@@ -31,8 +38,14 @@
     assert 1 == chrs2int('\x00\x00\x00\x01')
     assert -1 == chrs2int('\xFF\xFF\xFF\xFF')
 
+def test_chrs2long():
+    assert 1 == chrs2long('\x00\x00\x00\x00\x00\x00\x00\x01')
+    assert -1 == chrs2long('\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF')
+    assert 68002 == chrs2long(pack(">Q", 68002))
+    assert 68002 == swapped_chrs2long(pack("<Q", 68002))
+
 def test_stream():
-    stream = imagereader_mock('\x00\x00\x19\x66').stream
+    stream = imagestream_mock(SIMPLE_VERSION_HEADER)
     n = stream.peek()
     assert n == 6502 
     n = stream.next()
@@ -40,14 +53,14 @@
     py.test.raises(IndexError, lambda: stream.next())
     
 def test_stream_swap():
-    stream = imagereader_mock('\x66\x19\x00\x00').stream
+    stream = imagestream_mock('\x66\x19\x00\x00')
     stream.swap = True
     first = stream.next()
     assert first == 6502 
     py.test.raises(IndexError, lambda: stream.next())
     
 def test_stream_many():
-    stream = imagereader_mock('\x00\x00\x19\x66' * 5).stream
+    stream = imagestream_mock(SIMPLE_VERSION_HEADER * 5)
     for each in range(5):
         first = stream.peek()
         assert first == 6502 
@@ -56,14 +69,14 @@
     py.test.raises(IndexError, lambda: stream.next())
     
 def test_stream_skipbytes():
-    stream = imagereader_mock('\xFF\xFF\xFF\x00\x00\x19\x66').stream
+    stream = imagestream_mock('\xFF\xFF\xFF' + SIMPLE_VERSION_HEADER)
     stream.skipbytes(3)
     value = stream.next()
     assert value == 6502 
     py.test.raises(IndexError, lambda: stream.next())
         
 def test_stream_count():
-    stream = imagereader_mock('\xFF' * 20).stream
+    stream = imagestream_mock('\xFF' * 20)
     stream.next()
     stream.next()
     stream.reset_count()
@@ -85,41 +98,125 @@
     
 def test_ints2str():
     assert "\x00\x00\x00\x02" == ints2str(2)       
-    assert '\x00\x00\x19\x66\x00\x00\x00\x02' == ints2str(6502,2)
+    assert SIMPLE_VERSION_HEADER + '\x00\x00\x00\x02' == ints2str(6502,2)
     
 def test_freeblock():
-    r = imagereader_mock("\x00\x00\x00\x02")
+    r = imagereader_mock(SIMPLE_VERSION_HEADER + "\x00\x00\x00\x02")
+    r.read_version()
     py.test.raises(squeakimage.CorruptImageError, lambda: r.read_object())
 
 def test_1wordobjectheader():
     s = ints2str(joinbits([3, 1, 2, 3, 4], [2,6,4,5,12]))
-    r = imagereader_mock(s)
-    assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 0) == 
r.read_1wordobjectheader()
+    r = imagereader_mock(SIMPLE_VERSION_HEADER + s)
+    r.read_version()
+    l = len(SIMPLE_VERSION_HEADER)
+    assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 0 + l) == 
r.read_1wordobjectheader()
 
 def test_1wordobjectheader2():
     s = ints2str(joinbits([3, 1, 2, 3, 4], [2,6,4,5,12]))
-    r = imagereader_mock(s * 3)
-    assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 0) == 
r.read_1wordobjectheader()
-    assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 4) == 
r.read_1wordobjectheader()
-    assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 8) == 
r.read_1wordobjectheader()
+    r = imagereader_mock(SIMPLE_VERSION_HEADER + (s * 3))
+    r.read_version()
+    l = len(SIMPLE_VERSION_HEADER)
+    assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 0 + l) == 
r.read_1wordobjectheader()
+    assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 4 + l) == 
r.read_1wordobjectheader()
+    assert (squeakimage.ImageChunk(space, 1, 2, 3, 4), 8 + l) == 
r.read_1wordobjectheader()
 
 def test_2wordobjectheader():
     s = ints2str(4200 + 1, joinbits([1, 1, 2, 3, 4], [2,6,4,5,12]))
-    r = imagereader_mock(s)
-    assert (squeakimage.ImageChunk(space, 1, 2, 4200, 4), 4) == 
r.read_2wordobjectheader()
+    r = imagereader_mock(SIMPLE_VERSION_HEADER + s)
+    r.read_version()
+    l = len(SIMPLE_VERSION_HEADER)
+    assert (squeakimage.ImageChunk(space, 1, 2, 4200, 4), 4 + l) == 
r.read_2wordobjectheader()
 
 def test_3wordobjectheader():
     s = ints2str(1701 << 2, 4200 + 0, joinbits([0, 1, 2, 3, 4], [2,6,4,5,12]))
-    r = imagereader_mock(s)
-    assert (squeakimage.ImageChunk(space, 1701, 2, 4200, 4), 8) == 
r.read_3wordobjectheader()
+    r = imagereader_mock(SIMPLE_VERSION_HEADER + s)
+    r.read_version()
+    l = len(SIMPLE_VERSION_HEADER)
+    assert (squeakimage.ImageChunk(space, 1701, 2, 4200, 4), 8 + l) == 
r.read_3wordobjectheader()
     
 def test_read3wordheaderobject():
     size = 42
     s = ints2str(size << 2, 4200 + 0, joinbits([0, 1, 2, 3, 4], [2,6,4,5,12]))
-    r = imagereader_mock(s + '\x00\x00\x19\x66' * (size - 1))
+    r = imagereader_mock(SIMPLE_VERSION_HEADER + s + SIMPLE_VERSION_HEADER * 
(size - 1))
+    r.read_version()
+    l = len(SIMPLE_VERSION_HEADER)
     chunk, pos = r.read_object()
     chunk0 = squeakimage.ImageChunk(space, size, 2, 4200, 4)
     chunk0.data = [6502] * (size - 1)
-    assert pos == 8
+    assert pos == 8 + l
     assert chunk0 == chunk
     
+def test_simple_image():
+    word_size = 4
+    header_size = 16 * word_size
+
+    image_1 = (SIMPLE_VERSION_HEADER     # 1
+               + pack(">i", header_size) # 2 64 byte header
+               + pack(">i", 0)           # 3 no body
+               + pack(">i", 0)           # 4 old base addresss unset
+               + pack(">i", 0)           # 5 no spl objs array
+               + "\x12\x34\x56\x78"      # 6 last hash
+               + pack(">h", 480)         # 7 window 480 height
+               +     pack(">h", 640)     #   window 640 width
+               + pack(">i", 0)           # 8 not fullscreen
+               + pack(">i", 0)           # 9 no extra memory
+               + ("\x00" * (header_size - (9 * word_size))))
+    r = imagereader_mock(image_1)
+    # does not raise
+    r.read_header()
+    assert r.stream.pos == len(image_1)
+
+    image_2 = (SIMPLE_VERSION_HEADER_LE  # 1
+               + pack("<i", header_size) # 2 64 byte header
+               + pack("<i", 0)           # 3 no body
+               + pack("<i", 0)           # 4 old base addresss unset
+               + pack("<i", 0)           # 5 no spl objs array
+               + "\x12\x34\x56\x78"      # 6 last hash
+               + pack("<h", 480)         # 7 window 480 height
+               +     pack("<h", 640)     #   window 640 width
+               + pack("<i", 0)           # 8 not fullscreen
+               + pack("<i", 0)           # 9 no extra memory
+               + ("\x00" * (header_size - (9 * word_size))))
+    r = imagereader_mock(image_2)
+    # does not raise
+    r.read_header()
+    assert r.stream.pos == len(image_2)
+
+def test_simple_image64():
+    word_size = 8
+    header_size = 16 * word_size
+
+    image_1 = (pack(">Q", 68002)         # 1 version
+               + pack(">q", header_size) # 2 64 byte header
+               + pack(">q", 0)           # 3 no body
+               + pack(">q", 0)           # 4 old base addresss unset
+               + pack(">q", 0)           # 5 no spl objs array
+               + ("\x12\x34\x56\x78" * 2)# 6 last hash
+               + pack(">H", 480)         # 7 window 480 height
+               +     pack(">H", 640)     #   window 640 width
+               +     pack(">i", 0)       #   pad
+               + pack(">q", 0)           # 8 not fullscreen
+               + pack(">q", 0)           # 9 no extra memory
+               + ("\x00" * (header_size - (9 * word_size))))
+    r = imagereader_mock(image_1)
+    # does not raise
+    r.read_header()
+    assert r.stream.pos == len(image_1)
+
+    image_2 = (pack("<Q", 68002)         # 1 version
+               + pack("<q", header_size) # 2 64 byte header
+               + pack("<q", 0)           # 3 no body
+               + pack("<q", 0)           # 4 old base addresss unset
+               + pack("<q", 0)           # 5 no spl objs array
+               + ("\x12\x34\x56\x78" * 2)# 6 last hash
+               + pack("<H", 480)         # 7 window 480 height
+               +     pack("<H", 640)     #   window 640 width
+               +     pack(">i", 0)       #   pad
+               + pack(">q", 0)           # 8 not fullscreen
+               + pack("<q", 0)           # 9 no extra memory
+               + ("\x00" * (header_size - (9 * word_size))))
+    r = imagereader_mock(image_2)
+    # does not raise
+    r.read_header()
+    assert r.stream.pos == len(image_2)
diff --git a/spyvm/tool/analyseimage.py b/spyvm/tool/analyseimage.py
--- a/spyvm/tool/analyseimage.py
+++ b/spyvm/tool/analyseimage.py
@@ -11,10 +11,10 @@
 minitest_image = image_dir.join('minitest.image')
 
 def get_miniimage(space):
-    return squeakimage.ImageReader(space, 
squeakimage.Stream(mini_image.open()))
+    return squeakimage.reader_for_image(space, 
squeakimage.Stream(mini_image.open()))
 
 def get_minitestimage(space):
-    return squeakimage.ImageReader(space, 
squeakimage.Stream(minitest_image.open()))
+    return squeakimage.reader_for_image(space, 
squeakimage.Stream(minitest_image.open()))
 
 def create_image(space, image_reader):
     image_reader.initialize()
diff --git a/spyvm/wrapper.py b/spyvm/wrapper.py
--- a/spyvm/wrapper.py
+++ b/spyvm/wrapper.py
@@ -1,4 +1,4 @@
-from spyvm import model
+from spyvm import model, constants
 from spyvm.error import FatalError, WrapperException
 
 class Wrapper(object):
@@ -215,9 +215,29 @@
 
  
 class BlockClosureWrapper(VarsizedWrapper):
-    outerContext, store_outerContext = make_getter_setter(0)
-    startpc, store_startpc = make_int_getter_setter(1)
-    numArgs, store_numArgs = make_int_getter_setter(2)
+    outerContext, store_outerContext = 
make_getter_setter(constants.BLKCLSR_OUTER_CONTEXT)
+    startpc, store_startpc = make_int_getter_setter(constants.BLKCLSR_STARTPC)
+    numArgs, store_numArgs = make_int_getter_setter(constants.BLKCLSR_NUMARGS)
+
+    def asContextWithSender(self, w_aContext, arguments):
+        from spyvm import shadow
+        s_outerContext = self.outerContext().get_shadow(self.space)
+        w_method = s_outerContext.w_method()
+        w_receiver = s_outerContext.w_receiver()
+        w_new_frame = shadow.MethodContextShadow.make_context(self.space , 
w_method, w_receiver,
+                     arguments, w_sender=w_aContext, pc=self.startpc(), 
closure=self)
+        return w_new_frame
+
+    def tempsize(self):
+        # We ignore the number of temps a block has, because the first 
+        # bytecodes of the block will initialize them for us. We will only 
+        # use this information for decinding where the stack pointer should be 
+        # initialy.
+        # For a finding the correct number, see BlockClosure>#numTemps in an 
Image.
+        return self.size() + self.numArgs()
+    
+    def size(self):
+        return self._w_self.size() - constants.BLKCLSR_SIZE
 
 # XXX Wrappers below are not used yet.
 class OffsetWrapper(Wrapper):
diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py
--- a/targetimageloadingsmalltalk.py
+++ b/targetimageloadingsmalltalk.py
@@ -45,7 +45,7 @@
     else:
         print "usage:", argv[0], "<image name>"
         return -1
-    reader = squeakimage.ImageReader(space, 
squeakimage.Stream(DummyFile(filename)))
+    reader = squeakimage.reader_for_image(space, 
squeakimage.Stream(DummyFile(filename)))
     reader.initialize()
     image = squeakimage.SqueakImage()
     image.from_reader(space, reader)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to