Author: Anton Gulenko <[email protected]>
Branch: storage-context-state-v2
Changeset: r956:f500ff8dea45
Date: 2014-07-25 16:33 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/f500ff8dea45/

Log:    Added some Squeak image tests.

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
@@ -979,7 +979,7 @@
         test)
 
 def test_frame_dirty_if_active():
-    bytes = reduce(operator.add, map(chr, [0x84, 0xc0, 0x00])) + 
returnReceiverBytecode
+    bytes = reduce(operator.add, map(chr, [0x84, 0xc0, 0x00]))
     w_frame, s_frame = new_frame(bytes)
     s_frame.store_w_receiver(w_frame)
     s_frame.push(w_frame)
@@ -988,7 +988,7 @@
     assert s_frame.state is shadow.DirtyContext
 
 def test_frame_not_dirty_if_inactive():
-    bytes = reduce(operator.add, map(chr, [0x84, 0xc0, 0x00])) + 
returnReceiverBytecode
+    bytes = reduce(operator.add, map(chr, [0x84, 0xc0, 0x00]))
     w_frame, s_frame = new_frame(bytes)
     w_other_frame, s_other_frame = new_frame("")
     s_frame.store_w_receiver(w_other_frame)
@@ -998,12 +998,14 @@
     assert s_frame.state is shadow.ActiveContext
     assert s_other_frame.state is shadow.InactiveContext
     
-def test_raise_SenderManipulation_on_dirty_frame():
-    w_frame, s_frame = new_frame(returnReceiverBytecode)
-    s_frame.state = shadow.DirtyContext
-    def run_frame():
-        #import pdb; pdb.set_trace()
-        interp._loop = True
+def test_raise_NonVirtualReturn_on_dirty_frame():
+    bytes = reduce(operator.add, map(chr, [0x84, 0xc0, 0x00])) + 
returnTopFromMethodBytecode
+    w_frame, s_frame = new_frame(bytes)
+    s_frame.store_w_receiver(w_frame)
+    s_frame.push(w_frame)
+    
+    interp._loop = True
+    def do_test():
         interp.stack_frame(s_frame, None)
-    py.test.raises(interpreter.SenderChainManipulation, run_frame)
+    py.test.raises(interpreter.NonVirtualReturn, do_test)
     
\ No newline at end of file
diff --git a/spyvm/test/test_zin_squeak_4_5_image.py 
b/spyvm/test/test_zin_squeak_4_5_image.py
--- a/spyvm/test/test_zin_squeak_4_5_image.py
+++ b/spyvm/test/test_zin_squeak_4_5_image.py
@@ -1,6 +1,8 @@
 from spyvm import squeakimage, model, constants, interpreter, shadow, objspace
 from .util import read_image, find_symbol_in_methoddict_of, copy_to_module, 
cleanup_module
 
+import operator
+
 def setup_module():
     space, interp, image, reader = read_image('Squeak4.5-12568.image')
     w = space.w
@@ -25,21 +27,13 @@
     w_method.setliterals(literals)
     return w_method
 
-def test_ensure():
-    #ensure
-    #    [^'b1'] ensure: [^'b2']
-    import operator
-    bytes = reduce(operator.add, map(chr, [0x8F, 0, 0, 2, 0x21, 0x7c,
-                                           0x8F, 0, 0, 2, 0x22, 0x7c,
-                                           0xe0, 0x87, 0x78]))
-
-    s_class = space.w_BlockClosure.as_class_get_shadow(space)
-    ensure_ = find_symbol_in_methoddict_of('ensure:', s_class)
-    assert ensure_ is not None, 'Using image without #ensure:-method.'
-
-    w_method = create_method(bytes, [ensure_, w('b1'), w('b2'),
-                                            w('ensure'), space.w_BlockClosure])
-
+def find_symbol(w_class, symbolname):
+    s_class = w_class.as_class_get_shadow(space)
+    symbol = find_symbol_in_methoddict_of(symbolname, s_class)
+    assert symbol is not None, 'Using image without %s method.' % symbolname
+    return symbol
+    
+def execute_frame(w_method):
     # create a frame for our newly crafted method with a valid sender (to 
avoid raising returnFromTop to early)
     s_initial_frame = create_method(chr(0x7c)).create_frame(space, w(0), [])
     s_frame = w_method.create_frame(space, w(0))
@@ -48,33 +42,141 @@
     try:
         interp.loop(s_frame.w_self())
     except interpreter.ReturnFromTopLevel, e:
-        assert e.object.as_string() == 'b2'
-    except interpreter.StackOverflow, e:
-        assert False
+        return e.object
+    
+def test_ensure():
+    #ensure
+    #    [^'b1'] ensure: [^'b2']
+    
+    ensure_ = find_symbol(space.w_BlockClosure, "ensure:")
+    bytes = reduce(operator.add, map(chr, [0x8F, 0, 0, 2, 0x21, 0x7c,
+                                           0x8F, 0, 0, 2, 0x22, 0x7c,
+                                           0xe0, 0x87, 0x78]))
+    
+    w_method = create_method(bytes, [ensure_, w('b1'), w('b2'),
+                                            w('ensure'), space.w_BlockClosure])
+    result = execute_frame(w_method)
+    assert result.as_string() == 'b2'
 
 def test_ensure_save_original_nlr():
     #ensure
     #    [^'b1'] ensure: ['b2']
-    import operator
+    
+    ensure_ = find_symbol(space.w_BlockClosure, "ensure:")
     bytes = reduce(operator.add, map(chr, [0x8F, 0, 0, 2, 0x21, 0x7c,
                                            0x8F, 0, 0, 2, 0x22, 0x7d,
                                            0xe0, 0x87, 0x78]))
 
-    s_class = space.w_BlockClosure.as_class_get_shadow(space)
-    ensure_ = find_symbol_in_methoddict_of('ensure:', s_class)
-    assert ensure_ is not None, 'Using image without #ensure:-method.'
-
     w_method = create_method(bytes, [ensure_, w('b1'), w('b2'),
                                             w('ensure'), space.w_BlockClosure])
+    result = execute_frame(w_method)
+    assert result.as_string() == 'b1'
 
-    # create a frame for our newly crafted method with a valid sender (to 
avoid raising returnFromTop to early)
-    s_initial_frame = create_method(chr(0x7c)).create_frame(space, w(0))
-    s_frame = w_method.create_frame(space, w(0))
-    s_frame.store_s_sender(s_initial_frame)
+def test_ContextPart_jump():
+    """
+    Code: Create a Block context that jumps back to its sender, instead of 
returning normally.
+    The Block is not executed to the end, the sender chain is manipulated.
+    The local variable should be the value pushed on the sender context before 
jumping to it.
+    a := 5.
+    a := [ thisContext sender push: 2. thisContext sender jump. 10 ] value.
+    ^ a
+    """
+    ContextPart = 
space.w_MethodContext.as_class_get_shadow(space).s_superclass().w_self()
+    push = find_symbol(ContextPart, "push:")
+    sender = find_symbol(ContextPart, "sender")
+    jump = find_symbol(ContextPart, "jump")
     
-    try:
-        interp.loop(s_frame.w_self())
-    except interpreter.ReturnFromTopLevel, e:
-        assert e.object.as_string() == 'b1'
-    except interpreter.StackOverflow, e:
-        assert False
+    bytes = reduce(operator.add, map(chr, [0x21, 0x82, 0xc0, # Set a
+                                           0x8f, 0x00, 0x00, 0x0b, # Push block
+                                                0x89, 0xd3, # Send sender
+                                                0x77, 0xe2, # Send push
+                                                0x87, 0x89, 0xd3, 0xd4, # Send 
jump
+                                                0x87, 0x25, 0x7d, # Block rest 
(not executed)
+                                           0xc9, 0x82, 0xc0, 0x40, 0x7c])) # 
Send value and return
+    
+    Association = space.classtable["w_Point"] # Wrong class, doesn't matter.
+    assoc = model.W_PointersObject(space, Association, 2)
+    assoc.store(space, 0, w('a'))
+    assoc.store(space, 1, w(3))
+    w_method = create_method(bytes, [assoc, w(5), push, sender, jump, w(10)])
+    result = execute_frame(w_method)
+    assert isinstance(result, model.W_SmallInteger)
+    assert result.value == 2
+
+def test_ContextPart_jump_nonlocal():
+    """
+    Like above test, but with three blocks to make the return non-local.
+    Also, store the outer context beforehand.
+    a := 5.
+    outer := thisContext.
+    a := [[[ outer push: 2. outer jump. 10 ] value ] value] value.
+    ^ a
+    """
+    ContextPart = 
space.w_MethodContext.as_class_get_shadow(space).s_superclass().w_self()
+    push = find_symbol(ContextPart, "push:")
+    jump = find_symbol(ContextPart, "jump")
+    
+    bytes = reduce(operator.add, map(chr, [0x21, 0x82, 0xc0, # Set a
+                                           0x89, 0x82, 0xc2, # Set outer
+                                           0x8f, 0x00, 0x00, 0x15, # Push block
+                                                0x8f, 0x00, 0x00, 0x0f, # Push 
block
+                                                    0x8f, 0x00, 0x00, 0x09, # 
Push block
+                                                        0x42, 0x77, 0xe3, # 
Push 2
+                                                        0x87, 0x42, 0xd4, # 
Send jump
+                                                        0x87, 0x25, 0x7d, # 
Block rest (not executed)
+                                                    0xc9, 0x7d, # Send value 
and return
+                                                0xc9, 0x7d, # Send value and 
return
+                                           0xc9, 0x82, 0xc0, 0x40, 0x7c])) # 
Send value and return
+    
+    Association = space.classtable["w_Point"] # Wrong class, doesn't matter.
+    assoc = model.W_PointersObject(space, Association, 2)
+    assoc.store(space, 0, w('a'))
+    assoc.store(space, 1, space.w_nil)
+    assoc2 = model.W_PointersObject(space, Association, 2)
+    assoc2.store(space, 0, w('outer'))
+    assoc2.store(space, 1, space.w_nil)
+    w_method = create_method(bytes, [assoc, w(5), assoc2, push, jump, w(10)])
+    result = execute_frame(w_method)
+    assert isinstance(result, model.W_SmallInteger)
+    assert result.value == 2
+
+def test_contextOn_do_():
+    """
+    contextOn:do: is some very heavy meta programming. It creates and returns 
a separate stack frame,
+    settings it's sender to nil, thereby manipulating the senders of two 
contexts.
+    The Point in there should actually be UnhandledError or something.
+    The test here is just that this works.
+    ctx := ContextPart contextOn: Point do: ['nothing']
+    """
+    ContextPart = 
space.w_MethodContext.as_class_get_shadow(space).s_superclass().w_self()
+    ContextPartClass = 
ContextPart.getclass(space).as_class_get_shadow(space).w_self()
+    contextOnDo = find_symbol(ContextPartClass, "contextOn:do:")
+    
+    bytes = reduce(operator.add, map(chr, [
+        0x42, 0x43, # Push the classes
+        0x8f, 0x00, 0x00, 0x02, # Push block,
+            0x24, 0x7d, # in the block
+        0xf1, 0x81, 0xc0, 0x7c # Send contextOn:do:
+    ]))
+    
+    Association = space.classtable["w_Point"] # Wrong class, doesn't matter.
+    ctxAssoc = model.W_PointersObject(space, Association, 2)
+    ctxAssoc.store(space, 0, w('ctx'))
+    ctxAssoc.store(space, 1, space.w_nil)
+    contextPartAssoc = model.W_PointersObject(space, Association, 2)
+    contextPartAssoc.store(space, 0, w('ContextPart'))
+    contextPartAssoc.store(space, 1, ContextPart)
+    errorAssoc = model.W_PointersObject(space, Association, 2)
+    errorAssoc.store(space, 0, w('Point'))
+    errorAssoc.store(space, 1, Association)
+    w_method = create_method(bytes, [ctxAssoc, contextOnDo, contextPartAssoc, 
errorAssoc, w('nothing')])
+    
+    interp.trace = True
+    
+    result = execute_frame(w_method)
+    assert isinstance(result, model.W_PointersObject)
+    s = result.as_context_get_shadow(space)
+    assert s.w_method().lookup_selector == "on:do:"
+    assert s.w_method().primitive() == 199
+    assert s.s_sender() == None
+    
\ No newline at end of file
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to