[pypy-commit] pypy default: merge
fijal
noreply at buildbot.pypy.org
Sun Feb 8 20:08:03 CET 2015
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch:
Changeset: r75765:221df618cf77
Date: 2015-02-08 20:59 +0200
http://bitbucket.org/pypy/pypy/changeset/221df618cf77/
Log: merge
diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -235,6 +235,11 @@
config.translation.suggest(check_str_without_nul=True)
config.translation.suggest(shared=True)
+ if config.translation.shared:
+ if config.translation.output is not None:
+ raise Exception("Cannot use the --output option with PyPy "
+ "when --shared is on (it is by default). "
+ "See issue #1971.")
if config.translation.thread:
config.objspace.usemodules.thread = True
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -81,7 +81,10 @@
return w_object.descr_copy(space, w_order)
elif not copy and (subok or type(w_object) is W_NDimArray):
return w_object
- # we have a ndarray, but need to copy or change dtype or create W_NDimArray
+ if subok:
+ raise oefmt(space.w_NotImplementedError,
+ "array(..., subok=True) only partially implemented")
+ # we have a ndarray, but need to copy or change dtype
if dtype is None:
dtype = w_object.get_dtype()
if dtype != w_object.get_dtype():
@@ -89,13 +92,12 @@
copy = True
if copy:
shape = w_object.get_shape()
- _elems_w = w_object.reshape(space, space.wrap(-1))
elems_w = [None] * w_object.get_size()
- for i in range(len(elems_w)):
- elems_w[i] = _elems_w.descr_getitem(space, space.wrap(i))
- elif subok:
- raise oefmt(space.w_NotImplementedError,
- "array(...copy=False, subok=True) not implemented yet")
+ elsize = w_object.get_dtype().elsize
+ # TODO - use w_object.implementation without copying to a list
+ # unfortunately that causes a union error in translation
+ for i in range(w_object.get_size()):
+ elems_w[i] = w_object.implementation.getitem(i * elsize)
else:
sz = support.product(w_object.get_shape()) * dtype.elsize
return W_NDimArray.from_shape_and_storage(space,
@@ -113,7 +115,7 @@
dtype = descriptor.variable_dtype(space, dtype.char + '1')
w_arr = W_NDimArray.from_shape(space, shape, dtype, order=order)
- if len(elems_w) == 1:
+ if support.product(shape) == 1:
w_arr.set_scalar_value(dtype.coerce(space, elems_w[0]))
else:
loop.assign(space, w_arr, elems_w)
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -272,40 +272,103 @@
import numpy as N
# numpy's matrix class caused an infinite loop
class matrix(N.ndarray):
- getcnt = 0
def __new__(subtype, data, dtype=None, copy=True):
+ print('matrix __new__')
+ if isinstance(data, matrix):
+ dtype2 = data.dtype
+ if (dtype is None):
+ dtype = dtype2
+ if (dtype2 == dtype) and (not copy):
+ return data
+ return data.astype(dtype)
+
+ if isinstance(data, N.ndarray):
+ if dtype is None:
+ intype = data.dtype
+ else:
+ intype = N.dtype(dtype)
+ new = data.view(subtype)
+ if intype != data.dtype:
+ return new.astype(intype)
+ if copy: return new.copy()
+ else: return new
+
+ if isinstance(data, str):
+ data = _convert_from_string(data)
+
+ # now convert data to an array
arr = N.array(data, dtype=dtype, copy=copy)
+ ndim = arr.ndim
shape = arr.shape
+ if (ndim > 2):
+ raise ValueError("matrix must be 2-dimensional")
+ elif ndim == 0:
+ shape = (1, 1)
+ elif ndim == 1:
+ shape = (1, shape[0])
+
+ order = False
+ if (ndim == 2) and arr.flags.fortran:
+ order = True
+
+ if not (order or arr.flags.contiguous):
+ arr = arr.copy()
ret = N.ndarray.__new__(subtype, shape, arr.dtype,
buffer=arr,
- order=True)
+ order=order)
return ret
+ def __array_finalize__(self, obj):
+ print('matrix __array_finalize__')
+ self._getitem = False
+ if (isinstance(obj, matrix) and obj._getitem): return
+ ndim = self.ndim
+ if (ndim == 2):
+ return
+ if (ndim > 2):
+ newshape = tuple([x for x in self.shape if x > 1])
+ ndim = len(newshape)
+ if ndim == 2:
+ self.shape = newshape
+ return
+ elif (ndim > 2):
+ raise ValueError("shape too large to be a matrix.")
+ else:
+ newshape = self.shape
+ if ndim == 0:
+ self.shape = (1, 1)
+ elif ndim == 1:
+ self.shape = (1, newshape[0])
+ return
+
def __getitem__(self, index):
- matrix.getcnt += 1
- if matrix.getcnt > 10:
- # XXX strides.find_shape_and_elems is sensitive
- # to shape modification
- xxx
- out = N.ndarray.__getitem__(self, index)
+ print('matrix __getitem__')
+ self._getitem = True
+
+ try:
+ out = N.ndarray.__getitem__(self, index)
+ finally:
+ self._getitem = False
if not isinstance(out, N.ndarray):
return out
+
+ if out.ndim == 0:
+ return out[()]
+ if out.ndim == 1:
+ sh = out.shape[0]
# Determine when we should have a column array
- old_shape = out.shape
- if out.ndim < 2:
- sh = out.shape[0]
try:
n = len(index)
except:
n = 0
- if n > 1:
+ if n > 1 and isscalar(index[1]):
out.shape = (sh, 1)
else:
out.shape = (1, sh)
- #print 'out, shape was',old_shape,'now',out.shape,'out',out
return out
+
a = matrix([[1., 2.], [3., 4.]])
b = N.array([a])
assert (b == a).all()
@@ -318,6 +381,17 @@
assert len(b.shape) == 2
assert (b == a).all()
+ b = N.array(a, copy=True, dtype=int)
+ assert len(b.shape) == 2
+ assert (b == a).all()
+
+ c = matrix(a, copy=False)
+ assert c.base is not None
+ c[0, 0] = 100
+ assert a[0, 0] == 100
+ b = N.array(c, copy=True)
+ assert (b == a).all()
+
def test_setstate_no_version(self):
# Some subclasses of ndarray, like MaskedArray, do not use
# version in __setstare__
diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py
--- a/rpython/config/translationoption.py
+++ b/rpython/config/translationoption.py
@@ -151,9 +151,7 @@
default=False, cmdline="--dont-write-c-files"),
ArbitraryOption("instrumentctl", "internal",
default=None),
- StrOption("output", "Output file name (don't change for PyPy!"
- " doesn't work with virtualenv+shared: issue 1971)",
- cmdline="--really-force-output"),
+ StrOption("output", "Output file name", cmdline="--output"),
StrOption("secondaryentrypoints",
"Comma separated list of keys choosing secondary entrypoints",
cmdline="--entrypoints", default="main"),
diff --git a/rpython/flowspace/generator.py b/rpython/flowspace/generator.py
--- a/rpython/flowspace/generator.py
+++ b/rpython/flowspace/generator.py
@@ -107,7 +107,7 @@
# First, always run simplify_graph in order to reduce the number of
# variables passed around
simplify_graph(graph)
- insert_empty_startblock(None, graph)
+ insert_empty_startblock(graph)
_insert_reads(graph.startblock, Entry.varnames)
Entry.block = graph.startblock
#
@@ -130,7 +130,7 @@
if hlop.opname == 'yield_':
[v_yielded_value] = hlop.args
del block.operations[index]
- newlink = split_block(None, block, index)
+ newlink = split_block(block, index)
newblock = newlink.target
#
class Resume(AbstractPosition):
diff --git a/rpython/jit/backend/x86/arch.py b/rpython/jit/backend/x86/arch.py
--- a/rpython/jit/backend/x86/arch.py
+++ b/rpython/jit/backend/x86/arch.py
@@ -35,7 +35,9 @@
PASS_ON_MY_FRAME = 15
JITFRAME_FIXED_SIZE = 6 + 8 * 2 # 6 GPR + 8 XMM * 2 WORDS/float
# 'threadlocal_addr' is passed as 2nd argument on the stack,
- # and it can be left here for when it is needed
+ # and it can be left here for when it is needed. As an additional hack,
+ # with asmgcc, it is made odd-valued to mean "already seen this frame
+ # during the previous minor collection".
THREADLOCAL_OFS = (FRAME_FIXED_SIZE + 2) * WORD
else:
# rbp + rbx + r12 + r13 + r14 + r15 + threadlocal + 12 extra words = 19
@@ -43,7 +45,9 @@
PASS_ON_MY_FRAME = 12
JITFRAME_FIXED_SIZE = 28 # 13 GPR + 15 XMM
# 'threadlocal_addr' is passed as 2nd argument in %esi,
- # and is moved into this frame location
+ # and is moved into this frame location. As an additional hack,
+ # with asmgcc, it is made odd-valued to mean "already seen this frame
+ # during the previous minor collection".
THREADLOCAL_OFS = (FRAME_FIXED_SIZE - 1) * WORD
assert PASS_ON_MY_FRAME >= 12 # asmgcc needs at least JIT_USE_WORDS + 3
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -1980,6 +1980,23 @@
def _call_assembler_emit_call(self, addr, argloc, _):
threadlocal_loc = RawEspLoc(THREADLOCAL_OFS, INT)
+ if self._is_asmgcc():
+ # We need to remove the bit "already seen during the
+ # previous minor collection" instead of passing this
+ # value directly.
+ if IS_X86_64:
+ tmploc = esi # already the correct place
+ if argloc is tmploc:
+ self.mc.MOV_rr(esi.value, edi.value)
+ argloc = edi
+ else:
+ tmploc = eax
+ if tmploc is argloc:
+ tmploc = edx
+ self.mc.MOV(tmploc, threadlocal_loc)
+ self.mc.AND_ri(tmploc.value, ~1)
+ threadlocal_loc = tmploc
+ #
self.simple_call(addr, [argloc, threadlocal_loc])
def _call_assembler_emit_helper_call(self, addr, arglocs, result_loc):
@@ -2355,6 +2372,8 @@
assert self.cpu.translate_support_code
assert isinstance(resloc, RegLoc)
self.mc.MOV_rs(resloc.value, THREADLOCAL_OFS)
+ if self._is_asmgcc():
+ self.mc.AND_ri(resloc.value, ~1)
self.load_from_mem(resloc, addr_add_const(resloc, offset),
imm(size), imm(sign))
diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py
--- a/rpython/jit/backend/x86/callbuilder.py
+++ b/rpython/jit/backend/x86/callbuilder.py
@@ -167,6 +167,8 @@
self.tlofs_reg = r12
self.mc.MOV_rs(self.tlofs_reg.value,
THREADLOCAL_OFS - self.current_esp)
+ if self.asm._is_asmgcc():
+ self.mc.AND_ri(self.tlofs_reg.value, ~1)
return self.tlofs_reg
def save_stack_position(self):
diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py
--- a/rpython/jit/backend/x86/rx86.py
+++ b/rpython/jit/backend/x86/rx86.py
@@ -304,13 +304,20 @@
REX_B = 1
@specialize.arg(2)
-def encode_rex(mc, rexbyte, basevalue, orbyte):
+def encode_rex(mc, rexbyte, w, orbyte):
if mc.WORD == 8:
assert 0 <= rexbyte < 8
- if basevalue != 0 or rexbyte != 0:
- if basevalue == 0:
- basevalue = 0x40
- mc.writechar(chr(basevalue | rexbyte))
+ mc.writechar(chr(0x40 | w | rexbyte))
+ else:
+ assert rexbyte == 0
+ return 0
+
+ at specialize.arg(2)
+def encode_rex_opt(mc, rexbyte, _, orbyte):
+ if mc.WORD == 8:
+ assert 0 <= rexbyte < 8
+ if rexbyte != 0:
+ mc.writechar(chr(0x40 | rexbyte))
else:
assert rexbyte == 0
return 0
@@ -322,9 +329,9 @@
# the REX prefix in all cases. It is only useful on instructions which
# have an 8-bit register argument, to force access to the "sil" or "dil"
# registers (as opposed to "ah-dh").
-rex_w = encode_rex, 0, (0x40 | REX_W), None # a REX.W prefix
-rex_nw = encode_rex, 0, 0, None # an optional REX prefix
-rex_fw = encode_rex, 0, 0x40, None # a forced REX prefix
+rex_w = encode_rex, 0, REX_W, None # a REX.W prefix
+rex_nw = encode_rex_opt, 0, 0, None # an optional REX prefix
+rex_fw = encode_rex, 0, 0, None # a forced REX prefix
# ____________________________________________________________
diff --git a/rpython/jit/codewriter/support.py b/rpython/jit/codewriter/support.py
--- a/rpython/jit/codewriter/support.py
+++ b/rpython/jit/codewriter/support.py
@@ -107,7 +107,7 @@
"""
# split the block just before the jit_merge_point()
if portalopindex > 0:
- link = split_block(None, portalblock, portalopindex)
+ link = split_block(portalblock, portalopindex)
portalblock = link.target
portalop = portalblock.operations[0]
# split again, this time enforcing the order of the live vars
@@ -115,7 +115,7 @@
assert portalop.opname == 'jit_marker'
assert portalop.args[0].value == 'jit_merge_point'
greens_v, reds_v = decode_hp_hint_args(portalop)
- link = split_block(None, portalblock, 0, greens_v + reds_v)
+ link = split_block(portalblock, 0, greens_v + reds_v)
return link.target
def sort_vars(args_v):
diff --git a/rpython/jit/metainterp/test/support.py b/rpython/jit/metainterp/test/support.py
--- a/rpython/jit/metainterp/test/support.py
+++ b/rpython/jit/metainterp/test/support.py
@@ -162,41 +162,67 @@
class JitMixin:
basic = True
+ # Basic terminology: the JIT produces "loops" and "bridges".
+ # Bridges are always attached to failing guards. Every loop is
+ # the "trunk" of a tree of compiled code, which is formed by first
+ # compiling a loop and then incrementally adding some number of
+ # bridges to it. Each loop and each bridge ends with either a
+ # FINISH or a JUMP instruction (the name "loop" is not really
+ # adapted any more). The JUMP instruction jumps to any LABEL
+ # pseudo-instruction, which can be anywhere, within the same tree
+ # or another one.
+
def check_resops(self, expected=None, **check):
+ """Check the instructions in all loops and bridges, ignoring
+ the ones that end in FINISH. Either pass a dictionary (then
+ the check must match exactly), or some keyword arguments (then
+ the check is only about the instructions named)."""
get_stats().check_resops(expected=expected, **check)
def check_simple_loop(self, expected=None, **check):
+ """Useful in the simplest case when we have only one loop
+ ending with a jump back to itself and possibly a few bridges.
+ Only the operations within the loop formed by that single jump
+ will be counted; the bridges are all ignored. If several loops
+ were compiled, complains."""
get_stats().check_simple_loop(expected=expected, **check)
def check_trace_count(self, count): # was check_loop_count
- # The number of traces compiled
+ """Check the number of loops and bridges compiled."""
assert get_stats().compiled_count == count
def check_trace_count_at_most(self, count):
+ """Check the number of loops and bridges compiled."""
assert get_stats().compiled_count <= count
def check_jitcell_token_count(self, count): # was check_tree_loop_count
+ """This should check the number of independent trees of code.
+ (xxx it is not 100% clear that the count is correct)"""
assert len(get_stats().jitcell_token_wrefs) == count
def check_target_token_count(self, count):
+ """(xxx unknown)"""
tokens = get_stats().get_all_jitcell_tokens()
n = sum([len(t.target_tokens) for t in tokens])
assert n == count
def check_enter_count(self, count):
+ """Check the number of times pyjitpl ran. (Every time, it
+ should have produced either one loop or one bridge, or aborted;
+ but it is not 100% clear that this is still correct in the
+ presence of unrolling.)"""
assert get_stats().enter_count == count
def check_enter_count_at_most(self, count):
+ """Check the number of times pyjitpl ran."""
assert get_stats().enter_count <= count
- def check_jumps(self, maxcount):
- return # FIXME
- assert get_stats().exec_jumps <= maxcount
-
def check_aborted_count(self, count):
+ """Check the number of times pyjitpl was aborted."""
assert get_stats().aborted_count == count
def check_aborted_count_at_least(self, count):
+ """Check the number of times pyjitpl was aborted."""
assert get_stats().aborted_count >= count
def meta_interp(self, *args, **kwds):
diff --git a/rpython/jit/metainterp/test/test_send.py b/rpython/jit/metainterp/test/test_send.py
--- a/rpython/jit/metainterp/test/test_send.py
+++ b/rpython/jit/metainterp/test/test_send.py
@@ -202,7 +202,7 @@
# the final one.
self.check_trace_count(1)
self.check_resops(guard_class=1, int_add=4, int_sub=4)
- self.check_jumps(14)
+ #self.check_jumps(14)
def test_oosend_guard_failure_2(self):
# same as above, but using prebuilt objects 'w1' and 'w2'
@@ -244,7 +244,7 @@
assert res == f(4, 28)
self.check_trace_count(1)
self.check_resops(guard_class=1, int_add=4, int_sub=4)
- self.check_jumps(14)
+ #self.check_jumps(14)
def test_oosend_different_initial_class(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'w'])
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -375,6 +375,10 @@
# the nursery.
self.pinned_objects_in_nursery = 0
#
+ # This flag is set if the previous minor collection found at least
+ # one pinned object alive.
+ self.any_pinned_object_kept = False
+ #
# Keeps track of old objects pointing to pinned objects. These objects
# must be traced every minor collection. Without tracing them the
# referenced pinned object wouldn't be visited and therefore collected.
@@ -1489,7 +1493,9 @@
# The following counter keeps track of alive and pinned young objects
# inside the nursery. We reset it here and increace it in
# '_trace_drag_out()'.
+ any_pinned_object_from_earlier = self.any_pinned_object_kept
self.pinned_objects_in_nursery = 0
+ self.any_pinned_object_kept = False
#
# Before everything else, remove from 'old_objects_pointing_to_young'
# the young arrays.
@@ -1513,7 +1519,7 @@
# are copied out or flagged. They are also added to the list
# 'old_objects_pointing_to_young'.
self.nursery_surviving_size = 0
- self.collect_roots_in_nursery()
+ self.collect_roots_in_nursery(any_pinned_object_from_earlier)
#
# visit all objects that are known for pointing to pinned
# objects. This way we populate 'surviving_pinned_objects'
@@ -1649,7 +1655,7 @@
def _visit_old_objects_pointing_to_pinned(self, obj, ignore):
self.trace(obj, self._trace_drag_out, obj)
- def collect_roots_in_nursery(self):
+ def collect_roots_in_nursery(self, any_pinned_object_from_earlier):
# we don't need to trace prebuilt GcStructs during a minor collect:
# if a prebuilt GcStruct contains a pointer to a young object,
# then the write_barrier must have ensured that the prebuilt
@@ -1659,10 +1665,19 @@
callback = IncrementalMiniMarkGC._trace_drag_out1_marking_phase
else:
callback = IncrementalMiniMarkGC._trace_drag_out1
+ #
+ # Note a subtlety: if the nursery contains pinned objects "from
+ # earlier", i.e. created earlier than the previous minor
+ # collection, then we can't use the "is_minor=True" optimization.
+ # We really need to walk the complete stack to be sure we still
+ # see them.
+ use_jit_frame_stoppers = not any_pinned_object_from_earlier
+ #
self.root_walker.walk_roots(
callback, # stack roots
callback, # static in prebuilt non-gc
- None) # static in prebuilt gc
+ None, # static in prebuilt gc
+ is_minor=use_jit_frame_stoppers)
debug_stop("gc-minor-walkroots")
def collect_cardrefs_to_nursery(self):
@@ -1844,6 +1859,7 @@
self.surviving_pinned_objects.append(
llarena.getfakearenaaddress(obj - size_gc_header))
self.pinned_objects_in_nursery += 1
+ self.any_pinned_object_kept = True
return
else:
# First visit to an object that has already a shadow.
diff --git a/rpython/memory/gc/minimark.py b/rpython/memory/gc/minimark.py
--- a/rpython/memory/gc/minimark.py
+++ b/rpython/memory/gc/minimark.py
@@ -1322,7 +1322,8 @@
self.root_walker.walk_roots(
MiniMarkGC._trace_drag_out1, # stack roots
MiniMarkGC._trace_drag_out1, # static in prebuilt non-gc
- None) # static in prebuilt gc
+ None, # static in prebuilt gc
+ is_minor=True)
debug_stop("gc-minor-walkroots")
def collect_cardrefs_to_nursery(self):
diff --git a/rpython/memory/gc/test/test_direct.py b/rpython/memory/gc/test/test_direct.py
--- a/rpython/memory/gc/test/test_direct.py
+++ b/rpython/memory/gc/test/test_direct.py
@@ -34,7 +34,8 @@
def walk_roots(self, collect_stack_root,
collect_static_in_prebuilt_nongc,
- collect_static_in_prebuilt_gc):
+ collect_static_in_prebuilt_gc,
+ is_minor=False):
gc = self.tester.gc
layoutbuilder = self.tester.layoutbuilder
if collect_static_in_prebuilt_gc:
diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py
--- a/rpython/memory/gctransform/asmgcroot.py
+++ b/rpython/memory/gctransform/asmgcroot.py
@@ -340,9 +340,10 @@
# called first, to initialize self.belongs_to_current_thread.
assert not hasattr(self, 'gc_detach_callback_pieces_ptr')
- def walk_stack_roots(self, collect_stack_root):
+ def walk_stack_roots(self, collect_stack_root, is_minor=False):
gcdata = self.gcdata
gcdata._gc_collect_stack_root = collect_stack_root
+ gcdata._gc_collect_is_minor = is_minor
pypy_asm_stackwalk(llhelper(ASM_CALLBACK_PTR, self._asm_callback),
gcrootanchor)
@@ -468,6 +469,13 @@
if gc.points_to_valid_gc_object(addr):
collect_stack_root(gc, addr)
#
+ # small hack: the JIT reserves THREADLOCAL_OFS's last bit for
+ # us. We use it to store an "already traced past this frame"
+ # flag.
+ if self._with_jit and self.gcdata._gc_collect_is_minor:
+ if self.mark_jit_frame_can_stop(callee):
+ return False
+ #
# track where the caller_frame saved the registers from its own
# caller
#
@@ -548,6 +556,19 @@
else: # kind == LOC_EBP_MINUS: at -N(%ebp)
return ebp_in_caller - offset
+ def mark_jit_frame_can_stop(self, callee):
+ location = self._shape_decompressor.get_threadlocal_loc()
+ if location == LOC_NOWHERE:
+ return False
+ addr = self.getlocation(callee, llmemory.NULL, location)
+ #
+ x = addr.signed[0]
+ if x & 1:
+ return True # this JIT stack frame is already marked!
+ else:
+ addr.signed[0] = x | 1 # otherwise, mark it but don't stop
+ return False
+
LOC_REG = 0
LOC_ESP_PLUS = 1
@@ -729,6 +750,17 @@
llop.debug_fatalerror(lltype.Void, "asmgcroot: invalid index")
return 0 # annotator fix
+ def get_threadlocal_loc(self):
+ index = self.jit_index
+ if index < 0:
+ return LOC_NOWHERE # case "outside the jit"
+ else:
+ # case "in the jit"
+ from rpython.jit.backend.x86.arch import THREADLOCAL_OFS, WORD
+ return (LOC_ESP_PLUS |
+ ((THREADLOCAL_OFS // WORD + self.extra_stack_depth) << 2))
+
+
# ____________________________________________________________
#
diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -1462,7 +1462,8 @@
def walk_roots(self, collect_stack_root,
collect_static_in_prebuilt_nongc,
- collect_static_in_prebuilt_gc):
+ collect_static_in_prebuilt_gc,
+ is_minor=False):
gcdata = self.gcdata
gc = self.gc
if collect_static_in_prebuilt_nongc:
@@ -1482,7 +1483,7 @@
collect_static_in_prebuilt_gc(gc, result)
addr += sizeofaddr
if collect_stack_root:
- self.walk_stack_roots(collect_stack_root) # abstract
+ self.walk_stack_roots(collect_stack_root, is_minor) # abstract
def finished_minor_collection(self):
func = self.finished_minor_collection_func
diff --git a/rpython/memory/gctransform/shadowstack.py b/rpython/memory/gctransform/shadowstack.py
--- a/rpython/memory/gctransform/shadowstack.py
+++ b/rpython/memory/gctransform/shadowstack.py
@@ -99,7 +99,7 @@
self.shadow_stack_pool.initial_setup()
BaseRootWalker.setup_root_walker(self)
- def walk_stack_roots(self, collect_stack_root):
+ def walk_stack_roots(self, collect_stack_root, is_minor=False):
gcdata = self.gcdata
self.rootstackhook(collect_stack_root,
gcdata.root_stack_base, gcdata.root_stack_top)
diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py
--- a/rpython/memory/gctransform/transform.py
+++ b/rpython/memory/gctransform/transform.py
@@ -221,7 +221,7 @@
# for sanity, we need an empty block at the start of the graph
inserted_empty_startblock = False
if not starts_with_empty_block(graph):
- insert_empty_startblock(self.translator.annotator, graph)
+ insert_empty_startblock(graph)
inserted_empty_startblock = True
is_borrowed = self.compute_borrowed_vars(graph)
@@ -239,7 +239,7 @@
if link.prevblock.exitswitch is None:
link.prevblock.operations.extend(llops)
else:
- insert_empty_block(self.translator.annotator, link, llops)
+ insert_empty_block(link, llops)
# remove the empty block at the start of the graph, which should
# still be empty (but let's check)
diff --git a/rpython/memory/gcwrapper.py b/rpython/memory/gcwrapper.py
--- a/rpython/memory/gcwrapper.py
+++ b/rpython/memory/gcwrapper.py
@@ -191,7 +191,8 @@
def walk_roots(self, collect_stack_root,
collect_static_in_prebuilt_nongc,
- collect_static_in_prebuilt_gc):
+ collect_static_in_prebuilt_gc,
+ is_minor=False):
gcheap = self.gcheap
gc = gcheap.gc
if collect_static_in_prebuilt_gc:
@@ -203,7 +204,7 @@
if self.gcheap.gc.points_to_valid_gc_object(addrofaddr):
collect_static_in_prebuilt_nongc(gc, addrofaddr)
if collect_stack_root:
- for addrofaddr in gcheap.llinterp.find_roots():
+ for addrofaddr in gcheap.llinterp.find_roots(is_minor):
if self.gcheap.gc.points_to_valid_gc_object(addrofaddr):
collect_stack_root(gc, addrofaddr)
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -146,13 +146,21 @@
}
return self._tlobj
- def find_roots(self):
+ def find_roots(self, is_minor=False):
"""Return a list of the addresses of the roots."""
#log.findroots("starting")
roots = []
- for frame in self.frame_stack:
+ for frame in reversed(self.frame_stack):
#log.findroots("graph", frame.graph.name)
frame.find_roots(roots)
+ # If a call is done with 'is_minor=True', we can stop after the
+ # first frame in the stack that was already seen by the previous
+ # call with 'is_minor=True'. (We still need to trace that frame,
+ # but not its callers.)
+ if is_minor:
+ if getattr(frame, '_find_roots_already_seen', False):
+ break
+ frame._find_roots_already_seen = True
return roots
def find_exception(self, exc):
diff --git a/rpython/rtyper/rtyper.py b/rpython/rtyper/rtyper.py
--- a/rpython/rtyper/rtyper.py
+++ b/rpython/rtyper/rtyper.py
@@ -371,9 +371,7 @@
assert 0 <= pos < len(newops) - 1
extraops = block.operations[pos+1:]
del block.operations[pos+1:]
- extrablock = insert_empty_block(self.annotator,
- noexclink,
- newops = extraops)
+ extrablock = insert_empty_block(noexclink, newops=extraops)
if extrablock is None:
self.insert_link_conversions(block)
@@ -447,10 +445,9 @@
# cannot insert conversion operations around a single
# link, unless it is the only exit of this block.
# create a new block along the link...
- newblock = insert_empty_block(self.annotator,
- link,
+ newblock = insert_empty_block(link,
# ...and store the conversions there.
- newops=newops)
+ newops=newops)
link = newblock.exits[0]
for i, new_a1 in newlinkargs.items():
link.args[i] = new_a1
diff --git a/rpython/translator/backendopt/constfold.py b/rpython/translator/backendopt/constfold.py
--- a/rpython/translator/backendopt/constfold.py
+++ b/rpython/translator/backendopt/constfold.py
@@ -171,7 +171,7 @@
v_result.concretetype = nextop.result.concretetype
constants[nextop.result] = v_result
callop = SpaceOperation('direct_call', callargs, v_result)
- newblock = insert_empty_block(None, link, [callop])
+ newblock = insert_empty_block(link, [callop])
[link] = newblock.exits
assert link.target is block
folded_count += 1
@@ -197,7 +197,7 @@
splitlink = block.exits[0]
else:
# split the block at the given position
- splitlink = split_block(None, block, position)
+ splitlink = split_block(block, position)
assert list(block.exits) == [splitlink]
assert link.target is block
assert splitlink.prevblock is block
diff --git a/rpython/translator/backendopt/inline.py b/rpython/translator/backendopt/inline.py
--- a/rpython/translator/backendopt/inline.py
+++ b/rpython/translator/backendopt/inline.py
@@ -396,7 +396,7 @@
copiedexceptblock.recloseblock(Link(linkargs, blocks[0]))
def do_inline(self, block, index_operation):
- splitlink = split_block(None, block, index_operation)
+ splitlink = split_block(block, index_operation)
afterblock = splitlink.target
# these variables have to be passed along all the links in the inlined
# graph because the original function needs them in the blocks after
diff --git a/rpython/translator/c/gcc/test/test_asmgcroot.py b/rpython/translator/c/gcc/test/test_asmgcroot.py
--- a/rpython/translator/c/gcc/test/test_asmgcroot.py
+++ b/rpython/translator/c/gcc/test/test_asmgcroot.py
@@ -251,13 +251,17 @@
def define_callback_with_collect(cls):
return lambda: 0
-class TestAsmGCRootWithSemiSpaceGC_Shared(TestAsmGCRootWithSemiSpaceGC):
- @classmethod
- def make_config(cls):
- config = TestAsmGCRootWithSemiSpaceGC.make_config()
- config.translation.shared = True
- return config
+#class TestAsmGCRootWithSemiSpaceGC_Shared(TestAsmGCRootWithSemiSpaceGC):
+# @classmethod
+# def make_config(cls):
+# config = TestAsmGCRootWithSemiSpaceGC.make_config()
+# config.translation.shared = True
+# return config
class TestAsmGCRootWithHybridTagged(AbstractTestAsmGCRoot,
test_newgc.TestHybridTaggedPointers):
pass
+
+class TestAsmGCRootWithIncrementalMinimark(AbstractTestAsmGCRoot,
+ test_newgc.TestIncrementalMiniMarkGC):
+ pass
diff --git a/rpython/translator/c/support.py b/rpython/translator/c/support.py
--- a/rpython/translator/c/support.py
+++ b/rpython/translator/c/support.py
@@ -89,7 +89,8 @@
''')
def _char_repr(c):
- if c in '\\"': return '\\' + c
+ # escape with a '\' the characters '\', '"' or (for trigraphs) '?'
+ if c in '\\"?': return '\\' + c
if ' ' <= c < '\x7F': return c
return '\\%03o' % ord(c)
diff --git a/rpython/translator/exceptiontransform.py b/rpython/translator/exceptiontransform.py
--- a/rpython/translator/exceptiontransform.py
+++ b/rpython/translator/exceptiontransform.py
@@ -259,7 +259,7 @@
if not self.raise_analyzer.can_raise(op):
continue
- splitlink = split_block(None, block, i+1)
+ splitlink = split_block(block, i+1)
afterblock = splitlink.target
if lastblock is block:
lastblock = afterblock
@@ -432,7 +432,7 @@
if insert_zeroing_op:
if normalafterblock is None:
- normalafterblock = insert_empty_block(None, l0)
+ normalafterblock = insert_empty_block(l0)
v_result = spaceop.result
if v_result in l0.args:
result_i = l0.args.index(v_result)
diff --git a/rpython/translator/goal/translate.py b/rpython/translator/goal/translate.py
--- a/rpython/translator/goal/translate.py
+++ b/rpython/translator/goal/translate.py
@@ -308,7 +308,9 @@
samefile = this_exe.samefile(exe_name)
assert not samefile, (
'Output file %s is the currently running '
- 'interpreter (use --output=...)' % exe_name)
+ 'interpreter (please move the executable, and '
+ 'possibly its associated libpypy-c, somewhere else '
+ 'before you execute it)' % exe_name)
except EnvironmentError:
pass
diff --git a/rpython/translator/simplify.py b/rpython/translator/simplify.py
--- a/rpython/translator/simplify.py
+++ b/rpython/translator/simplify.py
@@ -1072,7 +1072,7 @@
link.target in stopblocks):
hints['exactlength'] = True
chints = Constant(hints)
- newblock = unsimplify.insert_empty_block(None, link)
+ newblock = unsimplify.insert_empty_block(link)
index = link.args.index(vlist)
vlist2 = newblock.inputargs[index]
vlist3 = Variable(vlist2)
diff --git a/rpython/translator/test/test_unsimplify.py b/rpython/translator/test/test_unsimplify.py
--- a/rpython/translator/test/test_unsimplify.py
+++ b/rpython/translator/test/test_unsimplify.py
@@ -21,7 +21,7 @@
w = x * y
return z + w
graph, t = translate(f, [int, int])
- split_block(t.annotator, graph.startblock, i)
+ split_block(graph.startblock, i)
checkgraph(graph)
interp = LLInterpreter(t.rtyper)
result = interp.eval_graph(graph, [1, 2])
@@ -35,7 +35,7 @@
else:
return y + 2
graph, t = translate(f, [int, int])
- split_block(t.annotator, graph.startblock, i)
+ split_block(graph.startblock, i)
checkgraph(graph)
interp = LLInterpreter(t.rtyper)
result = interp.eval_graph(graph, [-12, 2])
@@ -61,7 +61,7 @@
return 1
return x
graph, t = translate(catches, [int])
- split_block(t.annotator, graph.startblock, i)
+ split_block(graph.startblock, i)
checkgraph(graph)
interp = LLInterpreter(t.rtyper)
result = interp.eval_graph(graph, [0])
diff --git a/rpython/translator/unsimplify.py b/rpython/translator/unsimplify.py
--- a/rpython/translator/unsimplify.py
+++ b/rpython/translator/unsimplify.py
@@ -7,7 +7,7 @@
var.concretetype = concretetype
return var
-def insert_empty_block(annotator, link, newops=[]):
+def insert_empty_block(link, newops=[]):
"""Insert and return a new block along the given link."""
vars = {}
for v in link.args:
@@ -30,7 +30,7 @@
link.target = newblock
return newblock
-def insert_empty_startblock(annotator, graph):
+def insert_empty_startblock(graph):
vars = [v.copy() for v in graph.startblock.inputargs]
newblock = Block(vars)
newblock.closeblock(Link(vars, graph.startblock))
@@ -41,7 +41,7 @@
and graph.startblock.exitswitch is None
and graph.startblock.exits[0].args == graph.getargs())
-def split_block(annotator, block, index, _forcelink=None):
+def split_block(block, index, _forcelink=None):
"""return a link where prevblock is the block leading up but excluding the
index'th operation and target is a new block with the neccessary variables
passed on.
More information about the pypy-commit
mailing list