[pypy-commit] pypy win64-stage1: Merge with default (2 mon)
ctismer
noreply at buildbot.pypy.org
Tue Mar 13 00:03:03 CET 2012
Author: Christian Tismer <tismer at stackless.com>
Branch: win64-stage1
Changeset: r53376:d067bda477b7
Date: 2012-03-12 16:02 -0700
http://bitbucket.org/pypy/pypy/changeset/d067bda477b7/
Log: Merge with default (2 mon)
diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py
--- a/pypy/jit/backend/llsupport/descr.py
+++ b/pypy/jit/backend/llsupport/descr.py
@@ -425,7 +425,15 @@
self.arg_classes.count('L')) == len(args_f or ())
def repr_of_descr(self):
- return '<CallDescr(%s,%s)>' % (self.arg_classes, self.result_type)
+ res = 'Call%s %d' % (self.result_type, self.result_size)
+ if self.arg_classes:
+ res += ' ' + self.arg_classes
+ if self.extrainfo:
+ res += ' EF=%d' % self.extrainfo.extraeffect
+ oopspecindex = self.extrainfo.oopspecindex
+ if oopspecindex:
+ res += ' OS=%d' % oopspecindex
+ return '<%s>' % res
def map_type_to_argclass(ARG, accept_void=False):
diff --git a/pypy/jit/backend/llsupport/test/test_descr.py b/pypy/jit/backend/llsupport/test/test_descr.py
--- a/pypy/jit/backend/llsupport/test/test_descr.py
+++ b/pypy/jit/backend/llsupport/test/test_descr.py
@@ -313,6 +313,10 @@
def test_repr_of_descr():
+ def repr_of_descr(descr):
+ s = descr.repr_of_descr()
+ assert ',' not in s # makes the life easier for pypy.tool.jitlogparser
+ return s
c0 = GcCache(False)
T = lltype.GcStruct('T')
S = lltype.GcStruct('S', ('x', lltype.Char),
@@ -320,34 +324,34 @@
('z', lltype.Ptr(T)))
descr1 = get_size_descr(c0, S)
s = symbolic.get_size(S, False)
- assert descr1.repr_of_descr() == '<SizeDescr %d>' % s
+ assert repr_of_descr(descr1) == '<SizeDescr %d>' % s
#
descr2 = get_field_descr(c0, S, 'y')
o, _ = symbolic.get_field_token(S, 'y', False)
- assert descr2.repr_of_descr() == '<FieldP S.y %d>' % o
+ assert repr_of_descr(descr2) == '<FieldP S.y %d>' % o
#
descr2i = get_field_descr(c0, S, 'x')
o, _ = symbolic.get_field_token(S, 'x', False)
- assert descr2i.repr_of_descr() == '<FieldU S.x %d>' % o
+ assert repr_of_descr(descr2i) == '<FieldU S.x %d>' % o
#
descr3 = get_array_descr(c0, lltype.GcArray(lltype.Ptr(S)))
o = symbolic.get_size(lltype.Ptr(S), False)
- assert descr3.repr_of_descr() == '<ArrayP %d>' % o
+ assert repr_of_descr(descr3) == '<ArrayP %d>' % o
#
descr3i = get_array_descr(c0, lltype.GcArray(lltype.Char))
- assert descr3i.repr_of_descr() == '<ArrayU 1>'
+ assert repr_of_descr(descr3i) == '<ArrayU 1>'
#
descr4 = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Ptr(S))
- assert descr4.repr_of_descr() == '<CallDescr(ir,r)>'
+ assert repr_of_descr(descr4) == '<Callr %d ir>' % o
#
descr4i = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Char)
- assert descr4i.repr_of_descr() == '<CallDescr(ir,i)>'
+ assert repr_of_descr(descr4i) == '<Calli 1 ir>'
#
descr4f = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Float)
- assert descr4f.repr_of_descr() == '<CallDescr(ir,f)>'
+ assert repr_of_descr(descr4f) == '<Callf 8 ir>'
#
descr5f = get_call_descr(c0, [lltype.Char], lltype.SingleFloat)
- assert descr5f.repr_of_descr() == '<CallDescr(i,S)>'
+ assert repr_of_descr(descr5f) == '<CallS 4 i>'
def test_call_stubs_1():
c0 = GcCache(False)
diff --git a/pypy/jit/backend/x86/test/test_jump.py b/pypy/jit/backend/x86/test/test_jump.py
--- a/pypy/jit/backend/x86/test/test_jump.py
+++ b/pypy/jit/backend/x86/test/test_jump.py
@@ -20,6 +20,11 @@
def regalloc_pop(self, loc):
self.ops.append(('pop', loc))
+ def regalloc_immedmem2mem(self, from_loc, to_loc):
+ assert isinstance(from_loc, ConstFloatLoc)
+ assert isinstance(to_loc, StackLoc)
+ self.ops.append(('immedmem2mem', from_loc, to_loc))
+
def got(self, expected):
print '------------------------ comparing ---------------------------'
for op1, op2 in zip(self.ops, expected):
@@ -244,6 +249,13 @@
else:
return pick1()
#
+ def pick2c():
+ n = random.randrange(-2000, 500)
+ if n >= 0:
+ return ConstFloatLoc(n) # n is the address, not really used here
+ else:
+ return pick2()
+ #
def pick_dst(fn, count, seen):
result = []
while len(result) < count:
@@ -280,12 +292,12 @@
if loc.get_width() > WORD:
stack[loc.value+WORD] = 'value-hiword-%d' % i
else:
- assert isinstance(loc, ImmedLoc)
+ assert isinstance(loc, (ImmedLoc, ConstFloatLoc))
return regs1, regs2, stack
#
for i in range(500):
seen = {}
- src_locations2 = [pick2() for i in range(4)]
+ src_locations2 = [pick2c() for i in range(4)]
dst_locations2 = pick_dst(pick2, 4, seen)
src_locations1 = [pick1c() for i in range(5)]
dst_locations1 = pick_dst(pick1, 5, seen)
@@ -312,9 +324,15 @@
return got
if isinstance(loc, ImmedLoc):
return 'const-%d' % loc.value
+ if isinstance(loc, ConstFloatLoc):
+ got = 'constfloat-@%d' % loc.value
+ if loc.get_width() > WORD:
+ got = (got, 'constfloat-next-@%d' % loc.value)
+ return got
assert 0, loc
#
def write(loc, newvalue):
+ assert (type(newvalue) is tuple) == (loc.get_width() > WORD)
if isinstance(loc, RegLoc):
if loc.is_xmm:
regs2[loc.value] = newvalue
@@ -337,10 +355,14 @@
for op in assembler.ops:
if op[0] == 'mov':
src, dst = op[1:]
- assert isinstance(src, (RegLoc, StackLoc, ImmedLoc))
- assert isinstance(dst, (RegLoc, StackLoc))
- assert not (isinstance(src, StackLoc) and
- isinstance(dst, StackLoc))
+ if isinstance(src, ConstFloatLoc):
+ assert isinstance(dst, RegLoc)
+ assert dst.is_xmm
+ else:
+ assert isinstance(src, (RegLoc, StackLoc, ImmedLoc))
+ assert isinstance(dst, (RegLoc, StackLoc))
+ assert not (isinstance(src, StackLoc) and
+ isinstance(dst, StackLoc))
write(dst, read(src))
elif op[0] == 'push':
src, = op[1:]
@@ -350,6 +372,11 @@
dst, = op[1:]
assert isinstance(dst, (RegLoc, StackLoc))
write(dst, extrapushes.pop())
+ elif op[0] == 'immedmem2mem':
+ src, dst = op[1:]
+ assert isinstance(src, ConstFloatLoc)
+ assert isinstance(dst, StackLoc)
+ write(dst, read(src, 8))
else:
assert 0, "unknown op: %r" % (op,)
assert not extrapushes
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -105,7 +105,7 @@
def compile_loop(metainterp, greenkey, start,
inputargs, jumpargs,
- start_resumedescr, full_preamble_needed=True):
+ resume_at_jump_descr, full_preamble_needed=True):
"""Try to compile a new procedure by closing the current history back
to the first operation.
"""
@@ -126,10 +126,11 @@
part = create_empty_loop(metainterp)
part.inputargs = inputargs[:]
h_ops = history.operations
- part.start_resumedescr = start_resumedescr
+ part.resume_at_jump_descr = resume_at_jump_descr
part.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(jitcell_token))] + \
[h_ops[i].clone() for i in range(start, len(h_ops))] + \
- [ResOperation(rop.JUMP, jumpargs, None, descr=jitcell_token)]
+ [ResOperation(rop.LABEL, jumpargs, None, descr=jitcell_token)]
+
try:
optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts)
except InvalidLoop:
@@ -184,7 +185,7 @@
def compile_retrace(metainterp, greenkey, start,
inputargs, jumpargs,
- start_resumedescr, partial_trace, resumekey):
+ resume_at_jump_descr, partial_trace, resumekey):
"""Try to compile a new procedure by closing the current history back
to the first operation.
"""
@@ -200,7 +201,7 @@
part = create_empty_loop(metainterp)
part.inputargs = inputargs[:]
- part.start_resumedescr = start_resumedescr
+ part.resume_at_jump_descr = resume_at_jump_descr
h_ops = history.operations
part.operations = [partial_trace.operations[-1]] + \
@@ -212,13 +213,12 @@
try:
optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts)
except InvalidLoop:
- #return None # XXX: Dissable for now
# Fall back on jumping to preamble
target_token = label.getdescr()
assert isinstance(target_token, TargetToken)
assert target_token.exported_state
part.operations = [orignial_label] + \
- [ResOperation(rop.JUMP, target_token.exported_state.jump_args,
+ [ResOperation(rop.JUMP, inputargs[:],
None, descr=loop_jitcell_token)]
try:
optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts,
@@ -751,7 +751,7 @@
metainterp_sd.stats.add_jitcell_token(jitcell_token)
-def compile_trace(metainterp, resumekey, start_resumedescr=None):
+def compile_trace(metainterp, resumekey, resume_at_jump_descr=None):
"""Try to compile a new bridge leading from the beginning of the history
to some existing place.
"""
@@ -767,7 +767,7 @@
# clone ops, as optimize_bridge can mutate the ops
new_trace.operations = [op.clone() for op in metainterp.history.operations]
- new_trace.start_resumedescr = start_resumedescr
+ new_trace.resume_at_jump_descr = resume_at_jump_descr
metainterp_sd = metainterp.staticdata
state = metainterp.jitdriver_sd.warmstate
if isinstance(resumekey, ResumeAtPositionDescr):
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -706,6 +706,9 @@
self.virtual_state = None
self.exported_state = None
+
+ def repr_of_descr(self):
+ return 'TargetToken(%d)' % compute_unique_id(self)
class TreeLoop(object):
inputargs = None
@@ -713,7 +716,7 @@
call_pure_results = None
logops = None
quasi_immutable_deps = None
- start_resumedescr = None
+ resume_at_jump_descr = None
def _token(*args):
raise Exception("TreeLoop.token is killed")
diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py
--- a/pypy/jit/metainterp/logger.py
+++ b/pypy/jit/metainterp/logger.py
@@ -5,7 +5,7 @@
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp.history import Const, ConstInt, Box, \
- BoxInt, ConstFloat, BoxFloat, AbstractFailDescr
+ BoxInt, ConstFloat, BoxFloat, AbstractFailDescr, TargetToken
class Logger(object):
@@ -135,6 +135,13 @@
fail_args = ''
return s_offset + res + op.getopname() + '(' + args + ')' + fail_args
+ def _log_inputarg_setup_ops(self, op):
+ target_token = op.getdescr()
+ if isinstance(target_token, TargetToken):
+ if target_token.exported_state:
+ for op in target_token.exported_state.inputarg_setup_ops:
+ debug_print(' ' + self.repr_of_resop(op))
+
def _log_operations(self, inputargs, operations, ops_offset):
if not have_debug_prints():
return
@@ -146,6 +153,8 @@
for i in range(len(operations)):
op = operations[i]
debug_print(self.repr_of_resop(operations[i], ops_offset))
+ if op.getopnum() == rop.LABEL:
+ self._log_inputarg_setup_ops(op)
if ops_offset and None in ops_offset:
offset = ops_offset[None]
debug_print("+%d: --end of the loop--" % offset)
diff --git a/pypy/jit/metainterp/memmgr.py b/pypy/jit/metainterp/memmgr.py
--- a/pypy/jit/metainterp/memmgr.py
+++ b/pypy/jit/metainterp/memmgr.py
@@ -1,5 +1,5 @@
import math
-from pypy.rlib.rarithmetic import r_int64, r_uint
+from pypy.rlib.rarithmetic import r_int64
from pypy.rlib.debug import debug_start, debug_print, debug_stop
from pypy.rlib.objectmodel import we_are_translated
@@ -21,7 +21,6 @@
#
class MemoryManager(object):
- NO_NEXT_CHECK = r_int64(2 ** 63 - 1)
def __init__(self):
self.check_frequency = -1
@@ -37,13 +36,12 @@
# According to my estimates it's about 5e9 years given 1000 loops
# per second
self.current_generation = r_int64(1)
- self.next_check = self.NO_NEXT_CHECK
+ self.next_check = r_int64(-1)
self.alive_loops = {}
- self._cleanup_jitcell_dicts = lambda: None
def set_max_age(self, max_age, check_frequency=0):
if max_age <= 0:
- self.next_check = self.NO_NEXT_CHECK
+ self.next_check = r_int64(-1)
else:
self.max_age = max_age
if check_frequency <= 0:
@@ -51,11 +49,10 @@
self.check_frequency = check_frequency
self.next_check = self.current_generation + 1
- def next_generation(self, do_cleanups_now=True):
+ def next_generation(self):
self.current_generation += 1
- if do_cleanups_now and self.current_generation >= self.next_check:
+ if self.current_generation == self.next_check:
self._kill_old_loops_now()
- self._cleanup_jitcell_dicts()
self.next_check = self.current_generation + self.check_frequency
def keep_loop_alive(self, looptoken):
@@ -84,22 +81,3 @@
# a single one is not enough for all tests :-(
rgc.collect(); rgc.collect(); rgc.collect()
debug_stop("jit-mem-collect")
-
- def get_current_generation_uint(self):
- """Return the current generation, possibly truncated to a uint.
- To use only as an approximation for decaying counters."""
- return r_uint(self.current_generation)
-
- def record_jitcell_dict(self, callback):
- """NOT_RPYTHON. The given jitcell_dict is a dict that needs
- occasional clean-ups of old cells. A cell is old if it never
- reached the threshold, and its counter decayed to a tiny value."""
- # note that the various jitcell_dicts have different RPython types,
- # so we have to make a different function for each one. These
- # functions are chained to each other: each calls the previous one.
- def cleanup_dict():
- callback()
- cleanup_previous()
- #
- cleanup_previous = self._cleanup_jitcell_dicts
- self._cleanup_jitcell_dicts = cleanup_dict
diff --git a/pypy/jit/metainterp/optimize.py b/pypy/jit/metainterp/optimize.py
--- a/pypy/jit/metainterp/optimize.py
+++ b/pypy/jit/metainterp/optimize.py
@@ -5,58 +5,3 @@
"""Raised when the optimize*.py detect that the loop that
we are trying to build cannot possibly make sense as a
long-running loop (e.g. it cannot run 2 complete iterations)."""
-
-class RetraceLoop(JitException):
- """ Raised when inlining a short preamble resulted in an
- InvalidLoop. This means the optimized loop is too specialized
- to be useful here, so we trace it again and produced a second
- copy specialized in some different way.
- """
-
-# ____________________________________________________________
-
-def optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts):
- debug_start("jit-optimize")
- try:
- return _optimize_loop(metainterp_sd, old_loop_tokens, loop,
- enable_opts)
- finally:
- debug_stop("jit-optimize")
-
-def _optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts):
- from pypy.jit.metainterp.optimizeopt import optimize_loop_1
- loop.logops = metainterp_sd.logger_noopt.log_loop(loop.inputargs,
- loop.operations)
- # XXX do we really still need a list?
- if old_loop_tokens:
- return old_loop_tokens[0]
- optimize_loop_1(metainterp_sd, loop, enable_opts)
- return None
-
-# ____________________________________________________________
-
-def optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts,
- inline_short_preamble=True, retraced=False):
- debug_start("jit-optimize")
- try:
- return _optimize_bridge(metainterp_sd, old_loop_tokens, bridge,
- enable_opts,
- inline_short_preamble, retraced)
- finally:
- debug_stop("jit-optimize")
-
-def _optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts,
- inline_short_preamble, retraced=False):
- from pypy.jit.metainterp.optimizeopt import optimize_bridge_1
- bridge.logops = metainterp_sd.logger_noopt.log_loop(bridge.inputargs,
- bridge.operations)
- if old_loop_tokens:
- old_loop_token = old_loop_tokens[0]
- bridge.operations[-1].setdescr(old_loop_token) # patch jump target
- optimize_bridge_1(metainterp_sd, bridge, enable_opts,
- inline_short_preamble, retraced)
- return old_loop_tokens[0]
- #return bridge.operations[-1].getdescr()
- return None
-
-# ____________________________________________________________
diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py
--- a/pypy/jit/metainterp/optimizeopt/__init__.py
+++ b/pypy/jit/metainterp/optimizeopt/__init__.py
@@ -51,34 +51,6 @@
return optimizations, unroll
-
-def optimize_loop_1(metainterp_sd, loop, enable_opts,
- inline_short_preamble=True, retraced=False):
- """Optimize loop.operations to remove internal overheadish operations.
- """
-
- optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts,
- inline_short_preamble, retraced)
- if unroll:
- optimize_unroll(metainterp_sd, loop, optimizations)
- else:
- optimizer = Optimizer(metainterp_sd, loop, optimizations)
- optimizer.propagate_all_forward()
-
-def optimize_bridge_1(metainterp_sd, bridge, enable_opts,
- inline_short_preamble=True, retraced=False):
- """The same, but for a bridge. """
- enable_opts = enable_opts.copy()
- try:
- del enable_opts['unroll']
- except KeyError:
- pass
- optimize_loop_1(metainterp_sd, bridge, enable_opts,
- inline_short_preamble, retraced)
-
-if __name__ == '__main__':
- print ALL_OPTS_NAMES
-
def optimize_trace(metainterp_sd, loop, enable_opts, inline_short_preamble=True):
"""Optimize loop.operations to remove internal overheadish operations.
"""
@@ -96,3 +68,6 @@
finally:
debug_stop("jit-optimize")
+if __name__ == '__main__':
+ print ALL_OPTS_NAMES
+
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -453,6 +453,7 @@
def clear_newoperations(self):
self._newoperations = []
+ self.seen_results = {}
def make_equal_to(self, box, value, replace=False):
assert isinstance(value, OptValue)
diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py
--- a/pypy/jit/metainterp/optimizeopt/simplify.py
+++ b/pypy/jit/metainterp/optimizeopt/simplify.py
@@ -35,6 +35,9 @@
pass
def optimize_LABEL(self, op):
+ descr = op.getdescr()
+ if isinstance(descr, JitCellToken):
+ return self.optimize_JUMP(op.copy_and_change(rop.JUMP))
self.last_label_descr = op.getdescr()
self.emit_operation(op)
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
@@ -1,3 +1,4 @@
+from __future__ import with_statement
from pypy.jit.metainterp.optimizeopt.test.test_util import (
LLtypeMixin, BaseTest, Storage, _sortboxes, FakeDescrWithSnapshot)
from pypy.jit.metainterp.history import TreeLoop, JitCellToken, TargetToken
@@ -8,14 +9,14 @@
class BaseTestMultiLabel(BaseTest):
enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll"
- def optimize_loop(self, ops, expected):
+ def optimize_loop(self, ops, expected, expected_shorts=None):
loop = self.parse(ops)
if expected != "crash!":
expected = self.parse(expected)
part = TreeLoop('part')
part.inputargs = loop.inputargs
- part.start_resumedescr = FakeDescrWithSnapshot()
+ part.resume_at_jump_descr = FakeDescrWithSnapshot()
token = loop.original_jitcell_token
optimized = TreeLoop('optimized')
@@ -32,15 +33,17 @@
if nxt < len(loop.operations):
label = loop.operations[nxt]
assert label.getopnum() == rop.LABEL
- jumpop = ResOperation(rop.JUMP, label.getarglist(),
- None, descr=token)
- operations.append(jumpop)
+ if label.getdescr() is None:
+ label.setdescr(token)
+ operations.append(label)
part.operations = operations
+
self._do_optimize_loop(part, None)
if part.operations[-1].getopnum() == rop.LABEL:
last_label = [part.operations.pop()]
else:
last_label = []
+
optimized.operations.extend(part.operations)
prv = nxt + 1
@@ -53,9 +56,32 @@
print 'Failed!'
print
+ shorts = [op.getdescr().short_preamble
+ for op in optimized.operations
+ if op.getopnum() == rop.LABEL]
+
+ if expected_shorts:
+ for short in shorts:
+ print
+ print "Short preamble:"
+ print '\n'.join([str(o) for o in short])
+
+
assert expected != "crash!", "should have raised an exception"
self.assert_equal(optimized, expected)
+ if expected_shorts:
+ assert len(shorts) == len(expected_shorts)
+ for short, expected_short in zip(shorts, expected_shorts):
+ expected_short = self.parse(expected_short)
+ short_preamble = TreeLoop('short preamble')
+ assert short[0].getopnum() == rop.LABEL
+ short_preamble.inputargs = short[0].getarglist()
+ short_preamble.operations = short
+ self.assert_equal(short_preamble, expected_short,
+ text_right='expected short preamble')
+
+
return optimized
def test_simple(self):
@@ -193,8 +219,168 @@
"""
with raises(InvalidLoop):
self.optimize_loop(ops, ops)
-
+
+ def test_two_intermediate_labels_basic_1(self):
+ ops = """
+ [p1, i1]
+ i2 = getfield_gc(p1, descr=valuedescr)
+ label(p1, i1)
+ i3 = getfield_gc(p1, descr=valuedescr)
+ i4 = int_add(i1, i3)
+ label(p1, i4)
+ i5 = int_add(i4, 1)
+ jump(p1, i5)
+ """
+ expected = """
+ [p1, i1]
+ i2 = getfield_gc(p1, descr=valuedescr)
+ label(p1, i1, i2)
+ i4 = int_add(i1, i2)
+ label(p1, i4)
+ i5 = int_add(i4, 1)
+ jump(p1, i5)
+ """
+ short1 = """
+ [p1, i1]
+ label(p1, i1)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ short2 = """
+ [p1, i1]
+ label(p1, i1)
+ jump(p1, i1)
+ """
+ self.optimize_loop(ops, expected, expected_shorts=[short1, short2])
+
+ def test_two_intermediate_labels_basic_2(self):
+ ops = """
+ [p1, i1]
+ i2 = int_add(i1, 1)
+ label(p1, i1)
+ i3 = getfield_gc(p1, descr=valuedescr)
+ i4 = int_add(i1, i3)
+ label(p1, i4)
+ i5 = getfield_gc(p1, descr=valuedescr)
+ i6 = int_add(i4, i5)
+ jump(p1, i6)
+ """
+ expected = """
+ [p1, i1]
+ i2 = int_add(i1, 1)
+ label(p1, i1)
+ i3 = getfield_gc(p1, descr=valuedescr)
+ i4 = int_add(i1, i3)
+ label(p1, i4, i3)
+ i6 = int_add(i4, i3)
+ jump(p1, i6, i3)
+ """
+ short1 = """
+ [p1, i1]
+ label(p1, i1)
+ jump(p1, i1)
+ """
+ short2 = """
+ [p1, i1]
+ label(p1, i1)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ self.optimize_loop(ops, expected, expected_shorts=[short1, short2])
+
+ def test_two_intermediate_labels_both(self):
+ ops = """
+ [p1, i1]
+ i2 = getfield_gc(p1, descr=valuedescr)
+ label(p1, i1)
+ i3 = getfield_gc(p1, descr=valuedescr)
+ i4 = int_add(i1, i3)
+ label(p1, i4)
+ i5 = getfield_gc(p1, descr=valuedescr)
+ i6 = int_mul(i4, i5)
+ jump(p1, i6)
+ """
+ expected = """
+ [p1, i1]
+ i2 = getfield_gc(p1, descr=valuedescr)
+ label(p1, i1, i2)
+ i4 = int_add(i1, i2)
+ label(p1, i4, i2)
+ i6 = int_mul(i4, i2)
+ jump(p1, i6, i2)
+ """
+ short = """
+ [p1, i1]
+ label(p1, i1)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ self.optimize_loop(ops, expected, expected_shorts=[short, short])
+
+ def test_import_across_multiple_labels_basic(self):
+ # Not supported, juts make sure we get a functional trace
+ ops = """
+ [p1, i1]
+ i2 = getfield_gc(p1, descr=valuedescr)
+ label(p1, i1)
+ i3 = int_add(i1, 1)
+ label(p1, i1)
+ i4 = getfield_gc(p1, descr=valuedescr)
+ i5 = int_add(i4, 1)
+ jump(p1, i5)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_import_across_multiple_labels_with_duplication(self):
+ # Not supported, juts make sure we get a functional trace
+ ops = """
+ [p1, i1]
+ i2 = getfield_gc(p1, descr=valuedescr)
+ label(p1, i2)
+ i3 = int_add(i2, 1)
+ label(p1, i2)
+ i4 = getfield_gc(p1, descr=valuedescr)
+ i5 = int_add(i4, 1)
+ jump(p1, i5)
+ """
+ exported = """
+ [p1, i1]
+ i2 = getfield_gc(p1, descr=valuedescr)
+ i6 = same_as(i2)
+ label(p1, i2)
+ i3 = int_add(i2, 1)
+ label(p1, i2)
+ i4 = getfield_gc(p1, descr=valuedescr)
+ i5 = int_add(i4, 1)
+ jump(p1, i5)
+ """
+ self.optimize_loop(ops, exported)
+ def test_import_virtual_across_multiple_labels(self):
+ ops = """
+ [p0, i1]
+ i1a = int_add(i1, 1)
+ pv = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(pv, i1a, descr=valuedescr)
+ label(pv, i1)
+ i2 = int_mul(i1, 3)
+ label(pv, i2)
+ i3 = getfield_gc(pv, descr=valuedescr)
+ i4 = int_add(i3, i2)
+ jump(pv, i4)
+ """
+ expected = """
+ [p0, i1]
+ i1a = int_add(i1, 1)
+ i5 = same_as(i1a)
+ label(i1a, i1)
+ i2 = int_mul(i1, 3)
+ label(i1a, i2)
+ i4 = int_add(i1a, i2)
+ jump(i1a, i4)
+ """
+ self.optimize_loop(ops, expected)
+
class TestLLtype(BaseTestMultiLabel, LLtypeMixin):
pass
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -4,7 +4,7 @@
LLtypeMixin, BaseTest, Storage, _sortboxes, convert_old_style_to_targets)
import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt
import pypy.jit.metainterp.optimizeopt.virtualize as virtualize
-from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT, build_opt_chain
+from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT, build_opt_chain
from pypy.jit.metainterp.optimize import InvalidLoop
from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt
from pypy.jit.metainterp.history import TreeLoop, JitCellToken, TargetToken
@@ -4211,7 +4211,6 @@
preamble = """
[p0]
i0 = strlen(p0)
- i3 = same_as(i0) # Should be killed by backend
jump(p0)
"""
expected = """
@@ -5668,8 +5667,7 @@
p3 = newstr(i3)
copystrcontent(p1, p3, 0, 0, i1)
copystrcontent(p2, p3, 0, i1, i2)
- i7 = same_as(i2)
- jump(p2, p3, i7)
+ jump(p2, p3, i2)
"""
expected = """
[p1, p2, i1]
@@ -5744,9 +5742,7 @@
copystrcontent(p1, p5, 0, 0, i1)
copystrcontent(p2, p5, 0, i1, i2)
copystrcontent(p3, p5, 0, i12, i3)
- i129 = same_as(i2)
- i130 = same_as(i3)
- jump(p2, p3, p5, i129, i130)
+ jump(p2, p3, p5, i2, i3)
"""
expected = """
[p1, p2, p3, i1, i2]
@@ -5959,8 +5955,7 @@
p4 = newstr(i5)
copystrcontent(p1, p4, i1, 0, i3)
copystrcontent(p2, p4, 0, i3, i4)
- i9 = same_as(i4)
- jump(p4, i1, i2, p2, i5, i3, i9)
+ jump(p4, i1, i2, p2, i5, i3, i4)
"""
expected = """
[p1, i1, i2, p2, i5, i3, i4]
@@ -6082,9 +6077,7 @@
copystrcontent(p2, p4, 0, i1, i2)
i0 = call(0, p3, p4, descr=strequaldescr)
escape(i0)
- i11 = same_as(i1)
- i12 = same_as(i2)
- jump(p1, p2, p3, i3, i11, i12)
+ jump(p1, p2, p3, i3, i1, i2)
"""
expected = """
[p1, p2, p3, i3, i1, i2]
@@ -6304,7 +6297,6 @@
i1 = strlen(p1)
i0 = int_eq(i1, 0)
escape(i0)
- i3 = same_as(i1)
jump(p1, i0)
"""
self.optimize_strunicode_loop_extradescrs(ops, expected, preamble)
@@ -6350,9 +6342,7 @@
copystrcontent(p2, p4, 0, i1, i2)
i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr)
escape(i0)
- i11 = same_as(i1)
- i12 = same_as(i2)
- jump(p1, p2, i3, i11, i12)
+ jump(p1, p2, i3, i1, i2)
"""
expected = """
[p1, p2, i3, i1, i2]
@@ -6925,8 +6915,7 @@
[p9]
i843 = strlen(p9)
call(i843, descr=nonwritedescr)
- i0 = same_as(i843)
- jump(p9, i0)
+ jump(p9, i843)
"""
short = """
[p9]
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_util.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py
@@ -430,18 +430,18 @@
preamble = TreeLoop('preamble')
preamble.inputargs = inputargs
- preamble.start_resumedescr = FakeDescrWithSnapshot()
+ preamble.resume_at_jump_descr = FakeDescrWithSnapshot()
token = JitCellToken()
preamble.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(token))] + \
operations + \
- [ResOperation(rop.JUMP, jump_args, None, descr=token)]
+ [ResOperation(rop.LABEL, jump_args, None, descr=token)]
self._do_optimize_loop(preamble, call_pure_results)
assert preamble.operations[-1].getopnum() == rop.LABEL
inliner = Inliner(inputargs, jump_args)
- loop.start_resumedescr = preamble.start_resumedescr
+ loop.resume_at_jump_descr = preamble.resume_at_jump_descr
loop.operations = [preamble.operations[-1]] + \
[inliner.inline_op(op, clone=False) for op in cloned_operations] + \
[ResOperation(rop.JUMP, [inliner.inline_arg(a) for a in jump_args],
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -3,7 +3,7 @@
from pypy.jit.metainterp.compile import ResumeGuardDescr
from pypy.jit.metainterp.history import TreeLoop, TargetToken, JitCellToken
from pypy.jit.metainterp.jitexc import JitException
-from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop
+from pypy.jit.metainterp.optimize import InvalidLoop
from pypy.jit.metainterp.optimizeopt.optimizer import *
from pypy.jit.metainterp.optimizeopt.generalize import KillHugeIntBounds
from pypy.jit.metainterp.inliner import Inliner
@@ -51,10 +51,10 @@
distinction anymore)"""
inline_short_preamble = True
- did_import = False
def __init__(self, metainterp_sd, loop, optimizations):
self.optimizer = UnrollableOptimizer(metainterp_sd, loop, optimizations)
+ self.boxes_created_this_iteration = None
def fix_snapshot(self, jump_args, snapshot):
if snapshot is None:
@@ -71,7 +71,6 @@
loop = self.optimizer.loop
self.optimizer.clear_newoperations()
-
start_label = loop.operations[0]
if start_label.getopnum() == rop.LABEL:
loop.operations = loop.operations[1:]
@@ -82,7 +81,7 @@
start_label = None
jumpop = loop.operations[-1]
- if jumpop.getopnum() == rop.JUMP:
+ if jumpop.getopnum() == rop.JUMP or jumpop.getopnum() == rop.LABEL:
loop.operations = loop.operations[:-1]
else:
jumpop = None
@@ -91,48 +90,87 @@
self.optimizer.propagate_all_forward(clear=False)
if not jumpop:
- return
- if self.jump_to_already_compiled_trace(jumpop):
- # Found a compiled trace to jump to
- if self.did_import:
-
- self.close_bridge(start_label)
- self.finilize_short_preamble(start_label)
return
cell_token = jumpop.getdescr()
assert isinstance(cell_token, JitCellToken)
stop_label = ResOperation(rop.LABEL, jumpop.getarglist(), None, TargetToken(cell_token))
- if not self.did_import: # Enforce the previous behaviour of always peeling exactly one iteration (for now)
- self.optimizer.flush()
- KillHugeIntBounds(self.optimizer).apply()
+
+ if jumpop.getopnum() == rop.JUMP:
+ if self.jump_to_already_compiled_trace(jumpop):
+ # Found a compiled trace to jump to
+ if self.short:
+ # Construct our short preamble
+ assert start_label
+ self.close_bridge(start_label)
+ return
- loop.operations = self.optimizer.get_newoperations()
- self.export_state(stop_label)
- loop.operations.append(stop_label)
- else:
- assert stop_label
+ if start_label and self.jump_to_start_label(start_label, stop_label):
+ # Initial label matches, jump to it
+ jumpop = ResOperation(rop.JUMP, stop_label.getarglist(), None,
+ descr=start_label.getdescr())
+ if self.short:
+ # Construct our short preamble
+ self.close_loop(start_label, jumpop)
+ else:
+ self.optimizer.send_extra_operation(jumpop)
+ return
+
+ if cell_token.target_tokens:
+ limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit
+ if cell_token.retraced_count < limit:
+ cell_token.retraced_count += 1
+ debug_print('Retracing (%d/%d)' % (cell_token.retraced_count, limit))
+ else:
+ debug_print("Retrace count reached, jumping to preamble")
+ assert cell_token.target_tokens[0].virtual_state is None
+ jumpop.setdescr(cell_token.target_tokens[0])
+ self.optimizer.send_extra_operation(jumpop)
+ return
+
+ # Found nothing to jump to, emit a label instead
+
+ if self.short:
+ # Construct our short preamble
assert start_label
- stop_target = stop_label.getdescr()
- start_target = start_label.getdescr()
- assert isinstance(stop_target, TargetToken)
- assert isinstance(start_target, TargetToken)
- assert stop_target.targeting_jitcell_token is start_target.targeting_jitcell_token
- jumpop = ResOperation(rop.JUMP, stop_label.getarglist(), None, descr=start_label.getdescr())
+ self.close_bridge(start_label)
- self.close_loop(jumpop)
- self.finilize_short_preamble(start_label)
+ self.optimizer.flush()
+ KillHugeIntBounds(self.optimizer).apply()
+
+ loop.operations = self.optimizer.get_newoperations()
+ self.export_state(stop_label)
+ loop.operations.append(stop_label)
+
+ def jump_to_start_label(self, start_label, stop_label):
+ if not start_label or not stop_label:
+ return False
+
+ stop_target = stop_label.getdescr()
+ start_target = start_label.getdescr()
+ assert isinstance(stop_target, TargetToken)
+ assert isinstance(start_target, TargetToken)
+ if stop_target.targeting_jitcell_token is not start_target.targeting_jitcell_token:
+ return False
+
+ return True
+
+ #args = stop_label.getarglist()
+ #modifier = VirtualStateAdder(self.optimizer)
+ #virtual_state = modifier.get_virtual_state(args)
+ #if self.initial_virtual_state.generalization_of(virtual_state):
+ # return True
+
def export_state(self, targetop):
original_jump_args = targetop.getarglist()
jump_args = [self.getvalue(a).get_key_box() for a in original_jump_args]
- assert self.optimizer.loop.start_resumedescr
- start_resumedescr = self.optimizer.loop.start_resumedescr.clone_if_mutable()
- assert isinstance(start_resumedescr, ResumeGuardDescr)
- start_resumedescr.rd_snapshot = self.fix_snapshot(jump_args, start_resumedescr.rd_snapshot)
- # FIXME: I dont thnik we need fix_snapshot anymore
+ assert self.optimizer.loop.resume_at_jump_descr
+ resume_at_jump_descr = self.optimizer.loop.resume_at_jump_descr.clone_if_mutable()
+ assert isinstance(resume_at_jump_descr, ResumeGuardDescr)
+ resume_at_jump_descr.rd_snapshot = self.fix_snapshot(jump_args, resume_at_jump_descr.rd_snapshot)
modifier = VirtualStateAdder(self.optimizer)
virtual_state = modifier.get_virtual_state(jump_args)
@@ -141,26 +179,21 @@
inputargs = virtual_state.make_inputargs(values, self.optimizer)
short_inputargs = virtual_state.make_inputargs(values, self.optimizer, keyboxes=True)
- constant_inputargs = {}
- for box in jump_args:
- const = self.get_constant_box(box)
- if const:
- constant_inputargs[box] = const
- short_boxes = ShortBoxes(self.optimizer, inputargs + constant_inputargs.keys())
- aliased_vrituals = {}
- for i in range(len(original_jump_args)):
- if original_jump_args[i] is not jump_args[i]:
- if values[i].is_virtual():
- aliased_vrituals[original_jump_args[i]] = jump_args[i]
- else:
- short_boxes.alias(original_jump_args[i], jump_args[i])
+ if self.boxes_created_this_iteration is not None:
+ for box in self.inputargs:
+ self.boxes_created_this_iteration[box] = True
+
+ short_boxes = ShortBoxes(self.optimizer, inputargs,
+ self.boxes_created_this_iteration)
self.optimizer.clear_newoperations()
- for box in short_inputargs:
- value = self.getvalue(box)
- if value.is_virtual():
- value.force_box(self.optimizer)
+ for i in range(len(original_jump_args)):
+ if values[i].is_virtual():
+ values[i].force_box(self.optimizer)
+ if original_jump_args[i] is not jump_args[i]:
+ op = ResOperation(rop.SAME_AS, [jump_args[i]], original_jump_args[i])
+ self.optimizer.emit_operation(op)
inputarg_setup_ops = self.optimizer.get_newoperations()
target_token = targetop.getdescr()
@@ -168,78 +201,76 @@
targetop.initarglist(inputargs)
target_token.virtual_state = virtual_state
target_token.short_preamble = [ResOperation(rop.LABEL, short_inputargs, None)]
- target_token.start_resumedescr = start_resumedescr
- target_token.exported_state = ExportedState(constant_inputargs, short_boxes,
- inputarg_setup_ops, self.optimizer,
- aliased_vrituals, jump_args)
+ target_token.resume_at_jump_descr = resume_at_jump_descr
+
+ exported_values = {}
+ for box in inputargs:
+ exported_values[box] = self.optimizer.getvalue(box)
+ for op in short_boxes.operations():
+ if op and op.result:
+ box = op.result
+ exported_values[box] = self.optimizer.getvalue(box)
+
+ target_token.exported_state = ExportedState(short_boxes, inputarg_setup_ops,
+ exported_values)
def import_state(self, targetop):
- self.did_import = False
- if not targetop:
- # FIXME: Set up some sort of empty state with no virtuals?
+ if not targetop: # Trace did not start with a label
+ self.inputargs = self.optimizer.loop.inputargs
+ self.short = None
+ self.initial_virtual_state = None
return
+
+ self.inputargs = targetop.getarglist()
target_token = targetop.getdescr()
- if not target_token:
- return
assert isinstance(target_token, TargetToken)
exported_state = target_token.exported_state
if not exported_state:
- # FIXME: Set up some sort of empty state with no virtuals
+ # No state exported, construct one without virtuals
+ self.short = None
+ modifier = VirtualStateAdder(self.optimizer)
+ virtual_state = modifier.get_virtual_state(self.inputargs)
+ self.initial_virtual_state = virtual_state
return
- self.did_import = True
self.short = target_token.short_preamble[:]
self.short_seen = {}
- self.short_boxes = exported_state.short_boxes.clone()
- for box, const in exported_state.constant_inputargs.items():
- self.short_seen[box] = True
- self.imported_state = exported_state
- self.inputargs = targetop.getarglist()
+ self.short_boxes = exported_state.short_boxes
+ self.short_resume_at_jump_descr = target_token.resume_at_jump_descr
self.initial_virtual_state = target_token.virtual_state
- self.start_resumedescr = target_token.start_resumedescr
seen = {}
for box in self.inputargs:
if box in seen:
continue
seen[box] = True
- preamble_value = exported_state.optimizer.getvalue(box)
+ preamble_value = exported_state.exported_values[box]
value = self.optimizer.getvalue(box)
value.import_from(preamble_value, self.optimizer)
- for newbox, oldbox in self.short_boxes.aliases.items():
- self.optimizer.make_equal_to(newbox, self.optimizer.getvalue(oldbox))
-
# Setup the state of the new optimizer by emiting the
# short operations and discarding the result
self.optimizer.emitting_dissabled = True
for op in exported_state.inputarg_setup_ops:
self.optimizer.send_extra_operation(op)
+
seen = {}
-
for op in self.short_boxes.operations():
self.ensure_short_op_emitted(op, self.optimizer, seen)
if op and op.result:
- preamble_value = exported_state.optimizer.getvalue(op.result)
+ preamble_value = exported_state.exported_values[op.result]
value = self.optimizer.getvalue(op.result)
if not value.is_virtual():
imp = ValueImporter(self, preamble_value, op)
self.optimizer.importable_values[value] = imp
newvalue = self.optimizer.getvalue(op.result)
newresult = newvalue.get_key_box()
- if newresult is not op.result and not newvalue.is_constant():
- self.short_boxes.alias(newresult, op.result)
- op = ResOperation(rop.SAME_AS, [op.result], newresult)
- self.optimizer._newoperations = [op] + self.optimizer._newoperations # XXX
- #self.optimizer.getvalue(op.result).box = op.result # FIXME: HACK!!!
+ assert newresult is op.result or newvalue.is_constant()
self.optimizer.flush()
self.optimizer.emitting_dissabled = False
- for box, key_box in exported_state.aliased_vrituals.items():
- self.optimizer.make_equal_to(box, self.getvalue(key_box))
-
def close_bridge(self, start_label):
- inputargs = self.inputargs
+ inputargs = self.inputargs
short_jumpargs = inputargs[:]
# We dont need to inline the short preamble we are creating as we are conneting
@@ -249,8 +280,6 @@
newoperations = self.optimizer.get_newoperations()
self.boxes_created_this_iteration = {}
i = 0
- while newoperations[i].getopnum() != rop.LABEL:
- i += 1
while i < len(newoperations):
op = newoperations[i]
self.boxes_created_this_iteration[op.result] = True
@@ -262,11 +291,11 @@
i += 1
newoperations = self.optimizer.get_newoperations()
self.short.append(ResOperation(rop.JUMP, short_jumpargs, None, descr=start_label.getdescr()))
-
- def close_loop(self, jumpop):
+ self.finilize_short_preamble(start_label)
+
+ def close_loop(self, start_label, jumpop):
virtual_state = self.initial_virtual_state
short_inputargs = self.short[0].getarglist()
- constant_inputargs = self.imported_state.constant_inputargs
inputargs = self.inputargs
short_jumpargs = inputargs[:]
@@ -289,8 +318,6 @@
raise InvalidLoop
args[short_inputargs[i]] = jmp_to_short_args[i]
self.short_inliner = Inliner(short_inputargs, jmp_to_short_args)
- for box, const in constant_inputargs.items():
- self.short_inliner.argmap[box] = const
for op in self.short[1:]:
newop = self.short_inliner.inline_op(op)
self.optimizer.send_extra_operation(newop)
@@ -299,8 +326,6 @@
newoperations = self.optimizer.get_newoperations()
self.boxes_created_this_iteration = {}
i = j = 0
- while newoperations[i].getopnum() != rop.LABEL:
- i += 1
while i < len(newoperations) or j < len(jumpargs):
if i == len(newoperations):
while j < len(jumpargs):
@@ -353,6 +378,8 @@
assert isinstance(target_token, TargetToken)
target_token.targeting_jitcell_token.retraced_count = sys.maxint
+ self.finilize_short_preamble(start_label)
+
def finilize_short_preamble(self, start_label):
short = self.short
assert short[-1].getopnum() == rop.JUMP
@@ -365,7 +392,7 @@
if op.is_guard():
op = op.clone()
op.setfailargs(None)
- descr = target_token.start_resumedescr.clone_if_mutable()
+ descr = target_token.resume_at_jump_descr.clone_if_mutable()
op.setdescr(descr)
short[i] = op
@@ -381,13 +408,11 @@
newargs[i] = a.clonebox()
boxmap[a] = newargs[i]
inliner = Inliner(short_inputargs, newargs)
- for box, const in self.imported_state.constant_inputargs.items():
- inliner.argmap[box] = const
for i in range(len(short)):
short[i] = inliner.inline_op(short[i])
- target_token.start_resumedescr = self.start_resumedescr.clone_if_mutable()
- inliner.inline_descr_inplace(target_token.start_resumedescr)
+ target_token.resume_at_jump_descr = target_token.resume_at_jump_descr.clone_if_mutable()
+ inliner.inline_descr_inplace(target_token.resume_at_jump_descr)
# Forget the values to allow them to be freed
for box in short[0].getarglist():
@@ -398,31 +423,6 @@
target_token.short_preamble = self.short
target_token.exported_state = None
-
- def FIXME_old_stuff():
- preamble_optimizer = self.optimizer
- loop.preamble.quasi_immutable_deps = (
- self.optimizer.quasi_immutable_deps)
- self.optimizer = self.optimizer.new()
- loop.quasi_immutable_deps = self.optimizer.quasi_immutable_deps
-
-
- loop.inputargs = inputargs
- args = [preamble_optimizer.getvalue(self.short_boxes.original(a)).force_box(preamble_optimizer)\
- for a in inputargs]
- jmp = ResOperation(rop.JUMP, args, None)
- jmp.setdescr(loop.token)
- loop.preamble.operations.append(jmp)
-
- loop.operations = self.optimizer.get_newoperations()
- maxguards = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.max_retrace_guards
-
- if self.optimizer.emitted_guards > maxguards:
- loop.preamble.token.retraced_count = sys.maxint
-
- if short:
- pass
-
def ensure_short_op_emitted(self, op, optimizer, seen):
if op is None:
return
@@ -450,7 +450,7 @@
if not isinstance(a, Const) and a not in self.short_seen:
self.add_op_to_short(self.short_boxes.producer(a), emit, guards_needed)
if op.is_guard():
- descr = self.start_resumedescr.clone_if_mutable()
+ descr = self.short_resume_at_jump_descr.clone_if_mutable()
op.setdescr(descr)
if guards_needed and self.short_boxes.has_producer(op.result):
@@ -549,7 +549,7 @@
for guard in extra_guards:
if guard.is_guard():
- descr = target.start_resumedescr.clone_if_mutable()
+ descr = target.resume_at_jump_descr.clone_if_mutable()
inliner.inline_descr_inplace(descr)
guard.setdescr(descr)
self.optimizer.send_extra_operation(guard)
@@ -566,20 +566,7 @@
self.optimizer.send_extra_operation(jumpop)
return True
debug_stop('jit-log-virtualstate')
-
- if self.did_import:
- return False
- limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit
- if cell_token.retraced_count<limit:
- cell_token.retraced_count += 1
- debug_print('Retracing (%d/%d)' % (cell_token.retraced_count, limit))
- return False
- else:
- debug_print("Retrace count reached, jumping to preamble")
- assert cell_token.target_tokens[0].virtual_state is None
- jumpop.setdescr(cell_token.target_tokens[0])
- self.optimizer.send_extra_operation(jumpop)
- return True
+ return False
class ValueImporter(object):
def __init__(self, unroll, value, op):
@@ -592,12 +579,7 @@
self.unroll.add_op_to_short(self.op, False, True)
class ExportedState(object):
- def __init__(self, constant_inputargs,
- short_boxes, inputarg_setup_ops, optimizer, aliased_vrituals,
- jump_args):
- self.constant_inputargs = constant_inputargs
+ def __init__(self, short_boxes, inputarg_setup_ops, exported_values):
self.short_boxes = short_boxes
self.inputarg_setup_ops = inputarg_setup_ops
- self.optimizer = optimizer
- self.aliased_vrituals = aliased_vrituals
- self.jump_args = jump_args
+ self.exported_values = exported_values
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -559,13 +559,13 @@
pass
class ShortBoxes(object):
- def __init__(self, optimizer, surviving_boxes):
+ def __init__(self, optimizer, surviving_boxes, availible_boxes=None):
self.potential_ops = {}
self.alternatives = {}
self.synthetic = {}
- self.aliases = {}
self.rename = {}
self.optimizer = optimizer
+ self.availible_boxes = availible_boxes
if surviving_boxes is not None:
for box in surviving_boxes:
@@ -581,12 +581,9 @@
except BoxNotProducable:
pass
- def clone(self):
- sb = ShortBoxes(self.optimizer, None)
- sb.aliases.update(self.aliases)
- sb.short_boxes = {}
- sb.short_boxes.update(self.short_boxes)
- return sb
+ self.short_boxes_in_production = None # Not needed anymore
+ else:
+ self.short_boxes = {}
def prioritized_alternatives(self, box):
if box not in self.alternatives:
@@ -639,6 +636,8 @@
return
if box in self.short_boxes_in_production:
raise BoxNotProducable
+ if self.availible_boxes is not None and box not in self.availible_boxes:
+ raise BoxNotProducable
self.short_boxes_in_production[box] = True
if box in self.potential_ops:
@@ -690,13 +689,3 @@
def has_producer(self, box):
return box in self.short_boxes
-
- def alias(self, newbox, oldbox):
- if not isinstance(oldbox, Const) and newbox not in self.short_boxes:
- self.short_boxes[newbox] = self.short_boxes[oldbox]
- self.aliases[newbox] = oldbox
-
- def original(self, box):
- while box in self.aliases:
- box = self.aliases[box]
- return box
diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py
--- a/pypy/jit/metainterp/optimizeopt/vstring.py
+++ b/pypy/jit/metainterp/optimizeopt/vstring.py
@@ -46,7 +46,7 @@
class __extend__(optimizer.OptValue):
"""New methods added to the base class OptValue for this file."""
- def getstrlen(self, string_optimizer, mode):
+ def getstrlen(self, string_optimizer, mode, lengthbox):
if mode is mode_string:
s = self.get_constant_string_spec(mode_string)
if s is not None:
@@ -59,7 +59,8 @@
return None
self.ensure_nonnull()
box = self.force_box(string_optimizer)
- lengthbox = BoxInt()
+ if lengthbox is None:
+ lengthbox = BoxInt()
string_optimizer.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox))
return lengthbox
@@ -75,7 +76,7 @@
# Copies the pointer-to-string 'self' into the target string
# given by 'targetbox', at the specified offset. Returns the offset
# at the end of the copy.
- lengthbox = self.getstrlen(string_optimizer, mode)
+ lengthbox = self.getstrlen(string_optimizer, mode, None)
srcbox = self.force_box(string_optimizer)
return copy_str_content(string_optimizer, srcbox, targetbox,
CONST_0, offsetbox, lengthbox, mode)
@@ -104,7 +105,7 @@
return
assert self.source_op is not None
self.box = box = self.source_op.result
- lengthbox = self.getstrlen(optforce, self.mode)
+ lengthbox = self.getstrlen(optforce, self.mode, None)
op = ResOperation(self.mode.NEWSTR, [lengthbox], box)
if not we_are_translated():
op.name = 'FORCE'
@@ -137,7 +138,7 @@
self._chars = longerlist[start:stop]
# slice the 'longerlist', which may also contain Nones
- def getstrlen(self, _, mode):
+ def getstrlen(self, _, mode, lengthbox):
if self._lengthbox is None:
self._lengthbox = ConstInt(len(self._chars))
return self._lengthbox
@@ -218,12 +219,12 @@
self.left = left
self.right = right
- def getstrlen(self, string_optimizer, mode):
+ def getstrlen(self, string_optimizer, mode, lengthbox):
if self.lengthbox is None:
- len1box = self.left.getstrlen(string_optimizer, mode)
+ len1box = self.left.getstrlen(string_optimizer, mode, None)
if len1box is None:
return None
- len2box = self.right.getstrlen(string_optimizer, mode)
+ len2box = self.right.getstrlen(string_optimizer, mode, None)
if len2box is None:
return None
self.lengthbox = _int_add(string_optimizer, len1box, len2box)
@@ -270,7 +271,7 @@
self.vstart = vstart
self.vlength = vlength
- def getstrlen(self, optforce, mode):
+ def getstrlen(self, optforce, mode, lengthbox):
return self.vlength.force_box(optforce)
@specialize.arg(1)
@@ -287,7 +288,7 @@
return None
def string_copy_parts(self, string_optimizer, targetbox, offsetbox, mode):
- lengthbox = self.getstrlen(string_optimizer, mode)
+ lengthbox = self.getstrlen(string_optimizer, mode, None)
return copy_str_content(string_optimizer,
self.vstr.force_box(string_optimizer), targetbox,
self.vstart.force_box(string_optimizer), offsetbox,
@@ -362,7 +363,7 @@
string_optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox))
return resbox
-def _strgetitem(string_optimizer, strbox, indexbox, mode):
+def _strgetitem(string_optimizer, strbox, indexbox, mode, resbox=None):
if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt):
if mode is mode_string:
s = strbox.getref(lltype.Ptr(rstr.STR))
@@ -370,7 +371,8 @@
else:
s = strbox.getref(lltype.Ptr(rstr.UNICODE))
return ConstInt(ord(s.chars[indexbox.getint()]))
- resbox = BoxInt()
+ if resbox is None:
+ resbox = BoxInt()
string_optimizer.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox],
resbox))
return resbox
@@ -436,10 +438,13 @@
def _optimize_STRGETITEM(self, op, mode):
value = self.getvalue(op.getarg(0))
vindex = self.getvalue(op.getarg(1))
- vresult = self.strgetitem(value, vindex, mode)
- self.make_equal_to(op.result, vresult)
+ vresult = self.strgetitem(value, vindex, mode, op.result)
+ if op.result in self.optimizer.values:
+ assert self.getvalue(op.result) is vresult
+ else:
+ self.make_equal_to(op.result, vresult)
- def strgetitem(self, value, vindex, mode):
+ def strgetitem(self, value, vindex, mode, resbox=None):
value.ensure_nonnull()
#
if value.is_virtual() and isinstance(value, VStringSliceValue):
@@ -456,7 +461,7 @@
return result
#
if isinstance(value, VStringConcatValue) and vindex.is_constant():
- len1box = value.left.getstrlen(self, mode)
+ len1box = value.left.getstrlen(self, mode, None)
if isinstance(len1box, ConstInt):
index = vindex.box.getint()
len1 = len1box.getint()
@@ -466,7 +471,7 @@
vindex = optimizer.ConstantValue(ConstInt(index - len1))
return self.strgetitem(value.right, vindex, mode)
#
- resbox = _strgetitem(self, value.force_box(self), vindex.force_box(self), mode)
+ resbox = _strgetitem(self, value.force_box(self), vindex.force_box(self), mode, resbox)
return self.getvalue(resbox)
def optimize_STRLEN(self, op):
@@ -476,8 +481,11 @@
def _optimize_STRLEN(self, op, mode):
value = self.getvalue(op.getarg(0))
- lengthbox = value.getstrlen(self, mode)
- self.make_equal_to(op.result, self.getvalue(lengthbox))
+ lengthbox = value.getstrlen(self, mode, op.result)
+ if op.result in self.optimizer.values:
+ assert self.getvalue(op.result) is self.getvalue(lengthbox)
+ elif op.result is not lengthbox:
+ self.make_equal_to(op.result, self.getvalue(lengthbox))
def optimize_COPYSTRCONTENT(self, op):
self._optimize_COPYSTRCONTENT(op, mode_string)
@@ -596,8 +604,8 @@
v1 = self.getvalue(op.getarg(1))
v2 = self.getvalue(op.getarg(2))
#
- l1box = v1.getstrlen(None, mode)
- l2box = v2.getstrlen(None, mode)
+ l1box = v1.getstrlen(None, mode, None)
+ l2box = v2.getstrlen(None, mode, None)
if (l1box is not None and l2box is not None and
isinstance(l1box, ConstInt) and
isinstance(l2box, ConstInt) and
@@ -626,15 +634,15 @@
return False
def handle_str_equal_level1(self, v1, v2, resultbox, mode):
- l2box = v2.getstrlen(None, mode)
+ l2box = v2.getstrlen(None, mode, None)
if isinstance(l2box, ConstInt):
if l2box.value == 0:
- lengthbox = v1.getstrlen(self, mode)
+ lengthbox = v1.getstrlen(self, mode, None)
seo = self.optimizer.send_extra_operation
seo(ResOperation(rop.INT_EQ, [lengthbox, CONST_0], resultbox))
return True
if l2box.value == 1:
- l1box = v1.getstrlen(None, mode)
+ l1box = v1.getstrlen(None, mode, None)
if isinstance(l1box, ConstInt) and l1box.value == 1:
# comparing two single chars
vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO, mode)
@@ -670,7 +678,7 @@
return False
def handle_str_equal_level2(self, v1, v2, resultbox, mode):
- l2box = v2.getstrlen(None, mode)
+ l2box = v2.getstrlen(None, mode, None)
if isinstance(l2box, ConstInt):
if l2box.value == 1:
vchar = self.strgetitem(v2, optimizer.CVAL_ZERO, mode)
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
@@ -1548,11 +1548,6 @@
# ____________________________________________________________
-class RetraceState(object):
- def __init__(self, metainterp, live_arg_boxes):
- self.merge_point = len(metainterp.current_merge_points) - 1
- self.live_arg_boxes = live_arg_boxes
-
class MetaInterp(object):
in_recursion = 0
@@ -2062,7 +2057,7 @@
cell = self.jitdriver_sd.warmstate.jit_cell_at_key(greenkey)
return cell.get_procedure_token()
- def compile_loop(self, original_boxes, live_arg_boxes, start, start_resumedescr):
+ def compile_loop(self, original_boxes, live_arg_boxes, start, resume_at_jump_descr):
num_green_args = self.jitdriver_sd.num_green_args
greenkey = original_boxes[:num_green_args]
if not self.partial_trace:
@@ -2072,13 +2067,13 @@
target_token = compile.compile_retrace(self, greenkey, start,
original_boxes[num_green_args:],
live_arg_boxes[num_green_args:],
- start_resumedescr, self.partial_trace,
+ resume_at_jump_descr, self.partial_trace,
self.resumekey)
else:
target_token = compile.compile_loop(self, greenkey, start,
original_boxes[num_green_args:],
live_arg_boxes[num_green_args:],
- start_resumedescr)
+ resume_at_jump_descr)
if target_token is not None:
assert isinstance(target_token, TargetToken)
self.jitdriver_sd.warmstate.attach_procedure_to_interp(greenkey, target_token.targeting_jitcell_token)
@@ -2090,7 +2085,7 @@
jitcell_token = target_token.targeting_jitcell_token
self.raise_continue_running_normally(live_arg_boxes, jitcell_token)
- def compile_trace(self, live_arg_boxes, start_resumedescr):
+ def compile_trace(self, live_arg_boxes, resume_at_jump_descr):
num_green_args = self.jitdriver_sd.num_green_args
greenkey = live_arg_boxes[:num_green_args]
target_jitcell_token = self.get_procedure_token(greenkey)
@@ -2102,7 +2097,7 @@
self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None,
descr=target_jitcell_token)
try:
- target_token = compile.compile_trace(self, self.resumekey, start_resumedescr)
+ target_token = compile.compile_trace(self, self.resumekey, resume_at_jump_descr)
finally:
self.history.operations.pop() # remove the JUMP
if target_token is not None: # raise if it *worked* correctly
@@ -2110,43 +2105,6 @@
jitcell_token = target_token.targeting_jitcell_token
self.raise_continue_running_normally(live_arg_boxes, jitcell_token)
- def compile_bridge_and_loop(self, original_boxes, live_arg_boxes, start,
- bridge_arg_boxes, start_resumedescr):
- num_green_args = self.jitdriver_sd.num_green_args
- original_inputargs = self.history.inputargs
- greenkey = original_boxes[:num_green_args]
- old_loop_tokens = self.get_compiled_merge_points(greenkey)
- original_operations = self.history.operations
- self.history.inputargs = original_boxes[num_green_args:]
- greenkey = original_boxes[:num_green_args]
- self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None)
- loop_token = compile.compile_new_loop(self, [], greenkey, start,
- start_resumedescr, False)
- self.history.operations.pop() # remove the JUMP
- if loop_token is None:
- self.history.inputargs = original_inputargs
- self.history.operations = original_operations
- return
-
- if loop_token.short_preamble:
- old_loop_tokens[0].short_preamble.extend(loop_token.short_preamble)
-
- self.history.inputargs = original_inputargs
- self.history.operations = self.history.operations[:start]
-
- self.history.record(rop.JUMP, bridge_arg_boxes[num_green_args:], None)
- try:
- target_loop_token = compile.compile_new_bridge(self,
- #[loop_token],
- old_loop_tokens,
- self.resumekey,
- True)
- except RetraceLoop:
- assert False
- assert target_loop_token is not None
- self.raise_continue_running_normally(live_arg_boxes,
- old_loop_tokens[0])
-
def compile_done_with_this_frame(self, exitbox):
self.gen_store_back_in_virtualizable()
# temporarily put a JUMP to a pseudo-loop
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -2910,27 +2910,6 @@
res = self.meta_interp(f, [32])
assert res == f(32)
- def test_decay_counters(self):
- myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
- def f(m, n):
- while n > 0:
- myjitdriver.jit_merge_point(m=m, n=n)
- n += m
- n -= m
- n -= 1
- def main():
- f(5, 7) # run 7x with m=5 counter[m=5] = 7
- f(15, 10) # compiles one loop counter[m=5] = 3 (automatic decay)
- f(5, 5) # run 5x times with m=5 counter[m=5] = 8
- #
- self.meta_interp(main, [], decay_halflife=1,
- function_threshold=0, threshold=9, trace_eagerness=99)
- self.check_trace_count(1)
- #
- self.meta_interp(main, [], decay_halflife=1,
- function_threshold=0, threshold=8, trace_eagerness=99)
- self.check_trace_count(2)
-
class TestOOtype(BasicTests, OOJitMixin):
diff --git a/pypy/jit/metainterp/test/test_virtualstate.py b/pypy/jit/metainterp/test/test_virtualstate.py
--- a/pypy/jit/metainterp/test/test_virtualstate.py
+++ b/pypy/jit/metainterp/test/test_virtualstate.py
@@ -11,7 +11,6 @@
from pypy.jit.metainterp.optimizeopt.intutils import IntBound
from pypy.jit.metainterp.history import TreeLoop, JitCellToken
from pypy.jit.metainterp.optimizeopt.test.test_optimizeopt import FakeMetaInterpStaticData
-from pypy.jit.metainterp.optimize import RetraceLoop
from pypy.jit.metainterp.resoperation import ResOperation, rop
class TestBasic:
@@ -449,7 +448,7 @@
if hasattr(self, 'callinfocollection'):
metainterp_sd.callinfocollection = self.callinfocollection
#
- bridge.start_resumedescr = FakeDescrWithSnapshot()
+ bridge.resume_at_jump_descr = FakeDescrWithSnapshot()
optimize_trace(metainterp_sd, bridge, self.enable_opts)
diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py
--- a/pypy/jit/metainterp/test/test_warmstate.py
+++ b/pypy/jit/metainterp/test/test_warmstate.py
@@ -1,4 +1,3 @@
-import math
from pypy.rpython.test.test_llinterp import interpret
from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi
from pypy.rpython.ootypesystem import ootype
@@ -9,7 +8,7 @@
from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr
from pypy.jit.metainterp.history import ConstInt, ConstFloat, ConstPtr
from pypy.jit.codewriter import longlong
-from pypy.rlib.rarithmetic import r_singlefloat, r_uint
+from pypy.rlib.rarithmetic import r_singlefloat
def boxfloat(x):
return BoxFloat(longlong.getfloatstorage(x))
@@ -277,76 +276,51 @@
res = state.can_never_inline(5, 42.5)
assert res is True
-def test_decay_counters():
- cell = JitCell(r_uint(5))
- cell.counter = 100
- cell.adjust_counter(r_uint(5), math.log(0.9))
- assert cell.counter == 100
- cell.adjust_counter(r_uint(6), math.log(0.9))
- assert cell.counter == 90
- cell.adjust_counter(r_uint(9), math.log(0.9))
- assert cell.counter == int(90 * (0.9**3))
-
def test_cleanup_jitcell_dict():
- from pypy.jit.metainterp.memmgr import MemoryManager
- class FakeWarmRunnerDesc:
- memory_manager = MemoryManager()
- class cpu:
- pass
class FakeJitDriverSD:
_green_args_spec = [lltype.Signed]
#
# Test creating tons of jitcells that remain at 0
- warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
+ warmstate = WarmEnterState(None, FakeJitDriverSD())
get_jitcell = warmstate._make_jitcell_getter_default()
cell1 = get_jitcell(True, -1)
assert len(warmstate._jitcell_dict) == 1
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 1
#
for i in range(1, 20005):
get_jitcell(True, i) # should trigger a clean-up at 20001
assert len(warmstate._jitcell_dict) == (i % 20000) + 1
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 2
#
# Same test, with one jitcell that has a counter of BASE instead of 0
- warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
- warmstate.set_param_decay_halflife(2)
- warmstate.set_param_threshold(5)
- warmstate.set_param_function_threshold(0)
+ warmstate = WarmEnterState(None, FakeJitDriverSD())
get_jitcell = warmstate._make_jitcell_getter_default()
cell2 = get_jitcell(True, -2)
- cell2.counter = BASE = warmstate.increment_threshold * 3
+ cell2.counter = BASE = warmstate.THRESHOLD_LIMIT // 2 # 50%
#
for i in range(0, 20005):
get_jitcell(True, i)
assert len(warmstate._jitcell_dict) == (i % 19999) + 2
#
assert cell2 in warmstate._jitcell_dict.values()
- assert cell2.counter == int(BASE * math.sqrt(0.5)) # decayed once
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 3
+ assert cell2.counter == int(BASE * 0.92) # decayed once
#
- # Same test, with jitcells that are compiled and free by the memmgr
- warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
+ # Same test, with jitcells that are compiled and freed by the memmgr
+ warmstate = WarmEnterState(None, FakeJitDriverSD())
get_jitcell = warmstate._make_jitcell_getter_default()
get_jitcell(True, -1)
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 3
#
for i in range(1, 20005):
cell = get_jitcell(True, i)
cell.counter = -1
cell.wref_procedure_token = None # or a dead weakref, equivalently
assert len(warmstate._jitcell_dict) == (i % 20000) + 1
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 4
#
# Same test, with counter == -2 (rare case, kept alive)
- warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
+ warmstate = WarmEnterState(None, FakeJitDriverSD())
get_jitcell = warmstate._make_jitcell_getter_default()
cell = get_jitcell(True, -1)
cell.counter = -2
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 4
#
for i in range(1, 20005):
cell = get_jitcell(True, i)
cell.counter = -2
assert len(warmstate._jitcell_dict) == i + 1
- assert FakeWarmRunnerDesc.memory_manager.current_generation == 5
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -64,11 +64,9 @@
def jittify_and_run(interp, graph, args, repeat=1, graph_and_interp_only=False,
backendopt=False, trace_limit=sys.maxint,
- threshold=3, trace_eagerness=2,
inline=False, loop_longevity=0, retrace_limit=5,
- function_threshold=4, decay_halflife=0,
- enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15,
- **kwds):
+ function_threshold=4,
+ enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15, **kwds):
from pypy.config.config import ConfigError
translator = interp.typer.annotator.translator
try:
@@ -85,16 +83,15 @@
pass
warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds)
for jd in warmrunnerdesc.jitdrivers_sd:
- jd.warmstate.set_param_threshold(threshold)
+ jd.warmstate.set_param_threshold(3) # for tests
jd.warmstate.set_param_function_threshold(function_threshold)
- jd.warmstate.set_param_trace_eagerness(trace_eagerness)
+ jd.warmstate.set_param_trace_eagerness(2) # for tests
jd.warmstate.set_param_trace_limit(trace_limit)
jd.warmstate.set_param_inlining(inline)
jd.warmstate.set_param_loop_longevity(loop_longevity)
jd.warmstate.set_param_retrace_limit(retrace_limit)
jd.warmstate.set_param_max_retrace_guards(max_retrace_guards)
jd.warmstate.set_param_enable_opts(enable_opts)
- jd.warmstate.set_param_decay_halflife(decay_halflife)
warmrunnerdesc.finish()
if graph_and_interp_only:
return interp, graph
diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py
--- a/pypy/jit/metainterp/warmstate.py
+++ b/pypy/jit/metainterp/warmstate.py
@@ -1,10 +1,10 @@
-import sys, weakref, math
+import sys, weakref
from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi
from pypy.rpython.ootypesystem import ootype
from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance
from pypy.rpython.annlowlevel import cast_object_to_ptr
from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict
-from pypy.rlib.rarithmetic import intmask, r_uint
+from pypy.rlib.rarithmetic import intmask
from pypy.rlib.nonconst import NonConstant
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.jit import PARAMETERS
@@ -151,27 +151,9 @@
# counter == -2: tracing is currently going on for this cell
counter = 0
dont_trace_here = False
+ extra_delay = chr(0)
wref_procedure_token = None
- def __init__(self, generation):
- # The stored 'counter' value follows an exponential decay model.
- # Conceptually after every generation, it decays by getting
- # multiplied by a constant <= 1.0. In practice, decaying occurs
- # lazily: the following field records the latest seen generation
- # number, and adjustment is done by adjust_counter() when needed.
- self.latest_generation_seen = generation
-
- def adjust_counter(self, generation, log_decay_factor):
- if generation != self.latest_generation_seen:
- # The latest_generation_seen is older than the current generation.
- # Adjust by multiplying self.counter N times by decay_factor, i.e.
- # by decay_factor ** N, which is equal to exp(log(decay_factor)*N).
- assert self.counter >= 0
- N = generation - self.latest_generation_seen
- factor = math.exp(log_decay_factor * N)
- self.counter = int(self.counter * factor)
- self.latest_generation_seen = generation
-
def get_procedure_token(self):
if self.wref_procedure_token is not None:
token = self.wref_procedure_token()
@@ -231,17 +213,6 @@
def set_param_inlining(self, value):
self.inlining = value
- def set_param_decay_halflife(self, value):
- # Use 0 or -1 to mean "no decay". Initialize the internal variable
- # 'log_decay_factor'. It is choosen such that by multiplying the
- # counter on loops by 'exp(log_decay_factor)' (<= 1.0) every
- # generation, then the counter will be divided by two after 'value'
- # generations have passed.
- if value <= 0:
- self.log_decay_factor = 0.0 # log(1.0)
- else:
- self.log_decay_factor = math.log(0.5) / value
-
def set_param_enable_opts(self, value):
from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT, ALL_OPTS_NAMES
@@ -311,11 +282,6 @@
confirm_enter_jit = self.confirm_enter_jit
range_red_args = unrolling_iterable(
range(num_green_args, num_green_args + jitdriver_sd.num_red_args))
- memmgr = self.warmrunnerdesc.memory_manager
- if memmgr is not None:
- get_current_generation = memmgr.get_current_generation_uint
- else:
- get_current_generation = lambda: r_uint(0)
# get a new specialized copy of the method
ARGS = []
for kind in jitdriver_sd.red_args_types:
@@ -350,6 +316,36 @@
#
assert 0, "should have raised"
+ def bound_reached(cell, *args):
+ # bound reached, but we do a last check: if it is the first
+ # time we reach the bound, or if another loop or bridge was
+ # compiled since the last time we reached it, then decrease
+ # the counter by a few percents instead. It should avoid
+ # sudden bursts of JIT-compilation, and also corner cases
+ # where we suddenly compile more than one loop because all
+ # counters reach the bound at the same time, but where
+ # compiling all but the first one is pointless.
+ curgen = warmrunnerdesc.memory_manager.current_generation
+ curgen = chr(intmask(curgen) & 0xFF) # only use 8 bits
+ if we_are_translated() and curgen != cell.extra_delay:
+ cell.counter = int(self.THRESHOLD_LIMIT * 0.98)
+ cell.extra_delay = curgen
+ return
+ #
+ if not confirm_enter_jit(*args):
+ cell.counter = 0
+ return
+ # start tracing
+ from pypy.jit.metainterp.pyjitpl import MetaInterp
+ metainterp = MetaInterp(metainterp_sd, jitdriver_sd)
+ # set counter to -2, to mean "tracing in effect"
+ cell.counter = -2
+ try:
+ metainterp.compile_and_run_once(jitdriver_sd, *args)
+ finally:
+ if cell.counter == -2:
+ cell.counter = 0
+
def maybe_compile_and_run(threshold, *args):
"""Entry point to the JIT. Called at the point with the
can_enter_jit() hint.
@@ -360,25 +356,13 @@
if cell.counter >= 0:
# update the profiling counter
- cell.adjust_counter(get_current_generation(),
- self.log_decay_factor)
n = cell.counter + threshold
if n <= self.THRESHOLD_LIMIT: # bound not reached
cell.counter = n
return
- if not confirm_enter_jit(*args):
- cell.counter = 0
+ else:
+ bound_reached(cell, *args)
return
- # bound reached; start tracing
- from pypy.jit.metainterp.pyjitpl import MetaInterp
- metainterp = MetaInterp(metainterp_sd, jitdriver_sd)
- # set counter to -2, to mean "tracing in effect"
- cell.counter = -2
- try:
- metainterp.compile_and_run_once(jitdriver_sd, *args)
- finally:
- if cell.counter == -2:
- cell.counter = 0
else:
if cell.counter != -1:
assert cell.counter == -2
@@ -454,15 +438,6 @@
#
return jit_getter
- def _new_jitcell(self):
- warmrunnerdesc = self.warmrunnerdesc
- if (warmrunnerdesc is not None and
- warmrunnerdesc.memory_manager is not None):
- gen = warmrunnerdesc.memory_manager.get_current_generation_uint()
- else:
- gen = r_uint(0)
- return JitCell(gen)
-
def _make_jitcell_getter_default(self):
"NOT_RPYTHON"
jitdriver_sd = self.jitdriver_sd
@@ -492,44 +467,32 @@
except AttributeError:
pass
#
- memmgr = self.warmrunnerdesc and self.warmrunnerdesc.memory_manager
- if memmgr:
- def _cleanup_dict():
- minimum = sys.maxint
- if self.increment_threshold > 0:
- minimum = min(minimum, self.increment_threshold)
- if self.increment_function_threshold > 0:
- minimum = min(minimum, self.increment_function_threshold)
- currentgen = memmgr.get_current_generation_uint()
- killme = []
- for key, cell in jitcell_dict.iteritems():
- if cell.counter >= 0:
- cell.adjust_counter(currentgen, self.log_decay_factor)
- if cell.counter < minimum:
- killme.append(key)
- elif (cell.counter == -1
- and cell.get_procedure_token() is None):
+ def _cleanup_dict():
+ minimum = self.THRESHOLD_LIMIT // 20 # minimum 5%
+ killme = []
+ for key, cell in jitcell_dict.iteritems():
+ if cell.counter >= 0:
+ cell.counter = int(cell.counter * 0.92)
+ if cell.counter < minimum:
killme.append(key)
- for key in killme:
- del jitcell_dict[key]
- #
- def _maybe_cleanup_dict():
- # If no tracing goes on at all because the jitcells are
- # each time for new greenargs, the dictionary grows forever.
- # So every one in a (rare) while, we decide to force an
- # artificial next_generation() and _cleanup_dict().
- self._trigger_automatic_cleanup += 1
- if self._trigger_automatic_cleanup > 20000:
- self._trigger_automatic_cleanup = 0
- memmgr.next_generation(do_cleanups_now=False)
- _cleanup_dict()
- #
- self._trigger_automatic_cleanup = 0
- self._jitcell_dict = jitcell_dict # for tests
- memmgr.record_jitcell_dict(_cleanup_dict)
- else:
- def _maybe_cleanup_dict():
- pass
+ elif (cell.counter == -1
+ and cell.get_procedure_token() is None):
+ killme.append(key)
+ for key in killme:
+ del jitcell_dict[key]
+ #
+ def _maybe_cleanup_dict():
+ # Once in a while, rarely, when too many entries have
+ # been put in the jitdict_dict, we do a cleanup phase:
+ # we decay all counters and kill entries with a too
+ # low counter.
+ self._trigger_automatic_cleanup += 1
+ if self._trigger_automatic_cleanup > 20000:
+ self._trigger_automatic_cleanup = 0
+ _cleanup_dict()
+ #
+ self._trigger_automatic_cleanup = 0
+ self._jitcell_dict = jitcell_dict # for tests
#
def get_jitcell(build, *greenargs):
try:
@@ -538,7 +501,7 @@
if not build:
return None
_maybe_cleanup_dict()
- cell = self._new_jitcell()
+ cell = JitCell()
jitcell_dict[greenargs] = cell
return cell
return get_jitcell
@@ -549,7 +512,7 @@
get_jitcell_at_ptr = self.jitdriver_sd._get_jitcell_at_ptr
set_jitcell_at_ptr = self.jitdriver_sd._set_jitcell_at_ptr
lltohlhack = {}
- # note that there is no equivalent of record_jitcell_dict()
+ # note that there is no equivalent of _maybe_cleanup_dict()
# in the case of custom getters. We assume that the interpreter
# stores the JitCells on some objects that can go away by GC,
# like the PyCode objects in PyPy.
@@ -574,7 +537,7 @@
if not build:
return cell
if cell is None:
- cell = self._new_jitcell()
+ cell = JitCell()
# <hacks>
if we_are_translated():
cellref = cast_object_to_ptr(BASEJITCELL, cell)
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -45,6 +45,8 @@
import pypy.module.cpyext.longobject
import pypy.module.cpyext.listobject
import pypy.module.cpyext.sequence
+import pypy.module.cpyext.buffer
+import pypy.module.cpyext.bufferobject
import pypy.module.cpyext.eval
import pypy.module.cpyext.import_
import pypy.module.cpyext.mapping
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -319,6 +319,10 @@
INTERPLEVEL_API = {}
FUNCTIONS = {}
+
+# These are C symbols which cpyext will export, but which are defined in .c
+# files somewhere in the implementation of cpyext (rather than being defined in
+# RPython).
SYMBOLS_C = [
'Py_FatalError', 'PyOS_snprintf', 'PyOS_vsnprintf', 'PyArg_Parse',
'PyArg_ParseTuple', 'PyArg_UnpackTuple', 'PyArg_ParseTupleAndKeywords',
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/buffer.py
@@ -0,0 +1,11 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+ cpython_api, CANNOT_FAIL, Py_buffer)
+
+ at cpython_api([lltype.Ptr(Py_buffer), lltype.Char], rffi.INT_real, error=CANNOT_FAIL)
+def PyBuffer_IsContiguous(space, view, fortran):
+ """Return 1 if the memory defined by the view is C-style (fortran is
+ 'C') or Fortran-style (fortran is 'F') contiguous or either one
+ (fortran is 'A'). Return 0 otherwise."""
+ # PyPy only supports contiguous Py_buffers for now.
+ return space.wrap(1)
diff --git a/pypy/module/cpyext/bufferobject.py b/pypy/module/cpyext/bufferobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/bufferobject.py
@@ -0,0 +1,66 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+ cpython_api, Py_ssize_t, cpython_struct, bootstrap_function,
+ PyObjectFields, PyObject)
+from pypy.module.cpyext.pyobject import make_typedescr, Py_DecRef
+from pypy.interpreter.buffer import Buffer, StringBuffer, SubBuffer
+
+
+PyBufferObjectStruct = lltype.ForwardReference()
+PyBufferObject = lltype.Ptr(PyBufferObjectStruct)
+PyBufferObjectFields = PyObjectFields + (
+ ("b_base", PyObject),
+ ("b_ptr", rffi.VOIDP),
+ ("b_size", Py_ssize_t),
+ ("b_offset", Py_ssize_t),
+ ("b_readonly", rffi.INT),
+ ("b_hash", rffi.LONG),
+ )
+
+cpython_struct("PyBufferObject", PyBufferObjectFields, PyBufferObjectStruct)
+
+ at bootstrap_function
+def init_bufferobject(space):
+ "Type description of PyBufferObject"
+ make_typedescr(space.gettypefor(Buffer).instancetypedef,
+ basestruct=PyBufferObject.TO,
+ attach=buffer_attach,
+ dealloc=buffer_dealloc,
+ realize=buffer_realize)
+
+def buffer_attach(space, py_obj, w_obj):
+ """
+ Fills a newly allocated PyBufferObject with the given (str) buffer object.
+ """
+ py_buf = rffi.cast(PyBufferObject, py_obj)
+ py_buf.c_b_offset = 0
+ rffi.setintfield(py_buf, 'c_b_readonly', 1)
+ rffi.setintfield(py_buf, 'c_b_hash', -1)
+
+ if isinstance(w_obj, SubBuffer):
+ py_buf.c_b_offset = w_obj.offset
+ w_obj = w_obj.buffer
+
+ if isinstance(w_obj, StringBuffer):
+ py_buf.c_b_base = rffi.cast(PyObject, 0) # space.wrap(w_obj.value)
+ py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, rffi.str2charp(w_obj.as_str()))
+ py_buf.c_b_size = w_obj.getlength()
+ else:
+ raise Exception("Fail fail fail fail fail")
+
+
+def buffer_realize(space, py_obj):
+ """
+ Creates the buffer in the PyPy interpreter from a cpyext representation.
+ """
+ raise Exception("realize fail fail fail")
+
+
+
+ at cpython_api([PyObject], lltype.Void, external=False)
+def buffer_dealloc(space, py_obj):
+ py_buf = rffi.cast(PyBufferObject, py_obj)
+ Py_DecRef(space, py_buf.c_b_base)
+ rffi.free_charp(rffi.cast(rffi.CCHARP, py_buf.c_b_ptr))
+ from pypy.module.cpyext.object import PyObject_dealloc
+ PyObject_dealloc(space, py_obj)
diff --git a/pypy/module/cpyext/include/bufferobject.h b/pypy/module/cpyext/include/bufferobject.h
--- a/pypy/module/cpyext/include/bufferobject.h
+++ b/pypy/module/cpyext/include/bufferobject.h
@@ -9,6 +9,17 @@
extern "C" {
#endif
+typedef struct {
+ PyObject_HEAD
+ PyObject *b_base;
+ void *b_ptr;
+ Py_ssize_t b_size;
+ Py_ssize_t b_offset;
+ int b_readonly;
+ long b_hash;
+} PyBufferObject;
+
+
PyAPI_DATA(PyTypeObject) PyBuffer_Type;
#define PyBuffer_Check(op) (((PyObject*)(op))->ob_type == &PyBuffer_Type)
diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -234,7 +234,7 @@
writebufferproc bf_getwritebuffer;
segcountproc bf_getsegcount;
charbufferproc bf_getcharbuffer;
- getbufferproc bf_getbuffer;
+ getbufferproc bf_getbuffer;
releasebufferproc bf_releasebuffer;
} PyBufferProcs;
diff --git a/pypy/module/cpyext/src/bufferobject.c b/pypy/module/cpyext/src/bufferobject.c
--- a/pypy/module/cpyext/src/bufferobject.c
+++ b/pypy/module/cpyext/src/bufferobject.c
@@ -4,17 +4,6 @@
#include "Python.h"
-typedef struct {
- PyObject_HEAD
- PyObject *b_base;
- void *b_ptr;
- Py_ssize_t b_size;
- Py_ssize_t b_offset;
- int b_readonly;
- long b_hash;
-} PyBufferObject;
-
-
enum buffer_t {
READ_BUFFER,
WRITE_BUFFER,
diff --git a/pypy/module/cpyext/src/getargs.c b/pypy/module/cpyext/src/getargs.c
--- a/pypy/module/cpyext/src/getargs.c
+++ b/pypy/module/cpyext/src/getargs.c
@@ -777,18 +777,14 @@
Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *);
if (PyString_Check(arg)) {
+ fflush(stdout);
PyBuffer_FillInfo(p, arg,
PyString_AS_STRING(arg), PyString_GET_SIZE(arg),
1, 0);
- } else {
- PyErr_SetString(
- PyExc_NotImplementedError,
- "s* not implemented for non-string values");
- return NULL;
- }
-#if 0
+ }
#ifdef Py_USING_UNICODE
else if (PyUnicode_Check(arg)) {
+#if 0
uarg = UNICODE_DEFAULT_ENCODING(arg);
if (uarg == NULL)
return converterr(CONV_UNICODE,
@@ -796,6 +792,9 @@
PyBuffer_FillInfo(p, arg,
PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg),
1, 0);
+#else
+ return converterr("string or buffer", arg, msgbuf, bufsize);
+#endif
}
#endif
else { /* any buffer-like object */
@@ -803,7 +802,6 @@
if (getbuffer(arg, p, &buf) < 0)
return converterr(buf, arg, msgbuf, bufsize);
}
-#endif
if (addcleanup(p, freelist, cleanup_buffer)) {
return converterr(
"(cleanup problem)",
@@ -1342,7 +1340,6 @@
return count;
}
-#if 0 //YYY
static int
getbuffer(PyObject *arg, Py_buffer *view, char **errmsg)
{
@@ -1373,7 +1370,6 @@
PyBuffer_FillInfo(view, NULL, buf, count, 1, 0);
return 0;
}
-#endif
/* Support for keyword arguments donated by
Geoff Philbrick <philbric at delphi.hks.com> */
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -1,5 +1,5 @@
from pypy.module.cpyext.api import (
- cpython_api, PyObject, PyObjectP, CANNOT_FAIL
+ cpython_api, PyObject, PyObjectP, CANNOT_FAIL, Py_buffer
)
from pypy.module.cpyext.complexobject import Py_complex_ptr as Py_complex
from pypy.rpython.lltypesystem import rffi, lltype
@@ -10,7 +10,6 @@
PyMethodDef = rffi.VOIDP
PyGetSetDef = rffi.VOIDP
PyMemberDef = rffi.VOIDP
-Py_buffer = rffi.VOIDP
va_list = rffi.VOIDP
PyDateTime_Date = rffi.VOIDP
PyDateTime_DateTime = rffi.VOIDP
@@ -178,13 +177,6 @@
~Py_buffer.format."""
raise NotImplementedError
- at cpython_api([Py_buffer, lltype.Char], rffi.INT_real, error=CANNOT_FAIL)
-def PyBuffer_IsContiguous(space, view, fortran):
- """Return 1 if the memory defined by the view is C-style (fortran is
- 'C') or Fortran-style (fortran is 'F') contiguous or either one
- (fortran is 'A'). Return 0 otherwise."""
- raise NotImplementedError
-
@cpython_api([rffi.INT_real, Py_ssize_t, Py_ssize_t, Py_ssize_t, lltype.Char], lltype.Void)
def PyBuffer_FillContiguousStrides(space, ndim, shape, strides, itemsize, fortran):
"""Fill the strides array with byte-strides of a contiguous (C-style if
diff --git a/pypy/module/cpyext/test/test_getargs.py b/pypy/module/cpyext/test/test_getargs.py
--- a/pypy/module/cpyext/test/test_getargs.py
+++ b/pypy/module/cpyext/test/test_getargs.py
@@ -129,6 +129,21 @@
assert 'foo\0bar\0baz' == pybuffer('foo\0bar\0baz')
+ def test_pyarg_parse_string_old_buffer(self):
+ pybuffer = self.import_parser(
+ '''
+ Py_buffer buf;
+ PyObject *result;
+ if (!PyArg_ParseTuple(args, "s*", &buf)) {
+ return NULL;
+ }
+ result = PyString_FromStringAndSize(buf.buf, buf.len);
+ PyBuffer_Release(&buf);
+ return result;
+ ''')
+ assert 'foo\0bar\0baz' == pybuffer(buffer('foo\0bar\0baz'))
+
+
def test_pyarg_parse_charbuf_and_length(self):
"""
The `t#` format specifier can be used to parse a read-only 8-bit
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -28,6 +28,7 @@
PyNumberMethods, PyMappingMethods, PySequenceMethods, PyBufferProcs)
from pypy.module.cpyext.slotdefs import (
slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
+from pypy.interpreter.buffer import Buffer
from pypy.interpreter.error import OperationError
from pypy.rlib.rstring import rsplit
from pypy.rlib.objectmodel import specialize
@@ -418,8 +419,21 @@
Py_DecRef(space, pyref)
return space.len_w(w_str)
+ at cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
+ external=False, error=-1)
+def buf_getreadbuffer(space, pyref, segment, ref):
+ from pypy.module.cpyext.bufferobject import PyBufferObject
+ if segment != 0:
+ raise OperationError(space.w_SystemError, space.wrap
+ ("accessing non-existent string segment"))
+ py_buf = rffi.cast(PyBufferObject, pyref)
+ ref[0] = py_buf.c_b_ptr
+ #Py_DecRef(space, pyref)
+ return py_buf.c_b_size
+
def setup_string_buffer_procs(space, pto):
c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
+ lltype.render_immortal(c_buf)
c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype,
str_segcount.api_func.get_wrapper(space))
c_buf.c_bf_getreadbuffer = llhelper(str_getreadbuffer.api_func.functype,
@@ -429,6 +443,15 @@
pto.c_tp_as_buffer = c_buf
pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
+def setup_buffer_buffer_procs(space, pto):
+ c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
+ lltype.render_immortal(c_buf)
+ c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype,
+ str_segcount.api_func.get_wrapper(space))
+ c_buf.c_bf_getreadbuffer = llhelper(buf_getreadbuffer.api_func.functype,
+ buf_getreadbuffer.api_func.get_wrapper(space))
+ pto.c_tp_as_buffer = c_buf
+
@cpython_api([PyObject], lltype.Void, external=False)
def type_dealloc(space, obj):
from pypy.module.cpyext.object import PyObject_dealloc
@@ -484,6 +507,8 @@
# buffer protocol
if space.is_w(w_type, space.w_str):
setup_string_buffer_procs(space, pto)
+ if space.is_w(w_type, space.gettypefor(Buffer)):
+ setup_buffer_buffer_procs(space, pto)
pto.c_tp_free = llhelper(PyObject_Del.api_func.functype,
PyObject_Del.api_func.get_wrapper(space))
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -21,7 +21,6 @@
_immutable_fields_ = ["itemtype", "num", "kind"]
def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[]):
- self.signature = signature.BaseSignature()
self.itemtype = itemtype
self.num = num
self.kind = kind
@@ -228,4 +227,4 @@
)
def get_dtype_cache(space):
- return space.fromcache(DtypeCache)
\ No newline at end of file
+ return space.fromcache(DtypeCache)
diff --git a/pypy/module/micronumpy/interp_extras.py b/pypy/module/micronumpy/interp_extras.py
--- a/pypy/module/micronumpy/interp_extras.py
+++ b/pypy/module/micronumpy/interp_extras.py
@@ -4,4 +4,4 @@
@unwrap_spec(array=BaseArray)
def debug_repr(space, array):
- return space.wrap(array.debug_repr())
+ return space.wrap(array.find_sig().debug_repr())
diff --git a/pypy/module/micronumpy/interp_iter.py b/pypy/module/micronumpy/interp_iter.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_iter.py
@@ -0,0 +1,104 @@
+
+from pypy.rlib import jit
+from pypy.rlib.objectmodel import instantiate
+from pypy.module.micronumpy.strides import calculate_broadcast_strides
+
+# Iterators for arrays
+# --------------------
+# all those iterators with the exception of BroadcastIterator iterate over the
+# entire array in C order (the last index changes the fastest). This will
+# yield all elements. Views iterate over indices and look towards strides and
+# backstrides to find the correct position. Notably the offset between
+# x[..., i + 1] and x[..., i] will be strides[-1]. Offset between
+# x[..., k + 1, 0] and x[..., k, i_max] will be backstrides[-2] etc.
+
+# BroadcastIterator works like that, but for indexes that don't change source
+# in the original array, strides[i] == backstrides[i] == 0
+
+class BaseIterator(object):
+ def next(self, shapelen):
+ raise NotImplementedError
+
+ def done(self):
+ raise NotImplementedError
+
+class ArrayIterator(BaseIterator):
+ def __init__(self, size):
+ self.offset = 0
+ self.size = size
+
+ def next(self, shapelen):
+ arr = instantiate(ArrayIterator)
+ arr.size = self.size
+ arr.offset = self.offset + 1
+ return arr
+
+ def done(self):
+ return self.offset >= self.size
+
+class OneDimIterator(BaseIterator):
+ def __init__(self, start, step, stop):
+ self.offset = start
+ self.step = step
+ self.size = stop * step + start
+
+ def next(self, shapelen):
+ arr = instantiate(OneDimIterator)
+ arr.size = self.size
+ arr.step = self.step
+ arr.offset = self.offset + self.step
+ return arr
+
+ def done(self):
+ return self.offset == self.size
+
+def view_iter_from_arr(arr):
+ return ViewIterator(arr.start, arr.strides, arr.backstrides, arr.shape)
+
+class ViewIterator(BaseIterator):
+ def __init__(self, start, strides, backstrides, shape, res_shape=None):
+ self.offset = start
+ self._done = False
+ if res_shape is not None and res_shape != shape:
+ r = calculate_broadcast_strides(strides, backstrides,
+ shape, res_shape)
+ self.strides, self.backstrides = r
+ self.res_shape = res_shape
+ else:
+ self.strides = strides
+ self.backstrides = backstrides
+ self.res_shape = shape
+ self.indices = [0] * len(self.res_shape)
+
+ @jit.unroll_safe
+ def next(self, shapelen):
+ offset = self.offset
+ indices = [0] * shapelen
+ for i in range(shapelen):
+ indices[i] = self.indices[i]
+ done = False
+ for i in range(shapelen - 1, -1, -1):
+ if indices[i] < self.res_shape[i] - 1:
+ indices[i] += 1
+ offset += self.strides[i]
+ break
+ else:
+ indices[i] = 0
+ offset -= self.backstrides[i]
+ else:
+ done = True
+ res = instantiate(ViewIterator)
+ res.offset = offset
+ res.indices = indices
+ res.strides = self.strides
+ res.backstrides = self.backstrides
+ res.res_shape = self.res_shape
+ res._done = done
+ return res
+
+ def done(self):
+ return self._done
+
+class ConstantIterator(BaseIterator):
+ def next(self, shapelen):
+ return self
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -3,28 +3,33 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.module.micronumpy import interp_ufuncs, interp_dtype, signature
+from pypy.module.micronumpy.strides import calculate_slice_strides
from pypy.rlib import jit
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.tool.sourcetools import func_with_new_name
from pypy.rlib.rstring import StringBuilder
-from pypy.rlib.objectmodel import instantiate
-
+from pypy.module.micronumpy.interp_iter import ArrayIterator,\
+ view_iter_from_arr, OneDimIterator
numpy_driver = jit.JitDriver(
- greens=['shapelen', 'signature'],
- reds=['result_size', 'i', 'ri', 'self', 'result']
+ greens=['shapelen', 'sig'],
+ virtualizables=['frame'],
+ reds=['result_size', 'frame', 'ri', 'self', 'result']
)
all_driver = jit.JitDriver(
- greens=['shapelen', 'signature'],
- reds=['i', 'self', 'dtype']
+ greens=['shapelen', 'sig'],
+ virtualizables=['frame'],
+ reds=['frame', 'self', 'dtype']
)
any_driver = jit.JitDriver(
- greens=['shapelen', 'signature'],
- reds=['i', 'self', 'dtype']
+ greens=['shapelen', 'sig'],
+ virtualizables=['frame'],
+ reds=['frame', 'self', 'dtype']
)
slice_driver = jit.JitDriver(
- greens=['shapelen', 'signature'],
- reds=['self', 'source', 'source_iter', 'res_iter']
+ greens=['shapelen', 'sig'],
+ virtualizables=['frame'],
+ reds=['self', 'frame', 'source', 'res_iter']
)
def _find_shape_and_elems(space, w_iterable):
@@ -198,231 +203,17 @@
n_old_elems_to_use *= old_shape[oldI]
return new_strides
-# Iterators for arrays
-# --------------------
-# all those iterators with the exception of BroadcastIterator iterate over the
-# entire array in C order (the last index changes the fastest). This will
-# yield all elements. Views iterate over indices and look towards strides and
-# backstrides to find the correct position. Notably the offset between
-# x[..., i + 1] and x[..., i] will be strides[-1]. Offset between
-# x[..., k + 1, 0] and x[..., k, i_max] will be backstrides[-2] etc.
+class BaseArray(Wrappable):
+ _attrs_ = ["invalidates", "shape", 'size']
-# BroadcastIterator works like that, but for indexes that don't change source
-# in the original array, strides[i] == backstrides[i] == 0
-
-class BaseIterator(object):
- def next(self, shapelen):
- raise NotImplementedError
-
- def done(self):
- raise NotImplementedError
-
- def get_offset(self):
- raise NotImplementedError
-
-class ArrayIterator(BaseIterator):
- def __init__(self, size):
- self.offset = 0
- self.size = size
-
- def next(self, shapelen):
- arr = instantiate(ArrayIterator)
- arr.size = self.size
- arr.offset = self.offset + 1
- return arr
-
- def done(self):
- return self.offset >= self.size
-
- def get_offset(self):
- return self.offset
-
-class OneDimIterator(BaseIterator):
- def __init__(self, start, step, stop):
- self.offset = start
- self.step = step
- self.size = stop * step + start
-
- def next(self, shapelen):
- arr = instantiate(OneDimIterator)
- arr.size = self.size
- arr.step = self.step
- arr.offset = self.offset + self.step
- return arr
-
- def done(self):
- return self.offset == self.size
-
- def get_offset(self):
- return self.offset
-
-class ViewIterator(BaseIterator):
- def __init__(self, arr):
- self.indices = [0] * len(arr.shape)
- self.offset = arr.start
- self.arr = arr
- self._done = False
-
- @jit.unroll_safe
- def next(self, shapelen):
- offset = self.offset
- indices = [0] * shapelen
- for i in range(shapelen):
- indices[i] = self.indices[i]
- done = False
- for i in range(shapelen - 1, -1, -1):
- if indices[i] < self.arr.shape[i] - 1:
- indices[i] += 1
- offset += self.arr.strides[i]
- break
- else:
- indices[i] = 0
- offset -= self.arr.backstrides[i]
- else:
- done = True
- res = instantiate(ViewIterator)
- res.offset = offset
- res.indices = indices
- res.arr = self.arr
- res._done = done
- return res
-
- def done(self):
- return self._done
-
- def get_offset(self):
- return self.offset
-
-class BroadcastIterator(BaseIterator):
- '''Like a view iterator, but will repeatedly access values
- for all iterations across a res_shape, folding the offset
- using mod() arithmetic
- '''
- def __init__(self, arr, res_shape):
- self.indices = [0] * len(res_shape)
- self.offset = arr.start
- #strides are 0 where original shape==1
- self.strides = []
- self.backstrides = []
- for i in range(len(arr.shape)):
- if arr.shape[i] == 1:
- self.strides.append(0)
- self.backstrides.append(0)
- else:
- self.strides.append(arr.strides[i])
- self.backstrides.append(arr.backstrides[i])
- self.res_shape = res_shape
- self.strides = [0] * (len(res_shape) - len(arr.shape)) + self.strides
- self.backstrides = [0] * (len(res_shape) - len(arr.shape)) + self.backstrides
- self._done = False
-
- @jit.unroll_safe
- def next(self, shapelen):
- offset = self.offset
- indices = [0] * shapelen
- _done = False
- for i in range(shapelen):
- indices[i] = self.indices[i]
- for i in range(shapelen - 1, -1, -1):
- if indices[i] < self.res_shape[i] - 1:
- indices[i] += 1
- offset += self.strides[i]
- break
- else:
- indices[i] = 0
- offset -= self.backstrides[i]
- else:
- _done = True
- res = instantiate(BroadcastIterator)
- res.indices = indices
- res.offset = offset
- res._done = _done
- res.strides = self.strides
- res.backstrides = self.backstrides
- res.res_shape = self.res_shape
- return res
-
- def done(self):
- return self._done
-
- def get_offset(self):
- return self.offset
-
-class Call2Iterator(BaseIterator):
- def __init__(self, left, right):
- self.left = left
- self.right = right
-
- def next(self, shapelen):
- return Call2Iterator(self.left.next(shapelen),
- self.right.next(shapelen))
-
- def done(self):
- if isinstance(self.left, ConstantIterator):
- return self.right.done()
- return self.left.done()
-
- def get_offset(self):
- if isinstance(self.left, ConstantIterator):
- return self.right.get_offset()
- return self.left.get_offset()
-
-class Call1Iterator(BaseIterator):
- def __init__(self, child):
- self.child = child
-
- def next(self, shapelen):
- return Call1Iterator(self.child.next(shapelen))
-
- def done(self):
- return self.child.done()
-
- def get_offset(self):
- return self.child.get_offset()
-
-class ConstantIterator(BaseIterator):
- def next(self, shapelen):
- return self
-
- def done(self):
- return False
-
- def get_offset(self):
- return 0
-
-
-class BaseArray(Wrappable):
- _attrs_ = ["invalidates", "signature", "shape", "strides", "backstrides",
- "start", 'order']
-
- _immutable_fields_ = ['start', "order"]
+ _immutable_fields_ = []
strides = None
start = 0
- def __init__(self, shape, order):
+ def __init__(self, shape):
self.invalidates = []
self.shape = shape
- self.order = order
- if self.strides is None:
- self.calc_strides(shape)
-
- def calc_strides(self, shape):
- strides = []
- backstrides = []
- s = 1
- shape_rev = shape[:]
- if self.order == 'C':
- shape_rev.reverse()
- for sh in shape_rev:
- strides.append(s)
- backstrides.append(s * (sh - 1))
- s *= sh
- if self.order == 'C':
- strides.reverse()
- backstrides.reverse()
- self.strides = strides[:]
- self.backstrides = backstrides[:]
def invalidated(self):
if self.invalidates:
@@ -499,33 +290,34 @@
def _reduce_argmax_argmin_impl(op_name):
reduce_driver = jit.JitDriver(
- greens=['shapelen', 'signature'],
- reds=['result', 'idx', 'i', 'self', 'cur_best', 'dtype']
+ greens=['shapelen', 'sig'],
+ reds=['result', 'idx', 'frame', 'self', 'cur_best', 'dtype']
)
def loop(self):
- i = self.start_iter()
- cur_best = self.eval(i)
+ sig = self.find_sig()
+ frame = sig.create_frame(self)
+ cur_best = sig.eval(frame, self)
shapelen = len(self.shape)
- i = i.next(shapelen)
+ frame.next(shapelen)
dtype = self.find_dtype()
result = 0
idx = 1
- while not i.done():
- reduce_driver.jit_merge_point(signature=self.signature,
+ while not frame.done():
+ reduce_driver.jit_merge_point(sig=sig,
shapelen=shapelen,
self=self, dtype=dtype,
- i=i, result=result, idx=idx,
+ frame=frame, result=result,
+ idx=idx,
cur_best=cur_best)
- new_best = getattr(dtype.itemtype, op_name)(cur_best, self.eval(i))
+ new_best = getattr(dtype.itemtype, op_name)(cur_best, sig.eval(frame, self))
if dtype.itemtype.ne(new_best, cur_best):
result = idx
cur_best = new_best
- i = i.next(shapelen)
+ frame.next(shapelen)
idx += 1
return result
def impl(self, space):
- size = self.find_size()
- if size == 0:
+ if self.size == 0:
raise OperationError(space.w_ValueError,
space.wrap("Can't call %s on zero-size arrays" % op_name))
return space.wrap(loop(self))
@@ -533,15 +325,16 @@
def _all(self):
dtype = self.find_dtype()
- i = self.start_iter()
+ sig = self.find_sig()
+ frame = sig.create_frame(self)
shapelen = len(self.shape)
- while not i.done():
- all_driver.jit_merge_point(signature=self.signature,
+ while not frame.done():
+ all_driver.jit_merge_point(sig=sig,
shapelen=shapelen, self=self,
- dtype=dtype, i=i)
- if not dtype.itemtype.bool(self.eval(i)):
+ dtype=dtype, frame=frame)
+ if not dtype.itemtype.bool(sig.eval(frame, self)):
return False
- i = i.next(shapelen)
+ frame.next(shapelen)
return True
def descr_all(self, space):
@@ -549,15 +342,16 @@
def _any(self):
dtype = self.find_dtype()
- i = self.start_iter()
+ sig = self.find_sig()
+ frame = sig.create_frame(self)
shapelen = len(self.shape)
- while not i.done():
- any_driver.jit_merge_point(signature=self.signature,
+ while not frame.done():
+ any_driver.jit_merge_point(sig=sig, frame=frame,
shapelen=shapelen, self=self,
- dtype=dtype, i=i)
- if dtype.itemtype.bool(self.eval(i)):
+ dtype=dtype)
+ if dtype.itemtype.bool(sig.eval(frame, self)):
return True
- i = i.next(shapelen)
+ frame.next(shapelen)
return False
def descr_any(self, space):
@@ -586,26 +380,33 @@
return space.newtuple([space.wrap(i) for i in self.shape])
def descr_set_shape(self, space, w_iterable):
- concrete = self.get_concrete()
new_shape = get_shape_from_iterable(space,
- concrete.find_size(), w_iterable)
- concrete.setshape(space, new_shape)
+ self.size, w_iterable)
+ if isinstance(self, Scalar):
+ return
+ self.get_concrete().setshape(space, new_shape)
def descr_get_size(self, space):
- return space.wrap(self.find_size())
+ return space.wrap(self.size)
def descr_copy(self, space):
+ return self.copy()
+
+ def copy(self):
return self.get_concrete().copy()
def descr_len(self, space):
- return self.get_concrete().descr_len(space)
+ if len(self.shape):
+ return space.wrap(self.shape[0])
+ raise OperationError(space.w_TypeError, space.wrap(
+ "len() of unsized object"))
def descr_repr(self, space):
res = StringBuilder()
res.append("array(")
concrete = self.get_concrete()
dtype = concrete.find_dtype()
- if not concrete.find_size():
+ if not concrete.size:
res.append('[]')
if len(self.shape) > 1:
# An empty slice reports its shape
@@ -617,18 +418,417 @@
concrete.to_str(space, 1, res, indent=' ')
if (dtype is not interp_dtype.get_dtype_cache(space).w_float64dtype and
dtype is not interp_dtype.get_dtype_cache(space).w_int64dtype) or \
- not self.find_size():
+ not self.size:
res.append(", dtype=" + dtype.name)
res.append(")")
return space.wrap(res.build())
+ def descr_str(self, space):
+ ret = StringBuilder()
+ concrete = self.get_concrete_or_scalar()
+ concrete.to_str(space, 0, ret, ' ')
+ return space.wrap(ret.build())
+
+ @jit.unroll_safe
+ def _single_item_result(self, space, w_idx):
+ """ The result of getitem/setitem is a single item if w_idx
+ is a list of scalars that match the size of shape
+ """
+ shape_len = len(self.shape)
+ if shape_len == 0:
+ raise OperationError(space.w_IndexError, space.wrap(
+ "0-d arrays can't be indexed"))
+ if shape_len == 1:
+ if space.isinstance_w(w_idx, space.w_int):
+ return True
+ if space.isinstance_w(w_idx, space.w_slice):
+ return False
+ elif (space.isinstance_w(w_idx, space.w_slice) or
+ space.isinstance_w(w_idx, space.w_int)):
+ return False
+ lgt = space.len_w(w_idx)
+ if lgt > shape_len:
+ raise OperationError(space.w_IndexError,
+ space.wrap("invalid index"))
+ if lgt < shape_len:
+ return False
+ for w_item in space.fixedview(w_idx):
+ if space.isinstance_w(w_item, space.w_slice):
+ return False
+ return True
+
+ @jit.unroll_safe
+ def _prepare_slice_args(self, space, w_idx):
+ if (space.isinstance_w(w_idx, space.w_int) or
+ space.isinstance_w(w_idx, space.w_slice)):
+ return [space.decode_index4(w_idx, self.shape[0])]
+ return [space.decode_index4(w_item, self.shape[i]) for i, w_item in
+ enumerate(space.fixedview(w_idx))]
+
+ def descr_getitem(self, space, w_idx):
+ if self._single_item_result(space, w_idx):
+ concrete = self.get_concrete()
+ item = concrete._index_of_single_item(space, w_idx)
+ return concrete.getitem(item)
+ chunks = self._prepare_slice_args(space, w_idx)
+ return space.wrap(self.create_slice(chunks))
+
+ def descr_setitem(self, space, w_idx, w_value):
+ self.invalidated()
+ if self._single_item_result(space, w_idx):
+ concrete = self.get_concrete()
+ item = concrete._index_of_single_item(space, w_idx)
+ dtype = concrete.find_dtype()
+ concrete.setitem(item, dtype.coerce(space, w_value))
+ return
+ if not isinstance(w_value, BaseArray):
+ w_value = convert_to_array(space, w_value)
+ chunks = self._prepare_slice_args(space, w_idx)
+ view = self.create_slice(chunks).get_concrete()
+ view.setslice(space, w_value)
+
+ @jit.unroll_safe
+ def create_slice(self, chunks):
+ shape = []
+ i = -1
+ for i, (start_, stop, step, lgt) in enumerate(chunks):
+ if step != 0:
+ shape.append(lgt)
+ s = i + 1
+ assert s >= 0
+ shape += self.shape[s:]
+ if not isinstance(self, ConcreteArray):
+ return VirtualSlice(self, chunks, shape)
+ r = calculate_slice_strides(self.shape, self.start, self.strides,
+ self.backstrides, chunks)
+ _, start, strides, backstrides = r
+ return W_NDimSlice(start, strides[:], backstrides[:],
+ shape[:], self)
+
+ def descr_reshape(self, space, args_w):
+ """reshape(...)
+ a.reshape(shape)
+
+ Returns an array containing the same data with a new shape.
+
+ Refer to `numpypy.reshape` for full documentation.
+
+ See Also
+ --------
+ numpypy.reshape : equivalent function
+ """
+ if len(args_w) == 1:
+ w_shape = args_w[0]
+ else:
+ w_shape = space.newtuple(args_w)
+ concrete = self.get_concrete()
+ new_shape = get_shape_from_iterable(space, concrete.size, w_shape)
+ # Since we got to here, prod(new_shape) == self.size
+ new_strides = calc_new_strides(new_shape,
+ concrete.shape, concrete.strides)
+ if new_strides:
+ # We can create a view, strides somehow match up.
+ ndims = len(new_shape)
+ new_backstrides = [0] * ndims
+ for nd in range(ndims):
+ new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
+ arr = W_NDimSlice(concrete.start, new_strides, new_backstrides,
+ new_shape, self)
+ else:
+ # Create copy with contiguous data
+ arr = concrete.copy()
+ arr.setshape(space, new_shape)
+ return arr
+
+ def descr_tolist(self, space):
+ if len(self.shape) == 0:
+ assert isinstance(self, Scalar)
+ return self.value.descr_tolist(space)
+ w_result = space.newlist([])
+ for i in range(self.shape[0]):
+ space.call_method(w_result, "append",
+ space.call_method(self.descr_getitem(space, space.wrap(i)), "tolist")
+ )
+ return w_result
+
+ def descr_mean(self, space):
+ return space.div(self.descr_sum(space), space.wrap(self.size))
+
+ def descr_nonzero(self, space):
+ if self.size > 1:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"))
+ concr = self.get_concrete_or_scalar()
+ sig = concr.find_sig()
+ frame = sig.create_frame(self)
+ return space.wrap(space.is_true(
+ sig.eval(frame, concr)))
+
+ def get_concrete_or_scalar(self):
+ return self.get_concrete()
+
+ def descr_get_transpose(self, space):
+ concrete = self.get_concrete()
+ if len(concrete.shape) < 2:
+ return space.wrap(self)
+ strides = []
+ backstrides = []
+ shape = []
+ for i in range(len(concrete.shape) - 1, -1, -1):
+ strides.append(concrete.strides[i])
+ backstrides.append(concrete.backstrides[i])
+ shape.append(concrete.shape[i])
+ return space.wrap(W_NDimSlice(concrete.start, strides[:],
+ backstrides[:], shape[:], concrete))
+
+ def descr_get_flatiter(self, space):
+ return space.wrap(W_FlatIterator(self))
+
+ def getitem(self, item):
+ raise NotImplementedError
+
+ def find_sig(self, res_shape=None):
+ """ find a correct signature for the array
+ """
+ res_shape = res_shape or self.shape
+ return signature.find_sig(self.create_sig(res_shape), self)
+
+ def descr_array_iface(self, space):
+ if not self.shape:
+ raise OperationError(space.w_TypeError,
+ space.wrap("can't get the array data of a 0-d array for now")
+ )
+ concrete = self.get_concrete()
+ storage = concrete.storage
+ addr = rffi.cast(lltype.Signed, storage)
+ w_d = space.newdict()
+ space.setitem_str(w_d, 'data', space.newtuple([space.wrap(addr),
+ space.w_False]))
+ return w_d
+
+def convert_to_array(space, w_obj):
+ if isinstance(w_obj, BaseArray):
+ return w_obj
+ elif space.issequence_w(w_obj):
+ # Convert to array.
+ return array(space, w_obj, w_order=None)
+ else:
+ # If it's a scalar
+ dtype = interp_ufuncs.find_dtype_for_scalar(space, w_obj)
+ return scalar_w(space, dtype, w_obj)
+
+def scalar_w(space, dtype, w_obj):
+ return Scalar(dtype, dtype.coerce(space, w_obj))
+
+class Scalar(BaseArray):
+ """
+ Intermediate class representing a literal.
+ """
+ size = 1
+ _attrs_ = ["dtype", "value", "shape"]
+
+ def __init__(self, dtype, value):
+ self.shape = []
+ BaseArray.__init__(self, [])
+ self.dtype = dtype
+ self.value = value
+
+ def find_dtype(self):
+ return self.dtype
+
+ def to_str(self, space, comma, builder, indent=' ', use_ellipsis=False):
+ builder.append(self.dtype.itemtype.str_format(self.value))
+
+ def copy(self):
+ return Scalar(self.dtype, self.value)
+
+ def create_sig(self, res_shape):
+ return signature.ScalarSignature(self.dtype)
+
+ def get_concrete_or_scalar(self):
+ return self
+
+
+class VirtualArray(BaseArray):
+ """
+ Class for representing virtual arrays, such as binary ops or ufuncs
+ """
+ def __init__(self, name, shape, res_dtype):
+ BaseArray.__init__(self, shape)
+ self.forced_result = None
+ self.res_dtype = res_dtype
+ self.name = name
+
+ def _del_sources(self):
+ # Function for deleting references to source arrays, to allow garbage-collecting them
+ raise NotImplementedError
+
+ def compute(self):
+ result = W_NDimArray(self.size, self.shape, self.find_dtype())
+ shapelen = len(self.shape)
+ sig = self.find_sig()
+ frame = sig.create_frame(self)
+ ri = ArrayIterator(self.size)
+ while not ri.done():
+ numpy_driver.jit_merge_point(sig=sig,
+ shapelen=shapelen,
+ result_size=self.size,
+ frame=frame,
+ ri=ri,
+ self=self, result=result)
+ result.dtype.setitem(result.storage, ri.offset,
+ sig.eval(frame, self))
+ frame.next(shapelen)
+ ri = ri.next(shapelen)
+ return result
+
+ def force_if_needed(self):
+ if self.forced_result is None:
+ self.forced_result = self.compute()
+ self._del_sources()
+
+ def get_concrete(self):
+ self.force_if_needed()
+ res = self.forced_result
+ assert isinstance(res, ConcreteArray)
+ return res
+
+ def getitem(self, item):
+ return self.get_concrete().getitem(item)
+
+ def setitem(self, item, value):
+ return self.get_concrete().setitem(item, value)
+
+ def find_dtype(self):
+ return self.res_dtype
+
+class VirtualSlice(VirtualArray):
+ def __init__(self, child, chunks, shape):
+ size = 1
+ for sh in shape:
+ size *= sh
+ self.child = child
+ self.chunks = chunks
+ self.size = size
+ VirtualArray.__init__(self, 'slice', shape, child.find_dtype())
+
+ def create_sig(self, res_shape):
+ if self.forced_result is not None:
+ return self.forced_result.create_sig(res_shape)
+ return signature.VirtualSliceSignature(
+ self.child.create_sig(res_shape))
+
+ def force_if_needed(self):
+ if self.forced_result is None:
+ concr = self.child.get_concrete()
+ self.forced_result = concr.create_slice(self.chunks)
+
+ def _del_sources(self):
+ self.child = None
+
+class Call1(VirtualArray):
+ def __init__(self, ufunc, name, shape, res_dtype, values):
+ VirtualArray.__init__(self, name, shape, res_dtype)
+ self.values = values
+ self.size = values.size
+ self.ufunc = ufunc
+
+ def _del_sources(self):
+ self.values = None
+
+ def create_sig(self, res_shape):
+ if self.forced_result is not None:
+ return self.forced_result.create_sig(res_shape)
+ return signature.Call1(self.ufunc, self.name,
+ self.values.create_sig(res_shape))
+
+class Call2(VirtualArray):
+ """
+ Intermediate class for performing binary operations.
+ """
+ def __init__(self, ufunc, name, shape, calc_dtype, res_dtype, left, right):
+ VirtualArray.__init__(self, name, shape, res_dtype)
+ self.ufunc = ufunc
+ self.left = left
+ self.right = right
+ self.calc_dtype = calc_dtype
+ self.size = 1
+ for s in self.shape:
+ self.size *= s
+
+ def _del_sources(self):
+ self.left = None
+ self.right = None
+
+ def create_sig(self, res_shape):
+ if self.forced_result is not None:
+ return self.forced_result.create_sig(res_shape)
+ return signature.Call2(self.ufunc, self.name, self.calc_dtype,
+ self.left.create_sig(res_shape),
+ self.right.create_sig(res_shape))
+
+class ConcreteArray(BaseArray):
+ """ An array that have actual storage, whether owned or not
+ """
+ _immutable_fields_ = ['storage']
+
+ def __init__(self, size, shape, dtype, order='C', parent=None):
+ self.size = size
+ self.parent = parent
+ if parent is not None:
+ self.storage = parent.storage
+ else:
+ self.storage = dtype.malloc(size)
+ self.order = order
+ self.dtype = dtype
+ if self.strides is None:
+ self.calc_strides(shape)
+ BaseArray.__init__(self, shape)
+ if parent is not None:
+ self.invalidates = parent.invalidates
+
+ def get_concrete(self):
+ return self
+
+ def find_dtype(self):
+ return self.dtype
+
+ def getitem(self, item):
+ return self.dtype.getitem(self.storage, item)
+
+ def setitem(self, item, value):
+ self.invalidated()
+ self.dtype.setitem(self.storage, item, value)
+
+ def calc_strides(self, shape):
+ strides = []
+ backstrides = []
+ s = 1
+ shape_rev = shape[:]
+ if self.order == 'C':
+ shape_rev.reverse()
+ for sh in shape_rev:
+ strides.append(s)
+ backstrides.append(s * (sh - 1))
+ s *= sh
+ if self.order == 'C':
+ strides.reverse()
+ backstrides.reverse()
+ self.strides = strides[:]
+ self.backstrides = backstrides[:]
+
+ def array_sig(self, res_shape):
+ if res_shape is not None and self.shape != res_shape:
+ return signature.ViewSignature(self.dtype)
+ return signature.ArraySignature(self.dtype)
+
def to_str(self, space, comma, builder, indent=' ', use_ellipsis=False):
'''Modifies builder with a representation of the array/slice
The items will be seperated by a comma if comma is 1
Multidimensional arrays/slices will span a number of lines,
each line will begin with indent.
'''
- size = self.find_size()
+ size = self.size
if size < 1:
builder.append('[]')
return
@@ -654,7 +854,7 @@
builder.append(indent)
# create_slice requires len(chunks) > 1 in order to reduce
# shape
- view = self.create_slice(space, [(i, 0, 0, 1), (0, self.shape[1], 1, self.shape[1])])
+ view = self.create_slice([(i, 0, 0, 1), (0, self.shape[1], 1, self.shape[1])]).get_concrete()
view.to_str(space, comma, builder, indent=indent + ' ', use_ellipsis=use_ellipsis)
builder.append('\n' + indent + '..., ')
i = self.shape[0] - 3
@@ -669,7 +869,7 @@
builder.append(indent)
# create_slice requires len(chunks) > 1 in order to reduce
# shape
- view = self.create_slice(space, [(i, 0, 0, 1), (0, self.shape[1], 1, self.shape[1])])
+ view = self.create_slice([(i, 0, 0, 1), (0, self.shape[1], 1, self.shape[1])]).get_concrete()
view.to_str(space, comma, builder, indent=indent + ' ', use_ellipsis=use_ellipsis)
i += 1
elif ndims == 1:
@@ -705,12 +905,6 @@
builder.append('[')
builder.append(']')
- def descr_str(self, space):
- ret = StringBuilder()
- concrete = self.get_concrete()
- concrete.to_str(space, 0, ret, ' ')
- return space.wrap(ret.build())
-
@jit.unroll_safe
def _index_of_single_item(self, space, w_idx):
if space.isinstance_w(w_idx, space.w_int):
@@ -735,456 +929,55 @@
item += v * self.strides[i]
return item
- @jit.unroll_safe
- def _single_item_result(self, space, w_idx):
- """ The result of getitem/setitem is a single item if w_idx
- is a list of scalars that match the size of shape
- """
- shape_len = len(self.shape)
- if shape_len == 0:
- if not space.isinstance_w(w_idx, space.w_int):
- raise OperationError(space.w_IndexError, space.wrap(
- "wrong index"))
- return True
- if shape_len == 1:
- if space.isinstance_w(w_idx, space.w_int):
- return True
- if space.isinstance_w(w_idx, space.w_slice):
- return False
- elif (space.isinstance_w(w_idx, space.w_slice) or
- space.isinstance_w(w_idx, space.w_int)):
- return False
- lgt = space.len_w(w_idx)
- if lgt > shape_len:
- raise OperationError(space.w_IndexError,
- space.wrap("invalid index"))
- if lgt < shape_len:
- return False
- for w_item in space.fixedview(w_idx):
- if space.isinstance_w(w_item, space.w_slice):
- return False
- return True
- @jit.unroll_safe
- def _prepare_slice_args(self, space, w_idx):
- if (space.isinstance_w(w_idx, space.w_int) or
- space.isinstance_w(w_idx, space.w_slice)):
- return [space.decode_index4(w_idx, self.shape[0])]
- return [space.decode_index4(w_item, self.shape[i]) for i, w_item in
- enumerate(space.fixedview(w_idx))]
+class ViewArray(ConcreteArray):
+ def copy(self):
+ array = W_NDimArray(self.size, self.shape[:], self.find_dtype())
+ iter = view_iter_from_arr(self)
+ a_iter = ArrayIterator(array.size)
+ while not iter.done():
+ array.setitem(a_iter.offset, self.getitem(iter.offset))
+ iter = iter.next(len(self.shape))
+ a_iter = a_iter.next(len(array.shape))
+ return array
- def descr_getitem(self, space, w_idx):
- if self._single_item_result(space, w_idx):
- concrete = self.get_concrete()
- if len(concrete.shape) < 1:
- raise OperationError(space.w_IndexError, space.wrap(
- "0-d arrays can't be indexed"))
- item = concrete._index_of_single_item(space, w_idx)
- return concrete.getitem(item)
- chunks = self._prepare_slice_args(space, w_idx)
- return space.wrap(self.create_slice(space, chunks))
+ def create_sig(self, res_shape):
+ return signature.ViewSignature(self.dtype)
- def descr_setitem(self, space, w_idx, w_value):
- self.invalidated()
- if self._single_item_result(space, w_idx):
- concrete = self.get_concrete()
- if len(concrete.shape) < 1:
- raise OperationError(space.w_IndexError, space.wrap(
- "0-d arrays can't be indexed"))
- item = concrete._index_of_single_item(space, w_idx)
- dtype = concrete.find_dtype()
- concrete.setitem(item, dtype.coerce(space, w_value))
- return
- if not isinstance(w_value, BaseArray):
- w_value = convert_to_array(space, w_value)
- chunks = self._prepare_slice_args(space, w_idx)
- view = self.create_slice(space, chunks)
- view.setslice(space, w_value)
- @jit.unroll_safe
- def create_slice(self, space, chunks):
- if len(chunks) == 1:
- start, stop, step, lgt = chunks[0]
- if step == 0:
- shape = self.shape[1:]
- strides = self.strides[1:]
- backstrides = self.backstrides[1:]
- else:
- shape = [lgt] + self.shape[1:]
- strides = [self.strides[0] * step] + self.strides[1:]
- backstrides = [(lgt - 1) * self.strides[0] * step] + self.backstrides[1:]
- start *= self.strides[0]
- start += self.start
- else:
- shape = []
- strides = []
- backstrides = []
- start = self.start
- i = -1
- for i, (start_, stop, step, lgt) in enumerate(chunks):
- if step != 0:
- shape.append(lgt)
- strides.append(self.strides[i] * step)
- backstrides.append(self.strides[i] * (lgt - 1) * step)
- start += self.strides[i] * start_
- # add a reminder
- s = i + 1
- assert s >= 0
- shape += self.shape[s:]
- strides += self.strides[s:]
- backstrides += self.backstrides[s:]
- new_sig = signature.Signature.find_sig([
- W_NDimSlice.signature, self.signature,
- ])
- return W_NDimSlice(self, new_sig, start, strides[:], backstrides[:],
- shape[:])
-
- def descr_reshape(self, space, args_w):
- """reshape(...)
- a.reshape(shape)
-
- Returns an array containing the same data with a new shape.
-
- Refer to `numpypy.reshape` for full documentation.
-
- See Also
- --------
- numpypy.reshape : equivalent function
-"""
- if len(args_w) == 1:
- w_shape = args_w[0]
- else:
- w_shape = space.newtuple(args_w)
- concrete = self.get_concrete()
- new_shape = get_shape_from_iterable(space,
- concrete.find_size(), w_shape)
- # Since we got to here, prod(new_shape) == self.size
- new_strides = calc_new_strides(new_shape,
- concrete.shape, concrete.strides)
- if new_strides:
- # We can create a view, strides somehow match up.
- new_sig = signature.Signature.find_sig([
- W_NDimSlice.signature, self.signature
- ])
- ndims = len(new_shape)
- new_backstrides = [0] * ndims
- for nd in range(ndims):
- new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
- arr = W_NDimSlice(self, new_sig, self.start, new_strides,
- new_backstrides, new_shape)
- else:
- # Create copy with contiguous data
- arr = concrete.copy()
- arr.setshape(space, new_shape)
- return arr
-
- def descr_tolist(self, space):
- if len(self.shape) == 0:
- assert isinstance(self, Scalar)
- return self.value.descr_tolist(space)
- w_result = space.newlist([])
- for i in range(self.shape[0]):
- space.call_method(w_result, "append",
- space.call_method(self.descr_getitem(space, space.wrap(i)), "tolist")
- )
- return w_result
-
- def descr_mean(self, space):
- return space.div(self.descr_sum(space), space.wrap(self.find_size()))
-
- def descr_nonzero(self, space):
- if self.find_size() > 1:
- raise OperationError(space.w_ValueError, space.wrap(
- "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"))
- return space.wrap(space.is_true(
- self.get_concrete().eval(self.start_iter(self.shape))
- ))
-
- def descr_get_transpose(self, space):
- concrete = self.get_concrete()
- if len(concrete.shape) < 2:
- return space.wrap(self)
- new_sig = signature.Signature.find_sig([
- W_NDimSlice.signature, self.signature
- ])
- strides = []
- backstrides = []
- shape = []
- for i in range(len(concrete.shape) - 1, -1, -1):
- strides.append(concrete.strides[i])
- backstrides.append(concrete.backstrides[i])
- shape.append(concrete.shape[i])
- return space.wrap(W_NDimSlice(concrete, new_sig, self.start, strides[:],
- backstrides[:], shape[:]))
-
- def descr_get_flatiter(self, space):
- return space.wrap(W_FlatIterator(self))
-
- def getitem(self, item):
- raise NotImplementedError
-
- def start_iter(self, res_shape=None):
- raise NotImplementedError
-
- def descr_array_iface(self, space):
- concrete = self.get_concrete()
- storage = concrete.get_storage(space)
- addr = rffi.cast(lltype.Signed, storage)
- w_d = space.newdict()
- space.setitem_str(w_d, 'data', space.newtuple([space.wrap(addr),
- space.w_False]))
- return w_d
-
-def convert_to_array(space, w_obj):
- if isinstance(w_obj, BaseArray):
- return w_obj
- elif space.issequence_w(w_obj):
- # Convert to array.
- return array(space, w_obj, w_order=None)
- else:
- # If it's a scalar
- dtype = interp_ufuncs.find_dtype_for_scalar(space, w_obj)
- return scalar_w(space, dtype, w_obj)
-
-def scalar_w(space, dtype, w_obj):
- return Scalar(dtype, dtype.coerce(space, w_obj))
-
-class Scalar(BaseArray):
- """
- Intermediate class representing a literal.
- """
- signature = signature.BaseSignature()
-
- _attrs_ = ["dtype", "value", "shape"]
-
- def __init__(self, dtype, value):
- self.shape = self.strides = []
- BaseArray.__init__(self, [], 'C')
- self.dtype = dtype
- self.value = value
-
- def find_size(self):
- return 1
-
- def get_concrete(self):
- return self
-
- def find_dtype(self):
- return self.dtype
-
- def getitem(self, item):
- raise NotImplementedError
-
- def eval(self, iter):
- return self.value
-
- def start_iter(self, res_shape=None):
- return ConstantIterator()
-
- def to_str(self, space, comma, builder, indent=' ', use_ellipsis=False):
- builder.append(self.dtype.itemtype.str_format(self.value))
-
- def copy(self):
- return Scalar(self.dtype, self.value)
-
- def debug_repr(self):
- return 'Scalar'
-
- def setshape(self, space, new_shape):
- # In order to get here, we already checked that prod(new_shape) == 1,
- # so in order to have a consistent API, let it go through.
- pass
-
- def get_storage(self, space):
- raise OperationError(space.w_TypeError, space.wrap("Cannot get array interface on scalars in pypy"))
-
-class VirtualArray(BaseArray):
- """
- Class for representing virtual arrays, such as binary ops or ufuncs
- """
- def __init__(self, signature, shape, res_dtype, order):
- BaseArray.__init__(self, shape, order)
- self.forced_result = None
- self.signature = signature
- self.res_dtype = res_dtype
-
- def _del_sources(self):
- # Function for deleting references to source arrays, to allow garbage-collecting them
- raise NotImplementedError
-
- def compute(self):
- i = 0
- signature = self.signature
- result_size = self.find_size()
- result = W_NDimArray(result_size, self.shape, self.find_dtype())
- shapelen = len(self.shape)
- i = self.start_iter()
- ri = result.start_iter()
- while not ri.done():
- numpy_driver.jit_merge_point(signature=signature,
- shapelen=shapelen,
- result_size=result_size, i=i, ri=ri,
- self=self, result=result)
- result.dtype.setitem(result.storage, ri.offset, self.eval(i))
- i = i.next(shapelen)
- ri = ri.next(shapelen)
- return result
-
- def force_if_needed(self):
- if self.forced_result is None:
- self.forced_result = self.compute()
- self._del_sources()
-
- def get_concrete(self):
- self.force_if_needed()
- return self.forced_result
-
- def eval(self, iter):
- if self.forced_result is not None:
- return self.forced_result.eval(iter)
- return self._eval(iter)
-
- def getitem(self, item):
- return self.get_concrete().getitem(item)
-
- def setitem(self, item, value):
- return self.get_concrete().setitem(item, value)
-
- def find_size(self):
- if self.forced_result is not None:
- # The result has been computed and sources may be unavailable
- return self.forced_result.find_size()
- return self._find_size()
-
- def find_dtype(self):
- return self.res_dtype
-
-
-class Call1(VirtualArray):
- def __init__(self, signature, shape, res_dtype, values, order):
- VirtualArray.__init__(self, signature, shape, res_dtype,
- values.order)
- self.values = values
-
- def _del_sources(self):
- self.values = None
-
- def _find_size(self):
- return self.values.find_size()
-
- def _find_dtype(self):
- return self.res_dtype
-
- def _eval(self, iter):
- assert isinstance(iter, Call1Iterator)
- val = self.values.eval(iter.child).convert_to(self.res_dtype)
- sig = jit.promote(self.signature)
- assert isinstance(sig, signature.Signature)
- call_sig = sig.components[0]
- assert isinstance(call_sig, signature.Call1)
- return call_sig.func(self.res_dtype, val)
-
- def start_iter(self, res_shape=None):
- if self.forced_result is not None:
- return self.forced_result.start_iter(res_shape)
- return Call1Iterator(self.values.start_iter(res_shape))
-
- def debug_repr(self):
- sig = self.signature
- assert isinstance(sig, signature.Signature)
- call_sig = sig.components[0]
- assert isinstance(call_sig, signature.Call1)
- if self.forced_result is not None:
- return 'Call1(%s, forced=%s)' % (call_sig.name,
- self.forced_result.debug_repr())
- return 'Call1(%s, %s)' % (call_sig.name,
- self.values.debug_repr())
-
-class Call2(VirtualArray):
- """
- Intermediate class for performing binary operations.
- """
- def __init__(self, signature, shape, calc_dtype, res_dtype, left, right):
- # XXX do something if left.order != right.order
- VirtualArray.__init__(self, signature, shape, res_dtype, left.order)
- self.left = left
- self.right = right
- self.calc_dtype = calc_dtype
- self.size = 1
- for s in self.shape:
- self.size *= s
-
- def _del_sources(self):
- self.left = None
- self.right = None
-
- def _find_size(self):
- return self.size
-
- def start_iter(self, res_shape=None):
- if self.forced_result is not None:
- return self.forced_result.start_iter(res_shape)
- if res_shape is None:
- res_shape = self.shape # we still force the shape on children
- return Call2Iterator(self.left.start_iter(res_shape),
- self.right.start_iter(res_shape))
-
- def _eval(self, iter):
- assert isinstance(iter, Call2Iterator)
- lhs = self.left.eval(iter.left).convert_to(self.calc_dtype)
- rhs = self.right.eval(iter.right).convert_to(self.calc_dtype)
- sig = jit.promote(self.signature)
- assert isinstance(sig, signature.Signature)
- call_sig = sig.components[0]
- assert isinstance(call_sig, signature.Call2)
- return call_sig.func(self.calc_dtype, lhs, rhs)
-
- def debug_repr(self):
- sig = self.signature
- assert isinstance(sig, signature.Signature)
- call_sig = sig.components[0]
- assert isinstance(call_sig, signature.Call2)
- if self.forced_result is not None:
- return 'Call2(%s, forced=%s)' % (call_sig.name,
- self.forced_result.debug_repr())
- return 'Call2(%s, %s, %s)' % (call_sig.name,
- self.left.debug_repr(),
- self.right.debug_repr())
-
-class ViewArray(BaseArray):
- """
- Class for representing views of arrays, they will reflect changes of parent
- arrays. Example: slices
- """
- def __init__(self, parent, signature, strides, backstrides, shape):
+class W_NDimSlice(ViewArray):
+ def __init__(self, start, strides, backstrides, shape, parent):
+ assert isinstance(parent, ConcreteArray)
+ if isinstance(parent, W_NDimSlice):
+ parent = parent.parent
+ size = 1
+ for sh in shape:
+ size *= sh
self.strides = strides
self.backstrides = backstrides
- BaseArray.__init__(self, shape, parent.order)
- self.signature = signature
- self.parent = parent
- self.invalidates = parent.invalidates
+ ViewArray.__init__(self, size, shape, parent.dtype, parent.order,
+ parent)
+ self.start = start
- def get_concrete(self):
- # in fact, ViewArray never gets "concrete" as it never stores data.
- # This implementation is needed for BaseArray getitem/setitem to work,
- # can be refactored.
- self.parent.get_concrete()
- return self
+ def setslice(self, space, w_value):
+ res_shape = shape_agreement(space, self.shape, w_value.shape)
+ self._sliceloop(w_value, res_shape)
- def getitem(self, item):
- return self.parent.getitem(item)
-
- def eval(self, iter):
- return self.parent.getitem(iter.get_offset())
-
- def setitem(self, item, value):
- # This is currently not possible to be called from anywhere.
- raise NotImplementedError
-
- def descr_len(self, space):
- if self.shape:
- return space.wrap(self.shape[0])
- return space.wrap(1)
+ def _sliceloop(self, source, res_shape):
+ sig = source.find_sig(res_shape)
+ frame = sig.create_frame(source, res_shape)
+ res_iter = view_iter_from_arr(self)
+ shapelen = len(res_shape)
+ while not res_iter.done():
+ slice_driver.jit_merge_point(sig=sig,
+ frame=frame,
+ shapelen=shapelen,
+ self=self, source=source,
+ res_iter=res_iter)
+ self.setitem(res_iter.offset, sig.eval(frame, source).convert_to(
+ self.find_dtype()))
+ frame.next(shapelen)
+ res_iter = res_iter.next(shapelen)
def setshape(self, space, new_shape):
if len(self.shape) < 1:
@@ -1220,96 +1013,10 @@
self.backstrides = new_backstrides[:]
self.shape = new_shape[:]
-class W_NDimSlice(ViewArray):
- signature = signature.BaseSignature()
-
- def __init__(self, parent, signature, start, strides, backstrides,
- shape):
- if isinstance(parent, W_NDimSlice):
- parent = parent.parent
- ViewArray.__init__(self, parent, signature, strides, backstrides, shape)
- self.start = start
- self.size = 1
- for sh in shape:
- self.size *= sh
-
- def find_size(self):
- return self.size
-
- def find_dtype(self):
- return self.parent.find_dtype()
-
- def setslice(self, space, w_value):
- res_shape = shape_agreement(space, self.shape, w_value.shape)
- self._sliceloop(w_value, res_shape)
-
- def _sliceloop(self, source, res_shape):
- source_iter = source.start_iter(res_shape)
- res_iter = self.start_iter(res_shape)
- shapelen = len(res_shape)
- while not res_iter.done():
- slice_driver.jit_merge_point(signature=source.signature,
- shapelen=shapelen,
- self=self, source=source,
- res_iter=res_iter,
- source_iter=source_iter)
- self.setitem(res_iter.offset, source.eval(source_iter).convert_to(
- self.find_dtype()))
- source_iter = source_iter.next(shapelen)
- res_iter = res_iter.next(shapelen)
-
- def start_iter(self, res_shape=None):
- if res_shape is not None and res_shape != self.shape:
- return BroadcastIterator(self, res_shape)
- if len(self.shape) == 1:
- return OneDimIterator(self.start, self.strides[0], self.shape[0])
- return ViewIterator(self)
-
- def setitem(self, item, value):
- self.parent.setitem(item, value)
-
- def debug_repr(self):
- return 'Slice(%s)' % self.parent.debug_repr()
-
- def copy(self):
- array = W_NDimArray(self.size, self.shape[:], self.find_dtype())
- iter = self.start_iter()
- a_iter = array.start_iter()
- while not iter.done():
- array.setitem(a_iter.offset, self.getitem(iter.offset))
- iter = iter.next(len(self.shape))
- a_iter = a_iter.next(len(array.shape))
- return array
-
- def get_storage(self, space):
- return self.parent.get_storage(space)
-
-class W_NDimArray(BaseArray):
+class W_NDimArray(ConcreteArray):
""" A class representing contiguous array. We know that each iteration
by say ufunc will increase the data index by one
"""
- def __init__(self, size, shape, dtype, order='C'):
- BaseArray.__init__(self, shape, order)
- self.size = size
- self.dtype = dtype
- self.storage = dtype.malloc(size)
- self.signature = dtype.signature
-
- def get_concrete(self):
- return self
-
- def find_size(self):
- return self.size
-
- def find_dtype(self):
- return self.dtype
-
- def getitem(self, item):
- return self.dtype.getitem(self.storage, item)
-
- def eval(self, iter):
- return self.dtype.getitem(self.storage, iter.get_offset())
-
def copy(self):
array = W_NDimArray(self.size, self.shape[:], self.dtype, self.order)
rffi.c_memcpy(
@@ -1319,32 +1026,16 @@
)
return array
- def descr_len(self, space):
- if len(self.shape):
- return space.wrap(self.shape[0])
- raise OperationError(space.w_TypeError, space.wrap(
- "len() of unsized object"))
-
def setitem(self, item, value):
self.invalidated()
self.dtype.setitem(self.storage, item, value)
- def start_iter(self, res_shape=None):
- if self.order == 'C':
- if res_shape is not None and res_shape != self.shape:
- return BroadcastIterator(self, res_shape)
- return ArrayIterator(self.size)
- raise NotImplementedError # use ViewIterator simply, test it
-
def setshape(self, space, new_shape):
self.shape = new_shape
self.calc_strides(new_shape)
- def debug_repr(self):
- return 'Array'
-
- def get_storage(self, space):
- return self.storage
+ def create_sig(self, res_shape):
+ return self.array_sig(res_shape)
def __del__(self):
lltype.free(self.storage, flavor='raw', track_allocation=False)
@@ -1396,10 +1087,11 @@
)
arr = W_NDimArray(size, shape[:], dtype=dtype, order=order)
shapelen = len(shape)
- arr_iter = arr.start_iter(arr.shape)
+ arr_iter = ArrayIterator(arr.size)
for i in range(len(elems_w)):
w_elem = elems_w[i]
- dtype.setitem(arr.storage, arr_iter.offset, dtype.coerce(space, w_elem))
+ dtype.setitem(arr.storage, arr_iter.offset,
+ dtype.coerce(space, w_elem))
arr_iter = arr_iter.next(shapelen)
return arr
@@ -1492,48 +1184,31 @@
class W_FlatIterator(ViewArray):
- signature = signature.BaseSignature()
@jit.unroll_safe
def __init__(self, arr):
+ arr = arr.get_concrete()
size = 1
for sh in arr.shape:
size *= sh
- new_sig = signature.Signature.find_sig([
- W_FlatIterator.signature, arr.signature
- ])
- ViewArray.__init__(self, arr, new_sig, [arr.strides[-1]],
- [arr.backstrides[-1]], [size])
+ self.strides = [arr.strides[-1]]
+ self.backstrides = [arr.backstrides[-1]]
+ ViewArray.__init__(self, size, [size], arr.dtype, arr.order,
+ arr)
self.shapelen = len(arr.shape)
- self.arr = arr
- self.iter = self.start_iter()
-
- def start_iter(self, res_shape=None):
- if res_shape is not None and res_shape != self.shape:
- return BroadcastIterator(self, res_shape)
- return OneDimIterator(self.arr.start, self.strides[0],
- self.shape[0])
-
- def find_dtype(self):
- return self.arr.find_dtype()
-
- def find_size(self):
- return self.shape[0]
+ self.iter = OneDimIterator(arr.start, self.strides[0],
+ self.shape[0])
def descr_next(self, space):
if self.iter.done():
raise OperationError(space.w_StopIteration, space.w_None)
- result = self.eval(self.iter)
+ result = self.getitem(self.iter.offset)
self.iter = self.iter.next(self.shapelen)
return result
def descr_iter(self):
return self
- def debug_repr(self):
- return 'FlatIter(%s)' % self.arr.debug_repr()
-
-
W_FlatIterator.typedef = TypeDef(
'flatiter',
next = interp2app(W_FlatIterator.descr_next),
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -2,20 +2,21 @@
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
-from pypy.module.micronumpy import interp_boxes, interp_dtype, signature, types
+from pypy.module.micronumpy import interp_boxes, interp_dtype, types
+from pypy.module.micronumpy.signature import ReduceSignature, ScalarSignature, find_sig
from pypy.rlib import jit
from pypy.rlib.rarithmetic import LONG_BIT
from pypy.tool.sourcetools import func_with_new_name
-
reduce_driver = jit.JitDriver(
- greens = ['shapelen', "signature"],
- reds = ["i", "self", "dtype", "value", "obj"]
+ greens = ['shapelen', "sig"],
+ virtualizables = ["frame"],
+ reds = ["frame", "self", "dtype", "value", "obj"]
)
class W_Ufunc(Wrappable):
_attrs_ = ["name", "promote_to_float", "promote_bools", "identity"]
- _immutable_fields_ = ["promote_to_float", "promote_bools"]
+ _immutable_fields_ = ["promote_to_float", "promote_bools", "name"]
def __init__(self, name, promote_to_float, promote_bools, identity):
self.name = name
@@ -50,6 +51,7 @@
def reduce(self, space, w_obj, multidim):
from pypy.module.micronumpy.interp_numarray import convert_to_array, Scalar
+
if self.argcount != 2:
raise OperationError(space.w_ValueError, space.wrap("reduce only "
"supported for binary functions"))
@@ -60,13 +62,16 @@
raise OperationError(space.w_TypeError, space.wrap("cannot reduce "
"on a scalar"))
- size = obj.find_size()
+ size = obj.size
dtype = find_unaryop_result_dtype(
space, obj.find_dtype(),
promote_to_largest=True
)
- start = obj.start_iter(obj.shape)
shapelen = len(obj.shape)
+ sig = find_sig(ReduceSignature(self.func, self.name, dtype,
+ ScalarSignature(dtype),
+ obj.create_sig(obj.shape)), obj)
+ frame = sig.create_frame(obj)
if shapelen > 1 and not multidim:
raise OperationError(space.w_NotImplementedError,
space.wrap("not implemented yet"))
@@ -74,34 +79,33 @@
if size == 0:
raise operationerrfmt(space.w_ValueError, "zero-size array to "
"%s.reduce without identity", self.name)
- value = obj.eval(start).convert_to(dtype)
- start = start.next(shapelen)
+ value = sig.eval(frame, obj).convert_to(dtype)
+ frame.next(shapelen)
else:
value = self.identity.convert_to(dtype)
- new_sig = signature.Signature.find_sig([
- self.reduce_signature, obj.signature
- ])
- return self.reduce_loop(new_sig, shapelen, start, value, obj, dtype)
+ return self.reduce_loop(shapelen, sig, frame, value, obj, dtype)
- def reduce_loop(self, signature, shapelen, i, value, obj, dtype):
- while not i.done():
- reduce_driver.jit_merge_point(signature=signature,
+ def reduce_loop(self, shapelen, sig, frame, value, obj, dtype):
+ while not frame.done():
+ reduce_driver.jit_merge_point(sig=sig,
shapelen=shapelen, self=self,
- value=value, obj=obj, i=i,
+ value=value, obj=obj, frame=frame,
dtype=dtype)
- value = self.func(dtype, value, obj.eval(i).convert_to(dtype))
- i = i.next(shapelen)
+ assert isinstance(sig, ReduceSignature)
+ value = sig.binfunc(dtype, value, sig.eval(frame, obj).convert_to(dtype))
+ frame.next(shapelen)
return value
class W_Ufunc1(W_Ufunc):
argcount = 1
+ _immutable_fields_ = ["func", "name"]
+
def __init__(self, func, name, promote_to_float=False, promote_bools=False,
identity=None):
W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity)
self.func = func
- self.signature = signature.Call1(func)
def call(self, space, args_w):
from pypy.module.micronumpy.interp_numarray import (Call1,
@@ -117,14 +121,13 @@
if isinstance(w_obj, Scalar):
return self.func(res_dtype, w_obj.value.convert_to(res_dtype))
- new_sig = signature.Signature.find_sig([self.signature, w_obj.signature])
- w_res = Call1(new_sig, w_obj.shape, res_dtype, w_obj, w_obj.order)
+ w_res = Call1(self.func, self.name, w_obj.shape, res_dtype, w_obj)
w_obj.add_invalidates(w_res)
return w_res
class W_Ufunc2(W_Ufunc):
- _immutable_fields_ = ["comparison_func", "func"]
+ _immutable_fields_ = ["comparison_func", "func", "name"]
argcount = 2
def __init__(self, func, name, promote_to_float=False, promote_bools=False,
@@ -133,8 +136,6 @@
W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity)
self.func = func
self.comparison_func = comparison_func
- self.signature = signature.Call2(func)
- self.reduce_signature = signature.BaseSignature()
def call(self, space, args_w):
from pypy.module.micronumpy.interp_numarray import (Call2,
@@ -158,11 +159,9 @@
w_rhs.value.convert_to(calc_dtype)
)
- new_sig = signature.Signature.find_sig([
- self.signature, w_lhs.signature, w_rhs.signature
- ])
new_shape = shape_agreement(space, w_lhs.shape, w_rhs.shape)
- w_res = Call2(new_sig, new_shape, calc_dtype,
+ w_res = Call2(self.func, self.name,
+ new_shape, calc_dtype,
res_dtype, w_lhs, w_rhs)
w_lhs.add_invalidates(w_res)
w_rhs.add_invalidates(w_res)
diff --git a/pypy/module/micronumpy/signature.py b/pypy/module/micronumpy/signature.py
--- a/pypy/module/micronumpy/signature.py
+++ b/pypy/module/micronumpy/signature.py
@@ -1,54 +1,322 @@
-from pypy.rlib.objectmodel import r_dict, compute_identity_hash
+from pypy.rlib.objectmodel import r_dict, compute_identity_hash, compute_hash
from pypy.rlib.rarithmetic import intmask
+from pypy.module.micronumpy.interp_iter import ViewIterator, ArrayIterator, \
+ OneDimIterator, ConstantIterator
+from pypy.module.micronumpy.strides import calculate_slice_strides
+from pypy.rlib.jit import hint, unroll_safe, promote
+def sigeq(one, two):
+ return one.eq(two)
-def components_eq(lhs, rhs):
- if len(lhs) != len(rhs):
- return False
- for i in range(len(lhs)):
- v1, v2 = lhs[i], rhs[i]
- if type(v1) is not type(v2) or not v1.eq(v2):
+def sigeq_no_numbering(one, two):
+ """ Cache for iterator numbering should not compare array numbers
+ """
+ return one.eq(two, compare_array_no=False)
+
+def sighash(sig):
+ return sig.hash()
+
+known_sigs = r_dict(sigeq, sighash)
+
+def find_sig(sig, arr):
+ sig.invent_array_numbering(arr)
+ try:
+ return known_sigs[sig]
+ except KeyError:
+ sig.invent_numbering()
+ known_sigs[sig] = sig
+ return sig
+
+class NumpyEvalFrame(object):
+ _virtualizable2_ = ['iterators[*]', 'final_iter', 'arraylist[*]']
+
+ @unroll_safe
+ def __init__(self, iterators, arrays):
+ self = hint(self, access_directly=True, fresh_virtualizable=True)
+ self.iterators = iterators[:]
+ self.arrays = arrays[:]
+ for i in range(len(self.iterators)):
+ iter = self.iterators[i]
+ if not isinstance(iter, ConstantIterator):
+ self.final_iter = i
+ break
+ else:
+ self.final_iter = -1
+
+ def done(self):
+ final_iter = promote(self.final_iter)
+ if final_iter < 0:
return False
- return True
+ return self.iterators[final_iter].done()
-def components_hash(components):
- res = 0x345678
- for component in components:
- res = intmask((1000003 * res) ^ component.hash())
- return res
+ @unroll_safe
+ def next(self, shapelen):
+ for i in range(len(self.iterators)):
+ self.iterators[i] = self.iterators[i].next(shapelen)
-class BaseSignature(object):
- _attrs_ = []
+def _add_ptr_to_cache(ptr, cache):
+ i = 0
+ for p in cache:
+ if ptr == p:
+ return i
+ i += 1
+ else:
+ res = len(cache)
+ cache.append(ptr)
+ return res
- def eq(self, other):
- return self is other
+class Signature(object):
+ _attrs_ = ['iter_no', 'array_no']
+ _immutable_fields_ = ['iter_no', 'array_no']
+
+ array_no = 0
+ iter_no = 0
+
+ def invent_numbering(self):
+ cache = r_dict(sigeq_no_numbering, sighash)
+ allnumbers = []
+ self._invent_numbering(cache, allnumbers)
+
+ def invent_array_numbering(self, arr):
+ cache = []
+ self._invent_array_numbering(arr, cache)
+
+ def _invent_numbering(self, cache, allnumbers):
+ try:
+ no = cache[self]
+ except KeyError:
+ no = len(allnumbers)
+ cache[self] = no
+ allnumbers.append(no)
+ self.iter_no = no
+
+ def create_frame(self, arr, res_shape=None):
+ res_shape = res_shape or arr.shape
+ iterlist = []
+ arraylist = []
+ self._create_iter(iterlist, arraylist, arr, res_shape, [])
+ return NumpyEvalFrame(iterlist, arraylist)
+
+class ConcreteSignature(Signature):
+ _immutable_fields_ = ['dtype']
+
+ def __init__(self, dtype):
+ self.dtype = dtype
+
+ def eq(self, other, compare_array_no=True):
+ if type(self) is not type(other):
+ return False
+ assert isinstance(other, ConcreteSignature)
+ if compare_array_no:
+ if self.array_no != other.array_no:
+ return False
+ return self.dtype is other.dtype
def hash(self):
- return compute_identity_hash(self)
+ return compute_identity_hash(self.dtype)
-class Signature(BaseSignature):
- _known_sigs = r_dict(components_eq, components_hash)
+ def allocate_view_iter(self, arr, res_shape, chunklist):
+ r = arr.shape, arr.start, arr.strides, arr.backstrides
+ if chunklist:
+ for chunkelem in chunklist:
+ r = calculate_slice_strides(r[0], r[1], r[2], r[3], chunkelem)
+ shape, start, strides, backstrides = r
+ if len(res_shape) == 1:
+ return OneDimIterator(start, strides[0], res_shape[0])
+ return ViewIterator(start, strides, backstrides, shape, res_shape)
- _attrs_ = ["components"]
- _immutable_fields_ = ["components[*]"]
+class ArraySignature(ConcreteSignature):
+ def debug_repr(self):
+ return 'Array'
- def __init__(self, components):
- self.components = components
+ def _invent_array_numbering(self, arr, cache):
+ from pypy.module.micronumpy.interp_numarray import ConcreteArray
+ concr = arr.get_concrete()
+ assert isinstance(concr, ConcreteArray)
+ self.array_no = _add_ptr_to_cache(concr.storage, cache)
- @staticmethod
- def find_sig(components):
- return Signature._known_sigs.setdefault(components, Signature(components))
+ def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+ from pypy.module.micronumpy.interp_numarray import ConcreteArray
+ concr = arr.get_concrete()
+ assert isinstance(concr, ConcreteArray)
+ storage = concr.storage
+ if self.iter_no >= len(iterlist):
+ iterlist.append(self.allocate_iter(concr, res_shape, chunklist))
+ if self.array_no >= len(arraylist):
+ arraylist.append(storage)
-class Call1(BaseSignature):
- _immutable_fields_ = ["func", "name"]
+ def allocate_iter(self, arr, res_shape, chunklist):
+ if chunklist:
+ return self.allocate_view_iter(arr, res_shape, chunklist)
+ return ArrayIterator(arr.size)
- def __init__(self, func):
- self.func = func
- self.name = func.func_name
+ def eval(self, frame, arr):
+ iter = frame.iterators[self.iter_no]
+ return self.dtype.getitem(frame.arrays[self.array_no], iter.offset)
-class Call2(BaseSignature):
- _immutable_fields_ = ["func", "name"]
+class ScalarSignature(ConcreteSignature):
+ def debug_repr(self):
+ return 'Scalar'
- def __init__(self, func):
- self.func = func
- self.name = func.func_name
+ def _invent_array_numbering(self, arr, cache):
+ pass
+
+ def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+ if self.iter_no >= len(iterlist):
+ iter = ConstantIterator()
+ iterlist.append(iter)
+
+ def eval(self, frame, arr):
+ from pypy.module.micronumpy.interp_numarray import Scalar
+ assert isinstance(arr, Scalar)
+ return arr.value
+
+class ViewSignature(ArraySignature):
+ def debug_repr(self):
+ return 'Slice'
+
+ def _invent_numbering(self, cache, allnumbers):
+ # always invent a new number for view
+ no = len(allnumbers)
+ allnumbers.append(no)
+ self.iter_no = no
+
+ def allocate_iter(self, arr, res_shape, chunklist):
+ return self.allocate_view_iter(arr, res_shape, chunklist)
+
+class VirtualSliceSignature(Signature):
+ def __init__(self, child):
+ self.child = child
+
+ def _invent_array_numbering(self, arr, cache):
+ from pypy.module.micronumpy.interp_numarray import VirtualSlice
+ assert isinstance(arr, VirtualSlice)
+ self.child._invent_array_numbering(arr.child, cache)
+
+ def hash(self):
+ return intmask(self.child.hash() ^ 1234)
+
+ def eq(self, other, compare_array_no=True):
+ if type(self) is not type(other):
+ return False
+ assert isinstance(other, VirtualSliceSignature)
+ return self.child.eq(other.child, compare_array_no)
+
+ def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+ from pypy.module.micronumpy.interp_numarray import VirtualSlice
+ assert isinstance(arr, VirtualSlice)
+ chunklist.append(arr.chunks)
+ self.child._create_iter(iterlist, arraylist, arr.child, res_shape,
+ chunklist)
+
+ def eval(self, frame, arr):
+ from pypy.module.micronumpy.interp_numarray import VirtualSlice
+ assert isinstance(arr, VirtualSlice)
+ return self.child.eval(frame, arr.child)
+
+class Call1(Signature):
+ _immutable_fields_ = ['unfunc', 'name', 'child']
+
+ def __init__(self, func, name, child):
+ self.unfunc = func
+ self.child = child
+ self.name = name
+
+ def hash(self):
+ return compute_hash(self.name) ^ intmask(self.child.hash() << 1)
+
+ def eq(self, other, compare_array_no=True):
+ if type(self) is not type(other):
+ return False
+ assert isinstance(other, Call1)
+ return (self.unfunc is other.unfunc and
+ self.child.eq(other.child, compare_array_no))
+
+ def debug_repr(self):
+ return 'Call1(%s, %s)' % (self.name, self.child.debug_repr())
+
+ def _invent_numbering(self, cache, allnumbers):
+ self.child._invent_numbering(cache, allnumbers)
+
+ def _invent_array_numbering(self, arr, cache):
+ from pypy.module.micronumpy.interp_numarray import Call1
+ assert isinstance(arr, Call1)
+ self.child._invent_array_numbering(arr.values, cache)
+
+ def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+ from pypy.module.micronumpy.interp_numarray import Call1
+ assert isinstance(arr, Call1)
+ self.child._create_iter(iterlist, arraylist, arr.values, res_shape,
+ chunklist)
+
+ def eval(self, frame, arr):
+ from pypy.module.micronumpy.interp_numarray import Call1
+ assert isinstance(arr, Call1)
+ v = self.child.eval(frame, arr.values).convert_to(arr.res_dtype)
+ return self.unfunc(arr.res_dtype, v)
+
+class Call2(Signature):
+ _immutable_fields_ = ['binfunc', 'name', 'calc_dtype', 'left', 'right']
+
+ def __init__(self, func, name, calc_dtype, left, right):
+ self.binfunc = func
+ self.left = left
+ self.right = right
+ self.name = name
+ self.calc_dtype = calc_dtype
+
+ def hash(self):
+ return (compute_hash(self.name) ^ intmask(self.left.hash() << 1) ^
+ intmask(self.right.hash() << 2))
+
+ def eq(self, other, compare_array_no=True):
+ if type(self) is not type(other):
+ return False
+ assert isinstance(other, Call2)
+ return (self.binfunc is other.binfunc and
+ self.calc_dtype is other.calc_dtype and
+ self.left.eq(other.left, compare_array_no) and
+ self.right.eq(other.right, compare_array_no))
+
+ def _invent_array_numbering(self, arr, cache):
+ from pypy.module.micronumpy.interp_numarray import Call2
+ assert isinstance(arr, Call2)
+ self.left._invent_array_numbering(arr.left, cache)
+ self.right._invent_array_numbering(arr.right, cache)
+
+ def _invent_numbering(self, cache, allnumbers):
+ self.left._invent_numbering(cache, allnumbers)
+ self.right._invent_numbering(cache, allnumbers)
+
+ def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+ from pypy.module.micronumpy.interp_numarray import Call2
+
+ assert isinstance(arr, Call2)
+ self.left._create_iter(iterlist, arraylist, arr.left, res_shape,
+ chunklist)
+ self.right._create_iter(iterlist, arraylist, arr.right, res_shape,
+ chunklist)
+
+ def eval(self, frame, arr):
+ from pypy.module.micronumpy.interp_numarray import Call2
+ assert isinstance(arr, Call2)
+ lhs = self.left.eval(frame, arr.left).convert_to(self.calc_dtype)
+ rhs = self.right.eval(frame, arr.right).convert_to(self.calc_dtype)
+ return self.binfunc(self.calc_dtype, lhs, rhs)
+
+ def debug_repr(self):
+ return 'Call2(%s, %s, %s)' % (self.name, self.left.debug_repr(),
+ self.right.debug_repr())
+
+class ReduceSignature(Call2):
+ def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+ self.right._create_iter(iterlist, arraylist, arr, res_shape, chunklist)
+
+ def _invent_numbering(self, cache, allnumbers):
+ self.right._invent_numbering(cache, allnumbers)
+
+ def _invent_array_numbering(self, arr, cache):
+ self.right._invent_array_numbering(arr, cache)
+
+ def eval(self, frame, arr):
+ return self.right.eval(frame, arr)
diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/strides.py
@@ -0,0 +1,34 @@
+
+def calculate_slice_strides(shape, start, strides, backstrides, chunks):
+ rstrides = []
+ rbackstrides = []
+ rstart = start
+ rshape = []
+ i = -1
+ for i, (start_, stop, step, lgt) in enumerate(chunks):
+ if step != 0:
+ rstrides.append(strides[i] * step)
+ rbackstrides.append(strides[i] * (lgt - 1) * step)
+ rshape.append(lgt)
+ rstart += strides[i] * start_
+ # add a reminder
+ s = i + 1
+ assert s >= 0
+ rstrides += strides[s:]
+ rbackstrides += backstrides[s:]
+ rshape += shape[s:]
+ return rshape, rstart, rstrides, rbackstrides
+
+def calculate_broadcast_strides(strides, backstrides, orig_shape, res_shape):
+ rstrides = []
+ rbackstrides = []
+ for i in range(len(orig_shape)):
+ if orig_shape[i] == 1:
+ rstrides.append(0)
+ rbackstrides.append(0)
+ else:
+ rstrides.append(strides[i])
+ rbackstrides.append(backstrides[i])
+ rstrides = [0] * (len(res_shape) - len(orig_shape)) + rstrides
+ rbackstrides = [0] * (len(res_shape) - len(orig_shape)) + rbackstrides
+ return rstrides, rbackstrides
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -4,7 +4,6 @@
from pypy.module.micronumpy.interp_ufuncs import (find_binop_result_dtype,
find_unaryop_result_dtype)
-
class BaseNumpyAppTest(object):
def setup_class(cls):
cls.space = gettestobjspace(usemodules=['micronumpy'])
@@ -15,20 +14,37 @@
bool_dtype = get_dtype_cache(space).w_booldtype
ar = W_NDimArray(10, [10], dtype=float64_dtype)
+ ar2 = W_NDimArray(10, [10], dtype=float64_dtype)
v1 = ar.descr_add(space, ar)
v2 = ar.descr_add(space, Scalar(float64_dtype, 2.0))
- assert v1.signature is not v2.signature
+ sig1 = v1.find_sig()
+ sig2 = v2.find_sig()
+ assert v1 is not v2
+ assert sig1.left.iter_no == sig1.right.iter_no
+ assert sig2.left.iter_no != sig2.right.iter_no
+ assert sig1.left.array_no == sig1.right.array_no
+ sig1b = ar2.descr_add(space, ar).find_sig()
+ assert sig1b.left.array_no != sig1b.right.array_no
+ assert sig1b is not sig1
v3 = ar.descr_add(space, Scalar(float64_dtype, 1.0))
- assert v2.signature is v3.signature
+ sig3 = v3.find_sig()
+ assert sig2 is sig3
v4 = ar.descr_add(space, ar)
- assert v1.signature is v4.signature
+ assert v1.find_sig() is v4.find_sig()
bool_ar = W_NDimArray(10, [10], dtype=bool_dtype)
v5 = ar.descr_add(space, bool_ar)
- assert v5.signature is not v1.signature
- assert v5.signature is not v2.signature
+ assert v5.find_sig() is not v1.find_sig()
+ assert v5.find_sig() is not v2.find_sig()
v6 = ar.descr_add(space, bool_ar)
- assert v5.signature is v6.signature
+ assert v5.find_sig() is v6.find_sig()
+ v7 = v6.descr_add(space, v6)
+ sig7 = v7.find_sig()
+ assert sig7.left.left.iter_no == sig7.right.left.iter_no
+ assert sig7.left.left.iter_no != sig7.right.right.iter_no
+ assert sig7.left.right.iter_no == sig7.right.right.iter_no
+ v1.forced_result = ar
+ assert v1.find_sig() is not sig1
def test_slice_signature(self, space):
float64_dtype = get_dtype_cache(space).w_float64dtype
@@ -36,11 +52,14 @@
ar = W_NDimArray(10, [10], dtype=float64_dtype)
v1 = ar.descr_getitem(space, space.wrap(slice(1, 3, 1)))
v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1)))
- assert v1.signature is v2.signature
+ assert v1.find_sig() is v2.find_sig()
v3 = v2.descr_add(space, v1)
v4 = v1.descr_add(space, v2)
- assert v3.signature is v4.signature
+ assert v3.find_sig() is v4.find_sig()
+ v5 = ar.descr_add(space, ar).descr_getitem(space, space.wrap(slice(1, 3, 1)))
+ v6 = ar.descr_add(space, ar).descr_getitem(space, space.wrap(slice(1, 4, 1)))
+ assert v5.find_sig() is v6.find_sig()
class TestUfuncCoerscion(object):
def test_binops(self, space):
diff --git a/pypy/module/micronumpy/test/test_compile.py b/pypy/module/micronumpy/test/test_compile.py
--- a/pypy/module/micronumpy/test/test_compile.py
+++ b/pypy/module/micronumpy/test/test_compile.py
@@ -137,6 +137,16 @@
interp = self.run(code)
assert interp.results[0].value.value == 15
+ def test_sum2(self):
+ code = """
+ a = |30|
+ b = a + a
+ sum(b)
+ """
+ interp = self.run(code)
+ assert interp.results[0].value.value == 30 * (30 - 1)
+
+
def test_array_write(self):
code = """
a = [1,2,3,4,5]
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -8,8 +8,6 @@
class MockDtype(object):
- signature = signature.BaseSignature()
-
def malloc(self, size):
return None
@@ -38,92 +36,86 @@
assert a.backstrides == [135, 12, 2]
def test_create_slice_f(self):
- space = self.space
a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
- s = a.create_slice(space, [(3, 0, 0, 1)])
+ s = a.create_slice([(3, 0, 0, 1)])
assert s.start == 3
assert s.strides == [10, 50]
assert s.backstrides == [40, 100]
- s = a.create_slice(space, [(1, 9, 2, 4)])
+ s = a.create_slice([(1, 9, 2, 4)])
assert s.start == 1
assert s.strides == [2, 10, 50]
assert s.backstrides == [6, 40, 100]
- s = a.create_slice(space, [(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
+ s = a.create_slice([(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
assert s.shape == [2, 1]
assert s.strides == [3, 10]
assert s.backstrides == [3, 0]
- s = a.create_slice(space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+ s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
assert s.start == 20
assert s.shape == [10, 3]
def test_create_slice_c(self):
- space = self.space
a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'C')
- s = a.create_slice(space, [(3, 0, 0, 1)])
+ s = a.create_slice([(3, 0, 0, 1)])
assert s.start == 45
assert s.strides == [3, 1]
assert s.backstrides == [12, 2]
- s = a.create_slice(space, [(1, 9, 2, 4)])
+ s = a.create_slice([(1, 9, 2, 4)])
assert s.start == 15
assert s.strides == [30, 3, 1]
assert s.backstrides == [90, 12, 2]
- s = a.create_slice(space, [(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
+ s = a.create_slice([(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
assert s.start == 19
assert s.shape == [2, 1]
assert s.strides == [45, 3]
assert s.backstrides == [45, 0]
- s = a.create_slice(space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+ s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
assert s.start == 6
assert s.shape == [10, 3]
def test_slice_of_slice_f(self):
- space = self.space
a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
- s = a.create_slice(space, [(5, 0, 0, 1)])
+ s = a.create_slice([(5, 0, 0, 1)])
assert s.start == 5
- s2 = s.create_slice(space, [(3, 0, 0, 1)])
+ s2 = s.create_slice([(3, 0, 0, 1)])
assert s2.shape == [3]
assert s2.strides == [50]
assert s2.parent is a
assert s2.backstrides == [100]
assert s2.start == 35
- s = a.create_slice(space, [(1, 5, 3, 2)])
- s2 = s.create_slice(space, [(0, 2, 1, 2), (2, 0, 0, 1)])
+ s = a.create_slice([(1, 5, 3, 2)])
+ s2 = s.create_slice([(0, 2, 1, 2), (2, 0, 0, 1)])
assert s2.shape == [2, 3]
assert s2.strides == [3, 50]
assert s2.backstrides == [3, 100]
assert s2.start == 1 * 15 + 2 * 3
def test_slice_of_slice_c(self):
- space = self.space
a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), order='C')
- s = a.create_slice(space, [(5, 0, 0, 1)])
+ s = a.create_slice([(5, 0, 0, 1)])
assert s.start == 15 * 5
- s2 = s.create_slice(space, [(3, 0, 0, 1)])
+ s2 = s.create_slice([(3, 0, 0, 1)])
assert s2.shape == [3]
assert s2.strides == [1]
assert s2.parent is a
assert s2.backstrides == [2]
assert s2.start == 5 * 15 + 3 * 3
- s = a.create_slice(space, [(1, 5, 3, 2)])
- s2 = s.create_slice(space, [(0, 2, 1, 2), (2, 0, 0, 1)])
+ s = a.create_slice([(1, 5, 3, 2)])
+ s2 = s.create_slice([(0, 2, 1, 2), (2, 0, 0, 1)])
assert s2.shape == [2, 3]
assert s2.strides == [45, 1]
assert s2.backstrides == [45, 2]
assert s2.start == 1 * 15 + 2 * 3
def test_negative_step_f(self):
- space = self.space
a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
- s = a.create_slice(space, [(9, -1, -2, 5)])
+ s = a.create_slice([(9, -1, -2, 5)])
assert s.start == 9
assert s.strides == [-2, 10, 50]
assert s.backstrides == [-8, 40, 100]
def test_negative_step_c(self):
- space = self.space
a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), order='C')
- s = a.create_slice(space, [(9, -1, -2, 5)])
+ s = a.create_slice([(9, -1, -2, 5)])
assert s.start == 135
assert s.strides == [-30, 3, 1]
assert s.backstrides == [-120, 12, 2]
@@ -132,7 +124,7 @@
a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
r = a._index_of_single_item(self.space, self.newtuple(1, 2, 2))
assert r == 1 + 2 * 10 + 2 * 50
- s = a.create_slice(self.space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+ s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
r = s._index_of_single_item(self.space, self.newtuple(1, 0))
assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 0))
r = s._index_of_single_item(self.space, self.newtuple(1, 1))
@@ -142,7 +134,7 @@
a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'C')
r = a._index_of_single_item(self.space, self.newtuple(1, 2, 2))
assert r == 1 * 3 * 5 + 2 * 3 + 2
- s = a.create_slice(self.space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+ s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
r = s._index_of_single_item(self.space, self.newtuple(1, 0))
assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 0))
r = s._index_of_single_item(self.space, self.newtuple(1, 1))
@@ -897,13 +889,32 @@
a = zeros(1)
assert debug_repr(a) == 'Array'
assert debug_repr(a + a) == 'Call2(add, Array, Array)'
- assert debug_repr(a[::2]) == 'Slice(Array)'
+ assert debug_repr(a[::2]) == 'Slice'
assert debug_repr(a + 2) == 'Call2(add, Array, Scalar)'
- assert debug_repr(a + a.flat) == 'Call2(add, Array, FlatIter(Array))'
+ assert debug_repr(a + a.flat) == 'Call2(add, Array, Slice)'
assert debug_repr(sin(a)) == 'Call1(sin, Array)'
+
b = a + a
b[0] = 3
- assert debug_repr(b) == 'Call2(add, forced=Array)'
+ assert debug_repr(b) == 'Array'
+
+ def test_virtual_views(self):
+ from numpypy import arange
+ a = arange(15)
+ c = (a + a)
+ d = c[::2]
+ assert d[3] == 12
+ c[6] = 5
+ assert d[3] == 5
+ a = arange(15)
+ c = (a + a)
+ d = c[::2][::2]
+ assert d[1] == 8
+ b = a + a
+ c = b[::2]
+ c[:] = 3
+ assert b[0] == 3
+ assert b[1] == 2
def test_tolist_scalar(self):
from numpypy import int32, bool_
@@ -1075,10 +1086,10 @@
def test_broadcast_setslice(self):
from numpypy import zeros, ones
- a = zeros((100, 100))
- b = ones(100)
+ a = zeros((10, 10))
+ b = ones(10)
a[:, :] = b
- assert a[13, 15] == 1
+ assert a[3, 5] == 1
def test_broadcast_shape_agreement(self):
from numpypy import zeros, array
@@ -1112,6 +1123,14 @@
b[:] = (a + a)
assert (b == zeros((4, 3, 5))).all()
+ def test_broadcast_virtualview(self):
+ from numpypy import arange, zeros
+ a = arange(8).reshape([2, 2, 2])
+ b = (a + a)[1, 1]
+ c = zeros((2, 2, 2))
+ c[:] = b
+ assert (c == [[[12, 14], [12, 14]], [[12, 14], [12, 14]]]).all()
+
def test_argmax(self):
from numpypy import array
a = array([[1, 2], [3, 4], [5, 6]])
@@ -1173,6 +1192,11 @@
a = array([1, 2, 3])
assert dot(a.flat, a.flat) == 14
+ def test_flatiter_varray(self):
+ from numpypy import ones
+ a = ones((2, 2))
+ assert list(((a + a).flat)) == [2, 2, 2, 2]
+
def test_slice_copy(self):
from numpypy import zeros
a = zeros((10, 10))
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -49,10 +49,14 @@
interp.run(space)
w_res = interp.results[-1]
if isinstance(w_res, BaseArray):
- w_res = w_res.eval(w_res.start_iter())
-
+ concr = w_res.get_concrete_or_scalar()
+ sig = concr.find_sig()
+ frame = sig.create_frame(concr)
+ w_res = sig.eval(frame, concr)
if isinstance(w_res, interp_boxes.W_Float64Box):
return w_res.value
+ if isinstance(w_res, interp_boxes.W_Int64Box):
+ return float(w_res.value)
elif isinstance(w_res, interp_boxes.W_BoolBox):
return float(w_res.value)
raise TypeError(w_res)
@@ -78,8 +82,9 @@
def test_add(self):
result = self.run("add")
self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add': 1,
- 'setinteriorfield_raw': 1, 'int_add': 3,
- 'int_ge': 1, 'guard_false': 1, 'jump': 1})
+ 'setinteriorfield_raw': 1, 'int_add': 2,
+ 'int_ge': 1, 'guard_false': 1, 'jump': 1,
+ 'arraylen_gc': 1})
assert result == 3 + 3
def define_float_add():
@@ -93,7 +98,8 @@
assert result == 3 + 3
self.check_simple_loop({"getinteriorfield_raw": 1, "float_add": 1,
"setinteriorfield_raw": 1, "int_add": 2,
- "int_ge": 1, "guard_false": 1, "jump": 1})
+ "int_ge": 1, "guard_false": 1, "jump": 1,
+ 'arraylen_gc': 1})
def define_sum():
return """
@@ -106,8 +112,8 @@
result = self.run("sum")
assert result == 2 * sum(range(30))
self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 2,
- "int_add": 2, "int_ge": 1, "guard_false": 1,
- "jump": 1})
+ "int_add": 1, "int_ge": 1, "guard_false": 1,
+ "jump": 1, 'arraylen_gc': 1})
def define_prod():
return """
@@ -123,18 +129,22 @@
expected *= i * 2
assert result == expected
self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
- "float_mul": 1, "int_add": 2,
- "int_ge": 1, "guard_false": 1, "jump": 1})
+ "float_mul": 1, "int_add": 1,
+ "int_ge": 1, "guard_false": 1, "jump": 1,
+ 'arraylen_gc': 1})
- def test_max(self):
- py.test.skip("broken, investigate")
- result = self.run("""
+ def define_max():
+ return """
a = |30|
a[13] = 128
b = a + a
max(b)
- """)
+ """
+
+ def test_max(self):
+ result = self.run("max")
assert result == 256
+ py.test.skip("not there yet, getting though")
self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
"float_mul": 1, "int_add": 1,
"int_lt": 1, "guard_true": 1, "jump": 1})
@@ -164,9 +174,9 @@
result = self.run("any")
assert result == 1
self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
- "float_ne": 1, "int_add": 2,
+ "float_ne": 1, "int_add": 1,
"int_ge": 1, "jump": 1,
- "guard_false": 2})
+ "guard_false": 2, 'arraylen_gc': 1})
def define_already_forced():
return """
@@ -183,14 +193,13 @@
# This is the sum of the ops for both loops, however if you remove the
# optimization then you end up with 2 float_adds, so we can still be
# sure it was optimized correctly.
- # XXX the comment above is wrong now. We need preferrably a way to
- # count the two loops separately
- self.check_resops({'setinteriorfield_raw': 4, 'guard_nonnull': 1,
- 'getfield_gc': 35, 'getfield_gc_pure': 6,
- 'guard_class': 22, 'int_add': 8, 'float_mul': 2,
- 'guard_isnull': 2, 'jump': 2, 'int_ge': 4,
- 'getinteriorfield_raw': 4, 'float_add': 2, 'guard_false': 4,
- 'guard_value': 2})
+ self.check_resops({'setinteriorfield_raw': 4, 'getfield_gc': 26,
+ 'getarrayitem_gc': 4, 'getarrayitem_gc_pure': 2,
+ 'getfield_gc_pure': 4,
+ 'guard_class': 8, 'int_add': 8, 'float_mul': 2,
+ 'jump': 2, 'int_ge': 4,
+ 'getinteriorfield_raw': 4, 'float_add': 2,
+ 'guard_false': 4, 'arraylen_gc': 2, 'same_as': 2})
def define_ufunc():
return """
@@ -204,8 +213,9 @@
result = self.run("ufunc")
assert result == -6
self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1, "float_neg": 1,
- "setinteriorfield_raw": 1, "int_add": 3,
- "int_ge": 1, "guard_false": 1, "jump": 1})
+ "setinteriorfield_raw": 1, "int_add": 2,
+ "int_ge": 1, "guard_false": 1, "jump": 1,
+ 'arraylen_gc': 1})
def define_specialization():
return """
@@ -248,7 +258,8 @@
'setinteriorfield_raw': 1,
'int_add': 3,
'int_ge': 1, 'guard_false': 1,
- 'jump': 1})
+ 'jump': 1,
+ 'arraylen_gc': 1})
def define_multidim():
return """
@@ -263,8 +274,9 @@
# int_add might be 1 here if we try slightly harder with
# reusing indexes or some optimization
self.check_simple_loop({'float_add': 1, 'getinteriorfield_raw': 2,
- 'guard_false': 1, 'int_add': 3, 'int_ge': 1,
- 'jump': 1, 'setinteriorfield_raw': 1})
+ 'guard_false': 1, 'int_add': 2, 'int_ge': 1,
+ 'jump': 1, 'setinteriorfield_raw': 1,
+ 'arraylen_gc': 1})
def define_multidim_slice():
return """
@@ -312,7 +324,25 @@
self.check_trace_count(1)
self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add' : 1,
'setinteriorfield_raw': 1, 'int_add': 3,
- 'int_eq': 1, 'guard_false': 1, 'jump': 1})
+ 'int_lt': 1, 'guard_true': 1, 'jump': 1,
+ 'arraylen_gc': 3})
+
+ def define_virtual_slice():
+ return """
+ a = |30|
+ c = a + a
+ d = c -> 1:20
+ d -> 1
+ """
+
+ def test_virtual_slice(self):
+ result = self.run("virtual_slice")
+ assert result == 4
+ self.check_trace_count(1)
+ self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add' : 1,
+ 'setinteriorfield_raw': 1, 'int_add': 2,
+ 'int_ge': 1, 'guard_false': 1, 'jump': 1,
+ 'arraylen_gc': 1})
class TestNumpyOld(LLJitMixin):
def setup_class(cls):
diff --git a/pypy/module/micronumpy/test/test_ztranslation.py b/pypy/module/micronumpy/test/test_ztranslation.py
--- a/pypy/module/micronumpy/test/test_ztranslation.py
+++ b/pypy/module/micronumpy/test/test_ztranslation.py
@@ -1,5 +1,8 @@
-
+from pypy.module.micronumpy import signature
from pypy.objspace.fake.checkmodule import checkmodule
def test_numpy_translates():
+ # XXX: If there are signatures floating around this might explode. This fix
+ # is ugly.
+ signature.known_sigs.clear()
checkmodule('micronumpy')
diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -311,7 +311,7 @@
# to repeat it every time
ticker_check = """
guard_not_invalidated?
- ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+ ticker0 = getfield_raw(ticker_address, descr=<FieldS pypysig_long_struct.c_value .*>)
ticker_cond0 = int_lt(ticker0, 0)
guard_false(ticker_cond0, descr=...)
"""
@@ -320,9 +320,9 @@
# this is the ticker check generated if we have threads
thread_ticker_check = """
guard_not_invalidated?
- ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+ ticker0 = getfield_raw(ticker_address, descr=<FieldS pypysig_long_struct.c_value .*>)
ticker1 = int_sub(ticker0, _)
- setfield_raw(ticker_address, ticker1, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+ setfield_raw(ticker_address, ticker1, descr=<FieldS pypysig_long_struct.c_value .*>)
ticker_cond0 = int_lt(ticker1, 0)
guard_false(ticker_cond0, descr=...)
"""
@@ -330,7 +330,7 @@
#
# this is the ticker check generated in PyFrame.handle_operation_error
exc_ticker_check = """
- ticker2 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+ ticker2 = getfield_raw(ticker_address, descr=<FieldS pypysig_long_struct.c_value .*>)
ticker_cond1 = int_lt(ticker2, 0)
guard_false(ticker_cond1, descr=...)
"""
@@ -451,7 +451,6 @@
try:
self.match_loop(expected_ops, ignore_ops)
except InvalidMatch, e:
- #raise # uncomment this and use py.test --pdb for better debugging
print '@' * 40
print "Loops don't match"
print "================="
@@ -464,7 +463,7 @@
print
print "Expected:"
print format(expected_src)
- return False
+ raise # always propagate the exception in case of mismatch
else:
return True
diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
@@ -7,8 +7,9 @@
from pypy.tool.udir import udir
from pypy.tool import logparser
from pypy.jit.tool.jitoutput import parse_prof
-from pypy.module.pypyjit.test_pypy_c.model import Log, find_ids_range, find_ids, \
- TraceWithIds, OpMatcher
+from pypy.module.pypyjit.test_pypy_c.model import (Log, find_ids_range,
+ find_ids, TraceWithIds,
+ OpMatcher, InvalidMatch)
class BaseTestPyPyC(object):
def setup_class(cls):
@@ -115,13 +116,18 @@
assert opcodes_names == ['LOAD_FAST', 'LOAD_CONST', 'BINARY_ADD', 'STORE_FAST']
-class TestOpMatcher(object):
+class TestOpMatcher_(object):
def match(self, src1, src2, **kwds):
from pypy.tool.jitlogparser.parser import SimpleParser
loop = SimpleParser.parse_from_input(src1)
matcher = OpMatcher(loop.operations)
- return matcher.match(src2, **kwds)
+ try:
+ res = matcher.match(src2, **kwds)
+ assert res is True
+ return True
+ except InvalidMatch:
+ return False
def test_match_var(self):
match_var = OpMatcher([]).match_var
@@ -447,7 +453,7 @@
jump(p0, p1, p2, p3, i8, descr=...)
""")
#
- assert not loop.match("""
+ py.test.raises(InvalidMatch, loop.match, """
i6 = int_lt(i4, 1003)
guard_true(i6)
i8 = int_add(i5, 1) # variable mismatch
@@ -492,9 +498,8 @@
guard_no_exception(descr=...)
""")
#
- assert not loop.match_by_id('ntohs', """
+ py.test.raises(InvalidMatch, loop.match_by_id, 'ntohs', """
guard_not_invalidated(descr=...)
p12 = call(ConstClass(foobar), 1, descr=...)
guard_no_exception(descr=...)
""")
-
diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
@@ -35,7 +35,7 @@
guard_not_invalidated(descr=...)
i17 = force_token()
setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>)
- f21 = call_release_gil(%s, 2.000000, 3.000000, descr=<FloatCallDescr>)
+ f21 = call_release_gil(%s, 2.000000, 3.000000, descr=<Callf 8 ff EF=6>)
guard_not_forced(descr=...)
guard_no_exception(descr=...)
""" % pow_addr)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py
--- a/pypy/module/pypyjit/test_pypy_c/test_array.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_array.py
@@ -42,7 +42,7 @@
guard_not_invalidated(descr=...)
i13 = int_lt(i7, i9)
guard_true(i13, descr=...)
- i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>)
+ i15 = getarrayitem_raw(i10, i7, descr=<ArrayS .>)
i16 = int_add_ovf(i8, i15)
guard_no_overflow(descr=...)
i18 = int_add(i7, 1)
@@ -72,17 +72,17 @@
guard_true(i13, descr=...)
guard_not_invalidated(descr=...)
# the bound check guard on img has been killed (thanks to the asserts)
- i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>)
+ i14 = getarrayitem_raw(i10, i8, descr=<ArrayS .>)
i15 = int_add_ovf(i9, i14)
guard_no_overflow(descr=...)
i17 = int_sub(i8, 640)
# the bound check guard on intimg has been killed (thanks to the asserts)
- i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>)
+ i18 = getarrayitem_raw(i11, i17, descr=<ArrayS .>)
i19 = int_add_ovf(i18, i15)
guard_no_overflow(descr=...)
# on 64bit, there is a guard checking that i19 actually fits into 32bit
...
- setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>)
+ setarrayitem_raw(i11, i8, _, descr=<ArrayS .>)
i28 = int_add(i8, 1)
--TICK--
jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=...)
@@ -107,10 +107,10 @@
guard_true(i10, descr=...)
i11 = int_lt(i6, i7)
guard_true(i11, descr=...)
- f13 = getarrayitem_raw(i8, i6, descr=<FloatArrayNoLengthDescr>)
+ f13 = getarrayitem_raw(i8, i6, descr=<ArrayF 8>)
f15 = float_add(f13, 20.500000)
- setarrayitem_raw(i8, i6, f15, descr=<FloatArrayNoLengthDescr>)
- f16 = getarrayitem_raw(i8, i6, descr=<FloatArrayNoLengthDescr>)
+ setarrayitem_raw(i8, i6, f15, descr=<ArrayF 8>)
+ f16 = getarrayitem_raw(i8, i6, descr=<ArrayF 8>)
i18 = float_eq(f16, 42.000000)
guard_true(i18, descr=...)
i20 = int_add(i6, 1)
@@ -132,28 +132,24 @@
log = self.run(main, [])
assert log.result == 321
loop, = log.loops_by_filename(self.filepath)
- if sys.maxint == 2147483647:
- arraydescr = 'UnsignedArrayNoLengthDescr'
- else:
- arraydescr = 'UINTArrayNoLengthDescr'
assert loop.match("""
i10 = int_lt(i6, 1000)
guard_true(i10, descr=...)
i11 = int_lt(i6, i7)
guard_true(i11, descr=...)
- i13 = getarrayitem_raw(i8, i6, descr=<%s>)
+ i13 = getarrayitem_raw(i8, i6, descr=<Array. 4>)
f14 = cast_singlefloat_to_float(i13)
f16 = float_add(f14, 20.500000)
i17 = cast_float_to_singlefloat(f16)
- setarrayitem_raw(i8, i6,i17, descr=<%s>)
- i18 = getarrayitem_raw(i8, i6, descr=<%s>)
+ setarrayitem_raw(i8, i6,i17, descr=<Array. 4>)
+ i18 = getarrayitem_raw(i8, i6, descr=<Array. 4>)
f19 = cast_singlefloat_to_float(i18)
i21 = float_eq(f19, 42.000000)
guard_true(i21, descr=...)
i23 = int_add(i6, 1)
--TICK--
jump(..., descr=...)
- """ % (arraydescr, arraydescr, arraydescr))
+ """)
def test_zeropadded(self):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -75,12 +75,12 @@
assert log.opnames(ops) == []
#
assert entry_bridge.match_by_id('call', """
- p38 = call(ConstClass(getexecutioncontext), descr=<GcPtrCallDescr>)
- p39 = getfield_gc(p38, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
+ p38 = call(ConstClass(getexecutioncontext), descr=<Callr . EF=1>)
+ p39 = getfield_gc(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
i40 = force_token()
- p41 = getfield_gc(p38, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
+ p41 = getfield_gc(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
guard_isnull(p41, descr=...)
- i42 = getfield_gc(p38, descr=<NonGcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
+ i42 = getfield_gc(p38, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
i43 = int_is_zero(i42)
guard_true(i43, descr=...)
i50 = force_token()
@@ -192,7 +192,7 @@
assert log.result == 1000
loop, = log.loops_by_id('call')
assert loop.match_by_id('call', """
- p14 = getarrayitem_gc_pure(p8, i9, descr=<GcPtrArrayDescr>)
+ p14 = getarrayitem_gc_pure(p8, i9, descr=<ArrayP .>)
i14 = force_token()
i16 = force_token()
""")
@@ -336,15 +336,15 @@
loop, = log.loops_by_filename(self.filepath)
# the int strategy is used here
assert loop.match_by_id('append', """
- i13 = getfield_gc(p8, descr=<SignedFieldDescr list.length .*>)
+ i13 = getfield_gc(p8, descr=<FieldS list.length .*>)
i15 = int_add(i13, 1)
# Will be killed by the backend
- p15 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
- i17 = arraylen_gc(p15, descr=<SignedArrayDescr>)
- call(_, p8, i15, descr=<VoidCallDescr>) # this is a call to _ll_list_resize_ge_trampoline__...
+ p15 = getfield_gc(p8, descr=<FieldP list.items .*>)
+ i17 = arraylen_gc(p15, descr=<ArrayS .>)
+ call(_, p8, i15, descr=<Callv 0 ri EF=4>) # this is a call to _ll_list_resize_ge_trampoline__...
guard_no_exception(descr=...)
- p17 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
- setarrayitem_gc(p17, i13, i12, descr=<SignedArrayDescr>)
+ p17 = getfield_gc(p8, descr=<FieldP list.items .*>)
+ setarrayitem_gc(p17, i13, i12, descr=<ArrayS .>)
""")
def test_blockstack_virtualizable(self):
@@ -368,13 +368,13 @@
...
i20 = force_token()
p22 = new_with_vtable(19511408)
- p24 = new_array(1, descr=<GcPtrArrayDescr>)
+ p24 = new_array(1, descr=<ArrayP .>)
p26 = new_with_vtable(ConstClass(W_ListObject))
- setfield_gc(p0, i20, descr=<SignedFieldDescr .*PyFrame.vable_token .*>)
- setfield_gc(p26, ConstPtr(ptr22), descr=<GcPtrFieldDescr pypy.objspace.std.listobject.W_ListObject.inst_strategy .*>)
- setarrayitem_gc(p24, 0, p26, descr=<GcPtrArrayDescr>)
- setfield_gc(p22, p24, descr=<GcPtrFieldDescr .*Arguments.inst_arguments_w .*>)
- p32 = call_may_force(11376960, p18, p22, descr=<GcPtrCallDescr>)
+ setfield_gc(p0, i20, descr=<FieldS .*PyFrame.vable_token .*>)
+ setfield_gc(p26, ConstPtr(ptr22), descr=<FieldP pypy.objspace.std.listobject.W_ListObject.inst_strategy .*>)
+ setarrayitem_gc(p24, 0, p26, descr=<ArrayP .>)
+ setfield_gc(p22, p24, descr=<FieldP .*Arguments.inst_arguments_w .*>)
+ p32 = call_may_force(11376960, p18, p22, descr=<Callr . rr EF=6>)
...
""")
@@ -415,26 +415,26 @@
guard_nonnull_class(p8, ConstClass(W_IntObject), descr=...)
guard_value(i4, 0, descr=...)
guard_value(p3, ConstPtr(ptr14), descr=...)
- i15 = getfield_gc_pure(p8, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+ i15 = getfield_gc_pure(p8, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
i17 = int_lt(i15, 5000)
guard_true(i17, descr=...)
- p18 = getfield_gc(p0, descr=<GcPtrFieldDescr pypy.interpreter.eval.Frame.inst_w_globals .*>)
+ p18 = getfield_gc(p0, descr=<FieldP pypy.interpreter.eval.Frame.inst_w_globals .*>)
guard_value(p18, ConstPtr(ptr19), descr=...)
- p20 = getfield_gc(p18, descr=<GcPtrFieldDescr pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy .*>)
+ p20 = getfield_gc(p18, descr=<FieldP pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy .*>)
guard_value(p20, ConstPtr(ptr21), descr=...)
guard_not_invalidated(descr=...)
# most importantly, there is no getarrayitem_gc here
- p23 = call(ConstClass(getexecutioncontext), descr=<GcPtrCallDescr>)
- p24 = getfield_gc(p23, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
+ p23 = call(ConstClass(getexecutioncontext), descr=<Callr . EF=1>)
+ p24 = getfield_gc(p23, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
i25 = force_token()
- p26 = getfield_gc(p23, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
+ p26 = getfield_gc(p23, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
guard_isnull(p26, descr=...)
- i27 = getfield_gc(p23, descr=<NonGcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
+ i27 = getfield_gc(p23, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
i28 = int_is_zero(i27)
guard_true(i28, descr=...)
- p30 = getfield_gc(ConstPtr(ptr29), descr=<GcPtrFieldDescr pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
+ p30 = getfield_gc(ConstPtr(ptr29), descr=<FieldP pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
guard_nonnull_class(p30, ConstClass(W_IntObject), descr=...)
- i32 = getfield_gc_pure(p30, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+ i32 = getfield_gc_pure(p30, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
i33 = int_add_ovf(i15, i32)
guard_no_overflow(descr=...)
--TICK--
@@ -452,15 +452,15 @@
""", [])
loop, = log.loops_by_id('call')
assert loop.match("""
- i8 = getfield_gc_pure(p6, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+ i8 = getfield_gc_pure(p6, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
i10 = int_lt(i8, 5000)
guard_true(i10, descr=...)
i11 = force_token()
i13 = int_add(i8, 1)
--TICK--
p22 = new_with_vtable(ConstClass(W_IntObject))
- setfield_gc(p22, i13, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
- setfield_gc(p4, p22, descr=<GcPtrFieldDescr pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
+ setfield_gc(p22, i13, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+ setfield_gc(p4, p22, descr=<FieldP pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
jump(p0, p1, p2, p3, p4, p7, p22, p7, descr=...)
""")
diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_containers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py
@@ -46,7 +46,7 @@
assert loop.match_by_id("getitem", """
i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...)
...
- p33 = getinteriorfield_gc(p31, i26, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
+ p33 = getinteriorfield_gc(p31, i26, descr=<InteriorFieldDescr <FieldP dictentry.value .*>>)
...
""")
@@ -86,28 +86,28 @@
i8 = int_lt(i5, i7)
guard_true(i8, descr=...)
guard_not_invalidated(descr=...)
- p10 = call(ConstClass(ll_int_str), i5, descr=<GcPtrCallDescr>)
+ p10 = call(ConstClass(ll_int_str), i5, descr=<Callr . i EF=3>)
guard_no_exception(descr=...)
- i12 = call(ConstClass(ll_strhash), p10, descr=<SignedCallDescr>)
+ i12 = call(ConstClass(ll_strhash), p10, descr=<Calli . r EF=0>)
p13 = new(descr=...)
- p15 = new_array(8, descr=<dictentryArrayDescr>)
- setfield_gc(p13, p15, descr=<GcPtrFieldDescr dicttable.entries .*>)
- i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<SignedCallDescr>)
- setfield_gc(p13, 16, descr=<SignedFieldDescr dicttable.resize_counter .*>)
+ p15 = new_array(8, descr=<ArrayX .*>)
+ setfield_gc(p13, p15, descr=<FieldP dicttable.entries .*>)
+ i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<Calli . rri EF=4>)
+ setfield_gc(p13, 16, descr=<FieldS dicttable.resize_counter .*>)
guard_no_exception(descr=...)
p20 = new_with_vtable(ConstClass(W_IntObject))
- call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=<VoidCallDescr>)
- setfield_gc(p20, i5, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
+ call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=<Callv 0 rrrii EF=4>)
+ setfield_gc(p20, i5, descr=<FieldS .*W_IntObject.inst_intval .*>)
guard_no_exception(descr=...)
- i23 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<SignedCallDescr>)
+ i23 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<Calli . rri EF=4>)
guard_no_exception(descr=...)
i26 = int_and(i23, .*)
i27 = int_is_true(i26)
guard_false(i27, descr=...)
- p28 = getfield_gc(p13, descr=<GcPtrFieldDescr dicttable.entries .*>)
- p29 = getinteriorfield_gc(p28, i23, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
+ p28 = getfield_gc(p13, descr=<FieldP dicttable.entries .*>)
+ p29 = getinteriorfield_gc(p28, i23, descr=<InteriorFieldDescr <FieldP dictentry.value .*>>)
guard_nonnull_class(p29, ConstClass(W_IntObject), descr=...)
- i31 = getfield_gc_pure(p29, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
+ i31 = getfield_gc_pure(p29, descr=<FieldS .*W_IntObject.inst_intval .*>)
i32 = int_sub_ovf(i31, i5)
guard_no_overflow(descr=...)
i34 = int_add_ovf(i32, 1)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py
--- a/pypy/module/pypyjit/test_pypy_c/test_generators.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py
@@ -21,9 +21,9 @@
assert loop.match_by_id("generator", """
i16 = force_token()
p45 = new_with_vtable(ConstClass(W_IntObject))
- setfield_gc(p45, i29, descr=<SignedFieldDescr .*>)
- setarrayitem_gc(p8, 0, p45, descr=<GcPtrArrayDescr>)
- i47 = arraylen_gc(p8, descr=<GcPtrArrayDescr>) # Should be removed by backend
+ setfield_gc(p45, i29, descr=<FieldS .*>)
+ setarrayitem_gc(p8, 0, p45, descr=<ArrayP .>)
+ i47 = arraylen_gc(p8, descr=<ArrayP .>) # Should be removed by backend
jump(..., descr=...)
""")
assert loop.match_by_id("subtract", """
diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py
--- a/pypy/module/pypyjit/test_pypy_c/test_globals.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py
@@ -16,11 +16,11 @@
assert log.result == 500
loop, = log.loops_by_filename(self.filepath)
assert loop.match_by_id("loadglobal", """
- p10 = getfield_gc(p0, descr=<GcPtrFieldDescr .*Frame.inst_w_globals .*>)
+ p10 = getfield_gc(p0, descr=<FieldP .*Frame.inst_w_globals .*>)
guard_value(p10, ConstPtr(ptr11), descr=...)
- p12 = getfield_gc(p10, descr=<GcPtrFieldDescr .*W_DictMultiObject.inst_strategy .*>)
+ p12 = getfield_gc(p10, descr=<FieldP .*W_DictMultiObject.inst_strategy .*>)
guard_value(p12, ConstPtr(ptr13), descr=...)
guard_not_invalidated(descr=...)
- p19 = getfield_gc(ConstPtr(p17), descr=<GcPtrFieldDescr .*W_DictMultiObject.inst_strategy .*>)
+ p19 = getfield_gc(ConstPtr(p17), descr=<FieldP .*W_DictMultiObject.inst_strategy .*>)
guard_value(p19, ConstPtr(ptr20), descr=...)
- """)
\ No newline at end of file
+ """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py
--- a/pypy/module/pypyjit/test_pypy_c/test_instance.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py
@@ -125,8 +125,8 @@
i12 = force_token()
--TICK--
p20 = new_with_vtable(ConstClass(W_IntObject))
- setfield_gc(p20, i11, descr=<SignedFieldDescr.*W_IntObject.inst_intval .*>)
- setfield_gc(ConstPtr(ptr21), p20, descr=<GcPtrFieldDescr .*TypeCell.inst_w_value .*>)
+ setfield_gc(p20, i11, descr=<FieldS.*W_IntObject.inst_intval .*>)
+ setfield_gc(ConstPtr(ptr21), p20, descr=<FieldP .*TypeCell.inst_w_value .*>)
jump(p0, p1, p2, p3, p4, p20, p6, i7, p20, descr=...)
""")
diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py
--- a/pypy/module/pypyjit/test_pypy_c/test_math.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_math.py
@@ -23,8 +23,8 @@
f1 = cast_int_to_float(i0)
i3 = float_le(f1, 0)
guard_false(i3, descr=...)
- f2 = call(ConstClass(log), f1, descr=<FloatCallDescr>)
- f3 = call(ConstClass(log10), f1, descr=<FloatCallDescr>)
+ f2 = call(ConstClass(log), f1, descr=<Callf . f EF=2>)
+ f3 = call(ConstClass(log10), f1, descr=<Callf . f EF=2>)
f4 = float_sub(f2, f3)
f5 = float_add(f0, f4)
i4 = int_add(i0, 1)
@@ -52,8 +52,8 @@
f1 = cast_int_to_float(i0)
i6 = --ISINF--(f1)
guard_false(i6, descr=...)
- f2 = call(ConstClass(sin), f1, descr=<FloatCallDescr>)
- f3 = call(ConstClass(cos), f1, descr=<FloatCallDescr>)
+ f2 = call(ConstClass(sin), f1, descr=<Callf . f EF=2>)
+ f3 = call(ConstClass(cos), f1, descr=<Callf . f EF=2>)
f4 = float_sub(f2, f3)
f5 = float_add(f0, f4)
i7 = int_add(i0, f1)
@@ -84,7 +84,7 @@
i4 = int_or(i2, i3)
i5 = int_is_true(i4)
guard_false(i5, descr=...)
- f2 = call(ConstClass(fmod), f1, 2.0, descr=<FloatCallDescr>)
+ f2 = call(ConstClass(fmod), f1, 2.0, descr=<Callf . ff EF=2>)
f3 = float_add(f0, f2)
i6 = int_sub(i0, 1)
--TICK--
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -46,7 +46,7 @@
r *= n
n -= 1
return r
- log = self.run(fact, [7], threshold=5)
+ log = self.run(fact, [7], threshold=4)
assert log.result == 5040
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
@@ -204,18 +204,18 @@
assert log.result == 1000000
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
- i14 = getfield_gc(p12, descr=<SignedFieldDescr list.length .*>)
+ i14 = getfield_gc(p12, descr=<FieldS list.length .*>)
i16 = uint_ge(i12, i14)
guard_false(i16, descr=...)
- p16 = getfield_gc(p12, descr=<GcPtrFieldDescr list.items .*>)
- p17 = getarrayitem_gc(p16, i12, descr=<GcPtrArrayDescr>)
+ p16 = getfield_gc(p12, descr=<FieldP list.items .*>)
+ p17 = getarrayitem_gc(p16, i12, descr=<ArrayP .>)
i19 = int_add(i12, 1)
- setfield_gc(p9, i19, descr=<SignedFieldDescr .*W_AbstractSeqIterObject.inst_index .*>)
+ setfield_gc(p9, i19, descr=<FieldS .*W_AbstractSeqIterObject.inst_index .*>)
guard_nonnull_class(p17, 146982464, descr=...)
- i21 = getfield_gc(p17, descr=<SignedFieldDescr .*W_ArrayTypei.inst_len .*>)
+ i21 = getfield_gc(p17, descr=<FieldS .*W_ArrayTypei.inst_len .*>)
i23 = int_lt(0, i21)
guard_true(i23, descr=...)
- i24 = getfield_gc(p17, descr=<NonGcPtrFieldDescr .*W_ArrayTypei.inst_buffer .*>)
+ i24 = getfield_gc(p17, descr=<FieldU .*W_ArrayTypei.inst_buffer .*>)
i25 = getarrayitem_raw(i24, 0, descr=<.*>)
i27 = int_lt(1, i21)
guard_false(i27, descr=...)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -1,6 +1,9 @@
from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
+# XXX review the <Call> descrs to replace some EF=4 with EF=3 (elidable)
+
+
class TestString(BaseTestPyPyC):
def test_lookup_default_encoding(self):
def main(n):
@@ -52,8 +55,8 @@
i += int(long(string.digits[i % len(string.digits)], 16))
return i
- log = self.run(main, [1000])
- assert log.result == main(1000)
+ log = self.run(main, [1100])
+ assert log.result == main(1100)
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i11 = int_lt(i6, i7)
@@ -72,7 +75,7 @@
i23 = strgetitem(p10, i19)
p25 = newstr(1)
strsetitem(p25, 0, i23)
- p28 = call(ConstClass(strip_spaces), p25, descr=<GcPtrCallDescr>)
+ p28 = call(ConstClass(strip_spaces), p25, descr=<Callr . r EF=4>)
guard_no_exception(descr=...)
i29 = strlen(p28)
i30 = int_is_true(i29)
@@ -88,9 +91,9 @@
guard_false(i41, descr=...)
i43 = int_eq(i39, 43)
guard_false(i43, descr=...)
- i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=<BoolCallDescr>)
+ i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=<Calli 1 rr EF=0>)
guard_false(i43, descr=...)
- i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=<BoolCallDescr>)
+ i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=<Calli 1 rr EF=0>)
guard_false(i46, descr=...)
p51 = new_with_vtable(21136408)
setfield_gc(p51, _, descr=...) # 7 setfields, but the order is dict-order-dependent
@@ -100,9 +103,9 @@
setfield_gc(p51, _, descr=...)
setfield_gc(p51, _, descr=...)
setfield_gc(p51, _, descr=...)
- p55 = call(ConstClass(parse_digit_string), p51, descr=<GcPtrCallDescr>)
+ p55 = call(ConstClass(parse_digit_string), p51, descr=<Callr . r EF=4>)
guard_no_exception(descr=...)
- i57 = call(ConstClass(rbigint.toint), p55, descr=<SignedCallDescr>)
+ i57 = call(ConstClass(rbigint.toint), p55, descr=<Calli . r EF=3>)
guard_no_exception(descr=...)
i58 = int_add_ovf(i6, i57)
guard_no_overflow(descr=...)
@@ -125,7 +128,7 @@
i7 = int_gt(i4, 0)
guard_true(i7, descr=...)
guard_not_invalidated(descr=...)
- p9 = call(ConstClass(ll_int2dec__Signed), i4, descr=<GcPtrCallDescr>)
+ p9 = call(ConstClass(ll_int2dec__Signed), i4, descr=<Callr . i EF=3>)
guard_no_exception(descr=...)
i10 = strlen(p9)
i11 = int_is_true(i10)
@@ -149,7 +152,7 @@
copystrcontent(p9, p21, 0, i25, i10)
i33 = int_lt(i30, 23)
guard_true(i33, descr=...)
- p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=<GcPtrCallDescr>)
+ p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=<Callr . ri EF=4>)
guard_no_exception(descr=...)
i37 = strlen(p35)
i38 = int_add_ovf(i5, i37)
@@ -192,6 +195,6 @@
strsetitem(p35, 3, 104)
strsetitem(p35, 4, 95)
copystrcontent(p31, p35, 0, 5, i32)
- i49 = call(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=<SignedCallDescr>)
- guard_value(i49, 1, descr=<Guard8>)
+ i49 = call(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=<Calli [48] rr EF=0 OS=28>)
+ guard_value(i49, 1, descr=...)
''')
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -252,7 +252,7 @@
# grow the list
done = 0
while done < len(self._seen_extras):
- print self._seen_extras
+ #print self._seen_extras
ann.build_types(self._seen_extras[done], [],
complete_now=False)
done += 1
diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -514,29 +514,34 @@
if maxsplit == 0:
return space.wrap(input)
- # An ok guess at the default size
- builder = StringBuilder(len(input))
- first = True
-
if not sub:
upper = len(input)
if maxsplit > 0 and maxsplit < upper + 2:
upper = maxsplit - 1
assert upper >= 0
- first = False
+
try:
- for i in range(upper):
- builder.append(by)
- builder.append(input[i])
+ result_size = ovfcheck(upper * len(by))
+ result_size = ovfcheck(result_size + upper)
+ result_size = ovfcheck(result_size + len(by))
+ remaining_size = len(input) - upper
+ result_size = ovfcheck(result_size + remaining_size)
+ except OverflowError:
+ raise OperationError(space.w_OverflowError,
+ space.wrap("replace string is too long")
+ )
+ builder = StringBuilder(result_size)
+ for i in range(upper):
builder.append(by)
- builder.append_slice(input, upper, len(input))
- except MemoryError:
- raise OperationError(space.w_OverflowError,
- space.wrap("replace string too long")
- )
+ builder.append(input[i])
+ builder.append(by)
+ builder.append_slice(input, upper, len(input))
else:
+ # An ok guess for the result size
+ builder = StringBuilder(len(input))
start = 0
sublen = len(sub)
+ first = True
while maxsplit != 0:
next = input.find(sub, start)
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -395,7 +395,6 @@
'retrace_limit': 5,
'max_retrace_guards': 15,
'enable_opts': 'all',
- 'decay_halflife': 40,
}
unroll_parameters = unrolling_iterable(PARAMETERS.items())
DEFAULT = object()
diff --git a/testrunner/runner.py b/testrunner/runner.py
--- a/testrunner/runner.py
+++ b/testrunner/runner.py
@@ -21,6 +21,16 @@
win32api.CloseHandle(proch)
except pywintypes.error, e:
pass
+ #Try to avoid opeing a dialog box if one of the tests causes a system error
+ import ctypes
+ winapi = ctypes.windll.kernel32
+ SEM_FAILCRITICALERRORS = 1
+ SEM_NOGPFAULTERRORBOX = 2
+ SEM_NOOPENFILEERRORBOX = 0x8000
+ flags = SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX
+ #Since there is no GetErrorMode, do a double Set
+ old_mode = winapi.SetErrorMode(flags)
+ winapi.SetErrorMode(old_mode | flags)
SIGKILL = SIGTERM = 0
READ_MODE = 'rU'
More information about the pypy-commit
mailing list