Author: Lars Wassermann <[email protected]>
Branch:
Changeset: r157:665a6c1c322f
Date: 2013-03-10 19:26 +0100
http://bitbucket.org/pypy/lang-smalltalk/changeset/665a6c1c322f/
Log: Changed mapping of w_objects to shadows: Every w_object has at
most one shadow and that shadow can not be removed
Refactored test for shadow to has_shadow() method to reduce the
number of send sites of _shadow Added ObserveeShadow to fix a
problem with patching a method in a methoddict (see test
test_miniimage.test_cached_methoddict) Readded invalid flag for
methoddicts.
Removed invalid-flag sets for class-shadows during objspace-
generation. Instead, allowed sync_cache-calls before the whole
object has been read.
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -236,11 +236,11 @@
return "<%s %s>" % (self.__class__.__name__, self)
def __str__(self):
- if isinstance(self, W_PointersObject) and self._shadow is not None:
+ if isinstance(self, W_PointersObject) and self.has_shadow():
return self._shadow.getname()
else:
name = None
- if self.w_class._shadow is not None:
+ if self.w_class.has_shadow():
name = self.w_class._shadow.name
return "a %s" % (name or '?',)
@@ -269,6 +269,7 @@
vars = self._vars = [None] * size
for i in range(size): # do it by hand for the JIT's sake
vars[i] = w_nil
+ self._shadow = None
def at0(self, space, index0):
# To test, at0 = in varsize part
@@ -279,7 +280,7 @@
self.store(space, index0 + self.instsize(space), w_value)
def fetch(self, space, n0):
- if self._shadow is not None:
+ if self.has_shadow():
return self._shadow.fetch(n0)
return self._fetch(n0)
@@ -287,7 +288,7 @@
return self._vars[n0]
def store(self, space, n0, w_value):
- if self._shadow is not None:
+ if self.has_shadow():
return self._shadow.store(n0, w_value)
return self._store(n0, w_value)
@@ -305,7 +306,7 @@
return self.varsize(space)
def size(self):
- if self._shadow is not None:
+ if self.has_shadow():
return self._shadow.size()
return self._size()
@@ -317,12 +318,13 @@
isinstance(self._vars, list))
def store_shadow(self, shadow):
+ assert self._shadow is None or self._shadow is shadow
self._shadow = shadow
@objectmodel.specialize.arg(2)
def attach_shadow_of_class(self, space, TheClass):
shadow = TheClass(space, self)
- self._shadow = shadow
+ self.store_shadow(shadow)
shadow.attach_shadow()
return shadow
@@ -331,9 +333,9 @@
shadow = self._shadow
if not isinstance(shadow, TheClass):
if shadow is not None:
- shadow.detach_shadow()
+ raise DetachingShadowError(shadow, TheClass)
shadow = self.attach_shadow_of_class(space, TheClass)
- shadow.sync_shadow()
+ shadow.synchronize()
return shadow
def get_shadow(self, space):
@@ -369,6 +371,13 @@
from spyvm.shadow import CachedObjectShadow
return self.as_special_get_shadow(space, CachedObjectShadow)
+ def as_observed_get_shadow(self, space):
+ from spyvm.shadow import ObserveeShadow
+ return self.as_special_get_shadow(space, ObserveeShadow)
+
+ def has_shadow(self):
+ return self._shadow is not None
+
def become(self, w_other):
if not isinstance(w_other, W_PointersObject):
return False
@@ -508,7 +517,7 @@
self.header, w_other.header = w_other.header, self.header
self.literalsize, w_other.literalsize = w_other.literalsize,
self.literalsize
self.islarge, w_other.islarge = w_other.islarge, self.islarge
- self._shadow = w_other._shadow = None
+ self._shadow, w_other._shadow = w_other._shadow, self._shadow
W_AbstractObjectWithIdentityHash._become(self, w_other)
return True
@@ -594,12 +603,13 @@
"""NOT RPYTHON
Only for testing"""
self.literals = literals
- self._shadow = None
+ if self.has_shadow():
+ self._shadow.update()
def setbytes(self, bytes):
self.bytes = bytes
- def as_compiledmethod_get_shadow(self, space):
+ def as_compiledmethod_get_shadow(self, space=None):
from shadow import CompiledMethodShadow
if self._shadow is None:
self._shadow = CompiledMethodShadow(self)
@@ -617,7 +627,8 @@
self.setheader(header)
else:
self.literals[index0-1] = w_value
- self._shadow = None
+ if self.has_shadow():
+ self._shadow.update()
def store(self, space, index0, w_v):
self.atput0(space, index0, w_v)
@@ -650,7 +661,16 @@
def setchar(self, index0, character):
assert index0 >= 0
self.bytes[index0] = character
- self._shadow = None
+ if self.has_shadow():
+ self._shadow.update()
+
+ def has_shadow(self):
+ return self._shadow is not None
+
+class DetachingShadowError(Exception):
+ def __init__(self, old_shadow, new_shadow_class):
+ self.old_shadow = old_shadow
+ self.new_shadow_class = new_shadow_class
# Use black magic to create w_nil without running the constructor,
# thus allowing it to be used even in the constructor of its own
diff --git a/spyvm/objspace.py b/spyvm/objspace.py
--- a/spyvm/objspace.py
+++ b/spyvm/objspace.py
@@ -55,8 +55,10 @@
# XXX
proto_shadow = instantiate(shadow.ClassShadow)
proto_shadow.space = self
- proto_shadow.invalid = False
+ proto_shadow.name = ''
proto_shadow.w_superclass = w_Class
+ proto_shadow.version = shadow.Version()
+ w_ProtoObjectClass._shadow = None
w_ProtoObjectClass.store_shadow(proto_shadow)
# at this point, all classes that still lack a w_class are themselves
# metaclasses
@@ -299,10 +301,10 @@
s._w_self = w_class
s.w_superclass = w_superclass
s.name = name
+ s.version = shadow.Version()
s.instance_size = instsize
s.instance_kind = format
s.w_methoddict = None
s.instance_varsized = varsized or format != shadow.POINTERS
- s.invalid = False
w_class.store_shadow(s)
return w_class
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -23,40 +23,37 @@
def getname(self):
return repr(self)
def attach_shadow(self): pass
- def detach_shadow(self): pass
- def sync_shadow(self): pass
-
+ def synchronize(self): pass
+
class AbstractCachingShadow(AbstractShadow):
+ _immutable_fields_ = ['version?']
_attr_ = []
def __init__(self, space, w_self):
AbstractShadow.__init__(self, space, w_self)
+ self.version = Version()
- def detach_shadow(self):
- self.invalidate_shadow()
+ def attach_shadow(self):
+ self.w_self().store_shadow(self)
+ self.update()
- def invalidate_shadow(self):
+ def update(self):
"""This should get called whenever the base Smalltalk
object changes."""
- self._w_self.store_shadow(None)
+ self.sync_cache()
- def attach_shadow(self):
- self.update_shadow()
-
- def sync_shadow(self):
- pass
-
- def update_shadow(self):
- self.w_self().store_shadow(self)
- self.sync_cache()
+ def synchronize(self):
+ self.update()
def sync_cache(self):
raise NotImplementedError()
def store(self, n0, w_value):
- self.invalidate_shadow()
AbstractShadow.store(self, n0, w_value)
+ self.update()
+class Version:
+ pass
# ____________________________________________________________
POINTERS = 0
@@ -77,55 +74,63 @@
(i.e. used as the class of another Smalltalk object).
"""
- _immutable_fields_ = ["name", "instance_size", "instance_varsized",
"instance_kind", "w_methoddict", "s_methoddict", "w_superclass"]
+ _attr_ = ["name", "instance_size", "instance_varsized", "instance_kind",
"w_methoddict", "s_methoddict", "w_superclass"]
- name = None
def __init__(self, space, w_self):
- self.name = ""
+ # fields added here should also be in objspace.py:60ff, 300ff
+ self.name = ''
AbstractCachingShadow.__init__(self, space, w_self)
def getname(self):
return "%s class" % (self.name or '?',)
def sync_cache(self):
+ from spyvm.objspace import UnwrappingError
"Update the ClassShadow with data from the w_self class."
w_self = self.w_self()
+ if w_self.size() == 0:
+ return
+
# read and painfully decode the format
- classformat = self.space.unwrap_int(
- w_self._fetch(constants.CLASS_FORMAT_INDEX))
- # The classformat in Squeak, as an integer value, is:
- # <2 bits=instSize//64><5 bits=cClass><4 bits=instSpec>
- # <6 bits=instSize\\64><1 bit=0>
- # In Slang the value is read directly as a boxed integer, so that
- # the code gets a "pointer" whose bits are set as above, but
- # shifted one bit to the left and with the lowest bit set to 1.
+ try:
+ classformat = self.space.unwrap_int(
+ w_self._fetch(constants.CLASS_FORMAT_INDEX))
+ # The classformat in Squeak, as an integer value, is:
+ # <2 bits=instSize//64><5 bits=cClass><4 bits=instSpec>
+ # <6 bits=instSize\\64><1 bit=0>
+ # In Slang the value is read directly as a boxed integer, so that
+ # the code gets a "pointer" whose bits are set as above, but
+ # shifted one bit to the left and with the lowest bit set to 1.
- # compute the instance size (really the size, not the number of bytes)
- instsize_lo = (classformat >> 1) & 0x3F
- instsize_hi = (classformat >> (9 + 1)) & 0xC0
- self.instance_size = (instsize_lo | instsize_hi) - 1 # subtract hdr
- # decode the instSpec
- format = (classformat >> 7) & 15
- self.instance_varsized = format >= 2
- if format < 4:
- self.instance_kind = POINTERS
- elif format == 4:
- self.instance_kind = WEAK_POINTERS
- elif format == 6:
- self.instance_kind = WORDS
- if self.instance_size != 0:
- raise ClassShadowError("can't have both words and a non-zero "
- "base instance size")
- elif 8 <= format <= 11:
- self.instance_kind = BYTES
- if self.instance_size != 0:
- raise ClassShadowError("can't have both bytes and a non-zero "
- "base instance size")
- elif 12 <= format <= 15:
- self.instance_kind = COMPILED_METHOD
- else:
- raise ClassShadowError("unknown format %d" % (format,))
+ # compute the instance size (really the size, not the number of
bytes)
+ instsize_lo = (classformat >> 1) & 0x3F
+ instsize_hi = (classformat >> (9 + 1)) & 0xC0
+ self.instance_size = (instsize_lo | instsize_hi) - 1 # subtract
hdr
+ # decode the instSpec
+ format = (classformat >> 7) & 15
+ self.instance_varsized = format >= 2
+ if format < 4:
+ self.instance_kind = POINTERS
+ elif format == 4:
+ self.instance_kind = WEAK_POINTERS
+ elif format == 6:
+ self.instance_kind = WORDS
+ if self.instance_size != 0:
+ raise ClassShadowError("can't have both words and a
non-zero "
+ "base instance size")
+ elif 8 <= format <= 11:
+ self.instance_kind = BYTES
+ if self.instance_size != 0:
+ raise ClassShadowError("can't have both bytes and a
non-zero "
+ "base instance size")
+ elif 12 <= format <= 15:
+ self.instance_kind = COMPILED_METHOD
+ else:
+ raise ClassShadowError("unknown format %d" % (format,))
+ except UnwrappingError:
+ assert w_self._fetch(constants.CLASS_FORMAT_INDEX) is
self.space.w_nil
+ pass # not enough information stored in w_self, yet
self.guess_class_name()
@@ -140,8 +145,11 @@
else:
assert isinstance(w_superclass, model.W_PointersObject)
self.w_superclass = w_superclass
+ self.version = Version()
def guess_class_name(self):
+ if self.name != '':
+ return self.name
w_self = self.w_self()
w_name = None
@@ -164,6 +172,9 @@
if isinstance(w_name, model.W_BytesObject):
self.name = w_name.as_string()
+ else:
+ self.name = None
+ self.version = Version()
def new(self, extrasize=0):
w_cls = self.w_self()
@@ -215,15 +226,6 @@
" Number of named instance variables for each instance of this class "
return self.instance_size
- def inherits_from(self, s_superclass):
- classshadow = self
- while classshadow is not None:
- if classshadow is s_superclass:
- return True
- classshadow = classshadow.s_superclass()
- else:
- return False
-
# _______________________________________________________________
# Methods for querying the format word, taken from the blue book:
@@ -241,12 +243,25 @@
look_in_shadow = look_in_shadow.s_superclass()
raise MethodNotFound(self, w_selector)
+ # _______________________________________________________________
+ # Methods used only in testing
+
+ def inherits_from(self, s_superclass):
+ classshadow = self
+ while classshadow is not None:
+ if classshadow is s_superclass:
+ return True
+ classshadow = classshadow.s_superclass()
+ else:
+ return False
+
def initialize_methoddict(self):
"NOT_RPYTHON" # this is only for testing.
if self.w_methoddict is None:
self.w_methoddict = model.W_PointersObject(None, 2)
self.w_methoddict._store(1, model.W_PointersObject(None, 0))
- self.s_methoddict().invalid = False
+ self.s_methoddict().sync_cache()
+ self.s_methoddict().invalid = False
def installmethod(self, w_selector, w_method):
"NOT_RPYTHON" # this is only for testing.
@@ -259,16 +274,36 @@
class MethodDictionaryShadow(AbstractCachingShadow):
+ _immutable_fields_ = ['invalid?']
+
+ def __init__(self, space, w_self):
+ self.invalid = True
+ AbstractCachingShadow.__init__(self, space, w_self)
+
+ def find_selector(self, w_selector):
+ if self.invalid:
+ self.sync_cache()
+ jit.promote(self)
+ version = self.version
+ jit.promote(version)
+ return self._safe_find_selector(w_selector, version)
+
@jit.elidable
- def find_selector(self, w_selector):
+ def _safe_find_selector(self, w_selector, version):
+ assert version is self.version
return self.methoddict.get(w_selector, None)
+ def update(self):
+ # Sync_cache at this point has not the desired effect, because in
+ # the Smalltalk Implementation, the dictionary changes first.
Afterwards
+ # its contents array is filled with the value belonging to the new key.
+ self.invalid = True
+
def sync_cache(self):
w_values = self.w_self()._fetch(constants.METHODDICT_VALUES_INDEX)
assert isinstance(w_values, model.W_PointersObject)
- s_values = w_values.get_shadow(self.space)
- # XXX Should add!
- # s_values.notifyinvalid(self)
+ s_values = w_values.as_observed_get_shadow(self.space)
+ s_values.notify(self)
size = self.w_self().size() - constants.METHODDICT_NAMES_INDEX
self.methoddict = {}
for i in range(size):
@@ -283,6 +318,8 @@
self.methoddict[w_selector] = w_compiledmethod
selector = w_selector.as_string()
w_compiledmethod._likely_methodname = selector
+ self.version = Version()
+ self.invalid = False
class AbstractRedirectingShadow(AbstractShadow):
@@ -310,12 +347,12 @@
self.copy_from_w_self(i)
w_self._vars = None
- def detach_shadow(self):
- w_self = self.w_self()
- assert isinstance(w_self, model.W_PointersObject)
- w_self._vars = [self.space.w_nil] * self._w_self_size
- for i in range(self._w_self_size):
- self.copy_to_w_self(i)
+ # def detach_shadow(self):
+ # w_self = self.w_self()
+ # assert isinstance(w_self, model.W_PointersObject)
+ # w_self._vars = [self.space.w_nil] * self._w_self_size
+ # for i in range(self._w_self_size):
+ # self.copy_to_w_self(i)
def copy_from_w_self(self, n0):
self.store(n0, self.w_self()._fetch(n0))
@@ -846,14 +883,31 @@
return '%s %s (%i)' % (block, self.w_method().get_identifier_string(),
self.pc() + 1)
class CompiledMethodShadow(object):
- _immutable_fields_ = ["_w_self", "bytecode",
- "literals[*]", "bytecodeoffset",
- "literalsize", "tempsize", "primitive",
- "argsize", "islarge",
- "w_compiledin"]
+ _attr_ = ["_w_self", "bytecode",
+ "literals[*]", "bytecodeoffset",
+ "literalsize", "tempsize", "primitive",
+ "argsize", "islarge",
+ "w_compiledin"]
+ _immutable_fields_ = ["version?", "_w_self"]
def __init__(self, w_compiledmethod):
self._w_self = w_compiledmethod
+ self.update()
+
+ def w_self(self):
+ return self._w_self
+
+ def getliteral(self, index):
+ return self.literals[index]
+
+ def getliteralsymbol(self, index):
+ w_literal = self.getliteral(index)
+ assert isinstance(w_literal, model.W_BytesObject)
+ return w_literal.as_string() # XXX performance issue here
+
+ def update(self):
+ w_compiledmethod = self._w_self
+ self.version = Version()
self.bytecode = "".join(w_compiledmethod.bytes)
self.literals = w_compiledmethod.literals
self.bytecodeoffset = w_compiledmethod.bytecodeoffset()
@@ -876,32 +930,13 @@
association = wrapper.AssociationWrapper(None, w_association)
self.w_compiledin = association.value()
- def w_self(self):
- return self._w_self
-
- def getliteral(self, index):
- return self.literals[index]
-
- def getliteralsymbol(self, index):
- w_literal = self.getliteral(index)
- assert isinstance(w_literal, model.W_BytesObject)
- return w_literal.as_string() # XXX performance issue here
-
def create_frame(self, space, receiver, arguments, sender = None):
assert len(arguments) == self.argsize
s_new = MethodContextShadow.make_context(
space, self, receiver, arguments, sender)
return s_new
-class Version:
- pass
-
class CachedObjectShadow(AbstractCachingShadow):
- _immutable_fields_ = ['version?']
-
- def __init__(self, space, w_self):
- AbstractCachingShadow.__init__(self, space, w_self)
- self.version = Version()
def fetch(self, n0):
jit.promote(self)
@@ -918,5 +953,20 @@
self.version = Version()
return self._w_self._store(n0, w_value)
- def update_shadow(self):
- self.version = Version()
\ No newline at end of file
+ def update(self):
+ self.version = Version()
+
+class ObserveeShadow(AbstractShadow):
+ _attr_ = ['dependent']
+ def __init__(self, space, w_self):
+ AbstractShadow.__init__(self, space, w_self)
+ self.dependent = None
+
+ def store(self, n0, w_value):
+ AbstractShadow.store(self, n0, w_value)
+ self.dependent.update()
+
+ def notify(self, dependent):
+ if self.dependent is not None and dependent is not self.dependent:
+ raise RuntimeError('Meant to be observed by only one value, so
far')
+ self.dependent = dependent
\ No newline at end of file
diff --git a/spyvm/squeakimage.py b/spyvm/squeakimage.py
--- a/spyvm/squeakimage.py
+++ b/spyvm/squeakimage.py
@@ -227,6 +227,7 @@
self.init_g_objects()
self.init_w_objects()
self.fillin_w_objects()
+ self.synchronize_shadows()
def read_version(self):
# 1 word version
@@ -300,6 +301,12 @@
for chunk in self.chunks.itervalues():
chunk.g_object.fillin_w_object()
+ def synchronize_shadows(self):
+ for chunk in self.chunks.itervalues():
+ casted = chunk.g_object.w_object
+ if isinstance(casted, model.W_PointersObject) and
casted.has_shadow():
+ casted._shadow.update()
+
def init_compactclassesarray(self):
""" from the blue book (CompiledMethod Symbol Array PseudoContext
LargePositiveInteger nil MethodDictionary Association Point Rectangle nil
TranslatedMethod BlockContext MethodContext nil nil nil nil nil nil nil nil nil
nil nil nil nil nil nil nil nil ) """
special = self.chunks[self.specialobjectspointer]
@@ -491,9 +498,6 @@
self.w_object = objectmodel.instantiate(model.W_CompiledMethod)
else:
assert 0, "not reachable"
- else:
- #XXX invalidate shadow here
- pass
return self.w_object
def fillin_w_object(self):
@@ -515,9 +519,6 @@
def fillin_pointersobject(self, w_pointersobject):
assert self.pointers is not None
- # XXX is the following needed?
- if w_pointersobject._shadow is not None:
- w_pointersobject._shadow.detach_shadow()
w_pointersobject._vars = [g_object.w_object for g_object in
self.pointers]
w_class = self.g_class.w_object
assert isinstance(w_class, model.W_PointersObject)
diff --git a/spyvm/test/test_bootstrappedimage.py
b/spyvm/test/test_bootstrappedimage.py
--- a/spyvm/test/test_bootstrappedimage.py
+++ b/spyvm/test/test_bootstrappedimage.py
@@ -7,7 +7,9 @@
tools.setup_module(tools, filename='bootstrapped.image')
def find_symbol_in_methoddict_of(string, s_class):
- methoddict_w = s_class.s_methoddict().methoddict
+ s_methoddict = s_class.s_methoddict()
+ s_methoddict.sync_cache()
+ methoddict_w = s_methoddict.methoddict
for each in methoddict_w.keys():
if each.as_string() == string:
return each
@@ -55,4 +57,4 @@
sends = perform(w(5), 'benchFib')
t1 = time.time()
t = t1 - t0
- print str(tools.space.unwrap_int(sends)/t) + " sends per second"
\ No newline at end of file
+ print str(tools.space.unwrap_int(sends)/t) + " sends per second"
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
@@ -62,7 +62,8 @@
assert space.w_nil._shadow is None
for (w_class, _, _, methname) in methods:
s_class = w_class.as_class_get_shadow(space)
- del s_class.s_methoddict().methoddict[fakesymbol(methname)]
+ s_class.update()
+ s_class.s_methoddict().update()
def fakesymbol(s, _cache={}):
try:
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
@@ -270,7 +270,7 @@
perform(w(10).getclass(space), "compile:classified:notifying:",
w(sourcecode), w('pypy'), w(None))
w_result = perform(w(10), "testBecome")
assert space.unwrap_int(w_result) == 42
-
+
def perform(w_receiver, selector, *arguments_w):
return interp.perform(w_receiver, selector, *arguments_w)
@@ -282,6 +282,20 @@
assert isinstance(s_ctx, shadow.MethodContextShadow)
assert s_ctx.top().is_same_object(space.w_true)
+def test_cached_methoddict_compile():
+ sourcecode = """fib
+ ^self < 2
+ ifTrue: [ 1 ]
+ ifFalse: [ ((self - 1) fib + (self - 2) fib) + 1
]"""
+ perform(w(10).getclass(space), "compile:classified:notifying:",
w(sourcecode), w('pypy'), w(None))
+ assert perform(w(5), "fib").is_same_object(w(15))
+ sourcecode = """fib
+ ^self < 2
+ ifTrue: [ 1 ]
+ ifFalse: [ (self - 1) fib + (self - 2) fib ]"""
+ perform(w(10).getclass(space), "compile:classified:notifying:",
w(sourcecode), w('pypy'), w(None))
+ assert perform(w(10), "fib").is_same_object(w(89))
+
def test_step_run_something():
from spyvm.test import test_miniimage
setup_module(test_miniimage, filename='running-something-mini.image')
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
@@ -1,5 +1,5 @@
import random
-from spyvm import model, shadow, constants
+from spyvm import model, shadow, constants, interpreter
from spyvm import objspace
space = objspace.ObjSpace()
@@ -42,6 +42,7 @@
w_class.store(space, constants.CLASS_FORMAT_INDEX, space.wrap_int(format))
if name is not None:
w_class.store(space, constants.CLASS_NAME_INDEX,
space.wrap_string(name))
+ w_class.as_class_get_shadow(space).s_methoddict().sync_cache()
return w_class
def basicshape(name, format, kind, varsized, instsize):
@@ -152,32 +153,24 @@
assert s_object.getbytecode() == 101
assert s_object.s_home() == s_object
-def test_attach_detach_mc():
+def test_attach_mc():
w_m = method()
w_object = methodcontext(pc=13, method=w_m)
old_vars = w_object._vars
s_object = w_object.as_methodcontext_get_shadow(space)
assert w_object._vars is None
- s_object.detach_shadow()
- assert w_object._vars == old_vars
- assert w_object._vars is not old_vars
-def test_attach_detach_bc():
+def test_attach_bc():
w_object = blockcontext(pc=13)
old_vars = w_object._vars
s_object = w_object.as_blockcontext_get_shadow(space)
assert w_object._vars is None
- s_object.detach_shadow()
- assert w_object._vars == old_vars
- assert w_object._vars is not old_vars
def test_replace_to_bc():
w_object = blockcontext(pc=13)
old_vars = w_object._vars
s_object = w_object.as_blockcontext_get_shadow(space)
- s_object.detach_shadow()
- s_classshadow = shadow.ClassShadow(space, w_object)
- w_object._shadow = s_classshadow
+ s_object._shadow = None
s_newobject = w_object.as_blockcontext_get_shadow(space)
assert ([s_newobject.fetch(i) for i in range(s_newobject.size())] ==
[s_object.fetch(i) for i in range(s_newobject.size())])
@@ -197,16 +190,13 @@
w_compiledmethod.literalatput0(space, 1, 17)
w_compiledmethod.literalatput0(space, 2, 41)
- assert w_compiledmethod._shadow is None
-
- shadow = w_compiledmethod.as_compiledmethod_get_shadow(space)
+ assert w_compiledmethod._shadow is not None
assert shadow.literals == [17, 41]
w_compiledmethod.atput0(space, 14, space.wrap_int(ord("x")))
- assert w_compiledmethod._shadow is None
- shadow = w_compiledmethod.as_compiledmethod_get_shadow(space)
assert shadow.bytecode == "abx"
+ assert shadow is w_compiledmethod.as_compiledmethod_get_shadow(space)
def test_cached_object_shadow():
w_o = space.wrap_list([0, 1, 2, 3, 4, 5, 6, 7])
@@ -216,4 +206,24 @@
assert w_o.at0(space, i) == i
w_o.atput0(space, 0, 8)
assert version is not s_o.version
- assert w_o.at0(space, 0) == 8
\ No newline at end of file
+ assert w_o.at0(space, 0) == 8
+
+def test_observee_shadow():
+ notified = False
+ class Observer():
+ def __init__(self): self.notified = False
+ def update(self): self.notified = True
+ o = Observer()
+ w_o = w_Array.as_class_get_shadow(space).new(1)
+ w_o.as_observed_get_shadow(space).notify(o)
+ assert not o.notified
+ w_o.store(space, 0, 1)
+ assert o.notified
+ assert w_o.fetch(space, 0) == 1
+ try:
+ w_o._shadow.notify(Observer())
+ except RuntimeError:
+ pass
+ else:
+ assert False
+
diff --git a/spyvm/todo.txt b/spyvm/todo.txt
--- a/spyvm/todo.txt
+++ b/spyvm/todo.txt
@@ -53,9 +53,3 @@
return model.W_SmallInteger(rerased.erase_int(val))
except OverflowError:
raise WrappingError("integer too large to fit into a tagged
pointer")
-
-make classes
-
-
-Unclarities:
-[ ] should image loading invalidate the shadows of the precreated objects?
\ No newline at end of file
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit