[pypy-commit] pypy default: merge upstream
snus_mumrik
noreply at buildbot.pypy.org
Mon Jun 13 09:44:21 CEST 2011
Author: Ilya Osadchiy <osadchiy.ilya at gmail.com>
Branch:
Changeset: r44896:cc5eb3a2d608
Date: 2011-06-01 01:20 +0300
http://bitbucket.org/pypy/pypy/changeset/cc5eb3a2d608/
Log: merge upstream
diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py
--- a/pypy/annotation/model.py
+++ b/pypy/annotation/model.py
@@ -32,13 +32,15 @@
import pypy
from pypy.tool import descriptor
from pypy.tool.pairtype import pair, extendabletype
-from pypy.tool.tls import tlsobject
from pypy.rlib.rarithmetic import r_uint, r_ulonglong, base_int
from pypy.rlib.rarithmetic import r_singlefloat, r_longfloat
import inspect, weakref
DEBUG = False # set to False to disable recording of debugging information
-TLS = tlsobject()
+
+class State(object):
+ pass
+TLS = State()
class SomeObject(object):
"""The set of all objects. Each instance stands
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -11,14 +11,14 @@
"""Interpreter-level exception that signals an exception that should be
sent to the application level.
- OperationError instances have three public attributes (and no .args),
- w_type, w_value and application_traceback, which contain the wrapped
+ OperationError instances have three attributes (and no .args),
+ w_type, _w_value and _application_traceback, which contain the wrapped
type and value describing the exception, and a chained list of
PyTraceback objects making the application-level traceback.
"""
_w_value = None
- application_traceback = None
+ _application_traceback = None
def __init__(self, w_type, w_value, tb=None):
if not we_are_translated() and w_type is None:
@@ -26,7 +26,7 @@
raise FlowingError(w_value)
self.setup(w_type)
self._w_value = w_value
- self.application_traceback = tb
+ self._application_traceback = tb
def setup(self, w_type):
self.w_type = w_type
@@ -37,7 +37,7 @@
# for sys.exc_clear()
self.w_type = space.w_None
self._w_value = space.w_None
- self.application_traceback = None
+ self._application_traceback = None
if not we_are_translated():
del self.debug_excs[:]
@@ -103,7 +103,7 @@
def print_app_tb_only(self, file):
"NOT_RPYTHON"
- tb = self.application_traceback
+ tb = self._application_traceback
if tb:
import linecache
print >> file, "Traceback (application-level):"
@@ -251,6 +251,30 @@
def _compute_value(self):
raise NotImplementedError
+ def get_traceback(self):
+ """Calling this marks the PyTraceback as escaped, i.e. it becomes
+ accessible and inspectable by app-level Python code. For the JIT.
+ Note that this has no effect if there are already several traceback
+ frames recorded, because in this case they are already marked as
+ escaping by executioncontext.leave() being called with
+ got_exception=True.
+ """
+ from pypy.interpreter.pytraceback import PyTraceback
+ tb = self._application_traceback
+ if tb is not None and isinstance(tb, PyTraceback):
+ tb.frame.mark_as_escaped()
+ return tb
+
+ def set_traceback(self, traceback):
+ """Set the current traceback. It should either be a traceback
+ pointing to some already-escaped frame, or a traceback for the
+ current frame. To support the latter case we do not mark the
+ frame as escaped. The idea is that it will be marked as escaping
+ only if the exception really propagates out of this frame, by
+ executioncontext.leave() being called with got_exception=True.
+ """
+ self._application_traceback = traceback
+
# ____________________________________________________________
# optimization only: avoid the slowest operation -- the string
# formatting with '%' -- in the common case were we don't
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -58,13 +58,23 @@
frame.f_backref = self.topframeref
self.topframeref = jit.virtual_ref(frame)
- def leave(self, frame, w_exitvalue):
+ def leave(self, frame, w_exitvalue, got_exception):
try:
if self.profilefunc:
self._trace(frame, 'leaveframe', w_exitvalue)
finally:
+ frame_vref = self.topframeref
self.topframeref = frame.f_backref
- jit.virtual_ref_finish(frame)
+ if frame.escaped or got_exception:
+ # if this frame escaped to applevel, we must ensure that also
+ # f_back does
+ f_back = frame.f_backref()
+ if f_back:
+ f_back.mark_as_escaped()
+ # force the frame (from the JIT point of view), so that it can
+ # be accessed also later
+ frame_vref()
+ jit.virtual_ref_finish(frame_vref, frame)
if self.w_tracefunc is not None and not frame.hide():
self.space.frame_trace_action.fire()
@@ -276,7 +286,7 @@
if operr is not None:
w_value = operr.get_w_value(space)
w_arg = space.newtuple([operr.w_type, w_value,
- space.wrap(operr.application_traceback)])
+ space.wrap(operr.get_traceback())])
frame.fast2locals()
self.is_tracing += 1
diff --git a/pypy/interpreter/main.py b/pypy/interpreter/main.py
--- a/pypy/interpreter/main.py
+++ b/pypy/interpreter/main.py
@@ -118,7 +118,7 @@
operationerr.normalize_exception(space)
w_type = operationerr.w_type
w_value = operationerr.get_w_value(space)
- w_traceback = space.wrap(operationerr.application_traceback)
+ w_traceback = space.wrap(operationerr.get_traceback())
# for debugging convenience we also insert the exception into
# the interpreter-level sys.last_xxx
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -49,6 +49,7 @@
instr_ub = 0
instr_prev_plus_one = 0
is_being_profiled = False
+ escaped = False # see mark_as_escaped()
def __init__(self, space, code, w_globals, closure):
self = hint(self, access_directly=True, fresh_virtualizable=True)
@@ -67,6 +68,15 @@
make_sure_not_resized(self.fastlocals_w)
self.f_lineno = code.co_firstlineno
+ def mark_as_escaped(self):
+ """
+ Must be called on frames that are exposed to applevel, e.g. by
+ sys._getframe(). This ensures that the virtualref holding the frame
+ is properly forced by ec.leave(), and thus the frame will be still
+ accessible even after the corresponding C stack died.
+ """
+ self.escaped = True
+
def append_block(self, block):
block.previous = self.lastblock
self.lastblock = block
@@ -138,6 +148,7 @@
not self.space.config.translating)
executioncontext = self.space.getexecutioncontext()
executioncontext.enter(self)
+ got_exception = True
w_exitvalue = self.space.w_None
try:
executioncontext.call_trace(self)
@@ -164,8 +175,9 @@
# clean up the exception, might be useful for not
# allocating exception objects in some cases
self.last_exception = None
+ got_exception = False
finally:
- executioncontext.leave(self, w_exitvalue)
+ executioncontext.leave(self, w_exitvalue, got_exception)
return w_exitvalue
execute_frame.insert_stack_check_here = True
@@ -312,7 +324,7 @@
w_tb = space.w_None
else:
w_exc_value = self.last_exception.get_w_value(space)
- w_tb = w(self.last_exception.application_traceback)
+ w_tb = w(self.last_exception.get_traceback())
tup_state = [
w(self.f_backref()),
@@ -633,7 +645,7 @@
while f is not None and f.last_exception is None:
f = f.f_backref()
if f is not None:
- return space.wrap(f.last_exception.application_traceback)
+ return space.wrap(f.last_exception.get_traceback())
return space.w_None
def fget_f_restricted(self, space):
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -566,7 +566,7 @@
else:
msg = "raise: arg 3 must be a traceback or None"
tb = pytraceback.check_traceback(space, w_traceback, msg)
- operror.application_traceback = tb
+ operror.set_traceback(tb)
# special 3-arguments raise, no new traceback obj will be attached
raise RaiseWithExplicitTraceback(operror)
@@ -946,7 +946,7 @@
isinstance(unroller, SApplicationException))
if is_app_exc:
operr = unroller.operr
- w_traceback = self.space.wrap(operr.application_traceback)
+ w_traceback = self.space.wrap(operr.get_traceback())
w_suppress = self.call_contextmanager_exit_function(
w_exitfunc,
operr.w_type,
diff --git a/pypy/interpreter/pytraceback.py b/pypy/interpreter/pytraceback.py
--- a/pypy/interpreter/pytraceback.py
+++ b/pypy/interpreter/pytraceback.py
@@ -51,9 +51,9 @@
def record_application_traceback(space, operror, frame, last_instruction):
if frame.pycode.hidden_applevel:
return
- tb = operror.application_traceback
+ tb = operror.get_traceback()
tb = PyTraceback(space, frame, last_instruction, tb)
- operror.application_traceback = tb
+ operror.set_traceback(tb)
def offset2lineno(c, stopat):
tab = c.co_lnotab
diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -98,6 +98,15 @@
return sys._getframe().f_back.f_code.co_name
f()
+ def test_f_back_virtualref(self):
+ import sys
+ def f():
+ return g()
+ def g():
+ return sys._getframe()
+ frame = f()
+ assert frame.f_back.f_code.co_name == 'f'
+
def test_f_exc_xxx(self):
import sys
@@ -122,6 +131,21 @@
except:
g(sys.exc_info())
+ def test_virtualref_through_traceback(self):
+ import sys
+ def g():
+ try:
+ raise ValueError
+ except:
+ _, _, tb = sys.exc_info()
+ return tb
+ def f():
+ return g()
+ #
+ tb = f()
+ assert tb.tb_frame.f_code.co_name == 'g'
+ assert tb.tb_frame.f_back.f_code.co_name == 'f'
+
def test_trace_basic(self):
import sys
l = []
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -1102,6 +1102,8 @@
self.mc.MOV_bi(FORCE_INDEX_OFS, force_index)
return force_index
else:
+ # the return value is ignored, apart from the fact that it
+ # is not negative.
return 0
genop_int_neg = _unaryop("NEG")
diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py
--- a/pypy/jit/backend/x86/test/test_zrpy_gc.py
+++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py
@@ -525,8 +525,8 @@
glob = A()
def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s):
a = A()
- glob.v = virtual_ref(a)
- virtual_ref_finish(a)
+ glob.v = vref = virtual_ref(a)
+ virtual_ref_finish(vref, a)
n -= 1
return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s
return None, f, None
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -432,6 +432,9 @@
v1 = self.getvalue(op.getarg(0))
v2 = self.getvalue(op.getarg(1))
+ if v2.is_constant() and v2.box.getint() == 1:
+ self.make_equal_to(op.result, v1)
+ return
if v1.intbound.known_ge(IntBound(0, 0)) and v2.is_constant():
val = v2.box.getint()
if val & (val - 1) == 0 and val > 0: # val == 2**shift
diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py
--- a/pypy/jit/metainterp/optimizeopt/virtualize.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualize.py
@@ -330,18 +330,28 @@
vrefvalue.setfield(descr_virtual_token, self.getvalue(tokenbox))
def optimize_VIRTUAL_REF_FINISH(self, op):
- # Set the 'forced' field of the virtual_ref.
- # In good cases, this is all virtual, so has no effect.
- # Otherwise, this forces the real object -- but only now, as
- # opposed to much earlier. This is important because the object is
- # typically a PyPy PyFrame, and now is the end of its execution, so
- # forcing it now does not have catastrophic effects.
+ # This operation is used in two cases. In normal cases, it
+ # is the end of the frame, and op.getarg(1) is NULL. In this
+ # case we just clear the vref.virtual_token, because it contains
+ # a stack frame address and we are about to leave the frame.
+ # In that case vref.forced should still be NULL, and remains
+ # NULL; and accessing the frame through the vref later is
+ # *forbidden* and will raise InvalidVirtualRef.
+ #
+ # In the other (uncommon) case, the operation is produced
+ # earlier, because the vref was forced during tracing already.
+ # In this case, op.getarg(1) is the virtual to force, and we
+ # have to store it in vref.forced.
+ #
vrefinfo = self.optimizer.metainterp_sd.virtualref_info
- # op.getarg(1) should really never point to null here
+ seo = self.optimizer.send_extra_operation
+
# - set 'forced' to point to the real object
- seo = self.optimizer.send_extra_operation
- seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None,
- descr = vrefinfo.descr_forced))
+ objbox = op.getarg(1)
+ if not self.optimizer.cpu.ts.CONST_NULL.same_constant(objbox):
+ seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None,
+ descr = vrefinfo.descr_forced))
+
# - set 'virtual_token' to TOKEN_NONE
args = [op.getarg(0), ConstInt(vrefinfo.TOKEN_NONE)]
seo(ResOperation(rop.SETFIELD_GC, args, None,
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -4,7 +4,7 @@
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.debug import debug_start, debug_stop, debug_print
from pypy.rlib.debug import make_sure_not_resized
-from pypy.rlib import nonconst
+from pypy.rlib import nonconst, rstack
from pypy.jit.metainterp import history, compile, resume
from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstFloat
@@ -1049,8 +1049,10 @@
vrefinfo = metainterp.staticdata.virtualref_info
vref = vrefbox.getref_base()
if vrefinfo.is_virtual_ref(vref):
+ # XXX write a comment about nullbox
+ nullbox = self.metainterp.cpu.ts.CONST_NULL
metainterp.history.record(rop.VIRTUAL_REF_FINISH,
- [vrefbox, lastbox], None)
+ [vrefbox, nullbox], None)
@arguments()
def opimpl_ll_read_timestamp(self):
@@ -2052,10 +2054,16 @@
def initialize_state_from_guard_failure(self, resumedescr):
# guard failure: rebuild a complete MIFrame stack
- self.in_recursion = -1 # always one portal around
- self.history = history.History()
- inputargs_and_holes = self.rebuild_state_after_failure(resumedescr)
- self.history.inputargs = [box for box in inputargs_and_holes if box]
+ # This is stack-critical code: it must not be interrupted by StackOverflow,
+ # otherwise the jit_virtual_refs are left in a dangling state.
+ rstack._stack_criticalcode_start()
+ try:
+ self.in_recursion = -1 # always one portal around
+ self.history = history.History()
+ inputargs_and_holes = self.rebuild_state_after_failure(resumedescr)
+ self.history.inputargs = [box for box in inputargs_and_holes if box]
+ finally:
+ rstack._stack_criticalcode_stop()
def initialize_virtualizable(self, original_boxes):
vinfo = self.jitdriver_sd.virtualizable_info
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -6,7 +6,7 @@
from pypy.jit.metainterp import jitprof
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr
-from pypy.rlib import rarithmetic
+from pypy.rlib import rarithmetic, rstack
from pypy.rlib.objectmodel import we_are_translated, specialize
from pypy.rlib.debug import have_debug_prints, ll_assert
from pypy.rlib.debug import debug_start, debug_stop, debug_print
@@ -978,12 +978,18 @@
def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage,
all_virtuals=None):
- resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd,
- storage, all_virtuals)
- vinfo = jitdriver_sd.virtualizable_info
- ginfo = jitdriver_sd.greenfield_info
- vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info
- resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
+ # The initialization is stack-critical code: it must not be interrupted by
+ # StackOverflow, otherwise the jit_virtual_refs are left in a dangling state.
+ rstack._stack_criticalcode_start()
+ try:
+ resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd,
+ storage, all_virtuals)
+ vinfo = jitdriver_sd.virtualizable_info
+ ginfo = jitdriver_sd.greenfield_info
+ vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info
+ resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
+ finally:
+ rstack._stack_criticalcode_stop()
#
# First get a chain of blackhole interpreters whose length is given
# by the depth of rd_frame_info_list. The first one we get must be
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
--- a/pypy/jit/metainterp/test/support.py
+++ b/pypy/jit/metainterp/test/support.py
@@ -26,6 +26,10 @@
def attach_unoptimized_bridge_from_interp(self, greenkey, newloop):
pass
+ def helper_func(self, FUNCPTR, func):
+ from pypy.rpython.annlowlevel import llhelper
+ return llhelper(FUNCPTR, func)
+
def jit_cell_at_key(self, greenkey):
assert greenkey == []
return self._cell
@@ -37,6 +41,7 @@
func._jit_unroll_safe_ = True
rtyper = support.annotate(func, values, type_system=type_system)
graphs = rtyper.annotator.translator.graphs
+ testself.all_graphs = graphs
result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0]
class FakeJitDriverSD:
diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/test/test_optimizeopt.py
@@ -3899,7 +3899,7 @@
jump(i4, i10)
"""
self.optimize_loop(ops, expected)
-
+
def test_add_sub_ovf(self):
ops = """
[i1]
@@ -3939,7 +3939,7 @@
[i0, i1]
escape(i1)
i2 = int_add_ovf(i0, 1)
- guard_no_overflow() []
+ guard_no_overflow() []
jump(i2, i0)
"""
self.optimize_loop(ops, expected)
@@ -4420,7 +4420,6 @@
i8 = int_floordiv(4, i2)
i9 = int_rshift(i1, 2)
i10 = int_floordiv(i1, 0)
- i11 = int_rshift(i1, 0)
i12 = int_floordiv(i2, 2)
i13 = int_floordiv(i2, 3)
i14 = int_floordiv(i2, 4)
@@ -4497,6 +4496,18 @@
"""
self.optimize_loop(ops, expected)
+ def test_int_div_1(self):
+ ops = """
+ [i0]
+ i1 = int_floordiv(i0, 1)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
def test_subsub_ovf(self):
ops = """
[i0]
diff --git a/pypy/jit/metainterp/test/test_virtualref.py b/pypy/jit/metainterp/test/test_virtualref.py
--- a/pypy/jit/metainterp/test/test_virtualref.py
+++ b/pypy/jit/metainterp/test/test_virtualref.py
@@ -1,9 +1,10 @@
import py
from pypy.rpython.lltypesystem import lltype, llmemory, lloperation
+from pypy.rpython.llinterp import LLException
from pypy.rlib.jit import JitDriver, dont_look_inside, vref_None
-from pypy.rlib.jit import virtual_ref, virtual_ref_finish
+from pypy.rlib.jit import virtual_ref, virtual_ref_finish, InvalidVirtualRef
from pypy.rlib.objectmodel import compute_unique_id
-from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, _get_jitcodes
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp.virtualref import VirtualRefInfo
@@ -16,6 +17,29 @@
self.vrefinfo = VirtualRefInfo(self.warmrunnerstate)
self.cw.setup_vrefinfo(self.vrefinfo)
+ def test_rewrite_graphs(self):
+ class X:
+ pass
+ def fn():
+ x = X()
+ vref = virtual_ref(x)
+ x1 = vref() # jit_force_virtual
+ virtual_ref_finish(vref, x)
+ #
+ _get_jitcodes(self, self.CPUClass, fn, [], self.type_system)
+ graph = self.all_graphs[0]
+ assert graph.name == 'fn'
+ self.vrefinfo.replace_force_virtual_with_call([graph])
+ #
+ def check_call(op, fname):
+ assert op.opname == 'direct_call'
+ assert op.args[0].value._obj._name == fname
+ #
+ ops = [op for block, op in graph.iterblockops()]
+ check_call(ops[-3], 'virtual_ref')
+ check_call(ops[-2], 'force_virtual_if_necessary')
+ check_call(ops[-1], 'virtual_ref_finish')
+
def test_make_vref_simple(self):
class X:
pass
@@ -25,9 +49,9 @@
#
def f():
x = X()
- exctx.topframeref = virtual_ref(x)
+ exctx.topframeref = vref = virtual_ref(x)
exctx.topframeref = vref_None
- virtual_ref_finish(x)
+ virtual_ref_finish(vref, x)
return 1
#
self.interp_operations(f, [])
@@ -60,8 +84,9 @@
exctx._frame = x
exctx.topframeref = virtual_ref(x)
def leave():
+ vref = exctx.topframeref
exctx.topframeref = vref_None
- virtual_ref_finish(exctx._frame)
+ virtual_ref_finish(vref, exctx._frame)
def f(n):
enter(n)
n = external(n)
@@ -125,7 +150,8 @@
#
@dont_look_inside
def g(vref):
- debug_print(lltype.Void, '-+-+-+-+- external read:', vref().n)
+ # we cannot do anything with the vref after the call to finish()
+ pass
#
def f(n):
while n > 0:
@@ -136,7 +162,7 @@
exctx.topframeref = vref = virtual_ref(x)
# here, 'x' should be virtual
exctx.topframeref = vref_None
- virtual_ref_finish(x)
+ virtual_ref_finish(vref, x)
# 'x' and 'vref' can randomly escape after the call to
# finish().
g(vref)
@@ -144,7 +170,7 @@
return 1
#
self.meta_interp(f, [10])
- self.check_loops(new_with_vtable=2) # the vref and the X
+ self.check_loops(new_with_vtable=1) # the vref
self.check_aborted_count(0)
def test_simple_all_removed(self):
@@ -169,13 +195,13 @@
xy.next1 = lltype.malloc(A, 0)
xy.next2 = lltype.malloc(A, 0)
xy.next3 = lltype.malloc(A, 0)
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
n -= externalfn(n)
exctx.topframeref = vref_None
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
xy.next3 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
#
self.meta_interp(f, [15])
self.check_loops(new_with_vtable=0, # all virtualized
@@ -206,17 +232,17 @@
xy.next1 = lltype.malloc(A, 0)
xy.next2 = lltype.malloc(A, 0)
xy.next3 = lltype.malloc(A, 0)
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
n -= externalfn(n)
exctx.topframeref = vref_None
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
xy.next3 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
#
self.meta_interp(f, [15])
- self.check_loops(new_with_vtable=2, # the vref, and xy so far,
- new_array=0) # but not xy.next1/2/3
+ self.check_loops(new_with_vtable=1, # the vref: xy doesn't need to be forced
+ new_array=0) # and neither xy.next1/2/3
self.check_aborted_count(0)
def test_simple_force_always(self):
@@ -244,12 +270,12 @@
xy.next2 = lltype.malloc(A, 0)
xy.next3 = lltype.malloc(A, 0)
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
n -= externalfn(n)
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
xy.next3 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
exctx.topframeref = vref_None
#
self.meta_interp(f, [15])
@@ -282,19 +308,19 @@
xy.next2 = lltype.malloc(A, 0)
xy.next3 = lltype.malloc(A, 0)
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
n -= externalfn(n)
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
xy.next3 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
exctx.topframeref = vref_None
return exctx.m
#
res = self.meta_interp(f, [30])
assert res == 13
- self.check_loops(new_with_vtable=2, # the vref, XY() at the end
- new_array=0) # but not next1/2/3
+ self.check_loops(new_with_vtable=1, # the vref, but not XY()
+ new_array=0) # and neither next1/2/3
self.check_loop_count(1)
self.check_aborted_count(0)
@@ -322,7 +348,7 @@
xy.next2 = lltype.malloc(A, 0)
xy.next3 = lltype.malloc(A, 0)
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
if n == 13:
externalfn(n)
n -= 1
@@ -330,7 +356,7 @@
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
xy.next3 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
return exctx.m
#
res = self.meta_interp(f, [30])
@@ -366,7 +392,7 @@
xy.next4 = lltype.malloc(A, 0)
xy.next5 = lltype.malloc(A, 0)
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
if n % 6 == 0:
xy.next1 = lltype.nullptr(A)
xy.next2 = lltype.nullptr(A)
@@ -379,7 +405,7 @@
xy.next3 = lltype.nullptr(A)
xy.next4 = lltype.nullptr(A)
xy.next5 = lltype.nullptr(A)
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
return exctx.m
#
res = self.meta_interp(f, [72])
@@ -389,36 +415,6 @@
new_array=2) # bridge: next4, next5
self.check_aborted_count(0)
- def test_access_vref_later(self):
- myjitdriver = JitDriver(greens = [], reds = ['n'])
- #
- class XY:
- pass
- class ExCtx:
- pass
- exctx = ExCtx()
- #
- @dont_look_inside
- def g():
- return exctx.later().n
- #
- def f(n):
- while n > 0:
- myjitdriver.can_enter_jit(n=n)
- myjitdriver.jit_merge_point(n=n)
- xy = XY()
- xy.n = n
- exctx.topframeref = virtual_ref(xy)
- exctx.later = exctx.topframeref
- n -= 1
- exctx.topframeref = vref_None
- virtual_ref_finish(xy)
- return g()
- #
- res = self.meta_interp(f, [15])
- assert res == 1
- self.check_aborted_count(0)
-
def test_jit_force_virtual_seen(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
#
@@ -435,12 +431,12 @@
myjitdriver.jit_merge_point(n=n)
xy = XY()
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
xy.next1 = lltype.malloc(A, 0)
n = exctx.topframeref().n - 1
xy.next1 = lltype.nullptr(A)
exctx.topframeref = vref_None
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
return 1
#
res = self.meta_interp(f, [15])
@@ -465,12 +461,12 @@
if reclevel == 0:
return n
xy = XY()
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
m = f(xy, n, reclevel-1)
assert m == n
n -= 1
exctx.topframeref = vref_None
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
return 2
def main(n, reclevel):
return f(XY(), n, reclevel)
@@ -495,7 +491,7 @@
frame.n += 1
xy = XY()
xy.n = n
- exctx.topframeref = virtual_ref(xy)
+ exctx.topframeref = vref = virtual_ref(xy)
if reclevel > 0:
m = f(xy, frame.n, reclevel-1)
assert xy.n == m
@@ -503,7 +499,7 @@
else:
n -= 2
exctx.topframeref = vref_None
- virtual_ref_finish(xy)
+ virtual_ref_finish(vref, xy)
return frame.n
def main(n, reclevel):
return f(XY(), n, reclevel)
@@ -540,7 +536,7 @@
escapexy(xy)
# clean up
exctx.vr = vref_None
- virtual_ref_finish(xy)
+ virtual_ref_finish(vr, xy)
n -= 1
return 1
#
@@ -548,6 +544,57 @@
assert res == 1
self.check_loops(new_with_vtable=2) # vref, xy
+ def test_cannot_use_invalid_virtualref(self):
+ myjitdriver = JitDriver(greens = [], reds = ['n'])
+ #
+ class XY:
+ n = 0
+ #
+ def fn(n):
+ res = False
+ while n > 0:
+ myjitdriver.can_enter_jit(n=n)
+ myjitdriver.jit_merge_point(n=n)
+ xy = XY()
+ xy.n = n
+ vref = virtual_ref(xy)
+ virtual_ref_finish(vref, xy)
+ vref() # raises InvalidVirtualRef when jitted
+ n -= 1
+ return res
+ #
+ py.test.raises(InvalidVirtualRef, "fn(10)")
+ py.test.raises(LLException, "self.meta_interp(fn, [10])")
+
+ def test_call_virtualref_already_forced(self):
+ myjitdriver = JitDriver(greens = [], reds = ['n', 'res'])
+ #
+ class XY:
+ n = 0
+ #
+ @dont_look_inside
+ def force_it(vref, n):
+ if n % 6 == 0:
+ return vref().n
+ return 0
+ def fn(n):
+ res = 0
+ while n > 0:
+ myjitdriver.can_enter_jit(n=n, res=res)
+ myjitdriver.jit_merge_point(n=n, res=res)
+ xy = XY()
+ xy.n = n
+ vref = virtual_ref(xy)
+ force_it(vref, n)
+ virtual_ref_finish(vref, xy)
+ res += force_it(vref, n) # doesn't raise, because it was already forced
+ n -= 1
+ return res
+ #
+ assert fn(10) == 6
+ res = self.meta_interp(fn, [10])
+ assert res == 6
+
class TestLLtype(VRefTests, LLJitMixin):
pass
diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py
--- a/pypy/jit/metainterp/virtualref.py
+++ b/pypy/jit/metainterp/virtualref.py
@@ -2,7 +2,7 @@
from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass
from pypy.jit.metainterp import history
from pypy.jit.codewriter import heaptracker
-
+from pypy.rlib.jit import InvalidVirtualRef
class VirtualRefInfo:
@@ -38,23 +38,24 @@
def replace_force_virtual_with_call(self, graphs):
# similar to rvirtualizable2.replace_force_virtualizable_with_call().
- c_funcptr = None
- count = 0
+ c_force_virtual_ptr = None
+ force_virtual_count = 0
for graph in graphs:
for block in graph.iterblocks():
for op in block.operations:
if op.opname == 'jit_force_virtual':
# first compute c_funcptr, but only if there is any
# 'jit_force_virtual' around
- if c_funcptr is None:
- c_funcptr = self.get_force_virtual_fnptr()
+ if c_force_virtual_ptr is None:
+ c_force_virtual_ptr = self.get_force_virtual_fnptr()
#
op.opname = 'direct_call'
- op.args = [c_funcptr, op.args[0]]
- count += 1
- if c_funcptr is not None:
- log("replaced %d 'jit_force_virtual' with %r" % (count,
- c_funcptr.value))
+ op.args = [c_force_virtual_ptr, op.args[0]]
+ force_virtual_count += 1
+ #
+ if c_force_virtual_ptr is not None:
+ log("replaced %d 'jit_force_virtual' with %r" % (force_virtual_count,
+ c_force_virtual_ptr.value))
# ____________________________________________________________
@@ -145,7 +146,8 @@
ResumeGuardForcedDescr.force_now(self.cpu, token)
assert vref.virtual_token == self.TOKEN_NONE
assert vref.forced
- else:
- assert vref.forced
+ elif not vref.forced:
+ # token == TOKEN_NONE and the vref was not forced: it's invalid
+ raise InvalidVirtualRef
return vref.forced
force_virtual._dont_inline_ = True
diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -4,13 +4,13 @@
import errno
from pypy.rlib import streamio
from pypy.rlib.rarithmetic import r_longlong
-from pypy.module._file.interp_stream import W_AbstractStream
-from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror, wrap_oserror_as_ioerror
+from pypy.rlib.rstring import StringBuilder
+from pypy.module._file.interp_stream import (W_AbstractStream, StreamErrors,
+ wrap_streamerror, wrap_oserror_as_ioerror)
from pypy.module.posix.interp_posix import dispatch_filename
from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.interpreter.typedef import interp_attrproperty, make_weakref_descr
-from pypy.interpreter.typedef import interp_attrproperty_w
+from pypy.interpreter.typedef import (TypeDef, GetSetProperty,
+ interp_attrproperty, make_weakref_descr, interp_attrproperty_w)
from pypy.interpreter.gateway import interp2app, unwrap_spec
@@ -164,14 +164,14 @@
if n < 0:
return stream.readall()
else:
- result = []
+ result = StringBuilder(n)
while n > 0:
data = stream.read(n)
if not data:
break
n -= len(data)
result.append(data)
- return ''.join(result)
+ return result.build()
@unwrap_spec(size=int)
def direct_readline(self, size=-1):
diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py
--- a/pypy/module/_rawffi/callback.py
+++ b/pypy/module/_rawffi/callback.py
@@ -43,7 +43,7 @@
unwrap_value(space, push_elem, ll_res, 0,
callback_ptr.result, w_res)
except OperationError, e:
- tbprint(space, space.wrap(e.application_traceback),
+ tbprint(space, space.wrap(e.get_traceback()),
space.wrap(e.errorstr(space)))
# force the result to be zero
if callback_ptr.result is not None:
diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py
--- a/pypy/module/_stackless/interp_coroutine.py
+++ b/pypy/module/_stackless/interp_coroutine.py
@@ -125,7 +125,7 @@
if isinstance(operror, OperationError):
w_exctype = operror.w_type
w_excvalue = operror.get_w_value(space)
- w_exctraceback = operror.application_traceback
+ w_exctraceback = operror.get_traceback()
w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback])
if w_exctype is self.costate.w_CoroutineExit:
@@ -160,7 +160,7 @@
space.gettypeobject(pytraceback.PyTraceback.typedef))):
raise OperationError(space.w_TypeError,
space.wrap("throw: arg 3 must be a traceback or None"))
- operror.application_traceback = tb
+ operror.set_traceback(tb)
self._kill(operror)
diff --git a/pypy/module/_stackless/interp_greenlet.py b/pypy/module/_stackless/interp_greenlet.py
--- a/pypy/module/_stackless/interp_greenlet.py
+++ b/pypy/module/_stackless/interp_greenlet.py
@@ -124,7 +124,7 @@
space.gettypeobject(pytraceback.PyTraceback.typedef))):
raise OperationError(space.w_TypeError,
space.wrap("throw: arg 3 must be a traceback or None"))
- operror.application_traceback = tb
+ operror.set_traceback(tb)
# Dead greenlet: turn GreenletExit into a regular return
if self.isdead() and operror.match(space, self.costate.w_GreenletExit):
args_w = [operror.get_w_value(space)]
diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py
--- a/pypy/module/cpyext/pyerrors.py
+++ b/pypy/module/cpyext/pyerrors.py
@@ -57,7 +57,7 @@
if operror:
ptype[0] = make_ref(space, operror.w_type)
pvalue[0] = make_ref(space, operror.get_w_value(space))
- ptraceback[0] = make_ref(space, space.wrap(operror.application_traceback))
+ ptraceback[0] = make_ref(space, space.wrap(operror.get_traceback()))
else:
ptype[0] = lltype.nullptr(PyObject.TO)
pvalue[0] = lltype.nullptr(PyObject.TO)
@@ -268,7 +268,7 @@
w_type = operror.w_type
w_value = operror.get_w_value(space)
- w_tb = space.wrap(operror.application_traceback)
+ w_tb = space.wrap(operror.get_traceback())
if rffi.cast(lltype.Signed, set_sys_last_vars):
space.sys.setdictvalue(space, "last_type", w_type)
diff --git a/pypy/module/oracle/config.py b/pypy/module/oracle/config.py
--- a/pypy/module/oracle/config.py
+++ b/pypy/module/oracle/config.py
@@ -16,6 +16,7 @@
return space.str_w(w_obj)
def w_string(space, buf, len=-1):
+ #assert type(len) is int
if len < 0:
return space.wrap(rffi.charp2str(buf))
else:
diff --git a/pypy/module/oracle/interp_connect.py b/pypy/module/oracle/interp_connect.py
--- a/pypy/module/oracle/interp_connect.py
+++ b/pypy/module/oracle/interp_connect.py
@@ -371,6 +371,7 @@
finally:
stringBuffer.clear()
lltype.free(foundptr, flavor='raw')
+ lltype.free(handleptr, flavor='raw')
# eliminate the authorization handle immediately, if applicable
if authInfo:
diff --git a/pypy/module/oracle/interp_cursor.py b/pypy/module/oracle/interp_cursor.py
--- a/pypy/module/oracle/interp_cursor.py
+++ b/pypy/module/oracle/interp_cursor.py
@@ -459,7 +459,7 @@
self.environment.checkForError(
status,
"Cursor_ItemDescription(): name")
- name = rffi.charpsize2str(nameptr[0], lenptr[0])
+ name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0]))
finally:
lltype.free(nameptr, flavor='raw')
lltype.free(lenptr, flavor='raw')
diff --git a/pypy/module/oracle/interp_object.py b/pypy/module/oracle/interp_object.py
--- a/pypy/module/oracle/interp_object.py
+++ b/pypy/module/oracle/interp_object.py
@@ -38,7 +38,7 @@
self.environment.checkForError(
status,
"ObjectType_Initialize(): get schema name")
- self.schema = rffi.charpsize2str(nameptr[0], lenptr[0])
+ self.schema = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0]))
# determine the name of the type
status = roci.OCIAttrGet(
@@ -50,7 +50,7 @@
self.environment.checkForError(
status,
"ObjectType_Initialize(): get schema name")
- self.name = rffi.charpsize2str(nameptr[0], lenptr[0])
+ self.name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0]))
finally:
lltype.free(nameptr, flavor='raw')
lltype.free(lenptr, flavor='raw')
@@ -301,7 +301,7 @@
connection.environment.checkForError(
status,
"ObjectAttribute_Initialize(): get name")
- self.name = rffi.charpsize2str(nameptr[0], lenptr[0])
+ self.name = rffi.charpsize2str(nameptr[0], rffi.cast(lltype.Signed, lenptr[0]))
finally:
lltype.free(nameptr, flavor='raw')
lltype.free(lenptr, flavor='raw')
@@ -428,7 +428,7 @@
strValue = rffi.cast(roci.Ptr(roci.OCIString), value)[0]
ptr = roci.OCIStringPtr(environment.handle, strValue)
size = roci.OCIStringSize(environment.handle, strValue)
- return config.w_string(space, ptr, size)
+ return config.w_string(space, ptr, rffi.cast(lltype.Signed, size))
elif typeCode == roci.OCI_TYPECODE_NUMBER:
return transform.OracleNumberToPythonFloat(
environment,
diff --git a/pypy/module/oracle/interp_pool.py b/pypy/module/oracle/interp_pool.py
--- a/pypy/module/oracle/interp_pool.py
+++ b/pypy/module/oracle/interp_pool.py
@@ -100,11 +100,13 @@
status, "SessionPool_New(): create pool")
self.w_name = config.w_string(space, poolnameptr[0],
- poolnamelenptr[0])
+ rffi.cast(lltype.Signed, poolnamelenptr[0]))
finally:
user_buf.clear()
password_buf.clear()
dsn_buf.clear()
+ lltype.free(poolnameptr, flavor='raw')
+ lltype.free(poolnamelenptr, flavor='raw')
return space.wrap(self)
@@ -128,10 +130,19 @@
self.checkConnected(space)
+ if __args__.keywords:
+ keywords = __args__.keywords + ["pool"]
+ else:
+ keywords = ["pool"]
+ if __args__.keywords_w:
+ keywords_w = __args__.keywords_w + [space.wrap(self)]
+ else:
+ keywords_w = [space.wrap(self)]
+
newargs = Arguments(space,
__args__.arguments_w,
- __args__.keywords + ["pool"],
- __args__.keywords_w + [space.wrap(self)])
+ keywords,
+ keywords_w)
return space.call_args(self.w_connectionType, newargs)
def release(self, space, w_connection):
diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py
--- a/pypy/module/oracle/interp_variable.py
+++ b/pypy/module/oracle/interp_variable.py
@@ -279,6 +279,7 @@
self.actualLength, self.returnCode,
allocatedElements, actualElementsPtr,
roci.OCI_DEFAULT)
+ nameBuffer.clear()
else:
status = roci.OCIBindByPos(
self.boundCursorHandle, bindHandlePtr,
@@ -733,6 +734,7 @@
finally:
rffi.keep_buffer_alive_until_here(textbuf, text)
lltype.free(sizeptr, flavor='raw')
+ format_buf.clear()
if isinstance(self, VT_NumberAsString):
return w_strvalue
@@ -779,6 +781,8 @@
format_buf.ptr, format_buf.size,
None, 0,
dataptr)
+ text_buf.clear()
+ format_buf.clear()
self.environment.checkForError(
status, "NumberVar_SetValue(): from long")
return
@@ -811,6 +815,8 @@
format_buf.ptr, format_buf.size,
nls_params, len(nls_params),
dataptr)
+ text_buf.clear()
+ format_buf.clear()
self.environment.checkForError(
status, "NumberVar_SetValue(): from decimal")
return
diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py
--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -150,7 +150,7 @@
if operror is None:
return space.w_None
else:
- return space.wrap(operror.application_traceback)
+ return space.wrap(operror.get_traceback())
return None
def get_w_default_encoder(self):
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -40,6 +40,7 @@
break
depth -= 1
f = ec.getnextframe_nohidden(f)
+ f.mark_as_escaped()
return space.wrap(f)
def setrecursionlimit(space, w_new_limit):
@@ -90,7 +91,7 @@
return space.newtuple([space.w_None,space.w_None,space.w_None])
else:
return space.newtuple([operror.w_type, operror.get_w_value(space),
- space.wrap(operror.application_traceback)])
+ space.wrap(operror.get_traceback())])
def exc_clear(space):
"""Clear global information on the current exception. Subsequent calls
diff --git a/pypy/objspace/std/floattype.py b/pypy/objspace/std/floattype.py
--- a/pypy/objspace/std/floattype.py
+++ b/pypy/objspace/std/floattype.py
@@ -14,10 +14,8 @@
float_as_integer_ratio = SMM("as_integer_ratio", 1)
float_hex = SMM("hex", 1)
-float_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any float.")
-
-def float_conjugate__ANY(space, w_float):
- return space.pos(w_float)
+def descr_conjugate(space, w_float):
+ return space.float(w_float)
register_all(vars(), globals())
@@ -168,10 +166,10 @@
if total_digits > min(const_one, const_two) // 4:
raise OperationError(space.w_ValueError, space.wrap("way too long"))
if i < length and (s[i] == "p" or s[i] == "P"):
+ i += 1
if i == length:
raise OperationError(space.w_ValueError,
space.wrap("invalid hex string"))
- i += 1
exp_sign = 1
if s[i] == "-" or s[i] == "+":
if s[i] == "-":
@@ -280,6 +278,7 @@
as_classmethod=True),
fromhex = gateway.interp2app(descr_fromhex,
as_classmethod=True),
+ conjugate = gateway.interp2app(descr_conjugate),
real = typedef.GetSetProperty(descr_get_real),
imag = typedef.GetSetProperty(descr_get_imag),
)
diff --git a/pypy/objspace/std/inttype.py b/pypy/objspace/std/inttype.py
--- a/pypy/objspace/std/inttype.py
+++ b/pypy/objspace/std/inttype.py
@@ -11,14 +11,19 @@
# ____________________________________________________________
-int_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any int.")
+def descr_conjugate(space, w_int):
+ "Returns self, the complex conjugate of any int."
+ return space.int(w_int)
-def int_conjugate__ANY(space, w_int):
- return space.pos(w_int)
+def descr_bit_length(space, w_int):
+ """int.bit_length() -> int
-int_bit_length = SMM("bit_length", 1, doc="int.bit_length() -> int\n\nNumber of bits necessary to represent self in binary.\n>>> bin(37)\n'0b100101'\n>>> (37).bit_length()\n6")
-
-def int_bit_length__ANY(space, w_int):
+ Number of bits necessary to represent self in binary.
+ >>> bin(37)
+ '0b100101'
+ >>> (37).bit_length()
+ 6
+ """
val = space.int_w(w_int)
if val < 0:
val = -val
@@ -28,8 +33,6 @@
val >>= 1
return space.wrap(bits)
-register_all(vars(), globals())
-
def wrapint(space, x):
if space.config.objspace.std.withsmallint:
@@ -196,6 +199,8 @@
non-string. If the argument is outside the integer range a long object
will be returned instead.''',
__new__ = gateway.interp2app(descr__new__),
+ conjugate = gateway.interp2app(descr_conjugate),
+ bit_length = gateway.interp2app(descr_bit_length),
numerator = typedef.GetSetProperty(descr_get_numerator),
denominator = typedef.GetSetProperty(descr_get_denominator),
real = typedef.GetSetProperty(descr_get_real),
diff --git a/pypy/objspace/std/longtype.py b/pypy/objspace/std/longtype.py
--- a/pypy/objspace/std/longtype.py
+++ b/pypy/objspace/std/longtype.py
@@ -4,12 +4,8 @@
from pypy.objspace.std.stdtypedef import StdTypeDef, SMM
from pypy.objspace.std.strutil import string_to_bigint, ParseStringError
-long_conjugate = SMM("conjugate", 1, doc="Returns self, the complex conjugate of any long.")
-
-def long_conjugate__ANY(space, w_int):
- return space.pos(w_int)
-
-register_all(vars(), globals())
+def descr_conjugate(space, w_int):
+ return space.long(w_int)
def descr__new__(space, w_longtype, w_x=0, w_base=gateway.NoneNotWrapped):
@@ -128,6 +124,7 @@
string, use the optional base. It is an error to supply a base when
converting a non-string.''',
__new__ = gateway.interp2app(descr__new__),
+ conjugate = gateway.interp2app(descr_conjugate),
numerator = typedef.GetSetProperty(descr_get_numerator),
denominator = typedef.GetSetProperty(descr_get_denominator),
real = typedef.GetSetProperty(descr_get_real),
diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py
--- a/pypy/objspace/std/test/test_floatobject.py
+++ b/pypy/objspace/std/test/test_floatobject.py
@@ -751,3 +751,6 @@
pass
else:
self.identical(x, float.fromhex(x.hex()))
+
+ def test_invalid(self):
+ raises(ValueError, float.fromhex, "0P")
diff --git a/pypy/objspace/trace.py b/pypy/objspace/trace.py
--- a/pypy/objspace/trace.py
+++ b/pypy/objspace/trace.py
@@ -110,10 +110,10 @@
self.result.append(EnterFrame(frame))
self.ec.enter(frame)
- def leave(self, frame, w_exitvalue):
+ def leave(self, frame, w_exitvalue, got_exception):
""" called just after evaluating of a frame is suspended/finished. """
self.result.append(LeaveFrame(frame))
- self.ec.leave(frame, w_exitvalue)
+ self.ec.leave(frame, w_exitvalue, got_exception)
def bytecode_trace(self, frame):
""" called just before execution of a bytecode. """
diff --git a/pypy/rlib/_jit_vref.py b/pypy/rlib/_jit_vref.py
--- a/pypy/rlib/_jit_vref.py
+++ b/pypy/rlib/_jit_vref.py
@@ -50,6 +50,7 @@
def rtype_simple_call(self, hop):
[v] = hop.inputargs(self)
+ hop.exception_is_here()
v = hop.genop('jit_force_virtual', [v], resulttype = OBJECTPTR)
return hop.genop('cast_pointer', [v], resulttype = hop.r_result)
@@ -65,6 +66,7 @@
lowleveltype = OBJECT
def rtype_simple_call(self, hop):
[v] = hop.inputargs(self)
+ hop.exception_is_here()
v = hop.genop('jit_force_virtual', [v], resulttype = OBJECT)
return hop.genop('oodowncast', [v], resulttype = hop.r_result)
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -183,7 +183,6 @@
# VRefs
def virtual_ref(x):
-
"""Creates a 'vref' object that contains a reference to 'x'. Calls
to virtual_ref/virtual_ref_finish must be properly nested. The idea
is that the object 'x' is supposed to be JITted as a virtual between
@@ -194,10 +193,10 @@
return DirectJitVRef(x)
virtual_ref.oopspec = 'virtual_ref(x)'
-def virtual_ref_finish(x):
- """See docstring in virtual_ref(x). Note that virtual_ref_finish
- takes as argument the real object, not the vref."""
+def virtual_ref_finish(vref, x):
+ """See docstring in virtual_ref(x)"""
keepalive_until_here(x) # otherwise the whole function call is removed
+ _virtual_ref_finish(vref, x)
virtual_ref_finish.oopspec = 'virtual_ref_finish(x)'
def non_virtual_ref(x):
@@ -205,19 +204,39 @@
Used for None or for frames outside JIT scope."""
return DirectVRef(x)
+class InvalidVirtualRef(Exception):
+ """
+ Raised if we try to call a non-forced virtualref after the call to
+ virtual_ref_finish
+ """
+
# ---------- implementation-specific ----------
class DirectVRef(object):
def __init__(self, x):
self._x = x
+ self._state = 'non-forced'
+
def __call__(self):
+ if self._state == 'non-forced':
+ self._state = 'forced'
+ elif self._state == 'invalid':
+ raise InvalidVirtualRef
return self._x
+ def _finish(self):
+ if self._state == 'non-forced':
+ self._state = 'invalid'
+
class DirectJitVRef(DirectVRef):
def __init__(self, x):
assert x is not None, "virtual_ref(None) is not allowed"
DirectVRef.__init__(self, x)
+def _virtual_ref_finish(vref, x):
+ assert vref._x is x, "Invalid call to virtual_ref_finish"
+ vref._finish()
+
class Entry(ExtRegistryEntry):
_about_ = (non_virtual_ref, DirectJitVRef)
@@ -237,6 +256,15 @@
s_obj = self.bookkeeper.immutablevalue(self.instance())
return _jit_vref.SomeVRef(s_obj)
+class Entry(ExtRegistryEntry):
+ _about_ = _virtual_ref_finish
+
+ def compute_result_annotation(self, s_vref, s_obj):
+ pass
+
+ def specialize_call(self, hop):
+ pass
+
vref_None = non_virtual_ref(None)
# ____________________________________________________________
diff --git a/pypy/rlib/rstack.py b/pypy/rlib/rstack.py
--- a/pypy/rlib/rstack.py
+++ b/pypy/rlib/rstack.py
@@ -56,6 +56,12 @@
_stack_get_end_adr = llexternal('LL_stack_get_end_adr', [], lltype.Signed)
_stack_get_length_adr= llexternal('LL_stack_get_length_adr',[], lltype.Signed)
+# the following is also used by the JIT: "critical code" paths are paths in
+# which we should not raise StackOverflow at all, but just ignore the stack limit
+_stack_criticalcode_start = llexternal('LL_stack_criticalcode_start', [],
+ lltype.Void, lambda: None)
+_stack_criticalcode_stop = llexternal('LL_stack_criticalcode_stop', [],
+ lltype.Void, lambda: None)
def stack_check():
if not we_are_translated():
diff --git a/pypy/rlib/test/test__jit_vref.py b/pypy/rlib/test/test__jit_vref.py
--- a/pypy/rlib/test/test__jit_vref.py
+++ b/pypy/rlib/test/test__jit_vref.py
@@ -1,6 +1,6 @@
import py
from pypy.rlib.jit import virtual_ref, virtual_ref_finish
-from pypy.rlib.jit import vref_None, non_virtual_ref
+from pypy.rlib.jit import vref_None, non_virtual_ref, InvalidVirtualRef
from pypy.rlib._jit_vref import SomeVRef
from pypy.annotation import model as annmodel
from pypy.annotation.annrpython import RPythonAnnotator
@@ -23,18 +23,23 @@
pass
-def test_direct_1():
+def test_direct_forced():
x1 = X()
vref = virtual_ref(x1)
+ assert vref._state == 'non-forced'
assert vref() is x1
- virtual_ref_finish(x1)
+ assert vref._state == 'forced'
+ virtual_ref_finish(vref, x1)
+ assert vref._state == 'forced'
assert vref() is x1
-def test_direct_2():
+def test_direct_invalid():
x1 = X()
vref = virtual_ref(x1)
- virtual_ref_finish(x1)
- assert vref() is x1
+ assert vref._state == 'non-forced'
+ virtual_ref_finish(vref, x1)
+ assert vref._state == 'invalid'
+ py.test.raises(InvalidVirtualRef, "vref()")
def test_annotate_1():
def f():
@@ -50,7 +55,7 @@
x1 = X()
vref = virtual_ref(x1)
x2 = vref()
- virtual_ref_finish(x1)
+ virtual_ref_finish(vref, x1)
return x2
a = RPythonAnnotator()
s = a.build_types(f, [])
@@ -95,7 +100,7 @@
x1 = X()
vref = virtual_ref(x1)
x2 = vref()
- virtual_ref_finish(x2)
+ virtual_ref_finish(vref, x2)
return x2
x = self.interpret(f, [])
assert self.castable(self.OBJECTTYPE, x)
@@ -119,6 +124,18 @@
assert lltype.typeOf(x) == self.OBJECTTYPE
assert not x
+ def test_rtype_5(self):
+ def f():
+ vref = virtual_ref(X())
+ try:
+ vref()
+ return 42
+ except InvalidVirtualRef:
+ return -1
+ x = self.interpret(f, [])
+ assert x == 42
+
+
class TestLLtype(BaseTestVRef, LLRtypeMixin):
OBJECTTYPE = OBJECTPTR
def castable(self, TO, var):
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -20,7 +20,6 @@
from pypy.rpython.extfunc import ExtRegistryEntry
from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic
from pypy.tool.uid import fixid
-from pypy.tool.tls import tlsobject
from pypy.rlib.rarithmetic import r_uint, r_singlefloat, r_longfloat, intmask
from pypy.annotation import model as annmodel
from pypy.rpython.llinterp import LLInterpreter, LLException
@@ -28,6 +27,7 @@
from pypy.rpython import raddress
from pypy.translator.platform import platform
from array import array
+from thread import _local as tlsobject
# ____________________________________________________________
diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py
--- a/pypy/rpython/lltypesystem/lltype.py
+++ b/pypy/rpython/lltypesystem/lltype.py
@@ -4,14 +4,16 @@
base_int, normalizedinttype)
from pypy.rlib.objectmodel import Symbolic
from pypy.tool.uid import Hashable
-from pypy.tool.tls import tlsobject
from pypy.tool.identity_dict import identity_dict
from pypy.tool import leakfinder
from types import NoneType
from sys import maxint
import weakref
-TLS = tlsobject()
+class State(object):
+ pass
+
+TLS = State()
class WeakValueDictionary(weakref.WeakValueDictionary):
"""A subclass of weakref.WeakValueDictionary
diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py
--- a/pypy/tool/pytest/appsupport.py
+++ b/pypy/tool/pytest/appsupport.py
@@ -81,7 +81,7 @@
self.space = space
self.operr = operr
self.typename = operr.w_type.getname(space, "?")
- self.traceback = AppTraceback(space, self.operr.application_traceback)
+ self.traceback = AppTraceback(space, self.operr.get_traceback())
debug_excs = getattr(operr, 'debug_excs', [])
if debug_excs:
self._excinfo = debug_excs[0]
diff --git a/pypy/tool/tls.py b/pypy/tool/tls.py
deleted file mode 100644
--- a/pypy/tool/tls.py
+++ /dev/null
@@ -1,8 +0,0 @@
-
-"""Thread-local storage."""
-
-try:
- from thread import _local as tlsobject
-except ImportError:
- class tlsobject(object):
- pass
diff --git a/pypy/translator/c/src/debug_traceback.h b/pypy/translator/c/src/debug_traceback.h
--- a/pypy/translator/c/src/debug_traceback.h
+++ b/pypy/translator/c/src/debug_traceback.h
@@ -21,7 +21,11 @@
line to the f:17/KeyError line.
*/
-#define PYPY_DEBUG_TRACEBACK_DEPTH 128 /* a power of two */
+#ifdef RPY_LL_ASSERT
+# define PYPY_DEBUG_TRACEBACK_DEPTH 8192 /* a power of two */
+#else
+# define PYPY_DEBUG_TRACEBACK_DEPTH 128 /* a power of two */
+#endif
#define PYPYDTPOS_RERAISE ((struct pypydtpos_s *) -1)
#define PYPYDTSTORE(loc, etype) \
diff --git a/pypy/translator/c/src/stack.h b/pypy/translator/c/src/stack.h
--- a/pypy/translator/c/src/stack.h
+++ b/pypy/translator/c/src/stack.h
@@ -13,6 +13,7 @@
extern char *_LLstacktoobig_stack_end;
extern long _LLstacktoobig_stack_length;
+extern char _LLstacktoobig_report_error;
void LL_stack_unwind(void);
char LL_stack_too_big_slowpath(long); /* returns 0 (ok) or 1 (too big) */
@@ -24,6 +25,9 @@
#define LL_stack_get_end_adr() ((long)&_LLstacktoobig_stack_end) /* JIT */
#define LL_stack_get_length_adr() ((long)&_LLstacktoobig_stack_length)/* JIT */
+#define LL_stack_criticalcode_start() (_LLstacktoobig_report_error = 0)
+#define LL_stack_criticalcode_stop() (_LLstacktoobig_report_error = 1)
+
#ifdef __GNUC__
# define PYPY_INHIBIT_TAIL_CALL() asm("/* inhibit_tail_call */")
@@ -39,6 +43,7 @@
stack that grows downward here. */
char *_LLstacktoobig_stack_end = NULL;
long _LLstacktoobig_stack_length = MAX_STACK_SIZE;
+char _LLstacktoobig_report_error = 1;
static RPyThreadStaticTLS end_tls_key;
void LL_stack_set_length_fraction(double fraction)
@@ -86,8 +91,9 @@
/* stack underflowed: the initial estimation of
the stack base must be revised */
}
- else
- return 1; /* stack overflow (probably) */
+ else { /* stack overflow (probably) */
+ return _LLstacktoobig_report_error;
+ }
}
/* update the stack base pointer to the current value */
diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py
--- a/pypy/translator/c/test/test_standalone.py
+++ b/pypy/translator/c/test/test_standalone.py
@@ -727,6 +727,40 @@
assert counts[0.1] > counts[0.4] / 7
assert counts[0.4] > counts[1.0] / 4
+ def test_stack_criticalcode(self):
+ # check for pypy.rlib.rstack._stack_criticalcode_start/stop()
+ from pypy.rlib.rstack import _stack_criticalcode_start
+ from pypy.rlib.rstack import _stack_criticalcode_stop
+ from pypy.rlib.rstackovf import StackOverflow
+ class A:
+ pass
+ glob = A()
+ def f(n):
+ if n <= 0:
+ return 42
+ try:
+ return f(n+1)
+ except StackOverflow:
+ if glob.caught:
+ print 'Oups! already caught!'
+ glob.caught = True
+ _stack_criticalcode_start()
+ critical(100) # recurse another 100 times here
+ _stack_criticalcode_stop()
+ return 789
+ def critical(n):
+ if n > 0:
+ n = critical(n - 1)
+ return n - 42
+ def entry_point(argv):
+ glob.caught = False
+ print f(1)
+ return 0
+ t, cbuilder = self.compile(entry_point, stackcheck=True)
+ out = cbuilder.cmdexec('')
+ assert out.strip() == '789'
+
+
class TestMaemo(TestStandalone):
def setup_class(cls):
py.test.skip("TestMaemo: tests skipped for now")
diff --git a/pypy/translator/transform.py b/pypy/translator/transform.py
--- a/pypy/translator/transform.py
+++ b/pypy/translator/transform.py
@@ -175,41 +175,6 @@
# make sure the bookkeeper knows about AssertionError
self.bookkeeper.getuniqueclassdef(AssertionError)
-def insert_stackcheck(ann):
- from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles
- edges = []
- graphs_to_patch = {}
- for callposition, (caller, callee) in ann.translator.callgraph.items():
- if getattr(getattr(callee, 'func', None), 'insert_stack_check_here', False):
- graphs_to_patch[callee] = True
- continue
- edge = Edge(caller, callee)
- edge.callposition = callposition
- edges.append(edge)
-
- for graph in graphs_to_patch:
- v = Variable()
- ann.setbinding(v, annmodel.SomeImpossibleValue())
- unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v)
- graph.startblock.operations.insert(0, unwind_op)
-
- edgedict = make_edge_dict(edges)
- for edge in break_cycles(edgedict, edgedict):
- caller = edge.source
- _, _, call_tag = edge.callposition
- if call_tag:
- caller_block, _ = call_tag
- else:
- ann.warning("cycle detected but no information on where to insert "
- "stack_check()")
- continue
- # caller block found, insert stack_check()
- v = Variable()
- # push annotation on v
- ann.setbinding(v, annmodel.SomeImpossibleValue())
- unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v)
- caller_block.operations.insert(0, unwind_op)
-
def insert_ll_stackcheck(translator):
from pypy.translator.backendopt.support import find_calls_from
from pypy.rlib.rstack import stack_check
More information about the pypy-commit
mailing list