Author: Wim Lavrijsen <wlavrij...@lbl.gov> Branch: reflex-support Changeset: r53036:3847eddabfa1 Date: 2012-02-28 10:35 -0800 http://bitbucket.org/pypy/pypy/changeset/3847eddabfa1/
Log: merge default into branch diff --git a/lib-python/modified-2.7/ctypes/test/test_arrays.py b/lib-python/modified-2.7/ctypes/test/test_arrays.py --- a/lib-python/modified-2.7/ctypes/test/test_arrays.py +++ b/lib-python/modified-2.7/ctypes/test/test_arrays.py @@ -1,12 +1,23 @@ import unittest from ctypes import * +from test.test_support import impl_detail formats = "bBhHiIlLqQfd" +# c_longdouble commented out for PyPy, look at the commend in test_longdouble formats = c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, \ - c_long, c_ulonglong, c_float, c_double, c_longdouble + c_long, c_ulonglong, c_float, c_double #, c_longdouble class ArrayTestCase(unittest.TestCase): + + @impl_detail('long double not supported by PyPy', pypy=False) + def test_longdouble(self): + """ + This test is empty. It's just here to remind that we commented out + c_longdouble in "formats". If pypy will ever supports c_longdouble, we + should kill this test and uncomment c_longdouble inside formats. + """ + def test_simple(self): # create classes holding simple numeric types, and check # various properties. diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -13,7 +13,7 @@ and not p.basename.startswith('test')] essential_modules = dict.fromkeys( - ["exceptions", "_file", "sys", "__builtin__", "posix"] + ["exceptions", "_file", "sys", "__builtin__", "posix", "_warnings"] ) default_modules = essential_modules.copy() diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -1471,8 +1471,8 @@ def warn(self, msg, w_warningcls): self.appexec([self.wrap(msg), w_warningcls], """(msg, warningcls): - import warnings - warnings.warn(msg, warningcls, stacklevel=2) + import _warnings + _warnings.warn(msg, warningcls, stacklevel=2) """) def resolve_target(self, w_obj): diff --git a/pypy/interpreter/pyparser/parsestring.py b/pypy/interpreter/pyparser/parsestring.py --- a/pypy/interpreter/pyparser/parsestring.py +++ b/pypy/interpreter/pyparser/parsestring.py @@ -1,5 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter import unicodehelper +from pypy.rlib.rstring import StringBuilder def parsestr(space, encoding, s, unicode_literals=False): # compiler.transformer.Transformer.decode_literal depends on what @@ -115,21 +116,23 @@ the string is UTF-8 encoded and should be re-encoded in the specified encoding. """ - lis = [] + builder = StringBuilder(len(s)) ps = 0 end = len(s) - while ps < end: - if s[ps] != '\\': - # note that the C code has a label here. - # the logic is the same. + while 1: + ps2 = ps + while ps < end and s[ps] != '\\': if recode_encoding and ord(s[ps]) & 0x80: w, ps = decode_utf8(space, s, ps, end, recode_encoding) - # Append bytes to output buffer. - lis.append(w) + builder.append(w) + ps2 = ps else: - lis.append(s[ps]) ps += 1 - continue + if ps > ps2: + builder.append_slice(s, ps2, ps) + if ps == end: + break + ps += 1 if ps == end: raise_app_valueerror(space, 'Trailing \\ in string') @@ -140,25 +143,25 @@ if ch == '\n': pass elif ch == '\\': - lis.append('\\') + builder.append('\\') elif ch == "'": - lis.append("'") + builder.append("'") elif ch == '"': - lis.append('"') + builder.append('"') elif ch == 'b': - lis.append("\010") + builder.append("\010") elif ch == 'f': - lis.append('\014') # FF + builder.append('\014') # FF elif ch == 't': - lis.append('\t') + builder.append('\t') elif ch == 'n': - lis.append('\n') + builder.append('\n') elif ch == 'r': - lis.append('\r') + builder.append('\r') elif ch == 'v': - lis.append('\013') # VT + builder.append('\013') # VT elif ch == 'a': - lis.append('\007') # BEL, not classic C + builder.append('\007') # BEL, not classic C elif ch in '01234567': # Look for up to two more octal digits span = ps @@ -168,13 +171,13 @@ # emulate a strange wrap-around behavior of CPython: # \400 is the same as \000 because 0400 == 256 num = int(octal, 8) & 0xFF - lis.append(chr(num)) + builder.append(chr(num)) ps = span elif ch == 'x': if ps+2 <= end and isxdigit(s[ps]) and isxdigit(s[ps + 1]): hexa = s[ps : ps + 2] num = int(hexa, 16) - lis.append(chr(num)) + builder.append(chr(num)) ps += 2 else: raise_app_valueerror(space, 'invalid \\x escape') @@ -184,13 +187,13 @@ # this was not an escape, so the backslash # has to be added, and we start over in # non-escape mode. - lis.append('\\') + builder.append('\\') ps -= 1 assert ps >= 0 continue # an arbitry number of unescaped UTF-8 bytes may follow. - buf = ''.join(lis) + buf = builder.build() return buf diff --git a/pypy/interpreter/streamutil.py b/pypy/interpreter/streamutil.py new file mode 100644 --- /dev/null +++ b/pypy/interpreter/streamutil.py @@ -0,0 +1,17 @@ +from pypy.rlib.streamio import StreamError +from pypy.interpreter.error import OperationError, wrap_oserror2 + +def wrap_streamerror(space, e, w_filename=None): + if isinstance(e, StreamError): + return OperationError(space.w_ValueError, + space.wrap(e.message)) + elif isinstance(e, OSError): + return wrap_oserror_as_ioerror(space, e, w_filename) + else: + # should not happen: wrap_streamerror() is only called when + # StreamErrors = (OSError, StreamError) are raised + return OperationError(space.w_IOError, space.w_None) + +def wrap_oserror_as_ioerror(space, e, w_filename=None): + return wrap_oserror2(space, e, w_filename, + w_exception_class=space.w_IOError) diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py --- a/pypy/jit/backend/llsupport/gc.py +++ b/pypy/jit/backend/llsupport/gc.py @@ -769,11 +769,19 @@ self.generate_function('malloc_unicode', malloc_unicode, [lltype.Signed]) - # Rarely called: allocate a fixed-size amount of bytes, but - # not in the nursery, because it is too big. Implemented like - # malloc_nursery_slowpath() above. - self.generate_function('malloc_fixedsize', malloc_nursery_slowpath, - [lltype.Signed]) + # Never called as far as I can tell, but there for completeness: + # allocate a fixed-size object, but not in the nursery, because + # it is too big. + def malloc_big_fixedsize(size, tid): + if self.DEBUG: + self._random_usage_of_xmm_registers() + type_id = llop.extract_ushort(llgroup.HALFWORD, tid) + check_typeid(type_id) + return llop1.do_malloc_fixedsize_clear(llmemory.GCREF, + type_id, size, + False, False, False) + self.generate_function('malloc_big_fixedsize', malloc_big_fixedsize, + [lltype.Signed] * 2) def _bh_malloc(self, sizedescr): from pypy.rpython.memory.gctypelayout import check_typeid diff --git a/pypy/jit/backend/llsupport/rewrite.py b/pypy/jit/backend/llsupport/rewrite.py --- a/pypy/jit/backend/llsupport/rewrite.py +++ b/pypy/jit/backend/llsupport/rewrite.py @@ -96,8 +96,10 @@ def handle_new_fixedsize(self, descr, op): assert isinstance(descr, SizeDescr) size = descr.size - self.gen_malloc_nursery(size, op.result) - self.gen_initialize_tid(op.result, descr.tid) + if self.gen_malloc_nursery(size, op.result): + self.gen_initialize_tid(op.result, descr.tid) + else: + self.gen_malloc_fixedsize(size, descr.tid, op.result) def handle_new_array(self, arraydescr, op): v_length = op.getarg(0) @@ -112,8 +114,8 @@ pass # total_size is still -1 elif arraydescr.itemsize == 0: total_size = arraydescr.basesize - if 0 <= total_size <= 0xffffff: # up to 16MB, arbitrarily - self.gen_malloc_nursery(total_size, op.result) + if (total_size >= 0 and + self.gen_malloc_nursery(total_size, op.result)): self.gen_initialize_tid(op.result, arraydescr.tid) self.gen_initialize_len(op.result, v_length, arraydescr.lendescr) elif self.gc_ll_descr.kind == 'boehm': @@ -147,13 +149,22 @@ # mark 'v_result' as freshly malloced self.recent_mallocs[v_result] = None - def gen_malloc_fixedsize(self, size, v_result): - """Generate a CALL_MALLOC_GC(malloc_fixedsize_fn, Const(size)). - Note that with the framework GC, this should be called very rarely. + def gen_malloc_fixedsize(self, size, typeid, v_result): + """Generate a CALL_MALLOC_GC(malloc_fixedsize_fn, ...). + Used on Boehm, and on the framework GC for large fixed-size + mallocs. (For all I know this latter case never occurs in + practice, but better safe than sorry.) """ - addr = self.gc_ll_descr.get_malloc_fn_addr('malloc_fixedsize') - self._gen_call_malloc_gc([ConstInt(addr), ConstInt(size)], v_result, - self.gc_ll_descr.malloc_fixedsize_descr) + if self.gc_ll_descr.fielddescr_tid is not None: # framework GC + assert (size & (WORD-1)) == 0, "size not aligned?" + addr = self.gc_ll_descr.get_malloc_fn_addr('malloc_big_fixedsize') + args = [ConstInt(addr), ConstInt(size), ConstInt(typeid)] + descr = self.gc_ll_descr.malloc_big_fixedsize_descr + else: # Boehm + addr = self.gc_ll_descr.get_malloc_fn_addr('malloc_fixedsize') + args = [ConstInt(addr), ConstInt(size)] + descr = self.gc_ll_descr.malloc_fixedsize_descr + self._gen_call_malloc_gc(args, v_result, descr) def gen_boehm_malloc_array(self, arraydescr, v_num_elem, v_result): """Generate a CALL_MALLOC_GC(malloc_array_fn, ...) for Boehm.""" @@ -211,8 +222,7 @@ """ size = self.round_up_for_allocation(size) if not self.gc_ll_descr.can_use_nursery_malloc(size): - self.gen_malloc_fixedsize(size, v_result) - return + return False # op = None if self._op_malloc_nursery is not None: @@ -238,6 +248,7 @@ self._previous_size = size self._v_last_malloced_nursery = v_result self.recent_mallocs[v_result] = None + return True def gen_initialize_tid(self, v_newgcobj, tid): if self.gc_ll_descr.fielddescr_tid is not None: diff --git a/pypy/jit/backend/llsupport/test/test_rewrite.py b/pypy/jit/backend/llsupport/test/test_rewrite.py --- a/pypy/jit/backend/llsupport/test/test_rewrite.py +++ b/pypy/jit/backend/llsupport/test/test_rewrite.py @@ -119,12 +119,19 @@ jump() """, """ [] - p0 = call_malloc_gc(ConstClass(malloc_fixedsize), \ - %(adescr.basesize + 10 * adescr.itemsize)d, \ - descr=malloc_fixedsize_descr) - setfield_gc(p0, 10, descr=alendescr) + p0 = call_malloc_gc(ConstClass(malloc_array), \ + %(adescr.basesize)d, \ + 10, \ + %(adescr.itemsize)d, \ + %(adescr.lendescr.offset)d, \ + descr=malloc_array_descr) jump() """) +## should ideally be: +## p0 = call_malloc_gc(ConstClass(malloc_fixedsize), \ +## %(adescr.basesize + 10 * adescr.itemsize)d, \ +## descr=malloc_fixedsize_descr) +## setfield_gc(p0, 10, descr=alendescr) def test_new_array_variable(self): self.check_rewrite(""" @@ -178,13 +185,20 @@ jump() """, """ [i1] - p0 = call_malloc_gc(ConstClass(malloc_fixedsize), \ - %(unicodedescr.basesize + \ - 10 * unicodedescr.itemsize)d, \ - descr=malloc_fixedsize_descr) - setfield_gc(p0, 10, descr=unicodelendescr) + p0 = call_malloc_gc(ConstClass(malloc_array), \ + %(unicodedescr.basesize)d, \ + 10, \ + %(unicodedescr.itemsize)d, \ + %(unicodelendescr.offset)d, \ + descr=malloc_array_descr) jump() """) +## should ideally be: +## p0 = call_malloc_gc(ConstClass(malloc_fixedsize), \ +## %(unicodedescr.basesize + \ +## 10 * unicodedescr.itemsize)d, \ +## descr=malloc_fixedsize_descr) +## setfield_gc(p0, 10, descr=unicodelendescr) class TestFramework(RewriteTests): @@ -203,7 +217,7 @@ # class FakeCPU(object): def sizeof(self, STRUCT): - descr = SizeDescrWithVTable(102) + descr = SizeDescrWithVTable(104) descr.tid = 9315 return descr self.cpu = FakeCPU() @@ -368,11 +382,9 @@ jump() """, """ [] - p0 = call_malloc_gc(ConstClass(malloc_fixedsize), \ - %(bdescr.basesize + 104)d, \ - descr=malloc_fixedsize_descr) - setfield_gc(p0, 8765, descr=tiddescr) - setfield_gc(p0, 103, descr=blendescr) + p0 = call_malloc_gc(ConstClass(malloc_array), 1, \ + %(bdescr.tid)d, 103, \ + descr=malloc_array_descr) jump() """) @@ -435,9 +447,8 @@ jump() """, """ [p1] - p0 = call_malloc_gc(ConstClass(malloc_fixedsize), 104, \ - descr=malloc_fixedsize_descr) - setfield_gc(p0, 9315, descr=tiddescr) + p0 = call_malloc_gc(ConstClass(malloc_big_fixedsize), 104, 9315, \ + descr=malloc_big_fixedsize_descr) setfield_gc(p0, ConstClass(o_vtable), descr=vtable_descr) jump() """) diff --git a/pypy/jit/backend/x86/test/test_gc_integration.py b/pypy/jit/backend/x86/test/test_gc_integration.py --- a/pypy/jit/backend/x86/test/test_gc_integration.py +++ b/pypy/jit/backend/x86/test/test_gc_integration.py @@ -184,6 +184,8 @@ self.addrs[1] = self.addrs[0] + 64 self.calls = [] def malloc_slowpath(size): + if self.gcrootmap is not None: # hook + self.gcrootmap.hook_malloc_slowpath() self.calls.append(size) # reset the nursery nadr = rffi.cast(lltype.Signed, self.nursery) @@ -257,3 +259,218 @@ assert gc_ll_descr.addrs[0] == nurs_adr + 24 # this should call slow path once assert gc_ll_descr.calls == [24] + + def test_save_regs_around_malloc(self): + S1 = lltype.GcStruct('S1') + S2 = lltype.GcStruct('S2', ('s0', lltype.Ptr(S1)), + ('s1', lltype.Ptr(S1)), + ('s2', lltype.Ptr(S1)), + ('s3', lltype.Ptr(S1)), + ('s4', lltype.Ptr(S1)), + ('s5', lltype.Ptr(S1)), + ('s6', lltype.Ptr(S1)), + ('s7', lltype.Ptr(S1)), + ('s8', lltype.Ptr(S1)), + ('s9', lltype.Ptr(S1)), + ('s10', lltype.Ptr(S1)), + ('s11', lltype.Ptr(S1)), + ('s12', lltype.Ptr(S1)), + ('s13', lltype.Ptr(S1)), + ('s14', lltype.Ptr(S1)), + ('s15', lltype.Ptr(S1))) + cpu = self.cpu + self.namespace = self.namespace.copy() + for i in range(16): + self.namespace['ds%i' % i] = cpu.fielddescrof(S2, 's%d' % i) + ops = ''' + [p0] + p1 = getfield_gc(p0, descr=ds0) + p2 = getfield_gc(p0, descr=ds1) + p3 = getfield_gc(p0, descr=ds2) + p4 = getfield_gc(p0, descr=ds3) + p5 = getfield_gc(p0, descr=ds4) + p6 = getfield_gc(p0, descr=ds5) + p7 = getfield_gc(p0, descr=ds6) + p8 = getfield_gc(p0, descr=ds7) + p9 = getfield_gc(p0, descr=ds8) + p10 = getfield_gc(p0, descr=ds9) + p11 = getfield_gc(p0, descr=ds10) + p12 = getfield_gc(p0, descr=ds11) + p13 = getfield_gc(p0, descr=ds12) + p14 = getfield_gc(p0, descr=ds13) + p15 = getfield_gc(p0, descr=ds14) + p16 = getfield_gc(p0, descr=ds15) + # + # now all registers are in use + p17 = call_malloc_nursery(40) + p18 = call_malloc_nursery(40) # overflow + # + finish(p1, p2, p3, p4, p5, p6, p7, p8, \ + p9, p10, p11, p12, p13, p14, p15, p16) + ''' + s2 = lltype.malloc(S2) + for i in range(16): + setattr(s2, 's%d' % i, lltype.malloc(S1)) + s2ref = lltype.cast_opaque_ptr(llmemory.GCREF, s2) + # + self.interpret(ops, [s2ref]) + gc_ll_descr = cpu.gc_ll_descr + gc_ll_descr.check_nothing_in_nursery() + assert gc_ll_descr.calls == [40] + # check the returned pointers + for i in range(16): + s1ref = self.cpu.get_latest_value_ref(i) + s1 = lltype.cast_opaque_ptr(lltype.Ptr(S1), s1ref) + assert s1 == getattr(s2, 's%d' % i) + + +class MockShadowStackRootMap(MockGcRootMap): + is_shadow_stack = True + MARKER_FRAME = 88 # this marker follows the frame addr + S1 = lltype.GcStruct('S1') + + def __init__(self): + self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 20, + flavor='raw') + # root_stack_top + self.addrs[0] = rffi.cast(lltype.Signed, self.addrs) + 3*WORD + # random stuff + self.addrs[1] = 123456 + self.addrs[2] = 654321 + self.check_initial_and_final_state() + self.callshapes = {} + self.should_see = [] + + def check_initial_and_final_state(self): + assert self.addrs[0] == rffi.cast(lltype.Signed, self.addrs) + 3*WORD + assert self.addrs[1] == 123456 + assert self.addrs[2] == 654321 + + def get_root_stack_top_addr(self): + return rffi.cast(lltype.Signed, self.addrs) + + def compress_callshape(self, shape, datablockwrapper): + assert shape[0] == 'shape' + return ['compressed'] + shape[1:] + + def write_callshape(self, mark, force_index): + assert mark[0] == 'compressed' + assert force_index not in self.callshapes + assert force_index == 42 + len(self.callshapes) + self.callshapes[force_index] = mark + + def hook_malloc_slowpath(self): + num_entries = self.addrs[0] - rffi.cast(lltype.Signed, self.addrs) + assert num_entries == 5*WORD # 3 initially, plus 2 by the asm frame + assert self.addrs[1] == 123456 # unchanged + assert self.addrs[2] == 654321 # unchanged + frame_addr = self.addrs[3] # pushed by the asm frame + assert self.addrs[4] == self.MARKER_FRAME # pushed by the asm frame + # + from pypy.jit.backend.x86.arch import FORCE_INDEX_OFS + addr = rffi.cast(rffi.CArrayPtr(lltype.Signed), + frame_addr + FORCE_INDEX_OFS) + force_index = addr[0] + assert force_index == 43 # in this test: the 2nd call_malloc_nursery + # + # The callshapes[43] saved above should list addresses both in the + # COPY_AREA and in the "normal" stack, where all the 16 values p1-p16 + # of test_save_regs_at_correct_place should have been stored. Here + # we replace them with new addresses, to emulate a moving GC. + shape = self.callshapes[force_index] + assert len(shape[1:]) == len(self.should_see) + new_objects = [None] * len(self.should_see) + for ofs in shape[1:]: + assert isinstance(ofs, int) # not a register at all here + addr = rffi.cast(rffi.CArrayPtr(lltype.Signed), frame_addr + ofs) + contains = addr[0] + for j in range(len(self.should_see)): + obj = self.should_see[j] + if contains == rffi.cast(lltype.Signed, obj): + assert new_objects[j] is None # duplicate? + break + else: + assert 0 # the value read from the stack looks random? + new_objects[j] = lltype.malloc(self.S1) + addr[0] = rffi.cast(lltype.Signed, new_objects[j]) + self.should_see[:] = new_objects + + +class TestMallocShadowStack(BaseTestRegalloc): + + def setup_method(self, method): + cpu = CPU(None, None) + cpu.gc_ll_descr = GCDescrFastpathMalloc() + cpu.gc_ll_descr.gcrootmap = MockShadowStackRootMap() + cpu.setup_once() + for i in range(42): + cpu.reserve_some_free_fail_descr_number() + self.cpu = cpu + + def test_save_regs_at_correct_place(self): + cpu = self.cpu + gc_ll_descr = cpu.gc_ll_descr + S1 = gc_ll_descr.gcrootmap.S1 + S2 = lltype.GcStruct('S2', ('s0', lltype.Ptr(S1)), + ('s1', lltype.Ptr(S1)), + ('s2', lltype.Ptr(S1)), + ('s3', lltype.Ptr(S1)), + ('s4', lltype.Ptr(S1)), + ('s5', lltype.Ptr(S1)), + ('s6', lltype.Ptr(S1)), + ('s7', lltype.Ptr(S1)), + ('s8', lltype.Ptr(S1)), + ('s9', lltype.Ptr(S1)), + ('s10', lltype.Ptr(S1)), + ('s11', lltype.Ptr(S1)), + ('s12', lltype.Ptr(S1)), + ('s13', lltype.Ptr(S1)), + ('s14', lltype.Ptr(S1)), + ('s15', lltype.Ptr(S1))) + self.namespace = self.namespace.copy() + for i in range(16): + self.namespace['ds%i' % i] = cpu.fielddescrof(S2, 's%d' % i) + ops = ''' + [p0] + p1 = getfield_gc(p0, descr=ds0) + p2 = getfield_gc(p0, descr=ds1) + p3 = getfield_gc(p0, descr=ds2) + p4 = getfield_gc(p0, descr=ds3) + p5 = getfield_gc(p0, descr=ds4) + p6 = getfield_gc(p0, descr=ds5) + p7 = getfield_gc(p0, descr=ds6) + p8 = getfield_gc(p0, descr=ds7) + p9 = getfield_gc(p0, descr=ds8) + p10 = getfield_gc(p0, descr=ds9) + p11 = getfield_gc(p0, descr=ds10) + p12 = getfield_gc(p0, descr=ds11) + p13 = getfield_gc(p0, descr=ds12) + p14 = getfield_gc(p0, descr=ds13) + p15 = getfield_gc(p0, descr=ds14) + p16 = getfield_gc(p0, descr=ds15) + # + # now all registers are in use + p17 = call_malloc_nursery(40) + p18 = call_malloc_nursery(40) # overflow + # + finish(p1, p2, p3, p4, p5, p6, p7, p8, \ + p9, p10, p11, p12, p13, p14, p15, p16) + ''' + s2 = lltype.malloc(S2) + for i in range(16): + s1 = lltype.malloc(S1) + setattr(s2, 's%d' % i, s1) + gc_ll_descr.gcrootmap.should_see.append(s1) + s2ref = lltype.cast_opaque_ptr(llmemory.GCREF, s2) + # + self.interpret(ops, [s2ref]) + gc_ll_descr.check_nothing_in_nursery() + assert gc_ll_descr.calls == [40] + gc_ll_descr.gcrootmap.check_initial_and_final_state() + # check the returned pointers + for i in range(16): + s1ref = self.cpu.get_latest_value_ref(i) + s1 = lltype.cast_opaque_ptr(lltype.Ptr(S1), s1ref) + for j in range(16): + assert s1 != getattr(s2, 's%d' % j) + assert s1 == gc_ll_descr.gcrootmap.should_see[i] 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 @@ -289,8 +289,21 @@ assert isinstance(token, TargetToken) assert token.original_jitcell_token is None token.original_jitcell_token = trace.original_jitcell_token - - + + +def do_compile_loop(metainterp_sd, inputargs, operations, looptoken, + log=True, name=''): + metainterp_sd.logger_ops.log_loop(inputargs, operations, -2, + 'compiling', name=name) + return metainterp_sd.cpu.compile_loop(inputargs, operations, looptoken, + log=log, name=name) + +def do_compile_bridge(metainterp_sd, faildescr, inputargs, operations, + original_loop_token, log=True): + metainterp_sd.logger_ops.log_bridge(inputargs, operations, -2) + return metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations, + original_loop_token, log=log) + def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type): vinfo = jitdriver_sd.virtualizable_info if vinfo is not None: @@ -319,9 +332,9 @@ metainterp_sd.profiler.start_backend() debug_start("jit-backend") try: - asminfo = metainterp_sd.cpu.compile_loop(loop.inputargs, operations, - original_jitcell_token, - name=loopname) + asminfo = do_compile_loop(metainterp_sd, loop.inputargs, + operations, original_jitcell_token, + name=loopname) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() @@ -333,7 +346,6 @@ metainterp_sd.stats.compiled() metainterp_sd.log("compiled new " + type) # - loopname = jitdriver_sd.warmstate.get_location_str(greenkey) if asminfo is not None: ops_offset = asminfo.ops_offset else: @@ -365,9 +377,9 @@ metainterp_sd.profiler.start_backend() debug_start("jit-backend") try: - asminfo = metainterp_sd.cpu.compile_bridge(faildescr, inputargs, - operations, - original_loop_token) + asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs, + operations, + original_loop_token) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() 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 @@ -18,6 +18,10 @@ debug_start("jit-log-noopt-loop") logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-loop") + elif number == -2: + debug_start("jit-log-compiling-loop") + logops = self._log_operations(inputargs, operations, ops_offset) + debug_stop("jit-log-compiling-loop") else: debug_start("jit-log-opt-loop") debug_print("# Loop", number, '(%s)' % name , ":", type, @@ -31,6 +35,10 @@ debug_start("jit-log-noopt-bridge") logops = self._log_operations(inputargs, operations, ops_offset) debug_stop("jit-log-noopt-bridge") + elif number == -2: + debug_start("jit-log-compiling-bridge") + logops = self._log_operations(inputargs, operations, ops_offset) + debug_stop("jit-log-compiling-bridge") else: debug_start("jit-log-opt-bridge") debug_print("# bridge out of Guard", number, 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 @@ -398,6 +398,50 @@ with raises(InvalidLoop): self.optimize_loop(ops, ops) + def test_maybe_issue1045_related(self): + ops = """ + [p8] + p54 = getfield_gc(p8, descr=valuedescr) + mark_opaque_ptr(p54) + i55 = getfield_gc(p54, descr=nextdescr) + p57 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p57, i55, descr=otherdescr) + p69 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p69, i55, descr=otherdescr) + i71 = int_eq(i55, -9223372036854775808) + guard_false(i71) [] + i73 = int_mod(i55, 2) + i75 = int_rshift(i73, 63) + i76 = int_and(2, i75) + i77 = int_add(i73, i76) + p79 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p79, i77, descr=otherdescr) + i81 = int_eq(i77, 1) + guard_false(i81) [] + i0 = int_ge(i55, 1) + guard_true(i0) [] + label(p57) + jump(p57) + """ + expected = """ + [p8] + p54 = getfield_gc(p8, descr=valuedescr) + i55 = getfield_gc(p54, descr=nextdescr) + i71 = int_eq(i55, -9223372036854775808) + guard_false(i71) [] + i73 = int_mod(i55, 2) + i75 = int_rshift(i73, 63) + i76 = int_and(2, i75) + i77 = int_add(i73, i76) + i81 = int_eq(i77, 1) + guard_false(i81) [] + i0 = int_ge(i55, 1) + guard_true(i0) [] + label(i55) + jump(i55) + """ + self.optimize_loop(ops, expected) + class OptRenameStrlen(Optimization): def propagate_forward(self, op): dispatch_opt(self, op) @@ -457,7 +501,6 @@ jump(p1, i11) """ self.optimize_loop(ops, expected) - class TestLLtype(OptimizeoptTestMultiLabel, LLtypeMixin): diff --git a/pypy/jit/metainterp/test/test_quasiimmut.py b/pypy/jit/metainterp/test/test_quasiimmut.py --- a/pypy/jit/metainterp/test/test_quasiimmut.py +++ b/pypy/jit/metainterp/test/test_quasiimmut.py @@ -8,7 +8,7 @@ from pypy.jit.metainterp.quasiimmut import get_current_qmut_instance from pypy.jit.metainterp.test.support import LLJitMixin from pypy.jit.codewriter.policy import StopAtXPolicy -from pypy.rlib.jit import JitDriver, dont_look_inside +from pypy.rlib.jit import JitDriver, dont_look_inside, unroll_safe def test_get_current_qmut_instance(): @@ -480,6 +480,32 @@ assert res == 1 self.check_jitcell_token_count(2) + def test_for_loop_array(self): + myjitdriver = JitDriver(greens=[], reds=["n", "i"]) + class Foo(object): + _immutable_fields_ = ["x?[*]"] + def __init__(self, x): + self.x = x + f = Foo([1, 3, 5, 6]) + @unroll_safe + def g(v): + for x in f.x: + if x & 1 == 0: + v += 1 + return v + def main(n): + i = 0 + while i < n: + myjitdriver.jit_merge_point(n=n, i=i) + i = g(i) + return i + res = self.meta_interp(main, [10]) + assert res == 10 + self.check_resops({ + "int_add": 2, "int_lt": 2, "jump": 1, "guard_true": 2, + "guard_not_invalidated": 2 + }) + class TestLLtypeGreenFieldsTests(QuasiImmutTests, LLJitMixin): pass diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -5,14 +5,13 @@ from pypy.rlib import streamio from pypy.rlib.rarithmetic import r_longlong from pypy.rlib.rstring import StringBuilder -from pypy.module._file.interp_stream import (W_AbstractStream, StreamErrors, - wrap_streamerror, wrap_oserror_as_ioerror) +from pypy.module._file.interp_stream import W_AbstractStream, StreamErrors from pypy.module.posix.interp_posix import dispatch_filename from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.typedef import (TypeDef, GetSetProperty, interp_attrproperty, make_weakref_descr, interp_attrproperty_w) from pypy.interpreter.gateway import interp2app, unwrap_spec - +from pypy.interpreter.streamutil import wrap_streamerror, wrap_oserror_as_ioerror class W_File(W_AbstractStream): """An interp-level file object. This implements the same interface than diff --git a/pypy/module/_file/interp_stream.py b/pypy/module/_file/interp_stream.py --- a/pypy/module/_file/interp_stream.py +++ b/pypy/module/_file/interp_stream.py @@ -2,27 +2,13 @@ from pypy.rlib import streamio from pypy.rlib.streamio import StreamErrors -from pypy.interpreter.error import OperationError, wrap_oserror2 +from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app +from pypy.interpreter.streamutil import wrap_streamerror, wrap_oserror_as_ioerror -def wrap_streamerror(space, e, w_filename=None): - if isinstance(e, streamio.StreamError): - return OperationError(space.w_ValueError, - space.wrap(e.message)) - elif isinstance(e, OSError): - return wrap_oserror_as_ioerror(space, e, w_filename) - else: - # should not happen: wrap_streamerror() is only called when - # StreamErrors = (OSError, StreamError) are raised - return OperationError(space.w_IOError, space.w_None) - -def wrap_oserror_as_ioerror(space, e, w_filename=None): - return wrap_oserror2(space, e, w_filename, - w_exception_class=space.w_IOError) - class W_AbstractStream(Wrappable): """Base class for interp-level objects that expose streams to app-level""" slock = None 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 @@ -56,6 +56,8 @@ #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size) +#define _Py_ForgetReference(ob) /* nothing */ + #define Py_None (&_Py_NoneStruct) /* diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py --- a/pypy/module/imp/interp_imp.py +++ b/pypy/module/imp/interp_imp.py @@ -1,10 +1,11 @@ from pypy.module.imp import importing from pypy.module._file.interp_file import W_File from pypy.rlib import streamio +from pypy.rlib.streamio import StreamErrors from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.module import Module from pypy.interpreter.gateway import unwrap_spec -from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror +from pypy.interpreter.streamutil import wrap_streamerror def get_suffixes(space): 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 @@ -357,7 +357,7 @@ def test_cannot_write_pyc(self): import sys, os - p = os.path.join(sys.path[-1], 'readonly') + p = os.path.join(sys.path[0], 'readonly') try: os.chmod(p, 0555) except: 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 @@ -779,8 +779,6 @@ """ Intermediate class for performing binary operations. """ - _immutable_fields_ = ['left', 'right'] - def __init__(self, ufunc, name, shape, calc_dtype, res_dtype, left, right): VirtualArray.__init__(self, name, shape, res_dtype) self.ufunc = ufunc @@ -856,8 +854,6 @@ self.right.create_sig(), done_func) class AxisReduce(Call2): - _immutable_fields_ = ['left', 'right'] - def __init__(self, ufunc, name, identity, shape, dtype, left, right, dim): Call2.__init__(self, ufunc, name, shape, dtype, dtype, left, right) 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 @@ -60,6 +60,9 @@ stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = pipe.communicate() + if getattr(pipe, 'returncode', 0) < 0: + raise IOError("subprocess was killed by signal %d" % ( + pipe.returncode,)) if stderr.startswith('SKIP:'): py.test.skip(stderr) if stderr.startswith('debug_alloc.h:'): # lldebug builds diff --git a/pypy/module/pypyjit/test_pypy_c/test_alloc.py b/pypy/module/pypyjit/test_pypy_c/test_alloc.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_alloc.py @@ -0,0 +1,26 @@ +import py, sys +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + +class TestAlloc(BaseTestPyPyC): + + SIZES = dict.fromkeys([2 ** n for n in range(26)] + # up to 32MB + [2 ** n - 1 for n in range(26)]) + + def test_newstr_constant_size(self): + for size in TestAlloc.SIZES: + yield self.newstr_constant_size, size + + def newstr_constant_size(self, size): + src = """if 1: + N = %(size)d + part_a = 'a' * N + part_b = 'b' * N + for i in xrange(20): + ao = '%%s%%s' %% (part_a, part_b) + def main(): + return 42 +""" % {'size': size} + log = self.run(src, [], threshold=10) + assert log.result == 42 + loop, = log.loops_by_filename(self.filepath) + # assert did not crash 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 @@ -201,3 +201,28 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id("compare", "") # optimized away + def test_super(self): + def main(): + class A(object): + def m(self, x): + return x + 1 + class B(A): + def m(self, x): + return super(B, self).m(x) + i = 0 + while i < 300: + i = B().m(i) + return i + + log = self.run(main, []) + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i78 = int_lt(i72, 300) + guard_true(i78, descr=...) + guard_not_invalidated(descr=...) + i79 = force_token() + i80 = force_token() + i81 = int_add(i72, 1) + --TICK-- + jump(..., descr=...) + """) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -103,6 +103,7 @@ 'terminator', '_version_tag?', 'name?', + 'mro_w?[*]', ] # for config.objspace.std.getattributeshortcut @@ -345,9 +346,9 @@ return w_self._lookup_where(name) + @unroll_safe def lookup_starting_at(w_self, w_starttype, name): space = w_self.space - # XXX Optimize this with method cache look = False for w_class in w_self.mro_w: if w_class is w_starttype: diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py --- a/pypy/rpython/lltypesystem/rlist.py +++ b/pypy/rpython/lltypesystem/rlist.py @@ -392,7 +392,11 @@ ('list', r_list.lowleveltype), ('index', Signed))) self.ll_listiter = ll_listiter - self.ll_listnext = ll_listnext + if (isinstance(r_list, FixedSizeListRepr) + and not r_list.listitem.mutated): + self.ll_listnext = ll_listnext_foldable + else: + self.ll_listnext = ll_listnext self.ll_getnextindex = ll_getnextindex def ll_listiter(ITERPTR, lst): @@ -409,5 +413,14 @@ iter.index = index + 1 # cannot overflow because index < l.length return l.ll_getitem_fast(index) +def ll_listnext_foldable(iter): + from pypy.rpython.rlist import ll_getitem_foldable_nonneg + l = iter.list + index = iter.index + if index >= l.ll_length(): + raise StopIteration + iter.index = index + 1 # cannot overflow because index < l.length + return ll_getitem_foldable_nonneg(l, index) + def ll_getnextindex(iter): return iter.index diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -608,6 +608,11 @@ specified as 0 if the object is not varsized. The returned object is fully initialized and zero-filled.""" # + # Here we really need a valid 'typeid', not 0 (as the JIT might + # try to send us if there is still a bug). + ll_assert(bool(self.combine(typeid, 0)), + "external_malloc: typeid == 0") + # # Compute the total size, carefully checking for overflows. size_gc_header = self.gcheaderbuilder.size_gc_header nonvarsize = size_gc_header + self.fixed_size(typeid) diff --git a/pypy/rpython/test/test_rlist.py b/pypy/rpython/test/test_rlist.py --- a/pypy/rpython/test/test_rlist.py +++ b/pypy/rpython/test/test_rlist.py @@ -8,6 +8,7 @@ from pypy.rpython.rlist import * from pypy.rpython.lltypesystem.rlist import ListRepr, FixedSizeListRepr, ll_newlist, ll_fixed_newlist from pypy.rpython.lltypesystem import rlist as ll_rlist +from pypy.rpython.llinterp import LLException from pypy.rpython.ootypesystem import rlist as oo_rlist from pypy.rpython.rint import signed_repr from pypy.objspace.flow.model import Constant, Variable @@ -1477,6 +1478,80 @@ assert func1.oopspec == 'list.getitem_foldable(l, index)' assert not hasattr(func2, 'oopspec') + def test_iterate_over_immutable_list(self): + from pypy.rpython import rlist + class MyException(Exception): + pass + lst = list('abcdef') + def dummyfn(): + total = 0 + for c in lst: + total += ord(c) + return total + # + prev = rlist.ll_getitem_foldable_nonneg + try: + def seen_ok(l, index): + if index == 5: + raise KeyError # expected case + return prev(l, index) + rlist.ll_getitem_foldable_nonneg = seen_ok + e = raises(LLException, self.interpret, dummyfn, []) + assert 'KeyError' in str(e.value) + finally: + rlist.ll_getitem_foldable_nonneg = prev + + def test_iterate_over_immutable_list_quasiimmut_attr(self): + from pypy.rpython import rlist + class MyException(Exception): + pass + class Foo: + _immutable_fields_ = ['lst?[*]'] + lst = list('abcdef') + foo = Foo() + def dummyfn(): + total = 0 + for c in foo.lst: + total += ord(c) + return total + # + prev = rlist.ll_getitem_foldable_nonneg + try: + def seen_ok(l, index): + if index == 5: + raise KeyError # expected case + return prev(l, index) + rlist.ll_getitem_foldable_nonneg = seen_ok + e = raises(LLException, self.interpret, dummyfn, []) + assert 'KeyError' in str(e.value) + finally: + rlist.ll_getitem_foldable_nonneg = prev + + def test_iterate_over_mutable_list(self): + from pypy.rpython import rlist + class MyException(Exception): + pass + lst = list('abcdef') + def dummyfn(): + total = 0 + for c in lst: + total += ord(c) + lst[0] = 'x' + return total + # + prev = rlist.ll_getitem_foldable_nonneg + try: + def seen_ok(l, index): + if index == 5: + raise KeyError # expected case + return prev(l, index) + rlist.ll_getitem_foldable_nonneg = seen_ok + res = self.interpret(dummyfn, []) + assert res == sum(map(ord, 'abcdef')) + finally: + rlist.ll_getitem_foldable_nonneg = prev + + class TestOOtype(BaseTestRlist, OORtypeMixin): rlist = oo_rlist type_system = 'ootype' _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit