[pypy-commit] lang-smalltalk storage-vref: Added vref refactoring: keeping a virtual back-reference to the sender as long as possible.
anton_gulenko
noreply at buildbot.pypy.org
Mon Jul 28 10:11:29 CEST 2014
Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage-vref
Changeset: r992:3fa384225c32
Date: 2014-07-10 12:56 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/3fa384225c32/
Log: Added vref refactoring: keeping a virtual back-reference to the
sender as long as possible. TODO: Explore why this breaks
performance; it should actually improve it.
diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -67,6 +67,9 @@
s_new_context = w_active_context.as_context_get_shadow(self.space)
while True:
assert self.current_stack_depth == 0
+ # Need to save s_sender, loop_bytecodes will nil this on return
+ # Virtual references are not allowed here, and neither are "fresh" contexts (except for the toplevel one).
+ assert s_new_context.virtual_sender is jit.vref_None
s_sender = s_new_context.s_sender()
try:
self.loop_bytecodes(s_new_context)
@@ -119,19 +122,27 @@
# This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame
# and handles the stack overflow protection mechanism.
def stack_frame(self, s_frame, s_sender, may_context_switch=True):
+ assert s_frame.virtual_sender is jit.vref_None
try:
- if s_frame._s_sender is None and s_sender is not None:
- s_frame.store_s_sender(s_sender, raise_error=False)
-
+ # Enter the context - store a virtual reference back to the sender
+ # Non-fresh contexts can happen, e.g. when activating a stored BlockContext.
+ # The same frame object must not pass through here recursively!
+ if s_frame.is_fresh() and s_sender is not None:
+ s_frame.virtual_sender = jit.virtual_ref(s_sender)
+
self.current_stack_depth += 1
if self.max_stack_depth > 0:
if self.current_stack_depth >= self.max_stack_depth:
raise StackOverflow(s_frame)
-
+
# Now (continue to) execute the context bytecodes
self.loop_bytecodes(s_frame, may_context_switch)
finally:
self.current_stack_depth -= 1
+ # Cleanly leave the context. This will finish the virtual sender-reference, if
+ # it is still there, which can happen in case of ProcessSwitch or StackOverflow;
+ # in case of a Return, this will already be handled while unwinding the stack.
+ s_frame.finish_virtual_sender(s_sender)
def step(self, context):
bytecode = context.fetch_next_bytecode()
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -607,13 +607,13 @@
class ContextPartShadow(AbstractRedirectingShadow):
__metaclass__ = extendabletype
- _attrs_ = ['_s_sender',
+ _attrs_ = ['direct_sender', 'virtual_sender',
'_pc', '_temps_and_stack',
'_stack_ptr', 'instances_w']
repr_classname = "ContextPartShadow"
_virtualizable_ = [
- '_s_sender',
+ 'direct_sender', 'virtual_sender',
"_pc", "_temps_and_stack[*]", "_stack_ptr",
"_w_self", "_w_self_size"
]
@@ -622,7 +622,8 @@
# Initialization
def __init__(self, space, w_self):
- self._s_sender = None
+ self.direct_sender = None
+ self.virtual_sender = jit.vref_None
AbstractRedirectingShadow.__init__(self, space, w_self)
self.instances_w = {}
@@ -691,9 +692,25 @@
raise error.WrapperException("Index in context out of bounds")
# === Sender ===
+ # There are two fields for the sender (virtual and direct). Only one of them is can be set at a time.
+ # As long as the frame object is virtualized, using the virtual reference should increase performance.
+ # As soon as a frame object is forced to the heap, the direct reference must be used.
+
+ def is_fresh(self):
+ return self.direct_sender is None and self.virtual_sender is jit.vref_None
+
+ def finish_virtual_sender(self, s_sender):
+ if self.virtual_sender is not jit.vref_None:
+ if self.pc() != -1:
+ # stack is unrolling, but this frame was not
+ # marked_returned: it is an escaped frame
+ sender = self.virtual_sender()
+ self.direct_sender = sender
+ jit.virtual_ref_finish(self.virtual_sender, s_sender)
+ self.virtual_sender = jit.vref_None
def store_s_sender(self, s_sender, raise_error=True):
- self._s_sender = s_sender
+ self.direct_sender = s_sender
if raise_error:
raise error.SenderChainManipulation(self)
@@ -704,7 +721,11 @@
return sender.w_self()
def s_sender(self):
- return self._s_sender
+ if self.direct_sender:
+ return self.direct_sender
+ else:
+ result = self.virtual_sender()
+ return result
# === Stack Pointer ===
More information about the pypy-commit
mailing list