[pypy-commit] pypy py3k: merge default
pjenvey
noreply at buildbot.pypy.org
Fri Mar 21 00:02:33 CET 2014
Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k
Changeset: r70135:706e3a4c1ffa
Date: 2014-03-20 15:41 -0700
http://bitbucket.org/pypy/pypy/changeset/706e3a4c1ffa/
Log: merge default
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -292,6 +292,10 @@
depending on the compiler settings, the default of 768KB is enough
for about 1400 calls.
+* since the implementation of dictionary is different, the exact number
+ which ``__hash__`` and ``__eq__`` are called is different. Since CPython
+ does not give any specific guarantees either, don't rely on it.
+
* assignment to ``__class__`` is limited to the cases where it
works on CPython 2.5. On CPython 2.6 and 2.7 it works in a bit
more cases, which are not supported by PyPy so far. (If needed,
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -114,3 +114,6 @@
app-level. The `Buffer` class is now used by `W_MemoryView` and
`W_Buffer`, which is not present in Python 3. Previously `W_Buffer` was
an alias to `Buffer`, which was wrappable itself.
+
+.. branch: improve-consecutive-dict-lookups
+Improve the situation when dict lookups of the same key are performed in a chain
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -441,11 +441,10 @@
return name
- def getbuiltinmodule(self, name, force_init=False, reuse=True):
+ def getbuiltinmodule(self, name, force_init=False):
w_name = self.wrap(name)
w_modules = self.sys.get('modules')
if not force_init:
- assert reuse is True
try:
return self.getitem(w_modules, w_name)
except OperationError, e:
@@ -464,15 +463,7 @@
# Initialize the module
from pypy.interpreter.module import Module
if isinstance(w_mod, Module):
- if not reuse and w_mod.startup_called:
- # Create a copy of the module
- w_mod.getdict(self) # unlazy w_initialdict
- w_new = self.wrap(Module(self, w_name))
- self.call_method(w_new.getdict(self), 'update',
- w_mod.w_initialdict)
- w_mod = w_new
- else:
- w_mod.init(self)
+ w_mod.init(self)
# Add the module to sys.modules
self.setitem(w_modules, w_name, w_mod)
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -585,8 +585,7 @@
return space.call_method(find_info.w_loader, "load_module", w_modulename)
if find_info.modtype == C_BUILTIN:
- return space.getbuiltinmodule(find_info.filename, force_init=True,
- reuse=reuse)
+ return space.getbuiltinmodule(find_info.filename, force_init=True)
if find_info.modtype in (PY_SOURCE, PY_COMPILED, C_EXTENSION, PKG_DIRECTORY):
w_mod = None
diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py
--- a/pypy/module/imp/test/test_app.py
+++ b/pypy/module/imp/test/test_app.py
@@ -219,6 +219,7 @@
def test_builtin_reimport(self):
# from https://bugs.pypy.org/issue1514
+ skip("fix me")
import sys, marshal
old = marshal.loads
@@ -238,6 +239,7 @@
# taken from https://bugs.pypy.org/issue1514, with extra cases
# that show a difference with CPython: we can get on CPython
# several module objects for the same built-in module :-(
+ skip("several built-in module objects: not supported by pypy")
import sys, marshal
old = marshal.loads
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -652,6 +652,7 @@
assert hasattr(time, 'clock')
def test_reimport_builtin_simple_case_2(self):
+ skip("fix me")
import sys, time
time.foo = "bar"
del sys.modules['time']
@@ -660,6 +661,7 @@
def test_reimport_builtin(self):
import imp, sys, time
+ skip("fix me")
oldpath = sys.path
time.tzset = "<test_reimport_builtin removed this>"
diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -583,6 +583,10 @@
emit_op_getfield_raw_pure = emit_op_getfield_gc
emit_op_getfield_gc_pure = emit_op_getfield_gc
+ def emit_op_increment_debug_counter(self, op, arglocs, regalloc, fcond):
+ # XXX implement me
+ return fcond
+
def emit_op_getinteriorfield_gc(self, op, arglocs, regalloc, fcond):
(base_loc, index_loc, res_loc,
ofs_loc, ofs, itemsize, fieldsize) = arglocs
diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -849,6 +849,10 @@
prepare_op_getfield_raw_pure = prepare_op_getfield_gc
prepare_op_getfield_gc_pure = prepare_op_getfield_gc
+ def prepare_op_increment_debug_counter(self, op, fcond):
+ # XXX implement me
+ return []
+
def prepare_op_getinteriorfield_gc(self, op, fcond):
t = unpack_interiorfielddescr(op.getdescr())
ofs, itemsize, fieldsize, sign = t
diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -553,6 +553,10 @@
else:
return self.bh_raw_load_i(struct, offset, descr)
+ def bh_increment_debug_counter(self, addr):
+ p = rffi.cast(rffi.CArrayPtr(lltype.Signed), addr)
+ p[0] += 1
+
def unpack_arraydescr_size(self, arraydescr):
from rpython.jit.backend.llsupport.symbolic import get_array_token
from rpython.jit.backend.llsupport.descr import get_type_flag, FLAG_SIGNED
diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -15,7 +15,7 @@
DEBUG_COUNTER = lltype.Struct('DEBUG_COUNTER',
# 'b'ridge, 'l'abel or # 'e'ntry point
- ('i', lltype.Signed),
+ ('i', lltype.Signed), # first field, at offset 0
('type', lltype.Char),
('number', lltype.Signed)
)
@@ -64,7 +64,6 @@
self.cpu = cpu
self.memcpy_addr = 0
self.rtyper = cpu.rtyper
- self.debug_counter_descr = cpu.fielddescrof(DEBUG_COUNTER, 'i')
self._debug = False
def setup_once(self):
@@ -265,14 +264,8 @@
def _append_debugging_code(self, operations, tp, number, token):
counter = self._register_counter(tp, number, token)
c_adr = ConstInt(rffi.cast(lltype.Signed, counter))
- box = BoxInt()
- box2 = BoxInt()
- ops = [ResOperation(rop.GETFIELD_RAW, [c_adr],
- box, descr=self.debug_counter_descr),
- ResOperation(rop.INT_ADD, [box, ConstInt(1)], box2),
- ResOperation(rop.SETFIELD_RAW, [c_adr, box2],
- None, descr=self.debug_counter_descr)]
- operations.extend(ops)
+ operations.append(
+ ResOperation(rop.INCREMENT_DEBUG_COUNTER, [c_adr], None))
def _register_counter(self, tp, number, token):
# YYY very minor leak -- we need the counters to stay alive
diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -3736,7 +3736,7 @@
assert False, 'should not be called'
from rpython.jit.codewriter.effectinfo import EffectInfo
- effectinfo = EffectInfo([], [], [], [], EffectInfo.EF_CANNOT_RAISE, EffectInfo.OS_MATH_SQRT)
+ effectinfo = EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE, EffectInfo.OS_MATH_SQRT)
FPTR = self.Ptr(self.FuncType([lltype.Float], lltype.Float))
func_ptr = llhelper(FPTR, math_sqrt)
FUNC = deref(FPTR)
@@ -4338,3 +4338,12 @@
assert rffi.cast(lltype.Signed, a[0]) == -7654
assert rffi.cast(lltype.Signed, a[1]) == 777
lltype.free(a, flavor='raw')
+
+ def test_increment_debug_counter(self):
+ foo = lltype.malloc(rffi.CArray(lltype.Signed), 1, flavor='raw')
+ foo[0] = 1789200
+ self.execute_operation(rop.INCREMENT_DEBUG_COUNTER,
+ [ConstInt(rffi.cast(lltype.Signed, foo))],
+ 'void')
+ assert foo[0] == 1789201
+ lltype.free(foo, flavor='raw')
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -287,7 +287,6 @@
cast_instance_to_gcref(self.cpu.propagate_exception_descr))
ofs = self.cpu.get_ofs_of_frame_field('jf_descr')
self.mc.MOV(RawEbpLoc(ofs), imm(propagate_exception_descr))
- self.mc.MOV_rr(eax.value, ebp.value)
#
self._call_footer()
rawstart = self.mc.materialize(self.cpu.asmmemmgr, [])
@@ -435,8 +434,8 @@
self.wb_slowpath[withcards + 2 * withfloats] = rawstart
@rgc.no_release_gil
- def assemble_loop(self, logger, loopname, inputargs, operations, looptoken,
- log):
+ def assemble_loop(self, inputargs, operations, looptoken, log,
+ loopname, logger):
'''adds the following attributes to looptoken:
_ll_function_addr (address of the generated func, as an int)
_ll_loop_code (debug: addr of the start of the ResOps)
@@ -515,8 +514,8 @@
size_excluding_failure_stuff - looppos)
@rgc.no_release_gil
- def assemble_bridge(self, logger, faildescr, inputargs, operations,
- original_loop_token, log):
+ def assemble_bridge(self, faildescr, inputargs, operations,
+ original_loop_token, log, logger):
if not we_are_translated():
# Arguments should be unique
assert len(set(inputargs)) == len(inputargs)
@@ -761,6 +760,9 @@
#
def _call_footer(self):
+ # the return value is the jitframe
+ self.mc.MOV_rr(eax.value, ebp.value)
+
gcrootmap = self.cpu.gc_ll_descr.gcrootmap
if gcrootmap and gcrootmap.is_shadow_stack:
self._call_footer_shadowstack(gcrootmap)
@@ -1467,6 +1469,14 @@
ofs_loc)
self.load_from_mem(resloc, src_addr, fieldsize_loc, sign_loc)
+ def genop_discard_increment_debug_counter(self, op, arglocs):
+ # The argument should be an immediate address. This should
+ # generate code equivalent to a GETFIELD_RAW, an ADD(1), and a
+ # SETFIELD_RAW. Here we use the direct from-memory-to-memory
+ # increment operation of x86.
+ base_loc, = arglocs
+ self.mc.INC(mem(base_loc, 0))
+
def genop_discard_setfield_gc(self, op, arglocs):
base_loc, ofs_loc, size_loc, value_loc = arglocs
assert isinstance(size_loc, ImmedLoc)
@@ -1823,12 +1833,8 @@
# did just above.
ofs = self.cpu.get_ofs_of_frame_field('jf_descr')
ofs2 = self.cpu.get_ofs_of_frame_field('jf_gcmap')
- mc.POP(eax)
- mc.MOV_br(ofs2, eax.value)
- mc.POP(eax)
- mc.MOV_br(ofs, eax.value)
- # the return value is the jitframe
- mc.MOV_rr(eax.value, ebp.value)
+ mc.POP_b(ofs2)
+ mc.POP_b(ofs)
self._call_footer()
rawstart = mc.materialize(self.cpu.asmmemmgr, [])
@@ -1861,7 +1867,6 @@
# keep that one and kill all the others
ofs = self.cpu.get_ofs_of_frame_field('jf_gcmap')
self.mc.MOV_bi(ofs, 0)
- self.mc.MOV_rr(eax.value, ebp.value)
# exit function
self._call_footer()
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -1003,6 +1003,10 @@
consider_getfield_raw_pure = consider_getfield_gc
consider_getfield_gc_pure = consider_getfield_gc
+ def consider_increment_debug_counter(self, op):
+ base_loc = self.loc(op.getarg(0))
+ self.perform_discard(op, [base_loc])
+
def consider_getarrayitem_gc(self, op):
itemsize, ofs, sign = unpack_arraydescr(op.getdescr())
args = op.getarglist()
diff --git a/rpython/jit/backend/x86/regloc.py b/rpython/jit/backend/x86/regloc.py
--- a/rpython/jit/backend/x86/regloc.py
+++ b/rpython/jit/backend/x86/regloc.py
@@ -488,12 +488,22 @@
for possible_code in unrolling_location_codes:
if code == possible_code:
val = getattr(loc, "value_" + possible_code)()
- if self.WORD == 8 and possible_code == 'i' and not rx86.fits_in_32bits(val):
- self._load_scratch(val)
+ # Faking out of certain operations for x86_64
+ fits32 = rx86.fits_in_32bits
+ if possible_code == 'i' and not fits32(val):
+ self._load_scratch(val) # for 'PUSH(imm)'
_rx86_getattr(self, name + "_r")(X86_64_SCRATCH_REG.value)
- else:
- methname = name + "_" + possible_code
- _rx86_getattr(self, methname)(val)
+ return
+ if possible_code == 'j' and not fits32(val):
+ val = self._addr_as_reg_offset(val)
+ _rx86_getattr(self, name + "_m")(val)
+ return
+ if possible_code == 'm' and not fits32(val[1]):
+ val = self._fix_static_offset_64_m(val)
+ if possible_code == 'a' and not fits32(val[3]):
+ val = self._fix_static_offset_64_a(val)
+ methname = name + "_" + possible_code
+ _rx86_getattr(self, methname)(val)
return func_with_new_name(INSN, "INSN_" + name)
@@ -600,6 +610,7 @@
TEST8 = _binaryop('TEST8')
BTS = _binaryop('BTS')
+ INC = _unaryop('INC')
ADD = _binaryop('ADD')
SUB = _binaryop('SUB')
IMUL = _binaryop('IMUL')
diff --git a/rpython/jit/backend/x86/runner.py b/rpython/jit/backend/x86/runner.py
--- a/rpython/jit/backend/x86/runner.py
+++ b/rpython/jit/backend/x86/runner.py
@@ -93,16 +93,15 @@
def compile_loop(self, inputargs, operations, looptoken, log=True,
name='', logger=None):
- return self.assembler.assemble_loop(logger, name, inputargs, operations,
- looptoken, log=log)
+ return self.assembler.assemble_loop(inputargs, operations, looptoken, log,
+ name, logger)
def compile_bridge(self, faildescr, inputargs, operations,
original_loop_token, log=True, logger=None):
clt = original_loop_token.compiled_loop_token
clt.compiling_a_bridge()
- return self.assembler.assemble_bridge(logger, faildescr, inputargs,
- operations,
- original_loop_token, log=log)
+ return self.assembler.assemble_bridge(faildescr, inputargs, operations,
+ original_loop_token, log, logger)
def clear_latest_values(self, count):
setitem = self.assembler.fail_boxes_ptr.setitem
diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py
--- a/rpython/jit/backend/x86/rx86.py
+++ b/rpython/jit/backend/x86/rx86.py
@@ -470,6 +470,9 @@
# ------------------------------ Arithmetic ------------------------------
+ INC_m = insn(rex_w, '\xFF', orbyte(0), mem_reg_plus_const(1))
+ INC_j = insn(rex_w, '\xFF', orbyte(0), abs_(1))
+
ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0)
OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1)
AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4)
diff --git a/rpython/jit/backend/x86/test/test_assembler.py b/rpython/jit/backend/x86/test/test_assembler.py
--- a/rpython/jit/backend/x86/test/test_assembler.py
+++ b/rpython/jit/backend/x86/test/test_assembler.py
@@ -55,9 +55,7 @@
asm = cpu.assembler
asm.setup_once()
asm.setup(looptoken)
- self.fm = X86FrameManager(0)
- self.xrm = X86XMMRegisterManager(None, frame_manager=self.fm,
- assembler=asm)
+ self.xrm = X86XMMRegisterManager(None, assembler=asm)
callback(asm)
asm.mc.RET()
rawstart = asm.materialize_loop(looptoken)
@@ -75,29 +73,6 @@
res = self.do_test(callback)
assert res == 42
- def test_push_stack(self):
- def callback(asm):
- loc = self.fm.frame_pos(5, INT)
- asm.mc.SUB_ri(esp.value, 64)
- asm.mov(imm(42), loc)
- asm.regalloc_push(loc)
- asm.regalloc_pop(eax)
- asm.mc.ADD_ri(esp.value, 64)
- res = self.do_test(callback)
- assert res == 42
-
- def test_pop_stack(self):
- def callback(asm):
- loc = self.fm.frame_pos(5, INT)
- asm.mc.SUB_ri(esp.value, 64)
- asm.mov(imm(42), edx)
- asm.regalloc_push(edx)
- asm.regalloc_pop(loc)
- asm.mov(loc, eax)
- asm.mc.ADD_ri(esp.value, 64)
- res = self.do_test(callback)
- assert res == 42
-
def test_simple_xmm(self):
def callback(asm):
c = ConstFloat(longlong.getfloatstorage(-42.5))
@@ -109,32 +84,8 @@
res = self.do_test(callback)
assert res == -42
- def test_push_stack_xmm(self):
+ def test_xmm_pushes_8_bytes(self):
def callback(asm):
- c = ConstFloat(longlong.getfloatstorage(-42.5))
- loc = self.xrm.convert_to_imm(c)
- loc2 = self.fm.frame_pos(4, FLOAT)
- asm.mc.SUB_ri(esp.value, 64)
- asm.mov(loc, xmm5)
- asm.mov(xmm5, loc2)
- asm.regalloc_push(loc2)
- asm.regalloc_pop(xmm0)
- asm.mc.ADD_ri(esp.value, 64)
- asm.mc.CVTTSD2SI(eax, xmm0)
- res = self.do_test(callback)
- assert res == -42
-
- def test_pop_stack_xmm(self):
- def callback(asm):
- c = ConstFloat(longlong.getfloatstorage(-42.5))
- loc = self.xrm.convert_to_imm(c)
- loc2 = self.fm.frame_pos(4, FLOAT)
- asm.mc.SUB_ri(esp.value, 64)
- asm.mov(loc, xmm5)
asm.regalloc_push(xmm5)
- asm.regalloc_pop(loc2)
- asm.mov(loc2, xmm0)
- asm.mc.ADD_ri(esp.value, 64)
- asm.mc.CVTTSD2SI(eax, xmm0)
- res = self.do_test(callback)
- assert res == -42
+ asm.mc.ADD(esp, imm(8))
+ self.do_test(callback)
diff --git a/rpython/jit/backend/x86/test/test_regloc.py b/rpython/jit/backend/x86/test/test_regloc.py
--- a/rpython/jit/backend/x86/test/test_regloc.py
+++ b/rpython/jit/backend/x86/test/test_regloc.py
@@ -373,3 +373,56 @@
'\x59'
)
assert cb.getvalue() == expected_instructions
+
+ # ------------------------------------------------------------
+
+ def test_push_immed64(self):
+ immed = 0x0123456789ABCDEF
+ cb = LocationCodeBuilder64()
+ cb.PUSH(imm(immed))
+ #
+ expected_instructions = (
+ # mov r11, 0x0123456789ABCDEF
+ '\x49\xBB\xEF\xCD\xAB\x89\x67\x45\x23\x01'
+ # push r11
+ '\x41\x53'
+ )
+ assert cb.getvalue() == expected_instructions
+
+ def test_inc_64bit_address_1(self):
+ base_addr = 0x0123456789ABCDEF
+ cb = LocationCodeBuilder64()
+ cb.INC(AddressLoc(ImmedLoc(0), ImmedLoc(0), 0, base_addr))
+ # this case is a INC_j
+ #
+ expected_instructions = (
+ # mov r11, 0x0123456789ABCDEF
+ '\x49\xBB\xEF\xCD\xAB\x89\x67\x45\x23\x01'
+ # inc [r11]
+ '\x49\xFF\x03'
+ )
+ assert cb.getvalue() == expected_instructions
+
+ def test_inc_64bit_address_2(self):
+ py.test.skip("there is no unary instruction INSN_a so far")
+ base_addr = 0x0123456789ABCDEF
+ cb = LocationCodeBuilder64()
+ cb.INC(AddressLoc(ImmedLoc(0), edx, 3, base_addr))
+ # this case would be a INC_a
+ xxx
+
+ def test_inc_64bit_address_3(self):
+ base_addr = 0x0123456789ABCDEF
+ cb = LocationCodeBuilder64()
+ cb.INC(AddressLoc(eax, ImmedLoc(0), 0, base_addr))
+ # this case is a INC_m
+ #
+ expected_instructions = (
+ # mov r11, 0x0123456789ABCDEF
+ '\x49\xBB\xEF\xCD\xAB\x89\x67\x45\x23\x01'
+ # lea r11, [rax+r11]
+ '\x4E\x8D\x1C\x18'
+ # inc [r11]
+ '\x49\xFF\x03'
+ )
+ assert cb.getvalue() == expected_instructions
diff --git a/rpython/jit/backend/x86/test/test_runner.py b/rpython/jit/backend/x86/test/test_runner.py
--- a/rpython/jit/backend/x86/test/test_runner.py
+++ b/rpython/jit/backend/x86/test/test_runner.py
@@ -427,8 +427,8 @@
debug._log = None
#
assert ops_offset is looptoken._x86_ops_offset
- # 2*(getfield_raw/int_add/setfield_raw) + ops + None
- assert len(ops_offset) == 2*3 + len(operations) + 1
+ # 2*increment_debug_counter + ops + None
+ assert len(ops_offset) == 2 + len(operations) + 1
assert (ops_offset[operations[0]] <=
ops_offset[operations[1]] <=
ops_offset[operations[2]] <=
diff --git a/rpython/jit/codewriter/call.py b/rpython/jit/codewriter/call.py
--- a/rpython/jit/codewriter/call.py
+++ b/rpython/jit/codewriter/call.py
@@ -178,7 +178,7 @@
return (fnaddr, calldescr)
def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE,
- extraeffect=None):
+ extraeffect=None, extradescr=None):
"""Return the calldescr that describes all calls done by 'op'.
This returns a calldescr that we can put in the corresponding
call operation in the calling jitcode. It gets an effectinfo
@@ -259,6 +259,7 @@
effectinfo = effectinfo_from_writeanalyze(
self.readwrite_analyzer.analyze(op, self.seen), self.cpu,
extraeffect, oopspecindex, can_invalidate, call_release_gil_target,
+ extradescr,
)
#
assert effectinfo is not None
diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -21,6 +21,7 @@
OS_ARRAYCOPY = 1 # "list.ll_arraycopy"
OS_STR2UNICODE = 2 # "str.str2unicode"
OS_SHRINK_ARRAY = 3 # rgc.ll_shrink_array
+ OS_DICT_LOOKUP = 4 # ll_dict_lookup
#
OS_STR_CONCAT = 22 # "stroruni.concat"
OS_STR_SLICE = 23 # "stroruni.slice"
@@ -88,15 +89,18 @@
# for debugging:
_OS_CANRAISE = set([
OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, OS_RAW_MALLOC_VARSIZE_CHAR,
- OS_JIT_FORCE_VIRTUAL, OS_SHRINK_ARRAY,
+ OS_JIT_FORCE_VIRTUAL, OS_SHRINK_ARRAY, OS_DICT_LOOKUP,
])
def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays,
+ readonly_descrs_interiorfields,
write_descrs_fields, write_descrs_arrays,
+ write_descrs_interiorfields,
extraeffect=EF_CAN_RAISE,
oopspecindex=OS_NONE,
can_invalidate=False,
- call_release_gil_target=llmemory.NULL):
+ call_release_gil_target=llmemory.NULL,
+ extradescrs=None):
key = (frozenset_or_none(readonly_descrs_fields),
frozenset_or_none(readonly_descrs_arrays),
frozenset_or_none(write_descrs_fields),
@@ -121,17 +125,21 @@
result = object.__new__(cls)
result.readonly_descrs_fields = readonly_descrs_fields
result.readonly_descrs_arrays = readonly_descrs_arrays
+ result.readonly_descrs_interiorfields = readonly_descrs_interiorfields
if extraeffect == EffectInfo.EF_LOOPINVARIANT or \
extraeffect == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \
extraeffect == EffectInfo.EF_ELIDABLE_CAN_RAISE:
result.write_descrs_fields = []
result.write_descrs_arrays = []
+ result.write_descrs_interiorfields = []
else:
result.write_descrs_fields = write_descrs_fields
result.write_descrs_arrays = write_descrs_arrays
+ result.write_descrs_interiorfields = write_descrs_interiorfields
result.extraeffect = extraeffect
result.can_invalidate = can_invalidate
result.oopspecindex = oopspecindex
+ result.extradescrs = extradescrs
result.call_release_gil_target = call_release_gil_target
if result.check_can_raise():
assert oopspecindex in cls._OS_CANRAISE
@@ -163,7 +171,7 @@
return None
return frozenset(x)
-EffectInfo.MOST_GENERAL = EffectInfo(None, None, None, None,
+EffectInfo.MOST_GENERAL = EffectInfo(None, None, None, None, None, None,
EffectInfo.EF_RANDOM_EFFECTS,
can_invalidate=True)
@@ -172,19 +180,24 @@
extraeffect=EffectInfo.EF_CAN_RAISE,
oopspecindex=EffectInfo.OS_NONE,
can_invalidate=False,
- call_release_gil_target=llmemory.NULL):
+ call_release_gil_target=llmemory.NULL,
+ extradescr=None):
from rpython.translator.backendopt.writeanalyze import top_set
if effects is top_set or extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
readonly_descrs_fields = None
readonly_descrs_arrays = None
+ readonly_descrs_interiorfields = None
write_descrs_fields = None
write_descrs_arrays = None
+ write_descrs_interiorfields = None
extraeffect = EffectInfo.EF_RANDOM_EFFECTS
else:
readonly_descrs_fields = []
readonly_descrs_arrays = []
+ readonly_descrs_interiorfields = []
write_descrs_fields = []
write_descrs_arrays = []
+ write_descrs_interiorfields = []
def add_struct(descrs_fields, (_, T, fieldname)):
T = deref(T)
@@ -198,6 +211,17 @@
descr = cpu.arraydescrof(ARRAY)
descrs_arrays.append(descr)
+ def add_interiorfield(descrs_interiorfields, (_, T, fieldname)):
+ T = deref(T)
+ if not isinstance(T, lltype.Array):
+ return # let's not consider structs for now
+ if not consider_array(T):
+ return
+ if getattr(T.OF, fieldname) is lltype.Void:
+ return
+ descr = cpu.interiorfielddescrof(T, fieldname)
+ descrs_interiorfields.append(descr)
+
for tup in effects:
if tup[0] == "struct":
add_struct(write_descrs_fields, tup)
@@ -205,6 +229,12 @@
tupw = ("struct",) + tup[1:]
if tupw not in effects:
add_struct(readonly_descrs_fields, tup)
+ elif tup[0] == "interiorfield":
+ add_interiorfield(write_descrs_interiorfields, tup)
+ elif tup[0] == "readinteriorfield":
+ tupw = ('interiorfield',) + tup[1:]
+ if tupw not in effects:
+ add_interiorfield(readonly_descrs_interiorfields, tup)
elif tup[0] == "array":
add_array(write_descrs_arrays, tup)
elif tup[0] == "readarray":
@@ -216,12 +246,15 @@
#
return EffectInfo(readonly_descrs_fields,
readonly_descrs_arrays,
+ readonly_descrs_interiorfields,
write_descrs_fields,
write_descrs_arrays,
+ write_descrs_interiorfields,
extraeffect,
oopspecindex,
can_invalidate,
- call_release_gil_target)
+ call_release_gil_target,
+ extradescr)
def consider_struct(TYPE, fieldname):
if fieldType(TYPE, fieldname) is lltype.Void:
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -403,6 +403,9 @@
prepare = self._handle_math_sqrt_call
elif oopspec_name.startswith('rgc.'):
prepare = self._handle_rgc_call
+ elif oopspec_name.endswith('dict.lookup'):
+ # also ordereddict.lookup
+ prepare = self._handle_dict_lookup_call
else:
prepare = self.prepare_builtin_call
try:
@@ -1680,9 +1683,11 @@
# ----------
# Strings and Unicodes.
- def _handle_oopspec_call(self, op, args, oopspecindex, extraeffect=None):
+ def _handle_oopspec_call(self, op, args, oopspecindex, extraeffect=None,
+ extradescr=None):
calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
- extraeffect)
+ extraeffect,
+ extradescr=extradescr)
if extraeffect is not None:
assert (is_test_calldescr(calldescr) # for tests
or calldescr.get_extra_info().extraeffect == extraeffect)
@@ -1846,6 +1851,14 @@
return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT,
EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
+ def _handle_dict_lookup_call(self, op, oopspec_name, args):
+ extradescr1 = self.cpu.fielddescrof(op.args[1].concretetype.TO,
+ 'entries')
+ extradescr2 = self.cpu.interiorfielddescrof(
+ op.args[1].concretetype.TO.entries.TO, 'key')
+ return self._handle_oopspec_call(op, args, EffectInfo.OS_DICT_LOOKUP,
+ extradescr=[extradescr1, extradescr2])
+
def _handle_rgc_call(self, op, oopspec_name, args):
if oopspec_name == 'rgc.ll_shrink_array':
return self._handle_oopspec_call(op, args, EffectInfo.OS_SHRINK_ARRAY, EffectInfo.EF_CAN_RAISE)
diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -60,7 +60,8 @@
class FakeResidualCallControl:
def guess_call_kind(self, op):
return 'residual'
- def getcalldescr(self, op, oopspecindex=None, extraeffect=None):
+ def getcalldescr(self, op, oopspecindex=None, extraeffect=None,
+ extradescr=None):
return 'calldescr'
def calldescr_canraise(self, calldescr):
return True
@@ -117,7 +118,8 @@
self.callinfocollection = FakeCallInfoCollection()
def guess_call_kind(self, op):
return 'builtin'
- def getcalldescr(self, op, oopspecindex=None, extraeffect=None):
+ def getcalldescr(self, op, oopspecindex=None, extraeffect=None,
+ extradescr=None):
assert oopspecindex is not None # in this test
EI = effectinfo.EffectInfo
if oopspecindex != EI.OS_ARRAYCOPY:
diff --git a/rpython/jit/codewriter/test/test_list.py b/rpython/jit/codewriter/test/test_list.py
--- a/rpython/jit/codewriter/test/test_list.py
+++ b/rpython/jit/codewriter/test/test_list.py
@@ -37,7 +37,8 @@
class FakeCallControl:
class getcalldescr(AbstractDescr):
- def __init__(self, op, oopspecindex=0, extraeffect=None):
+ def __init__(self, op, oopspecindex=0, extraeffect=None,
+ extradescr=None):
self.op = op
self.oopspecindex = oopspecindex
def __repr__(self):
diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py
--- a/rpython/jit/metainterp/executor.py
+++ b/rpython/jit/metainterp/executor.py
@@ -332,6 +332,7 @@
continue
if value in (rop.FORCE_TOKEN,
rop.CALL_ASSEMBLER,
+ rop.INCREMENT_DEBUG_COUNTER,
rop.COND_CALL_GC_WB,
rop.COND_CALL_GC_WB_ARRAY,
rop.DEBUG_MERGE_POINT,
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -1,8 +1,10 @@
import os
+from rpython.jit.codewriter.effectinfo import EffectInfo
+from rpython.jit.metainterp.optimizeopt.util import args_dict
from rpython.jit.metainterp.history import Const
from rpython.jit.metainterp.jitexc import JitException
-from rpython.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY, LEVEL_KNOWNCLASS
+from rpython.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY, LEVEL_KNOWNCLASS, REMOVED
from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
from rpython.jit.metainterp.resoperation import rop, ResOperation
from rpython.rlib.objectmodel import we_are_translated
@@ -173,6 +175,10 @@
self.cached_fields = {}
# cached array items: {array descr: {index: CachedField}}
self.cached_arrayitems = {}
+ # cached dict items: {dict descr: {(optval, index): box-or-const}}
+ self.cached_dict_reads = {}
+ # cache of corresponding array descrs
+ self.corresponding_array_descrs = {}
#
self._lazy_setfields_and_arrayitems = []
self._remove_guard_not_invalidated = False
@@ -180,9 +186,13 @@
self.postponed_op = None
def force_at_end_of_preamble(self):
+ self.cached_dict_reads.clear()
+ self.corresponding_array_descrs.clear()
self.force_all_lazy_setfields_and_arrayitems()
def flush(self):
+ self.cached_dict_reads.clear()
+ self.corresponding_array_descrs.clear()
self.force_all_lazy_setfields_and_arrayitems()
self.emit_postponed_op()
@@ -214,6 +224,7 @@
del self._lazy_setfields_and_arrayitems[:]
self.cached_fields.clear()
self.cached_arrayitems.clear()
+ self.cached_dict_reads.clear()
def field_cache(self, descr):
try:
@@ -282,6 +293,44 @@
self.force_all_lazy_setfields_and_arrayitems()
self.clean_caches()
+ def optimize_CALL(self, op):
+ # dispatch based on 'oopspecindex' to a method that handles
+ # specifically the given oopspec call. For non-oopspec calls,
+ # oopspecindex is just zero.
+ effectinfo = op.getdescr().get_extra_info()
+ oopspecindex = effectinfo.oopspecindex
+ if oopspecindex == EffectInfo.OS_DICT_LOOKUP:
+ if self._optimize_CALL_DICT_LOOKUP(op):
+ return
+ self.emit_operation(op)
+
+ def _optimize_CALL_DICT_LOOKUP(self, op):
+ descrs = op.getdescr().get_extra_info().extradescrs
+ assert descrs # translation hint
+ descr1 = descrs[0]
+ try:
+ d = self.cached_dict_reads[descr1]
+ except KeyError:
+ d = self.cached_dict_reads[descr1] = args_dict()
+ self.corresponding_array_descrs[descrs[1]] = descr1
+ args = self.optimizer.make_args_key(op)
+ try:
+ res_v = d[args]
+ except KeyError:
+ d[args] = self.getvalue(op.result)
+ return False
+ else:
+ self.make_equal_to(op.result, res_v)
+ self.last_emitted_operation = REMOVED
+ return True
+
+ def optimize_GUARD_NO_EXCEPTION(self, op):
+ if self.last_emitted_operation is REMOVED:
+ return
+ self.emit_operation(op)
+
+ optimize_GUARD_EXCEPTION = optimize_GUARD_NO_EXCEPTION
+
def force_from_effectinfo(self, effectinfo):
# XXX we can get the wrong complexity here, if the lists
# XXX stored on effectinfo are large
@@ -290,9 +339,20 @@
for arraydescr in effectinfo.readonly_descrs_arrays:
self.force_lazy_setarrayitem(arraydescr)
for fielddescr in effectinfo.write_descrs_fields:
+ try:
+ del self.cached_dict_reads[fielddescr]
+ except KeyError:
+ pass
self.force_lazy_setfield(fielddescr, can_cache=False)
for arraydescr in effectinfo.write_descrs_arrays:
self.force_lazy_setarrayitem(arraydescr, can_cache=False)
+ for descr in effectinfo.write_descrs_interiorfields:
+ if descr in self.corresponding_array_descrs:
+ dictdescr = self.corresponding_array_descrs.pop(descr)
+ try:
+ del self.cached_dict_reads[dictdescr]
+ except KeyError:
+ pass # someone did it already
if effectinfo.check_forces_virtual_or_virtualizable():
vrefinfo = self.optimizer.metainterp_sd.virtualref_info
self.force_lazy_setfield(vrefinfo.descr_forced)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -5444,6 +5444,21 @@
"""
self.optimize_loop(ops, expected)
+ def test_consecutive_getinteriorfields(self):
+ py.test.skip("we want this to pass")
+ ops = """
+ [p0, i0]
+ i1 = getinteriorfield_gc(p0, i0, descr=valuedescr)
+ i2 = getinteriorfield_gc(p0, i0, descr=valuedescr)
+ jump(i1, i2)
+ """
+ expected = """
+ [p0, i0]
+ i1 = getinteriorfield_gc(p0, i0, descr=valuedescr)
+ jump(i1, i1)
+ """
+ self.optimize_loop(ops, expected)
+
class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
pass
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -181,28 +181,29 @@
plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
EffectInfo.MOST_GENERAL)
nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [], []))
+ EffectInfo([], [], [], [], [], []))
writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [adescr], []))
+ EffectInfo([], [], [], [adescr], [], []))
writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [adescr], [arraydescr]))
+ EffectInfo([], [], [], [adescr], [arraydescr],
+ []))
readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([adescr], [], [], []))
+ EffectInfo([adescr], [], [], [], [], []))
mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([nextdescr], [], [], [],
+ EffectInfo([nextdescr], [], [], [], [], [],
EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE,
can_invalidate=True))
arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [arraydescr], [], [arraydescr],
+ EffectInfo([], [arraydescr], [], [], [arraydescr], [],
EffectInfo.EF_CANNOT_RAISE,
oopspecindex=EffectInfo.OS_ARRAYCOPY))
raw_malloc_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [], [],
+ EffectInfo([], [], [], [], [], [],
EffectInfo.EF_CAN_RAISE,
oopspecindex=EffectInfo.OS_RAW_MALLOC_VARSIZE_CHAR))
raw_free_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [], [],
+ EffectInfo([], [], [], [], [], [],
EffectInfo.EF_CANNOT_RAISE,
oopspecindex=EffectInfo.OS_RAW_FREE))
@@ -251,17 +252,18 @@
_oopspecindex = getattr(EffectInfo, _os)
locals()[_name] = \
cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [], [], EffectInfo.EF_CANNOT_RAISE,
+ EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE,
oopspecindex=_oopspecindex))
#
_oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI'))
locals()[_name.replace('str', 'unicode')] = \
cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [], [], EffectInfo.EF_CANNOT_RAISE,
+ EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE,
oopspecindex=_oopspecindex))
s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo([], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE))
+ EffectInfo([], [], [], [], [], [],
+ oopspecindex=EffectInfo.OS_STR2UNICODE))
#
class LoopToken(AbstractDescr):
@@ -277,7 +279,7 @@
virtualtokendescr = vrefinfo.descr_virtual_token
virtualforceddescr = vrefinfo.descr_forced
FUNC = lltype.FuncType([], lltype.Void)
- ei = EffectInfo([], [], [], [], EffectInfo.EF_CANNOT_RAISE,
+ ei = EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE,
can_invalidate=False,
oopspecindex=EffectInfo.OS_JIT_FORCE_VIRTUALIZABLE)
clear_vable = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, ei)
diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -494,6 +494,7 @@
# must be forced, however we need to execute it anyway
'_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations -----
+ 'INCREMENT_DEBUG_COUNTER/1',
'SETARRAYITEM_GC/3d',
'SETARRAYITEM_RAW/3d',
'SETINTERIORFIELD_GC/3d',
diff --git a/rpython/jit/metainterp/test/test_dict.py b/rpython/jit/metainterp/test/test_dict.py
--- a/rpython/jit/metainterp/test/test_dict.py
+++ b/rpython/jit/metainterp/test/test_dict.py
@@ -193,6 +193,107 @@
self.check_simple_loop({'int_sub': 1, 'int_gt': 1, 'guard_true': 1,
'jump': 1})
+ def test_dict_two_lookups(self):
+ driver = JitDriver(greens = [], reds = 'auto')
+ d = {'a': 3, 'b': 4}
+ indexes = ['a', 'b']
+
+ def f(n):
+ s = 0
+ while n > 0:
+ driver.jit_merge_point()
+ s += d[indexes[n & 1]]
+ s += d[indexes[n & 1]]
+ n -= 1
+ return s
+
+ self.meta_interp(f, [10])
+ # XXX should be one getinteriorfield_gc
+ self.check_simple_loop(call=1, getinteriorfield_gc=2,
+ guard_no_exception=1)
+
+ def test_ordered_dict_two_lookups(self):
+ driver = JitDriver(greens = [], reds = 'auto')
+ d = OrderedDict()
+ d['a'] = 3
+ d['b'] = 4
+ indexes = ['a', 'b']
+
+ def f(n):
+ s = 0
+ while n > 0:
+ driver.jit_merge_point()
+ s += d[indexes[n & 1]]
+ s += d[indexes[n & 1]]
+ n -= 1
+ return s
+
+ self.meta_interp(f, [10])
+ # XXX should be one getinteriorfield_gc
+ self.check_simple_loop(call=1, getinteriorfield_gc=2,
+ guard_no_exception=1)
+
+ def test_dict_insert_invalidates_caches(self):
+ driver = JitDriver(greens = [], reds = 'auto')
+ indexes = ['aa', 'b', 'cc']
+
+ def f(n):
+ d = {'aa': 3, 'b': 4, 'cc': 5}
+ s = 0
+ while n > 0:
+ driver.jit_merge_point()
+ index = indexes[n & 1]
+ s += d[index]
+ d['aa'] += 1 # this will invalidate the index
+ s += d[index]
+ n -= 1
+ return s
+
+ res = self.meta_interp(f, [10])
+ assert res == f(10)
+ self.check_simple_loop(call=5)
+
+ def test_dict_array_write_invalidates_caches(self):
+ driver = JitDriver(greens = [], reds = 'auto')
+ indexes = ['aa', 'b', 'cc']
+
+ def f(n):
+ d = {'aa': 3, 'b': 4, 'cc': 5}
+ s = 0
+ while n > 0:
+ driver.jit_merge_point()
+ index = indexes[n & 1]
+ s += d[index]
+ del d['cc']
+ s += d[index]
+ d['cc'] = 3
+ n -= 1
+ return s
+
+ exp = f(10)
+ res = self.meta_interp(f, [10])
+ assert res == exp
+ self.check_simple_loop(call=7)
+
+ def test_dict_double_lookup_2(self):
+ driver = JitDriver(greens = [], reds = 'auto')
+ indexes = ['aa', 'b', 'cc']
+
+ def f(n):
+ d = {'aa': 3, 'b': 4, 'cc': 5}
+ s = 0
+ while n > 0:
+ driver.jit_merge_point()
+ index = indexes[n & 1]
+ s += d[index]
+ d[index] += 1
+ n -= 1
+ return s
+
+ res = self.meta_interp(f, [10])
+ assert res == f(10)
+ self.check_simple_loop(call=3)
+
class TestLLtype(DictTests, LLJitMixin):
pass
diff --git a/rpython/jit/metainterp/virtualizable.py b/rpython/jit/metainterp/virtualizable.py
--- a/rpython/jit/metainterp/virtualizable.py
+++ b/rpython/jit/metainterp/virtualizable.py
@@ -302,7 +302,7 @@
self.clear_vable_ptr = self.warmrunnerdesc.helper_func(
FUNCPTR, self.clear_vable_token)
FUNC = FUNCPTR.TO
- ei = EffectInfo([], [], [], [], EffectInfo.EF_CANNOT_RAISE,
+ ei = EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE,
can_invalidate=False,
oopspecindex=EffectInfo.OS_JIT_FORCE_VIRTUALIZABLE)
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -14,6 +14,11 @@
includes = ['stdio.h', 'sys/types.h']
if os.name == "posix":
includes += ['unistd.h']
+ ftruncate = 'ftruncate'
+ fileno = 'fileno'
+else:
+ ftruncate = '_chsize'
+ fileno = '_fileno'
eci = ExternalCompilationInfo(includes=includes)
def llexternal(*args, **kwargs):
@@ -41,10 +46,10 @@
c_fseek = llexternal('fseek', [lltype.Ptr(FILE), rffi.LONG, rffi.INT],
rffi.INT)
c_tmpfile = llexternal('tmpfile', [], lltype.Ptr(FILE))
-c_fileno = llexternal('fileno', [lltype.Ptr(FILE)], rffi.INT)
+c_fileno = llexternal(fileno, [lltype.Ptr(FILE)], rffi.INT)
c_ftell = llexternal('ftell', [lltype.Ptr(FILE)], rffi.LONG)
c_fflush = llexternal('fflush', [lltype.Ptr(FILE)], rffi.INT)
-c_ftruncate = llexternal('ftruncate', [rffi.INT, OFF_T], rffi.INT, macro=True)
+c_ftruncate = llexternal(ftruncate, [rffi.INT, OFF_T], rffi.INT, macro=True)
c_fgets = llexternal('fgets', [rffi.CCHARP, rffi.INT, lltype.Ptr(FILE)],
rffi.CCHARP)
diff --git a/rpython/rtyper/lltypesystem/rdict.py b/rpython/rtyper/lltypesystem/rdict.py
--- a/rpython/rtyper/lltypesystem/rdict.py
+++ b/rpython/rtyper/lltypesystem/rdict.py
@@ -569,6 +569,7 @@
PERTURB_SHIFT = 5
@jit.look_inside_iff(lambda d, key, hash: jit.isvirtual(d) and jit.isconstant(key))
+ at jit.oopspec('dict.lookup(d, key, hash)')
def ll_dict_lookup(d, key, hash):
entries = d.entries
ENTRIES = lltype.typeOf(entries).TO
diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py
--- a/rpython/rtyper/lltypesystem/rordereddict.py
+++ b/rpython/rtyper/lltypesystem/rordereddict.py
@@ -709,6 +709,7 @@
@jit.look_inside_iff(lambda d, key, hash, store_flag, T:
jit.isvirtual(d) and jit.isconstant(key))
+ at jit.oopspec('ordereddict.lookup(d, key, hash, store_flag, T)')
def ll_dict_lookup(d, key, hash, store_flag, T):
INDEXES = _ll_ptr_to_array_of(T)
entries = d.entries
diff --git a/rpython/translator/backendopt/test/test_writeanalyze.py b/rpython/translator/backendopt/test/test_writeanalyze.py
--- a/rpython/translator/backendopt/test/test_writeanalyze.py
+++ b/rpython/translator/backendopt/test/test_writeanalyze.py
@@ -353,3 +353,23 @@
result = wa.analyze(fgraph.startblock.operations[-1])
assert list(result) == [("struct", lltype.Ptr(S), "x")]
+
+ def test_interiorfield(self):
+ A = lltype.GcArray(lltype.Struct('x', ('x', lltype.Signed),
+ ('y', lltype.Signed)))
+
+ def g(x):
+ a = lltype.malloc(A, 1)
+ a[0].y = 3
+ return f(a, x)
+
+ def f(a, x):
+ a[0].x = x
+ return a[0].y
+
+ t, wa = self.translate(g, [int])
+ ggraph = graphof(t, g)
+ result = wa.analyze(ggraph.startblock.operations[-1])
+ res = list(result)
+ assert ('readinteriorfield', lltype.Ptr(A), 'y') in res
+ assert ('interiorfield', lltype.Ptr(A), 'x') in res
diff --git a/rpython/translator/backendopt/writeanalyze.py b/rpython/translator/backendopt/writeanalyze.py
--- a/rpython/translator/backendopt/writeanalyze.py
+++ b/rpython/translator/backendopt/writeanalyze.py
@@ -1,4 +1,4 @@
-from rpython.flowspace.model import Variable
+from rpython.flowspace.model import Variable, Constant
from rpython.translator.backendopt import graphanalyze
top_set = object()
@@ -37,6 +37,12 @@
return top_set
return result1.union(result2)
+ def _getinteriorname(self, op):
+ if (isinstance(op.args[1], Constant) and
+ isinstance(op.args[1].value, str)):
+ return op.args[1].value
+ return op.args[2].value
+
def analyze_simple_operation(self, op, graphinfo):
if op.opname == "setfield":
if graphinfo is None or not graphinfo.is_fresh_malloc(op.args[0]):
@@ -45,11 +51,18 @@
elif op.opname == "setarrayitem":
if graphinfo is None or not graphinfo.is_fresh_malloc(op.args[0]):
return self._array_result(op.args[0].concretetype)
+ elif op.opname == "setinteriorfield":
+ if graphinfo is None or not graphinfo.is_fresh_malloc(op.args[0]):
+ name = self._getinteriorname(op)
+ return self._interiorfield_result(op.args[0].concretetype, name)
return empty_set
def _array_result(self, TYPE):
return frozenset([("array", TYPE)])
+ def _interiorfield_result(self, TYPE, fieldname):
+ return frozenset([("interiorfield", TYPE, fieldname)])
+
def compute_graph_info(self, graph):
return FreshMallocs(graph)
@@ -99,4 +112,8 @@
elif op.opname == "getarrayitem":
return frozenset([
("readarray", op.args[0].concretetype)])
+ elif op.opname == "getinteriorfield":
+ name = self._getinteriorname(op)
+ return frozenset([("readinteriorfield", op.args[0].concretetype,
+ name)])
return WriteAnalyzer.analyze_simple_operation(self, op, graphinfo)
More information about the pypy-commit
mailing list