From pedronis at codespeak.net Tue Sep 1 10:37:08 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Sep 2009 10:37:08 +0200 (CEST) Subject: [pypy-svn] r67375 - in pypy/branch/newtrunk/pypy: . jit/metainterp jit/metainterp/test Message-ID: <20090901083708.71F0B168014@codespeak.net> Author: pedronis Date: Tue Sep 1 10:37:06 2009 New Revision: 67375 Modified: pypy/branch/newtrunk/pypy/ (props changed) pypy/branch/newtrunk/pypy/jit/metainterp/optimizefindnode.py pypy/branch/newtrunk/pypy/jit/metainterp/pyjitpl.py pypy/branch/newtrunk/pypy/jit/metainterp/test/oparser.py pypy/branch/newtrunk/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/branch/newtrunk/pypy/jit/metainterp/test/test_recursive.py pypy/branch/newtrunk/pypy/jit/metainterp/test/test_zrpy_recursive.py Log: (micke, pedronis) merge 67365 to 67370 from branch/pyjitpl5 Modified: pypy/branch/newtrunk/pypy/jit/metainterp/optimizefindnode.py ============================================================================== --- pypy/branch/newtrunk/pypy/jit/metainterp/optimizefindnode.py (original) +++ pypy/branch/newtrunk/pypy/jit/metainterp/optimizefindnode.py Tue Sep 1 10:37:06 2009 @@ -127,6 +127,16 @@ self.nodes[box] = node return node + def is_constant_box(self, box): + if isinstance(box, Const): + return True + try: + node = self.nodes[box] + except KeyError: + return False + else: + return node.is_constant() + def find_nodes(self, operations): for op in operations: opnum = op.opnum @@ -156,7 +166,6 @@ find_nodes_OOISNULL = find_nodes_no_escape find_nodes_OOIS = find_nodes_no_escape find_nodes_OOISNOT = find_nodes_no_escape - find_nodes_ARRAYLEN_GC = find_nodes_no_escape find_nodes_INSTANCEOF = find_nodes_no_escape def find_nodes_NEW_WITH_VTABLE(self, op): @@ -171,13 +180,19 @@ def find_nodes_NEW_ARRAY(self, op): lengthbox = op.args[0] - if not isinstance(lengthbox, ConstInt): + if not self.is_constant_box(lengthbox): return # var-sized arrays are not virtual arraynode = InstanceNode() - arraynode.arraysize = lengthbox.value + arraynode.arraysize = lengthbox.getint() arraynode.arraydescr = op.descr self.nodes[op.result] = arraynode + def find_nodes_ARRAYLEN_GC(self, op): + arraynode = self.getnode(op.args[0]) + if arraynode.arraydescr is not None: + assert op.result.getint() == arraynode.arraysize + self.set_constant_node(op.result) + def find_nodes_GUARD_CLASS(self, op): instnode = self.getnode(op.args[0]) if instnode.fromstart: # only useful (and safe) in this case @@ -225,7 +240,7 @@ def find_nodes_SETARRAYITEM_GC(self, op): indexbox = op.args[1] - if not isinstance(indexbox, ConstInt): + if not self.is_constant_box(indexbox): self.find_nodes_default(op) # not a Const index return arraynode = self.getnode(op.args[0]) @@ -235,18 +250,18 @@ return # nothing to be gained from tracking the item if arraynode.curitems is None: arraynode.curitems = {} - arraynode.curitems[indexbox.value] = itemnode + arraynode.curitems[indexbox.getint()] = itemnode arraynode.add_escape_dependency(itemnode) def find_nodes_GETARRAYITEM_GC(self, op): indexbox = op.args[1] - if not isinstance(indexbox, ConstInt): + if not self.is_constant_box(indexbox): self.find_nodes_default(op) # not a Const index return arraynode = self.getnode(op.args[0]) if arraynode.escaped: return # nothing to be gained from tracking the item - index = indexbox.value + index = indexbox.getint() if arraynode.curitems is not None and index in arraynode.curitems: itemnode = arraynode.curitems[index] elif arraynode.origitems is not None and index in arraynode.origitems: Modified: pypy/branch/newtrunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/newtrunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/newtrunk/pypy/jit/metainterp/pyjitpl.py Tue Sep 1 10:37:06 2009 @@ -809,7 +809,8 @@ pass # xxx? def generate_merge_point(self, pc, varargs): - if self.metainterp.is_blackholing(): + # XXX could be sped up by calling the portal if in_recursion is non-zero + if self.metainterp.is_blackholing() and not self.metainterp.in_recursion: raise self.metainterp.staticdata.ContinueRunningNormally(varargs) num_green_args = self.metainterp.staticdata.num_green_args for i in range(num_green_args): @@ -1246,7 +1247,6 @@ debug_print('~~~ LEAVE', self.history.extratext) def interpret(self): - self.in_recursion = 0 if we_are_translated(): self._interpret() else: @@ -1476,6 +1476,7 @@ *args[1:]) def initialize_state_from_start(self, *args): + self.in_recursion = 0 self.staticdata._setup_once() self.staticdata.profiler.start_tracing() self.create_empty_history() @@ -1492,6 +1493,7 @@ def initialize_state_from_guard_failure(self, guard_failure): # guard failure: rebuild a complete MIFrame stack + self.in_recursion = 0 resumedescr = guard_failure.descr assert isinstance(resumedescr, compile.ResumeGuardDescr) warmrunnerstate = self.staticdata.state @@ -1617,7 +1619,10 @@ jitcode, pc, exception_target = resumereader.consume_frame_info() env = resumereader.consume_boxes() f = self.newframe(jitcode) + if jitcode is self.staticdata.portal_code: + self.in_recursion += 1 f.setup_resume_at_op(pc, exception_target, env) + self.in_recursion -= 1 # always one portal around def check_synchronized_virtualizable(self): if not we_are_translated(): Modified: pypy/branch/newtrunk/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/newtrunk/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/newtrunk/pypy/jit/metainterp/test/oparser.py Tue Sep 1 10:37:06 2009 @@ -186,8 +186,10 @@ ops = [] newlines = [] for line in lines: - if not line.strip() or line.strip().startswith("#"): - continue # a comment + if '#' in line: + line = line[:line.index('#')] # remove comment + if not line.strip(): + continue # a comment or empty line newlines.append(line) base_indent, inpargs = self.parse_inpargs(newlines[0]) newlines = newlines[1:] Modified: pypy/branch/newtrunk/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/branch/newtrunk/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/branch/newtrunk/pypy/jit/metainterp/test/test_optimizefindnode.py Tue Sep 1 10:37:06 2009 @@ -74,8 +74,25 @@ sbox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S))) arraydescr2 = cpu.arraydescrof(lltype.GcArray(lltype.Ptr(S))) + T = lltype.GcStruct('TUPLE', + ('c', lltype.Signed), + ('d', lltype.Ptr(lltype.GcArray(lltype.Ptr(NODE))))) + tsize = cpu.sizeof(T) + cdescr = cpu.fielddescrof(T, 'c') + ddescr = cpu.fielddescrof(T, 'd') + arraydescr3 = cpu.arraydescrof(lltype.GcArray(lltype.Ptr(NODE))) + + U = lltype.GcStruct('U', + ('parent', OBJECT), + ('one', lltype.Ptr(lltype.GcArray(lltype.Ptr(NODE))))) + u_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) + u_vtable_adr = llmemory.cast_ptr_to_adr(u_vtable) + usize = cpu.sizeof(U) + onedescr = cpu.fielddescrof(U, 'one') + cpu.class_sizes = {cpu.cast_adr_to_int(node_vtable_adr): cpu.sizeof(NODE), - cpu.cast_adr_to_int(node_vtable_adr2): cpu.sizeof(NODE2)} + cpu.cast_adr_to_int(node_vtable_adr2): cpu.sizeof(NODE2), + cpu.cast_adr_to_int(u_vtable_adr): cpu.sizeof(U)} namespace = locals() class OOtypeMixin(object): @@ -117,6 +134,19 @@ sbox = BoxObj(ootype.cast_to_object(ootype.new(S))) arraydescr2 = cpu.arraydescrof(ootype.Array(S)) + T = ootype.Record({'c': ootype.Signed, + 'd': ootype.Array(NODE)}) + tsize = cpu.typedescrof(T) + cdescr = cpu.fielddescrof(T, 'c') + ddescr = cpu.fielddescrof(T, 'd') + arraydescr3 = cpu.arraydescrof(ootype.Array(NODE)) + + U = ootype.Instance('U', ootype.ROOT, {'one': ootype.Array(NODE)}) + usize = cpu.typedescrof(U) + onedescr = cpu.fielddescrof(U, 'one') + u_vtable = ootype.runtimeClass(U) + u_vtable_adr = ootype.cast_to_object(u_vtable) + # force a consistent order valuedescr.sort_key() nextdescr.sort_key() @@ -124,7 +154,8 @@ bdescr.sort_key() cpu.class_sizes = {node_vtable_adr: cpu.typedescrof(NODE), - node_vtable_adr2: cpu.typedescrof(NODE2)} + node_vtable_adr2: cpu.typedescrof(NODE2), + u_vtable_adr: cpu.typedescrof(U)} namespace = locals() class BaseTest(object): @@ -739,6 +770,128 @@ """ self.find_nodes(ops, 'Not, Not') + def test_find_nodes_arithmetic_propagation_bug_0(self): + ops = """ + [p1] + i1 = getarrayitem_gc(p1, 0, descr=arraydescr) + escape(i1) + i2 = int_add(0, 1) + p2 = new_array(i2, descr=arraydescr) + i3 = escape() + setarrayitem_gc(p2, 0, i3, descr=arraydescr) + jump(p2) + """ + self.find_nodes(ops, 'VArray(arraydescr, Not)', i2=1) + + def test_find_nodes_arithmetic_propagation_bug_1(self): + ops = """ + [p1] + i1 = getarrayitem_gc(p1, 0, descr=arraydescr) + escape(i1) + i2 = same_as(1) + p2 = new_array(i2, descr=arraydescr) + setarrayitem_gc(p2, 0, 5) + jump(p2) + """ + self.find_nodes(ops, 'VArray(arraydescr, Not)', i2=1) + + def test_find_nodes_arithmetic_propagation_bug_2(self): + ops = """ + [p1] + i0 = int_sub(17, 17) + i1 = getarrayitem_gc(p1, i0, descr=arraydescr) + escape(i1) + i2 = int_add(0, 1) + p2 = new_array(i2, descr=arraydescr) + i3 = escape() + setarrayitem_gc(p2, i0, i3, descr=arraydescr) + jump(p2) + """ + self.find_nodes(ops, 'VArray(arraydescr, Not)', i2=1, i0=0) + + def test_find_nodes_arithmetic_propagation_bug_3(self): + ops = """ + [p1] + i1 = getarrayitem_gc(p1, 0, descr=arraydescr) + escape(i1) + p3 = new_array(1, descr=arraydescr) + i2 = arraylen_gc(p3, descr=arraydescr) + p2 = new_array(i2, descr=arraydescr) + i3 = escape() + setarrayitem_gc(p2, 0, i3, descr=arraydescr) + jump(p2) + """ + self.find_nodes(ops, 'VArray(arraydescr, Not)', i2=1) + + def test_find_nodes_bug_1(self): + ops = """ + [p12] + i16 = ooisnull(p12) + guard_false(i16) + fail() + guard_class(p12, ConstClass(node_vtable)) + fail() + guard_class(p12, ConstClass(node_vtable)) + fail() + i22 = getfield_gc_pure(p12, descr=valuedescr) + escape(i22) + i25 = ooisnull(p12) + guard_false(i25) + fail() + guard_class(p12, ConstClass(node_vtable)) + fail() + guard_class(p12, ConstClass(node_vtable)) + fail() + i29 = getfield_gc_pure(p12, descr=valuedescr) + i31 = int_add_ovf(i29, 1) + guard_no_overflow() + fail() + p33 = new_with_vtable(ConstClass(node_vtable)) # NODE + setfield_gc(p33, i31, descr=valuedescr) + # + p35 = new_array(1, descr=arraydescr3) # Array(NODE) + setarrayitem_gc(p35, 0, p33, descr=arraydescr3) + p38 = new_with_vtable(ConstClass(u_vtable)) # U + setfield_gc(p38, p35, descr=onedescr) + i39 = ooisnull(p38) + guard_false(i39) + fail() + i40 = oononnull(p38) + guard_true(i40) + fail() + guard_class(p38, ConstClass(u_vtable)) + fail() + p42 = getfield_gc(p38, descr=onedescr) # Array(NODE) + i43 = arraylen_gc(p42, descr=arraydescr3) + i45 = int_sub(i43, 0) + p46 = new(descr=tsize) # T + setfield_gc(p46, i45, descr=cdescr) + p47 = new_array(i45, descr=arraydescr3) # Array(NODE) + setfield_gc(p46, p47, descr=ddescr) + i48 = int_lt(0, i43) + guard_true(i48) + fail() + p49 = getarrayitem_gc(p42, 0, descr=arraydescr3) # NODE + p50 = getfield_gc(p46, descr=ddescr) # Array(NODE) + setarrayitem_gc(p50, 0, p49, descr=arraydescr3) + i52 = int_lt(1, i43) + guard_false(i52) + fail() + i53 = getfield_gc(p46, descr=cdescr) + i55 = int_ne(i53, 1) + guard_false(i55) + fail() + p56 = getfield_gc(p46, descr=ddescr) # Array(NODE) + p58 = getarrayitem_gc(p56, 0, descr=arraydescr3) # NODE + i59 = ooisnull(p38) + guard_false(i59) + fail() + jump(p58) + """ + self.find_nodes(ops, 'Virtual(node_vtable, valuedescr=Not)', + i16=0, i25=0, i39=0, i52=0, i55=0, i59=0, + i43=1, i45=1, i48=1, i40=1) + # ------------------------------ # Bridge tests Modified: pypy/branch/newtrunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/newtrunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/newtrunk/pypy/jit/metainterp/test/test_recursive.py Tue Sep 1 10:37:06 2009 @@ -176,6 +176,41 @@ else: py.test.fail("DID NOT RAISE") + def test_inner_failure(self): + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], get_printable_location=p) + def f(code, n): + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(n=n, code=code, pc=pc) + op = code[pc] + if op == "-": + n -= 1 + elif op == "c": + n = f("---i---", n) + elif op == "i": + if n % 5 == 1: + return n + elif op == "l": + if n > 0: + myjitdriver.can_enter_jit(n=n, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return n + def main(n): + return f("c-l", n) + print main(100) + res = self.meta_interp(main, [100], optimizer=simple_optimize) + assert res == 0 + + class TestLLtype(RecursiveTests, LLJitMixin): pass Modified: pypy/branch/newtrunk/pypy/jit/metainterp/test/test_zrpy_recursive.py ============================================================================== --- pypy/branch/newtrunk/pypy/jit/metainterp/test/test_zrpy_recursive.py (original) +++ pypy/branch/newtrunk/pypy/jit/metainterp/test/test_zrpy_recursive.py Tue Sep 1 10:37:06 2009 @@ -14,6 +14,5 @@ # ==========> test_recursive.py - @py.test.mark.xfail def test_inline_faulty_can_inline(self): - test_recursive.RecursiveTests.test_inline_faulty_can_inline(self) + py.test.skip("XXX does not work with LLException") From pedronis at codespeak.net Tue Sep 1 10:39:34 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Sep 2009 10:39:34 +0200 (CEST) Subject: [pypy-svn] r67377 - in pypy: branch/newtrunk trunk Message-ID: <20090901083934.75BAA168014@codespeak.net> Author: pedronis Date: Tue Sep 1 10:39:33 2009 New Revision: 67377 Added: pypy/trunk/ - copied from r67376, pypy/branch/newtrunk/ Removed: pypy/branch/newtrunk/ Log: (micke, pedronis) newtrunk with old trunk and jit developments becomes trunk From pedronis at codespeak.net Tue Sep 1 10:41:43 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Sep 2009 10:41:43 +0200 (CEST) Subject: [pypy-svn] r67378 - pypy/branch/pyjitpl5 Message-ID: <20090901084143.AEEAA168014@codespeak.net> Author: pedronis Date: Tue Sep 1 10:41:43 2009 New Revision: 67378 Removed: pypy/branch/pyjitpl5/ Log: (micke, pedronis) use trunk for mainline jit development now! From pedronis at codespeak.net Tue Sep 1 10:46:48 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Sep 2009 10:46:48 +0200 (CEST) Subject: [pypy-svn] r67379 - pypy/build/bot2/pypybuildbot Message-ID: <20090901084648.A6F64168014@codespeak.net> Author: pedronis Date: Tue Sep 1 10:46:48 2009 New Revision: 67379 Modified: pypy/build/bot2/pypybuildbot/master.py Log: (micke, pedronis) run JITLINUX32 build against trunk now Modified: pypy/build/bot2/pypybuildbot/master.py ============================================================================== --- pypy/build/bot2/pypybuildbot/master.py (original) +++ pypy/build/bot2/pypybuildbot/master.py Tue Sep 1 10:46:48 2009 @@ -52,12 +52,8 @@ 'change_source': [], 'schedulers': [ Nightly("nightly", [LINUX32, CPYLINUX32, APPLVLLINUX32, CPYWIN32, - STACKLESSAPPLVLLINUX32], + STACKLESSAPPLVLLINUX32, JITLINUX32], hour=4, minute=45), - #Nightly("nightly-jit", [LINUX32, JITLINUX32], - # hour=1, minute=45, branch="branch/pyjitpl5"), - Nightly("nightly-jit", [LINUX32, JITLINUX32], - hour=1, minute=45, branch="branch/pyjitpl5-experiments"), ], 'status': [status], From cfbolz at codespeak.net Tue Sep 1 10:48:53 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 1 Sep 2009 10:48:53 +0200 (CEST) Subject: [pypy-svn] r67380 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090901084853.B793F168014@codespeak.net> Author: cfbolz Date: Tue Sep 1 10:48:52 2009 New Revision: 67380 Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/test_recursive.py pypy/trunk/pypy/jit/metainterp/warmspot.py Log: speed up the blackhole interpreter when getting out of recursive portal calls: use the actual portal to do most of the work, interpret one bytecode per recursion level with the blackhole interpreter. Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/codewriter.py Tue Sep 1 10:48:52 2009 @@ -141,9 +141,14 @@ return bytecode def get_jitcode_calldescr(self, graph, oosend_methdescr): - if self.portal_graph is None or graph is self.portal_graph: + if self.portal_graph is None: return () - fnptr = self.rtyper.getcallable(graph) + if graph is self.portal_graph: + fnptr = self.metainterp_sd.warmrunnerdesc.portal_ptr + FUNC = self.metainterp_sd.warmrunnerdesc.PORTAL_FUNCTYPE + else: + fnptr = self.rtyper.getcallable(graph) + FUNC = get_functype(lltype.typeOf(fnptr)) if self.rtyper.type_system.name == 'ootypesystem': if oosend_methdescr: return (None, oosend_methdescr) @@ -153,7 +158,6 @@ assert not oosend_methdescr cfnptr = history.ConstAddr(llmemory.cast_ptr_to_adr(fnptr), self.cpu) - FUNC = get_functype(lltype.typeOf(fnptr)) # # these functions come from somewhere and are never called. make sure # we never store a pointer to them since they make C explode, Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Tue Sep 1 10:48:52 2009 @@ -809,12 +809,25 @@ pass # xxx? def generate_merge_point(self, pc, varargs): - # XXX could be sped up by calling the portal if in_recursion is non-zero - if self.metainterp.is_blackholing() and not self.metainterp.in_recursion: - raise self.metainterp.staticdata.ContinueRunningNormally(varargs) + if self.metainterp.is_blackholing(): + if self.metainterp.in_recursion: + portal_code = self.metainterp.staticdata.portal_code + # small hack: fish for the result box + lenenv = len(self.env) + self.perform_call(portal_code, varargs) + if lenenv == len(self.env): + res = None + else: + assert lenenv == len(self.env) - 1 + res = self.env.pop() + self.metainterp.finishframe(res) + return True + else: + raise self.metainterp.staticdata.ContinueRunningNormally(varargs) num_green_args = self.metainterp.staticdata.num_green_args for i in range(num_green_args): varargs[i] = self.implement_guard_value(pc, varargs[i]) + return False @arguments("orgpc") def opimpl_can_enter_jit(self, pc): @@ -829,12 +842,13 @@ @arguments("orgpc") def opimpl_jit_merge_point(self, pc): - self.generate_merge_point(pc, self.env) + res = self.generate_merge_point(pc, self.env) if DEBUG > 0: self.debug_merge_point() if self.metainterp.seen_can_enter_jit: self.metainterp.seen_can_enter_jit = False self.metainterp.reached_can_enter_jit(self.env) + return res def debug_merge_point(self): # debugging: produce a DEBUG_MERGE_POINT operation Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Tue Sep 1 10:48:52 2009 @@ -176,12 +176,15 @@ else: py.test.fail("DID NOT RAISE") - def test_inner_failure(self): + def test_guard_failure_in_inlined_function(self): from pypy.rpython.annlowlevel import hlstr def p(code, pc): code = hlstr(code) return "%s %d %s" % (code, pc, code[pc]) - myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], get_printable_location=p) + def c(code, pc): + return "l" not in hlstr(code) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], + get_printable_location=p, can_inline=c) def f(code, n): pc = 0 while pc < len(code): @@ -207,7 +210,7 @@ def main(n): return f("c-l", n) print main(100) - res = self.meta_interp(main, [100], optimizer=simple_optimize) + res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) assert res == 0 Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Tue Sep 1 10:48:52 2009 @@ -371,6 +371,7 @@ # portal_ptr = self.cpu.ts.functionptr(PORTALFUNC, 'portal', graph = portalgraph) + self.portal_ptr = portal_ptr portalfunc_ARGS = unrolling_iterable( [(i, 'arg%d' % i, ARG) for i, ARG in enumerate(PORTALFUNC.ARGS)]) From pedronis at codespeak.net Tue Sep 1 10:53:24 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Sep 2009 10:53:24 +0200 (CEST) Subject: [pypy-svn] r67381 - pypy/extradoc/planning Message-ID: <20090901085324.95656168014@codespeak.net> Author: pedronis Date: Tue Sep 1 10:53:24 2009 New Revision: 67381 Modified: pypy/extradoc/planning/jit.txt Log: this is done now Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Tue Sep 1 10:53:24 2009 @@ -5,8 +5,6 @@ - streamline calls - stability! -- merge the jit branch to trunk - - upgrade python on wyvern - improve test running, compile only once - sort out a benchmark infrastructure. graphs!!! From cfbolz at codespeak.net Tue Sep 1 11:00:02 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 1 Sep 2009 11:00:02 +0200 (CEST) Subject: [pypy-svn] r67382 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090901090002.0A614168014@codespeak.net> Author: cfbolz Date: Tue Sep 1 11:00:02 2009 New Revision: 67382 Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py Log: Improve the precision of the optimization removing getfields: so far setfields to unrelated fields would kill all stored field information. Stop doing that. Also don't kill the fields on overflowing arithmetic operations and on setarrayitems. Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimizeopt.py Tue Sep 1 11:00:02 2009 @@ -335,8 +335,13 @@ self.cpu = cpu self.loop = loop self.values = {} - self.values_to_clean = [] # OptValues to clean when we see an - # operation with side-effects + # OptValues to clean when we see an operation with side-effects + # they are ordered by fielddescrs of the affected fields + # note: it is important that this is not a av_newdict2 dict! + # we want more precision to not clear unrelated fields, just because + # they are at the same offset (but in a different struct type) + self.values_to_clean = {} + self.interned_refs = {} def getinterned(self, box): @@ -504,6 +509,21 @@ op2.suboperations = op1.suboperations op1.optimized = op2 + def clean_fields_of_values(self, descr=None): + if descr is None: + for descr, values in self.values_to_clean.iteritems(): + for value in values: + value._fields.clear() + self.values_to_clean = {} + else: + for value in self.values_to_clean.get(descr, []): + del value._fields[descr] + self.values_to_clean[descr] = [] + + def register_value_to_clean(self, value, descr): + self.values_to_clean.setdefault(descr, []).append(value) + + def optimize_default(self, op): if op.is_always_pure(): for arg in op.args: @@ -513,10 +533,9 @@ # all constant arguments: constant-fold away self.make_constant(op.result) return - elif not op.has_no_side_effect(): - for value in self.values_to_clean: - value._fields.clear() - del self.values_to_clean[:] + elif not op.has_no_side_effect() and not op.is_ovf(): + print "cleaning everything", op + self.clean_fields_of_values() # otherwise, the operation remains self.emit_operation(op) @@ -567,6 +586,12 @@ self.emit_operation(op) self.exception_might_have_happened = False + def optimize_GUARD_NO_OVERFLOW(self, op): + # otherwise the default optimizer will clear fields, which is unwanted + # in this case + self.emit_operation(op) + + def _optimize_nullness(self, op, expect_nonnull): if self.known_nonnull(op.args[0]): assert op.result.getint() == expect_nonnull @@ -635,7 +660,7 @@ self.optimize_default(op) # then remember the result of reading the field value._fields[op.descr] = self.getvalue(op.result) - self.values_to_clean.append(value) + self.register_value_to_clean(value, op.descr) # note: the following line does not mean that the two operations are # completely equivalent, because GETFIELD_GC_PURE is_always_pure(). @@ -647,12 +672,15 @@ value.setfield(op.descr, self.getvalue(op.args[1])) else: value.make_nonnull() - self.optimize_default(op) + self.emit_operation(op) + # kill all fields with the same descr, as those could be affected + # by this setfield (via aliasing) + self.clean_fields_of_values(op.descr) # remember the result of future reads of the field if value._fields is None: value._fields = av_newdict2() value._fields[op.descr] = self.getvalue(op.args[1]) - self.values_to_clean.append(value) + self.register_value_to_clean(value, op.descr) def optimize_NEW_WITH_VTABLE(self, op): self.make_virtual(op.args[0], op.result, op) @@ -704,7 +732,9 @@ value.setitem(indexbox.getint(), self.getvalue(op.args[2])) else: value.make_nonnull() - self.optimize_default(op) + # don't use optimize_default, because otherwise unrelated struct + # fields will be cleared + self.emit_operation(op) def optimize_INSTANCEOF(self, op): value = self.getvalue(op.args[0]) @@ -716,6 +746,7 @@ def optimize_DEBUG_MERGE_POINT(self, op): # special-case this operation to prevent e.g. the handling of # 'values_to_clean' (the op cannot be marked as side-effect-free) + # otherwise it would be removed self.newoperations.append(op) optimize_ops = _findall(Optimizer, 'optimize_') Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py Tue Sep 1 11:00:02 2009 @@ -943,7 +943,7 @@ """ self.optimize_loop(ops, 'Not', expected) - def test_duplicate_getfield_2(self): + def test_getfield_after_setfield(self): ops = """ [p1, i1] setfield_gc(p1, i1, descr=valuedescr) @@ -959,7 +959,36 @@ """ self.optimize_loop(ops, 'Not, Not', expected) - def test_duplicate_getfield_3(self): + def test_setfield_of_different_type_does_not_clear(self): + ops = """ + [p1, p2, i1] + setfield_gc(p1, i1, descr=valuedescr) + setfield_gc(p2, p1, descr=nextdescr) + i2 = getfield_gc(p1, descr=valuedescr) + escape(i2) + jump(p1, p2, i1) + """ + expected = """ + [p1, p2, i1] + setfield_gc(p1, i1, descr=valuedescr) + setfield_gc(p2, p1, descr=nextdescr) + escape(i1) + jump(p1, p2, i1) + """ + self.optimize_loop(ops, 'Not, Not, Not', expected) + + def test_setfield_of_same_type_clears(self): + ops = """ + [p1, p2, i1, i2] + setfield_gc(p1, i1, descr=valuedescr) + setfield_gc(p2, i2, descr=valuedescr) + i3 = getfield_gc(p1, descr=valuedescr) + escape(i3) + jump(p1, p2, i1, i3) + """ + self.optimize_loop(ops, 'Not, Not, Not, Not', ops) + + def test_duplicate_getfield_mergepoint_has_no_side_effects(self): ops = """ [p1] i1 = getfield_gc(p1, descr=valuedescr) @@ -979,6 +1008,50 @@ """ self.optimize_loop(ops, 'Not', expected) + def test_duplicate_getfield_ovf_op_does_not_clear(self): + ops = """ + [p1] + i1 = getfield_gc(p1, descr=valuedescr) + i2 = int_add_ovf(i1, 14) + guard_no_overflow() + fail() + i3 = getfield_gc(p1, descr=valuedescr) + escape(i2) + escape(i3) + jump(p1) + """ + expected = """ + [p1] + i1 = getfield_gc(p1, descr=valuedescr) + i2 = int_add_ovf(i1, 14) + guard_no_overflow() + fail() + escape(i2) + escape(i1) + jump(p1) + """ + self.optimize_loop(ops, 'Not', expected) + + def test_duplicate_getfield_setarrayitem_does_not_clear(self): + ops = """ + [p1, p2] + i1 = getfield_gc(p1, descr=valuedescr) + setarrayitem_gc(p2, 0, p1, descr=arraydescr2) + i3 = getfield_gc(p1, descr=valuedescr) + escape(i1) + escape(i3) + jump(p1, p2) + """ + expected = """ + [p1, p2] + i1 = getfield_gc(p1, descr=valuedescr) + setarrayitem_gc(p2, 0, p1, descr=arraydescr2) + escape(i1) + escape(i1) + jump(p1, p2) + """ + self.optimize_loop(ops, 'Not, Not', expected) + def test_duplicate_getfield_constant(self): ops = """ [] From cfbolz at codespeak.net Tue Sep 1 11:35:43 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 1 Sep 2009 11:35:43 +0200 (CEST) Subject: [pypy-svn] r67383 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090901093543.DBD87168014@codespeak.net> Author: cfbolz Date: Tue Sep 1 11:35:41 2009 New Revision: 67383 Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py Log: kill debug print Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimizeopt.py Tue Sep 1 11:35:41 2009 @@ -534,7 +534,6 @@ self.make_constant(op.result) return elif not op.has_no_side_effect() and not op.is_ovf(): - print "cleaning everything", op self.clean_fields_of_values() # otherwise, the operation remains self.emit_operation(op) From cfbolz at codespeak.net Tue Sep 1 11:47:48 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 1 Sep 2009 11:47:48 +0200 (CEST) Subject: [pypy-svn] r67384 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090901094748.26B2E168014@codespeak.net> Author: cfbolz Date: Tue Sep 1 11:47:47 2009 New Revision: 67384 Modified: pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py Log: port the test from 67369 to use virtualizables Modified: pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py Tue Sep 1 11:47:47 2009 @@ -971,6 +971,59 @@ res = self.meta_interp(run_interp, [4]) assert res == run_interp(4) + def test_guard_failure_in_inlined_function(self): + from pypy.rpython.annlowlevel import hlstr + class Frame(object): + _virtualizable2_ = ['n', 'next'] + + def __init__(self, n): + self = hint(self, access_directly=True) + self.n = n + self.next = None + + driver = JitDriver(greens=[], reds=['frame', 'result'], + virtualizables=['frame']) + + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "l" not in hlstr(code) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['frame'], + virtualizables=["frame"], + get_printable_location=p, can_inline=c) + def f(code, frame): + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(frame=frame, code=code, pc=pc) + op = code[pc] + if op == "-": + frame.n -= 1 + elif op == "c": + subframe = Frame(frame.n) + frame.next = subframe + frame.n = f("---i---", subframe) + frame.next = None + elif op == "i": + if frame.n % 5 == 1: + return frame.n + elif op == "l": + if frame.n > 0: + myjitdriver.can_enter_jit(frame=frame, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return frame.n + def main(n): + frame = Frame(n) + return f("c-l", frame) + print main(100) + from pypy.jit.metainterp import optimize + res = self.meta_interp(main, [100], + inline=True, optimizer=optimize) class TestOOtype(#ExplicitVirtualizableTests, ImplicitVirtualizableTests, From cfbolz at codespeak.net Tue Sep 1 11:53:22 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 1 Sep 2009 11:53:22 +0200 (CEST) Subject: [pypy-svn] r67385 - pypy/trunk/pypy/jit/tl Message-ID: <20090901095322.C36F3168014@codespeak.net> Author: cfbolz Date: Tue Sep 1 11:53:21 2009 New Revision: 67385 Modified: pypy/trunk/pypy/jit/tl/pypyjit.py Log: use a module dict to execute stuff in :( Modified: pypy/trunk/pypy/jit/tl/pypyjit.py ============================================================================== --- pypy/trunk/pypy/jit/tl/pypyjit.py (original) +++ pypy/trunk/pypy/jit/tl/pypyjit.py Tue Sep 1 11:53:21 2009 @@ -55,7 +55,7 @@ import sys, pdb space = Space(config) -w_dict = space.newdict() +w_dict = space.newdict(module=True) def readfile(filename): From pedronis at codespeak.net Tue Sep 1 14:03:00 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Sep 2009 14:03:00 +0200 (CEST) Subject: [pypy-svn] r67386 - pypy/trunk/pypy/jit/tl Message-ID: <20090901120300.574BE16801D@codespeak.net> Author: pedronis Date: Tue Sep 1 14:02:58 2009 New Revision: 67386 Modified: pypy/trunk/pypy/jit/tl/pypyjit_child.py Log: (micke, pedronis) turn on backendopt for that nice feeling of realism Modified: pypy/trunk/pypy/jit/tl/pypyjit_child.py ============================================================================== --- pypy/trunk/pypy/jit/tl/pypyjit_child.py (original) +++ pypy/trunk/pypy/jit/tl/pypyjit_child.py Tue Sep 1 14:02:58 2009 @@ -42,6 +42,7 @@ option.view = True warmspot.jittify_and_run(interp, graph, [], policy=policy, listops=True, CPUClass=LLtypeCPU, + backendopt=True, optimizer=optimize) @@ -56,4 +57,5 @@ option.view = True warmspot.jittify_and_run(interp, graph, [], policy=policy, listops=True, CPUClass=OOtypeCPU, + backendopt=True, optimizer=optimize) From arigo at codespeak.net Tue Sep 1 14:57:33 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 14:57:33 +0200 (CEST) Subject: [pypy-svn] r67387 - in pypy/branch/pyjitpl5-llmodel/pypy/jit/backend: llsupport llsupport/test x86 x86/test Message-ID: <20090901125733.10AA716801B@codespeak.net> Author: arigo Date: Tue Sep 1 14:57:32 2009 New Revision: 67387 Modified: pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/descr.py pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/gc.py pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/llmodel.py pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/test/test_descr.py pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/test/test_gc.py pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/assembler.py pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/regalloc.py pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_regalloc.py pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_zrpy_gc.py Log: Tests and implementation in the x86 backend of proper gcrootmap support, marking which registers and stack locations contain GC pointers. This also fixes a bug existing in 'trunk', where stack locations were marked but not the ebx, esi and edi registers. Modified: pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/descr.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/descr.py (original) +++ pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/descr.py Tue Sep 1 14:57:32 2009 @@ -166,10 +166,18 @@ class BaseCallDescr(AbstractDescr): _clsname = '' call_loop = None - arg_classes = [] # <-- annotation hack + arg_classes = '' # <-- annotation hack def __init__(self, arg_classes): - self.arg_classes = arg_classes # list of BoxInt/BoxPtr classes + self.arg_classes = arg_classes # string of "p" and "i" (ptr/int) + + def instantiate_arg_classes(self): + result = [] + for c in self.arg_classes: + if c == 'i': box = BoxInt() + else: box = BoxPtr() + result.append(box) + return result def returns_a_pointer(self): return False # unless overridden by GcPtrCallDescr @@ -180,7 +188,7 @@ def get_loop_for_call(self, cpu): if self.call_loop is not None: return self.call_loop - args = [BoxInt()] + [cls() for cls in self.arg_classes] + args = [BoxInt()] + self.instantiate_arg_classes() if self.get_result_size(cpu.translate_support_code) == 0: result = None result_list = [] @@ -231,12 +239,13 @@ arg_classes = [] for ARG in ARGS: kind = getkind(ARG) - if kind == 'int': arg_classes.append(BoxInt) - elif kind == 'ptr': arg_classes.append(BoxPtr) + if kind == 'int': arg_classes.append('i') + elif kind == 'ptr': arg_classes.append('p') else: raise NotImplementedError('ARG = %r' % (ARG,)) + arg_classes = ''.join(arg_classes) cls = getCallDescrClass(RESULT) - key = (cls, tuple(arg_classes)) + key = (cls, arg_classes) cache = gccache._cache_call try: return cache[key] Modified: pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/gc.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/gc.py (original) +++ pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/gc.py Tue Sep 1 14:57:32 2009 @@ -114,7 +114,7 @@ HASHTABLE_BITS = 10 HASHTABLE_SIZE = 1 << HASHTABLE_BITS - def __init__(self): + def initialize(self): if we_are_translated(): n = 2000 else: n = 10 # tests only self.list = self.alloc_gcref_list(n) @@ -202,8 +202,10 @@ return llmemory.cast_ptr_to_adr(self._gcmap) def gcmapend(self): - start = self.gcmapstart() - return start + llmemory.sizeof(llmemory.Address)*self._gcmap_curlength + addr = self.gcmapstart() + if self._gcmap_curlength: + addr += llmemory.sizeof(llmemory.Address)*self._gcmap_curlength + return addr def put(self, retaddr, callshapeaddr): """'retaddr' is the address just after the CALL. @@ -226,24 +228,31 @@ if oldgcmap: lltype.free(oldgcmap, flavor='raw') - def encode_callshape(self, gclocs): - """Encode a callshape from the list of locations containing GC - pointers. 'gclocs' is a list of offsets relative to EBP.""" - shape = self._get_callshape(gclocs) - return self._compress_callshape(shape) - - def _get_callshape(self, gclocs): - shape = [self.LOC_EBP_BASED | 4, # return addr: at 4(%ebp) - self.LOC_EBP_BASED | (-4), # saved %ebx: at -4(%ebp) - self.LOC_EBP_BASED | (-8), # saved %esi: at -8(%ebp) - self.LOC_EBP_BASED | (-12), # saved %edi: at -12(%ebp) - self.LOC_EBP_BASED | 0, # saved %ebp: at (%ebp) - 0] - for loc in gclocs: - shape.append(self.LOC_EBP_BASED | loc) - return shape + def get_basic_shape(self): + return [self.LOC_EBP_BASED | 4, # return addr: at 4(%ebp) + self.LOC_EBP_BASED | (-4), # saved %ebx: at -4(%ebp) + self.LOC_EBP_BASED | (-8), # saved %esi: at -8(%ebp) + self.LOC_EBP_BASED | (-12), # saved %edi: at -12(%ebp) + self.LOC_EBP_BASED | 0, # saved %ebp: at (%ebp) + 0] + + def add_ebp_offset(self, shape, offset): + assert (offset & 3) == 0 + shape.append(self.LOC_EBP_BASED | offset) + + def add_ebx(self, shape): + shape.append(self.LOC_REG | 0) + + def add_esi(self, shape): + shape.append(self.LOC_REG | 4) + + def add_edi(self, shape): + shape.append(self.LOC_REG | 8) - def _compress_callshape(self, shape): + def add_ebp(self, shape): + shape.append(self.LOC_REG | 12) + + def compress_callshape(self, shape): # Similar to compress_callshape() in trackgcroot.py. XXX a bit slowish result = [] for loc in shape: @@ -292,6 +301,7 @@ " with the JIT" % (name,)) gcrootmap = cls() self.gcrootmap = gcrootmap + self.gcrefs = GcRefList() self.single_gcref_descr = GcPtrFieldDescr(0) # make a TransformerLayoutBuilder and save it on the translator @@ -336,7 +346,7 @@ self.array_length_ofs, True, False) self.malloc_array = malloc_array self.GC_MALLOC_ARRAY = lltype.Ptr(lltype.FuncType( - [lltype.Signed] * 4, llmemory.GCREF)) + [lltype.Signed] * 3, llmemory.GCREF)) # (str_basesize, str_itemsize, str_ofs_length ) = symbolic.get_array_token(rstr.STR, True) @@ -361,7 +371,8 @@ [lltype.Signed], llmemory.GCREF)) def initialize(self): - self.gcrefs = GcRefList() + self.gcrefs.initialize() + self.gcrootmap.initialize() def init_size_descr(self, S, descr): from pypy.rpython.memory.gctypelayout import weakpointer_offset Modified: pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/llmodel.py Tue Sep 1 14:57:32 2009 @@ -295,7 +295,7 @@ assert isinstance(calldescr, BaseCallDescr) assert len(args) == 1 + len(calldescr.arg_classes) if not we_are_translated(): - assert ([cls.type for cls in calldescr.arg_classes] == + assert (list(calldescr.arg_classes) == [arg.type for arg in args[1:]]) loop = calldescr.get_loop_for_call(self) set_future_values(self, args) Modified: pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/test/test_descr.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/test/test_descr.py (original) +++ pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/test/test_descr.py Tue Sep 1 14:57:32 2009 @@ -114,13 +114,13 @@ descr1 = get_call_descr(c0, [lltype.Char, lltype.Signed], lltype.Char) assert descr1.get_result_size(False) == rffi.sizeof(lltype.Char) assert not descr1.returns_a_pointer() - assert descr1.arg_classes == [BoxInt, BoxInt] + assert descr1.arg_classes == "ii" # T = lltype.GcStruct('T') descr2 = get_call_descr(c0, [lltype.Ptr(T)], lltype.Ptr(T)) assert descr2.get_result_size(False) == rffi.sizeof(lltype.Ptr(T)) assert descr2.returns_a_pointer() - assert descr2.arg_classes == [BoxPtr] + assert descr2.arg_classes == "p" # U = lltype.GcStruct('U', ('x', lltype.Signed)) assert descr2 == get_call_descr(c0, [lltype.Ptr(U)], lltype.Ptr(U)) @@ -129,7 +129,7 @@ descr3 = get_call_descr(c1, [lltype.Ptr(T)], lltype.Ptr(U)) assert isinstance(descr3.get_result_size(True), Symbolic) assert descr3.returns_a_pointer() - assert descr3.arg_classes == [BoxPtr] + assert descr3.arg_classes == "p" def test_repr_of_descr(): Modified: pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/test/test_gc.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/test/test_gc.py (original) +++ pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/test/test_gc.py Tue Sep 1 14:57:32 2009 @@ -54,6 +54,7 @@ allocs = [allocs[i] for i in order] # gcrefs = GcRefList() + gcrefs.initialize() addrs = [gcrefs.get_address_of_gcref(ptr) for ptr in allocs] for i in range(len(allocs)): assert addrs[i].address[0] == llmemory.cast_ptr_to_adr(allocs[i]) @@ -64,16 +65,27 @@ gcrootmap = GcRootMap_asmgcc() num1 = stack_pos(1) num2 = stack_pos(55) - shape = gcrootmap._get_callshape([num1, num2]) + shape = gcrootmap.get_basic_shape() + gcrootmap.add_ebp_offset(shape, num1) + gcrootmap.add_ebp_offset(shape, num2) assert shape == [6, -2, -6, -10, 2, 0, num1|2, num2|2] + gcrootmap.add_ebx(shape) + assert shape == [6, -2, -6, -10, 2, 0, num1|2, num2|2, 0|1] + gcrootmap.add_esi(shape) + assert shape == [6, -2, -6, -10, 2, 0, num1|2, num2|2, 0|1, 4|1] + gcrootmap.add_edi(shape) + assert shape == [6, -2, -6, -10, 2, 0, num1|2, num2|2, 0|1, 4|1, 8|1] + gcrootmap.add_ebp(shape) + assert shape == [6, -2, -6, -10, 2, 0, num1|2, num2|2, 0|1, 4|1, 8|1, 12|1] # - shapeaddr = gcrootmap.encode_callshape([num1, num2]) + shapeaddr = gcrootmap.compress_callshape(shape) PCALLSHAPE = lltype.Ptr(GcRootMap_asmgcc.CALLSHAPE_ARRAY) p = llmemory.cast_adr_to_ptr(shapeaddr, PCALLSHAPE) num1a = -2*(num1|2)-1 num2a = ((-2*(num2|2)-1) >> 7) | 128 num2b = (-2*(num2|2)-1) & 127 - for i, expected in enumerate([num2a, num2b, num1a, 0, 4, 19, 11, 3, 12]): + for i, expected in enumerate([26, 18, 10, 2, + num2a, num2b, num1a, 0, 4, 19, 11, 3, 12]): assert p[i] == expected # retaddr = rffi.cast(llmemory.Address, 1234567890) @@ -85,7 +97,9 @@ # the same as before, but enough times to trigger a few resizes expected_shapeaddr = {} for i in range(1, 600): - shapeaddr = gcrootmap.encode_callshape([stack_pos(i)]) + shape = gcrootmap.get_basic_shape() + gcrootmap.add_ebp_offset(shape, stack_pos(i)) + shapeaddr = gcrootmap.compress_callshape(shape) expected_shapeaddr[i] = shapeaddr retaddr = rffi.cast(llmemory.Address, 123456789 + i) gcrootmap.put(retaddr, shapeaddr) Modified: pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/assembler.py Tue Sep 1 14:57:32 2009 @@ -143,7 +143,6 @@ ll_new_unicode = gc_ll_descr.get_funcptr_for_newunicode() self.malloc_unicode_func_addr = rffi.cast(lltype.Signed, ll_new_unicode) - self.gcrootmap = gc_ll_descr.gcrootmap # done self.mc2 = self.mcstack.next_mc() self.mc = self.mcstack.next_mc() @@ -816,22 +815,11 @@ # self.mc.MOVZX(eax, eax) def mark_gc_roots(self): - if self.gcrootmap: - gclocs = [] - regalloc = self._regalloc - for v, val in regalloc.stack_bindings.items(): - if (isinstance(v, BoxPtr) and - regalloc.longevity[v][1] > regalloc.position): - gclocs.append(val) - #alllocs = [] - #for loc in gclocs: - # assert isinstance(loc, MODRM) - # alllocs.append(str(loc.position)) - #print self.mc.tell() - #print ", ".join(alllocs) - shape = self.gcrootmap.encode_callshape(gclocs) - self.gcrootmap.put(rffi.cast(llmemory.Address, self.mc.tell()), - shape) + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + if gcrootmap: + mark = self._regalloc.get_mark_gc_roots(gcrootmap) + gcrootmap.put(rffi.cast(llmemory.Address, self.mc.tell()), mark) + genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST genop_list = [Assembler386.not_implemented_op] * rop._LAST Modified: pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/regalloc.py Tue Sep 1 14:57:32 2009 @@ -931,6 +931,26 @@ def consider_debug_merge_point(self, op, ignored): pass + def get_mark_gc_roots(self, gcrootmap): + shape = gcrootmap.get_basic_shape() + for v, val in self.stack_bindings.items(): + if (isinstance(v, BoxPtr) and + self.longevity[v][1] > self.position): + assert isinstance(val, MODRM) + gcrootmap.add_ebp_offset(shape, get_ebp_ofs(val.position)) + for v, reg in self.reg_bindings.items(): + if (isinstance(v, BoxPtr) and + self.longevity[v][1] > self.position): + if reg is ebx: + gcrootmap.add_ebx(shape) + elif reg is esi: + gcrootmap.add_esi(shape) + elif reg is edi: + gcrootmap.add_edi(shape) + else: + assert reg is eax # ok to ignore this one + return gcrootmap.compress_callshape(shape) + def not_implemented_op(self, op, ignored): print "[regalloc] Not implemented operation: %s" % op.getopname() raise NotImplementedError @@ -943,12 +963,15 @@ num = getattr(rop, name.upper()) oplist[num] = value -def stack_pos(i): +def get_ebp_ofs(position): # Argument is a stack position (0, 1, 2...). # Returns (ebp-16), (ebp-20), (ebp-24)... # This depends on the fact that our function prologue contains # exactly 4 PUSHes. - res = mem(ebp, -WORD * (4 + i)) + return -WORD * (4 + position) + +def stack_pos(i): + res = mem(ebp, get_ebp_ofs(i)) res.position = i return res Modified: pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_regalloc.py Tue Sep 1 14:57:32 2009 @@ -27,8 +27,7 @@ self.performs = [] self.lea = [] self.cpu = cpu or CPU(None, None) - if not hasattr(self.cpu, 'gc_ll_descr'): - self.cpu.gc_ll_descr = MockGcDescr(False) + self.cpu.gc_ll_descr = MockGcDescr(False) def dump(self, *args): pass @@ -48,9 +47,20 @@ def load_effective_addr(self, *args): self.lea.append(args) -class GcRootMap(object): - def initialize(self): - pass +class MockGcRootMap(object): + def get_basic_shape(self): + return ['shape'] + def add_ebp_offset(self, shape, offset): + shape.append(offset) + def add_ebx(self, shape): + shape.append('ebx') + def add_esi(self, shape): + shape.append('esi') + def add_edi(self, shape): + shape.append('edi') + def compress_callshape(self, shape): + assert shape[0] == 'shape' + return ['compressed'] + shape[1:] class MockGcDescr(GcCache): def get_funcptr_for_new(self): @@ -60,7 +70,7 @@ get_funcptr_for_newunicode = get_funcptr_for_new moving_gc = True - gcrootmap = GcRootMap() + gcrootmap = MockGcRootMap() def initialize(self): pass @@ -74,10 +84,10 @@ return -1 class TestRegallocDirect(object): - def fill_regs(self, regalloc): + def fill_regs(self, regalloc, cls=BoxInt): allboxes = [] for reg in REGS: - box = BoxInt() + box = cls() allboxes.append(box) regalloc.reg_bindings[box] = reg regalloc.free_regs = [] @@ -130,15 +140,36 @@ TP = lltype.FuncType([], lltype.Void) calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) regalloc._check_invariants() - box = boxes[0] for box in boxes: regalloc.longevity[box] = (0, 1) + box = boxes[0] regalloc.position = 0 regalloc.consider_call(ResOperation(rop.CALL, [box], None, calldescr), None) assert len(regalloc.assembler.stores) == 3 regalloc._check_invariants() + def test_mark_gc_roots(self): + cpu = CPU(None, None) + regalloc = RegAlloc(MockAssembler(cpu), DummyTree()) + cpu = regalloc.assembler.cpu + boxes = self.fill_regs(regalloc, cls=BoxPtr) + TP = lltype.FuncType([], lltype.Signed) + calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) + regalloc._check_invariants() + for box in boxes: + regalloc.longevity[box] = (0, 1) + box = boxes[0] + regalloc.position = 0 + regalloc.consider_call(ResOperation(rop.CALL, [box], BoxInt(), + calldescr), None) + assert len(regalloc.assembler.stores) == 3 + # + mark = regalloc.get_mark_gc_roots(cpu.gc_ll_descr.gcrootmap) + assert mark[0] == 'compressed' + expected = ['ebx', 'esi', 'edi', -16, -20, -24] + assert dict.fromkeys(mark[1:]) == dict.fromkeys(expected) + def test_registers_around_newstr(self): cpu = CPU(None, None) regalloc = RegAllocForTests(MockAssembler(cpu), DummyTree()) Modified: pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_zrpy_gc.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_zrpy_gc.py (original) +++ pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_zrpy_gc.py Tue Sep 1 14:57:32 2009 @@ -18,6 +18,14 @@ class X(object): next = None +class CheckError(Exception): + pass + +def check(flag): + if not flag: + raise CheckError + + def get_test(main): main._dont_inline_ = True @@ -97,9 +105,6 @@ jit=True) assert int(res) == 20 -def test_get_callshape(): - xxx #test that _get_callshape() is called with the right arguments - def test_compile_hybrid_2(): # More complex test, requires root stack enumeration but # not write_barriers. @@ -131,18 +136,65 @@ y.foo = j+1 y.next = x.next x.next = y - assert x.next.foo == 101 + check(x.next.foo == 101) total = 0 y = x for j in range(101): y = y.next total += y.foo - assert not y.next - assert total == 101*102/2 + check(not y.next) + check(total == 101*102/2) n -= x.foo x_test = X() x_test.foo = 5 - main(6, x_test) # check that it does not raise AssertionError + main(6, x_test) # check that it does not raise CheckError + res = compile_and_run(get_test(main), "hybrid", gcrootfinder="asmgcc", + jit=True) + assert int(res) == 20 + +def test_compile_hybrid_3_extra(): + # Extra version of the test, with tons of live vars around the residual + # call that all contain a GC pointer. + myjitdriver = JitDriver(greens = [], reds = ['n', 'x0', 'x1', 'x2', 'x3', + 'x4', 'x5', 'x6', 'x7']) + def residual(n=26): + x = X() + x.next = X() + x.next.foo = n + return x + residual._look_inside_me_ = False + # + def main(n, x): + residual(5) + x0 = residual() + x1 = residual() + x2 = residual() + x3 = residual() + x4 = residual() + x5 = residual() + x6 = residual() + x7 = residual() + n *= 19 + while n > 0: + myjitdriver.can_enter_jit(n=n, x0=x0, x1=x1, x2=x2, x3=x3, + x4=x4, x5=x5, x6=x6, x7=x7) + myjitdriver.jit_merge_point(n=n, x0=x0, x1=x1, x2=x2, x3=x3, + x4=x4, x5=x5, x6=x6, x7=x7) + x8 = residual() + x9 = residual() + check(x0.next.foo == 26) + check(x1.next.foo == 26) + check(x2.next.foo == 26) + check(x3.next.foo == 26) + check(x4.next.foo == 26) + check(x5.next.foo == 26) + check(x6.next.foo == 26) + check(x7.next.foo == 26) + check(x8.next.foo == 26) + check(x9.next.foo == 26) + x0, x1, x2, x3, x4, x5, x6, x7 = x7, x4, x6, x5, x3, x2, x9, x8 + n -= 1 + main(6, None) # check that it does not raise AssertionError res = compile_and_run(get_test(main), "hybrid", gcrootfinder="asmgcc", jit=True) assert int(res) == 20 @@ -159,7 +211,7 @@ myjitdriver = JitDriver(greens = [], reds = ['n', 'x']) def main(n, x): debug_print('counter.cnt =', counter.cnt) - assert counter.cnt < 5 + check(counter.cnt < 5) counter.cnt = n // x.foo while n > 0: myjitdriver.can_enter_jit(n=n, x=x) @@ -180,7 +232,7 @@ myjitdriver.jit_merge_point(n=n, x=x, s=s) n -= x.foo s += str(n) - assert len(s) == 1*5 + 2*45 + 3*450 + 4*500 + check(len(s) == 1*5 + 2*45 + 3*450 + 4*500) res = compile_and_run(get_test(main), "hybrid", gcrootfinder="asmgcc", jit=True) assert int(res) == 20 @@ -196,15 +248,15 @@ if n < 200: l = [n, n, n] if n < 100: - assert len(l) == 3 - assert l[0] == n - assert l[1] == n - assert l[2] == n + check(len(l) == 3) + check(l[0] == n) + check(l[1] == n) + check(l[2] == n) n -= x.foo - assert len(l) == 3 - assert l[0] == 2 - assert l[1] == 2 - assert l[2] == 2 + check(len(l) == 3) + check(l[0] == 2) + check(l[1] == 2) + check(l[2] == 2) res = compile_and_run(get_test(main), "hybrid", gcrootfinder="asmgcc", jit=True) assert int(res) == 20 @@ -221,7 +273,7 @@ myjitdriver.can_enter_jit(n=n, x=x, l=l) myjitdriver.jit_merge_point(n=n, x=x, l=l) if n < 1900: - assert l[0].x == 123 + check(l[0].x == 123) l = [None] * 16 l[0] = X(123) l[1] = X(n) @@ -240,41 +292,41 @@ l[14] = X(n+130) l[15] = X(n+140) if n < 1800: - assert len(l) == 16 - assert l[0].x == 123 - assert l[1].x == n - assert l[2].x == n+10 - assert l[3].x == n+20 - assert l[4].x == n+30 - assert l[5].x == n+40 - assert l[6].x == n+50 - assert l[7].x == n+60 - assert l[8].x == n+70 - assert l[9].x == n+80 - assert l[10].x == n+90 - assert l[11].x == n+100 - assert l[12].x == n+110 - assert l[13].x == n+120 - assert l[14].x == n+130 - assert l[15].x == n+140 + check(len(l) == 16) + check(l[0].x == 123) + check(l[1].x == n) + check(l[2].x == n+10) + check(l[3].x == n+20) + check(l[4].x == n+30) + check(l[5].x == n+40) + check(l[6].x == n+50) + check(l[7].x == n+60) + check(l[8].x == n+70) + check(l[9].x == n+80) + check(l[10].x == n+90) + check(l[11].x == n+100) + check(l[12].x == n+110) + check(l[13].x == n+120) + check(l[14].x == n+130) + check(l[15].x == n+140) n -= x.foo - assert len(l) == 16 - assert l[0].x == 123 - assert l[1].x == 2 - assert l[2].x == 12 - assert l[3].x == 22 - assert l[4].x == 32 - assert l[5].x == 42 - assert l[6].x == 52 - assert l[7].x == 62 - assert l[8].x == 72 - assert l[9].x == 82 - assert l[10].x == 92 - assert l[11].x == 102 - assert l[12].x == 112 - assert l[13].x == 122 - assert l[14].x == 132 - assert l[15].x == 142 + check(len(l) == 16) + check(l[0].x == 123) + check(l[1].x == 2) + check(l[2].x == 12) + check(l[3].x == 22) + check(l[4].x == 32) + check(l[5].x == 42) + check(l[6].x == 52) + check(l[7].x == 62) + check(l[8].x == 72) + check(l[9].x == 82) + check(l[10].x == 92) + check(l[11].x == 102) + check(l[12].x == 112) + check(l[13].x == 122) + check(l[14].x == 132) + check(l[15].x == 142) res = compile_and_run(get_test(main), "hybrid", gcrootfinder="asmgcc", jit=True) assert int(res) == 20 From cfbolz at codespeak.net Tue Sep 1 15:21:50 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 1 Sep 2009 15:21:50 +0200 (CEST) Subject: [pypy-svn] r67388 - pypy/trunk/pypy/config Message-ID: <20090901132150.AB615168014@codespeak.net> Author: cfbolz Date: Tue Sep 1 15:21:46 2009 New Revision: 67388 Modified: pypy/trunk/pypy/config/pypyoption.py Log: Enable cell dicts by default when using the JIT. It's better than call_likely_builtin and helps global lookups too. Modified: pypy/trunk/pypy/config/pypyoption.py ============================================================================== --- pypy/trunk/pypy/config/pypyoption.py (original) +++ pypy/trunk/pypy/config/pypyoption.py Tue Sep 1 15:21:46 2009 @@ -356,8 +356,9 @@ backend = config.translation.backend # all the good optimizations for PyPy should be listed here - if level in ['2', '3', 'jit']: + if level in ['2', '3']: config.objspace.opcodes.suggest(CALL_LIKELY_BUILTIN=True) + if level in ['2', '3', 'jit']: config.objspace.opcodes.suggest(CALL_METHOD=True) config.objspace.std.suggest(withmultidict=True) config.objspace.std.suggest(withshadowtracking=True) @@ -395,6 +396,7 @@ # extra optimizations with the JIT if level == 'jit': config.objspace.std.suggest(withsharingdict=True) + config.objspace.std.suggest(withcelldict=True) def enable_allworkingmodules(config): From arigo at codespeak.net Tue Sep 1 16:04:48 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:04:48 +0200 (CEST) Subject: [pypy-svn] r67389 - pypy/branch/pyjitpl5-llmodel-merge Message-ID: <20090901140448.3C4ED16802C@codespeak.net> Author: arigo Date: Tue Sep 1 16:04:46 2009 New Revision: 67389 Added: pypy/branch/pyjitpl5-llmodel-merge/ - copied from r67388, pypy/trunk/ Log: A branch where I can try to merge pyjitpl5-llmodel. From pedronis at codespeak.net Tue Sep 1 16:07:24 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Sep 2009 16:07:24 +0200 (CEST) Subject: [pypy-svn] r67390 - pypy/trunk/pypy/objspace/std Message-ID: <20090901140724.0A03B168039@codespeak.net> Author: pedronis Date: Tue Sep 1 16:07:19 2009 New Revision: 67390 Modified: pypy/trunk/pypy/objspace/std/objspace.py Log: (micke, pedronis) this optimisation and code path is not used anymore with the jit, don't bother with we_are_jitted Modified: pypy/trunk/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/pypy/objspace/std/objspace.py Tue Sep 1 16:07:19 2009 @@ -168,11 +168,9 @@ def call_likely_builtin(f, w_function, nargs): if isinstance(w_function, function.Function): executioncontext = self.getexecutioncontext() - if not we_are_jitted(): - executioncontext.c_call_trace(f, w_function) + executioncontext.c_call_trace(f, w_function) res = w_function.funccall_valuestack(nargs, f) - if not we_are_jitted(): - executioncontext.c_return_trace(f, w_function) + executioncontext.c_return_trace(f, w_function) return res args = f.make_arguments(nargs) try: From arigo at codespeak.net Tue Sep 1 16:13:21 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:13:21 +0200 (CEST) Subject: [pypy-svn] r67392 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend Message-ID: <20090901141321.3B90316803D@codespeak.net> Author: arigo Date: Tue Sep 1 16:13:20 2009 New Revision: 67392 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/logger.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67321 | arigo | 2009-08-29 16:47:35 +0200 (Sat, 29 Aug 2009) | 2 lines In-progress. Attach the repr_of_descr() method to Descrs. ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py.merge.tmp Tue Sep 1 16:13:20 2009 @@ -30,7 +30,7 @@ compute_unique_id(loop)) def repr_of_descr(self, descr): - return '' + return descr.repr_of_descr() def repr_of_arg(self, memo, arg): try: @@ -119,3 +119,10 @@ args_s = ','.join([self.repr_of_arg(memo, box) for box in valueboxes]) os.write(self._log_fd, "CALL\n") os.write(self._log_fd, "%s %s\n" % (name, args_s)) + + +class LLLogger(AbstractLogger): + is_oo = False + +class OOLogger(AbstractLogger): + is_oo = True From arigo at codespeak.net Tue Sep 1 16:13:24 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:13:24 +0200 (CEST) Subject: [pypy-svn] r67393 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend Message-ID: <20090901141324.AA115168043@codespeak.net> Author: arigo Date: Tue Sep 1 16:13:23 2009 New Revision: 67393 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/model.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67353 | arigo | 2009-08-31 14:06:02 +0200 (Mon, 31 Aug 2009) | 2 lines Write test_cond_call_gc_wb and make it pass on the llgraph backend. ------------------------------------------------------------------------ r67343 | arigo | 2009-08-30 17:33:25 +0200 (Sun, 30 Aug 2009) | 3 lines Add COND_CALL and implement it in the backend. Meant to be used only for calls to helpers like malloc. ------------------------------------------------------------------------ r67331 | arigo | 2009-08-29 23:00:29 +0200 (Sat, 29 Aug 2009) | 2 lines In-progress. We can now at least test directly the code in gc.py. ------------------------------------------------------------------------ r67316 | arigo | 2009-08-29 16:09:13 +0200 (Sat, 29 Aug 2009) | 2 lines do_call. ------------------------------------------------------------------------ r67309 | arigo | 2009-08-29 14:21:29 +0200 (Sat, 29 Aug 2009) | 2 lines do_new with Boehm. ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py.merge.tmp Tue Sep 1 16:13:23 2009 @@ -70,6 +70,8 @@ @staticmethod def calldescrof(FUNC, ARGS, RESULT): + # FUNC is the original function type, but ARGS is a list of types + # with Voids removed raise NotImplementedError @staticmethod @@ -81,11 +83,11 @@ def typedescrof(TYPE): raise NotImplementedError - def cast_adr_to_int(self, adr): - raise NotImplementedError + #def cast_adr_to_int(self, adr): + # raise NotImplementedError - def cast_int_to_adr(self, int): - raise NotImplementedError + #def cast_int_to_adr(self, int): + # raise NotImplementedError # ---------- the backend-dependent operations ---------- @@ -119,7 +121,7 @@ def do_new(self, args, sizedescr): raise NotImplementedError - def do_new_with_vtable(self, args, sizedescr): + def do_new_with_vtable(self, args, descr=None): raise NotImplementedError def do_new_array(self, args, arraydescr): @@ -128,6 +130,9 @@ def do_setarrayitem_gc(self, args, arraydescr): raise NotImplementedError + def do_setarrayitem_raw(self, args, arraydescr): + raise NotImplementedError + def do_setfield_gc(self, args, fielddescr): raise NotImplementedError @@ -149,6 +154,13 @@ def do_call(self, args, calldescr): raise NotImplementedError + def do_cond_call_gc_wb(self, args, calldescr): + if args[0].getint() & args[1].getint(): + self.do_call(args[2:], calldescr) + + def do_cond_call_gc_malloc(self, args, calldescr): + xxx + def do_cast_int_to_ptr(self, args, descr=None): raise NotImplementedError From arigo at codespeak.net Tue Sep 1 16:13:28 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:13:28 +0200 (CEST) Subject: [pypy-svn] r67394 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp Message-ID: <20090901141328.D9CC7168049@codespeak.net> Author: arigo Date: Tue Sep 1 16:13:28 2009 New Revision: 67394 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/warmspot.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/warmspot.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/metainterp/warmspot.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67331 | arigo | 2009-08-29 23:00:29 +0200 (Sat, 29 Aug 2009) | 2 lines In-progress. We can now at least test directly the code in gc.py. ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/warmspot.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/warmspot.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/warmspot.py.merge.tmp Tue Sep 1 16:13:28 2009 @@ -217,7 +217,7 @@ else: annhelper = None cpu = CPUClass(self.translator.rtyper, self.stats, - translate_support_code, annhelper, self.gcdescr) + translate_support_code, gcdescr=self.gcdescr) self.cpu = cpu self.metainterp_sd = MetaInterpStaticData(self.portal_graph, self.translator.graphs, cpu, From arigo at codespeak.net Tue Sep 1 16:13:33 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:13:33 +0200 (CEST) Subject: [pypy-svn] r67395 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp Message-ID: <20090901141333.6B74216804C@codespeak.net> Author: arigo Date: Tue Sep 1 16:13:32 2009 New Revision: 67395 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/executor.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/executor.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/metainterp/executor.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67326 | arigo | 2009-08-29 18:23:36 +0200 (Sat, 29 Aug 2009) | 2 lines In-progress, more tests pass. ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/executor.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/executor.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/executor.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/executor.py.merge.tmp Tue Sep 1 16:13:32 2009 @@ -230,6 +230,18 @@ def make_execute_list(cpuclass): from pypy.jit.backend.model import AbstractCPU + if 0: # enable this to trace calls to do_xxx + def wrap(fn): + def myfn(*args): + print '<<<', fn.__name__ + try: + return fn(*args) + finally: + print fn.__name__, '>>>' + return myfn + else: + def wrap(fn): + return fn execute = [None] * (rop._LAST+1) for key, value in rop.__dict__.items(): if not key.startswith('_'): @@ -242,9 +254,9 @@ key = key[:-5] name = 'do_' + key.lower() if hasattr(cpuclass, name): - execute[value] = getattr(cpuclass, name) + execute[value] = wrap(getattr(cpuclass, name)) elif name in globals(): - execute[value] = globals()[name] + execute[value] = wrap(globals()[name]) else: assert hasattr(AbstractCPU, name), name cpuclass._execute_list = execute From arigo at codespeak.net Tue Sep 1 16:13:37 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:13:37 +0200 (CEST) Subject: [pypy-svn] r67396 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp Message-ID: <20090901141337.D2D8816804E@codespeak.net> Author: arigo Date: Tue Sep 1 16:13:36 2009 New Revision: 67396 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/history.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/history.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/metainterp/history.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67321 | arigo | 2009-08-29 16:47:35 +0200 (Sat, 29 Aug 2009) | 2 lines In-progress. Attach the repr_of_descr() method to Descrs. ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/history.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/history.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/history.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/history.py.merge.tmp Tue Sep 1 16:13:36 2009 @@ -123,6 +123,8 @@ raise NotImplementedError def compile_and_attach(self, metainterp, new_loop): raise NotImplementedError + def repr_of_descr(self): + return '%r' % (self,) class AbstractMethDescr(AbstractDescr): # the base class of the result of cpu.methdescrof() From arigo at codespeak.net Tue Sep 1 16:13:42 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:13:42 +0200 (CEST) Subject: [pypy-svn] r67397 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test Message-ID: <20090901141342.7237B16802A@codespeak.net> Author: arigo Date: Tue Sep 1 16:13:40 2009 New Revision: 67397 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test/runner_test.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test/runner_test.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/test/runner_test.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67353 | arigo | 2009-08-31 14:06:02 +0200 (Mon, 31 Aug 2009) | 2 lines Write test_cond_call_gc_wb and make it pass on the llgraph backend. ------------------------------------------------------------------------ r67343 | arigo | 2009-08-30 17:33:25 +0200 (Sun, 30 Aug 2009) | 3 lines Add COND_CALL and implement it in the backend. Meant to be used only for calls to helpers like malloc. ------------------------------------------------------------------------ r67326 | arigo | 2009-08-29 18:23:36 +0200 (Sat, 29 Aug 2009) | 2 lines In-progress, more tests pass. ------------------------------------------------------------------------ r67324 | arigo | 2009-08-29 17:38:24 +0200 (Sat, 29 Aug 2009) | 2 lines Test and fix. ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test/runner_test.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test/runner_test.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test/runner_test.py.merge.tmp Tue Sep 1 16:13:40 2009 @@ -107,9 +107,9 @@ func_ptr = llhelper(FPTR, func) FUNC = deref(FPTR) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) + funcbox = self.get_funcbox(cpu, func_ptr) res = self.execute_operation(rop.CALL, - [self.get_funcbox(cpu, func_ptr), - BoxInt(num), BoxInt(num)], + [funcbox, BoxInt(num), BoxInt(num)], 'int', descr=calldescr) assert res.value == 2 * num @@ -270,6 +270,11 @@ t_box, T_box = self.alloc_instance(self.T) fielddescr = self.cpu.fielddescrof(self.S, 'value') assert not fielddescr.is_pointer_field() + # + self.cpu.do_setfield_gc([t_box, BoxInt(1333)], fielddescr) + r = self.cpu.do_getfield_gc([t_box], fielddescr) + assert r.value == 1333 + # res = self.execute_operation(rop.SETFIELD_GC, [t_box, BoxInt(39082)], 'void', descr=fielddescr) assert res is None @@ -394,6 +399,13 @@ a_box, A = self.alloc_array_of(lltype.Signed, 342) arraydescr = self.cpu.arraydescrof(A) assert not arraydescr.is_array_of_pointers() + # + r = self.cpu.do_arraylen_gc([a_box], arraydescr) + assert r.value == 342 + self.cpu.do_setarrayitem_gc([a_box, BoxInt(311), BoxInt(170)], arraydescr) + r = self.cpu.do_getarrayitem_gc([a_box, BoxInt(311)], arraydescr) + assert r.value == 170 + # r = self.execute_operation(rop.ARRAYLEN_GC, [a_box], 'int', descr=arraydescr) assert r.value == 342 @@ -404,11 +416,6 @@ r = self.execute_operation(rop.GETARRAYITEM_GC, [a_box, BoxInt(310)], 'int', descr=arraydescr) assert r.value == 7441 - r = self.cpu.do_getarrayitem_gc([a_box, BoxInt(310)], arraydescr) - assert r.value == 7441 - self.cpu.do_setarrayitem_gc([a_box, BoxInt(3), BoxInt(170)], arraydescr) - r = self.cpu.do_getarrayitem_gc([a_box, BoxInt(3)], arraydescr) - assert r.value == 170 # a_box, A = self.alloc_array_of(lltype.Char, 11) arraydescr = self.cpu.arraydescrof(A) @@ -507,6 +514,11 @@ assert r.value == 153 def test_unicode_basic(self): + u_box = self.cpu.do_newunicode([ConstInt(5)]) + self.cpu.do_unicodesetitem([u_box, BoxInt(4), BoxInt(123)]) + r = self.cpu.do_unicodegetitem([u_box, BoxInt(4)]) + assert r.value == 123 + # u_box = self.alloc_unicode(u"hello\u1234") r = self.execute_operation(rop.UNICODELEN, [u_box], 'int') assert r.value == 6 @@ -522,10 +534,6 @@ r = self.execute_operation(rop.UNICODEGETITEM, [u_box, BoxInt(4)], 'int') assert r.value == 31313 - u_box = self.cpu.do_newunicode([ConstInt(5)]) - self.cpu.do_unicodesetitem([u_box, BoxInt(4), BoxInt(123)]) - r = self.cpu.do_unicodegetitem([u_box, BoxInt(4)]) - assert r.value == 123 def test_same_as(self): r = self.execute_operation(rop.SAME_AS, [ConstInt(5)], 'int') @@ -673,6 +681,8 @@ r = self.cpu.do_getfield_gc([r1], descrshort) assert r.value == 1313 self.cpu.do_setfield_gc([r1, BoxInt(1333)], descrshort) + r = self.cpu.do_getfield_gc([r1], descrshort) + assert r.value == 1333 r = self.execute_operation(rop.GETFIELD_GC, [r1], 'int', descr=descrshort) assert r.value == 1333 @@ -932,6 +942,32 @@ assert self.cpu.get_latest_value_int(0) == 0 self.cpu.clear_exception() + def test_cond_call_gc_wb(self): + def func_void(a, b): + record.append((a, b)) + record = [] + # + FUNC = self.FuncType([lltype.Signed, lltype.Signed], lltype.Void) + func_ptr = llhelper(lltype.Ptr(FUNC), func_void) + funcbox = self.get_funcbox(self.cpu, func_ptr) + calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) + for cond in [False, True]: + value = random.randrange(-sys.maxint, sys.maxint) + if cond: + value |= 4096 + else: + value &= ~4096 + del record[:] + self.execute_operation(rop.COND_CALL_GC_WB, + [BoxInt(value), ConstInt(4096), + funcbox, BoxInt(655360), BoxInt(-2121)], + 'void', descr=calldescr) + if cond: + assert record == [(655360, -2121)] + else: + assert record == [] + + class OOtypeBackendTest(BaseBackendTest): type_system = 'ootype' From arigo at codespeak.net Tue Sep 1 16:13:44 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:13:44 +0200 (CEST) Subject: [pypy-svn] r67398 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86 Message-ID: <20090901141344.12FE416802A@codespeak.net> Author: arigo Date: Tue Sep 1 16:13:44 2009 New Revision: 67398 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/runner.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67331 | arigo | 2009-08-29 23:00:29 +0200 (Sat, 29 Aug 2009) | 2 lines In-progress. We can now at least test directly the code in gc.py. ------------------------------------------------------------------------ r67322 | arigo | 2009-08-29 17:02:58 +0200 (Sat, 29 Aug 2009) | 2 lines A few tests start to pass again. ------------------------------------------------------------------------ r67321 | arigo | 2009-08-29 16:47:35 +0200 (Sat, 29 Aug 2009) | 2 lines In-progress. Attach the repr_of_descr() method to Descrs. ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py.merge.tmp Tue Sep 1 16:13:44 2009 @@ -1,69 +1,29 @@ import sys import ctypes import py -from pypy.rpython.lltypesystem import lltype, llmemory, ll2ctypes, rffi, rstr +from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.llinterp import LLInterpreter -from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rlib.objectmodel import CDefinedIntSymbolic, specialize, Symbolic -from pypy.rlib.objectmodel import we_are_translated, keepalive_until_here -from pypy.annotation import model as annmodel -from pypy.rpython.lltypesystem import rclass -from pypy.jit.metainterp import history, codewriter -from pypy.jit.metainterp.history import (ResOperation, Box, Const, - ConstInt, ConstPtr, BoxInt, BoxPtr, ConstAddr, AbstractDescr) -from pypy.jit.backend.x86.assembler import Assembler386, WORD, MAX_FAIL_BOXES -from pypy.jit.backend.x86.assembler import x86Logger -from pypy.jit.backend.x86 import symbolic -from pypy.jit.metainterp.resoperation import rop, opname -from pypy.rlib.objectmodel import r_dict +from pypy.rlib.objectmodel import we_are_translated +from pypy.jit.metainterp import history +from pypy.jit.backend.x86.assembler import Assembler386, MAX_FAIL_BOXES +from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU from pypy.jit.metainterp.typesystem import llhelper history.TreeLoop._x86_compiled = 0 history.TreeLoop._x86_bootstrap_code = 0 -class ConstDescr3(AbstractDescr): - call_loop = None - - def __init__(self, v0, v1, flag2): - self.v0 = v0 - self.v1 = v1 - self.flag2 = flag2 - - def sort_key(self): - return self.v0 # the ofs field for fielddescrs - - def is_pointer_field(self): - return self.flag2 # for fielddescrs - - def is_array_of_pointers(self): - return self.flag2 # for arraydescrs - - def __repr__(self): - return '' % (self.v0, self.v1, self.flag2) - -def _check_addr_range(x): - if sys.platform == 'linux2': - # this makes assumption about address ranges that are valid - # only on linux (?) - assert x == 0 or x > (1<<20) or x < (-1<<20) -class CPU386(object): +class CPU386(AbstractLLCPU): debug = True ts = llhelper - logger_cls = x86Logger BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) def __init__(self, rtyper, stats, translate_support_code=False, - mixlevelann=None, gcdescr=None): - from pypy.jit.backend.x86.gc import get_ll_description - self.rtyper = rtyper - self.stats = stats - self.translate_support_code = translate_support_code - if translate_support_code: - assert mixlevelann - self.mixlevelann = mixlevelann - else: + gcdescr=None): + AbstractLLCPU.__init__(self, rtyper, stats, translate_support_code, + gcdescr) + if not translate_support_code: self.current_interpreter = LLInterpreter(self.rtyper) def _store_exception(lle): @@ -76,38 +36,10 @@ TP = lltype.GcArray(llmemory.GCREF) self._bootstrap_cache = {} self._guard_list = [] - self._compiled_ops = {} - self._builtin_implementations = {} self.setup() self.caught_exception = None if rtyper is not None: # for tests self.lltype2vtable = rtyper.lltype_to_vtable_mapping() - self._setup_prebuilt_error('ovf', OverflowError) - self._setup_prebuilt_error('zer', ZeroDivisionError) - self._descr_caches = {} - self.gc_ll_descr = get_ll_description(gcdescr, self) - self.vtable_offset, _ = symbolic.get_field_token(rclass.OBJECT, - 'typeptr', - translate_support_code) - - def set_class_sizes(self, class_sizes): - self.class_sizes = class_sizes - - def _setup_prebuilt_error(self, prefix, Class): - if self.rtyper is not None: # normal case - bk = self.rtyper.annotator.bookkeeper - clsdef = bk.getuniqueclassdef(Class) - ll_inst = self.rtyper.exceptiondata.get_standard_ll_exc_instance( - self.rtyper, clsdef) - else: - # for tests, a random emulated ll_inst will do - ll_inst = lltype.malloc(rclass.OBJECT) - ll_inst.typeptr = lltype.malloc(rclass.OBJECT_VTABLE, - immortal=True) - setattr(self.assembler, '_%s_error_vtable' % prefix, - llmemory.cast_ptr_to_adr(ll_inst.typeptr)) - setattr(self.assembler, '_%s_error_inst' % prefix, - llmemory.cast_ptr_to_adr(ll_inst)) def setup(self): self.assembler = Assembler386(self, self.translate_support_code) @@ -128,20 +60,6 @@ self.assembler._exception_bck[0] = 0 self.assembler._exception_bck[1] = 0 - def get_overflow_error(self): - self.assembler.make_sure_mc_exists() - ovf_vtable = self.cast_adr_to_int(self.assembler._ovf_error_vtable) - ovf_inst = self.cast_int_to_gcref( - self.cast_adr_to_int(self.assembler._ovf_error_inst)) - return ovf_vtable, ovf_inst - - def get_zero_division_error(self): - self.assembler.make_sure_mc_exists() - zer_vtable = self.cast_adr_to_int(self.assembler._zer_error_vtable) - zer_inst = self.cast_int_to_gcref( - self.cast_adr_to_int(self.assembler._zer_error_inst)) - return zer_vtable, zer_inst - def compile_operations(self, tree, bridge=None): old_loop = tree._x86_compiled if old_loop: @@ -169,31 +87,6 @@ func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr) return func - def _new_box(self, ptr): - if ptr: - return BoxPtr(lltype.nullptr(llmemory.GCREF.TO)) - return BoxInt(0) - - def _get_loop_for_call(self, args, calldescr, ptr): - if calldescr.call_loop is not None: - if not we_are_translated(): - assert (calldescr.shape == - ([arg.type == history.REF for arg in args[1:]], ptr)) - return calldescr.call_loop - args = [arg.clonebox() for arg in args] - result = self._new_box(ptr) - operations = [ - ResOperation(rop.CALL, args, result, calldescr), - ResOperation(rop.GUARD_NO_EXCEPTION, [], None), - ResOperation(rop.FAIL, [result], None)] - operations[1].suboperations = [ResOperation(rop.FAIL, [], None)] - loop = history.TreeLoop('call') - loop.inputargs = args - loop.operations = operations - self.compile_operations(loop) - calldescr.call_loop = loop - return loop - def execute_operations(self, loop, verbose=False): assert isinstance(verbose, bool) func = self.get_bootstrap_code(loop) @@ -267,321 +160,11 @@ self._guard_list.append(guard_op) return index - def sizeof(self, S): - try: - return self._descr_caches['sizeof', S] - except KeyError: - pass - descr = self.gc_ll_descr.sizeof(S, self.translate_support_code) - self._descr_caches['sizeof', S] = descr - return descr - - # ------------------- backend-specific ops ------------------------ - - def do_arraylen_gc(self, args, arraydescr): - ofs = self.gc_ll_descr.array_length_ofs - gcref = args[0].getref(llmemory.GCREF) - length = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref)[ofs/WORD] - return BoxInt(length) - - def do_getarrayitem_gc(self, args, arraydescr): - field = args[1].getint() - gcref = args[0].getref(llmemory.GCREF) - shift, ofs, ptr = self.unpack_arraydescr(arraydescr) - size = 1 << shift - if size == 1: - return BoxInt(ord(rffi.cast(rffi.CArrayPtr(lltype.Char), gcref) - [ofs + field])) - elif size == WORD: - val = (rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref) - [ofs/WORD + field]) - if not ptr: - return BoxInt(val) - else: - return BoxPtr(self.cast_int_to_gcref(val)) - else: - raise NotImplementedError("size = %d" % size) - - def do_setarrayitem_gc(self, args, arraydescr): - field = args[1].getint() - gcref = args[0].getref(llmemory.GCREF) - shift, ofs, ptr = self.unpack_arraydescr(arraydescr) - size = 1 << shift - vbox = args[2] - if size == 1: - v = vbox.getint() - rffi.cast(rffi.CArrayPtr(lltype.Char), gcref)[ofs + field] = chr(v) - elif size == WORD: - if not ptr: - a = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref) - a[ofs/WORD + field] = vbox.getint() - else: - ptr = vbox.getref(llmemory.GCREF) - self.gc_ll_descr.do_write_barrier(gcref, ptr) - a = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref) - a[ofs/WORD + field] = self.cast_gcref_to_int(ptr) - else: - raise NotImplementedError("size = %d" % size) - - def _new_do_len(TP): - def do_strlen(self, args, descr=None): - basesize, itemsize, ofs_length = symbolic.get_array_token(TP, - self.translate_support_code) - gcref = args[0].getref(llmemory.GCREF) - v = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref)[ofs_length/WORD] - return BoxInt(v) - return do_strlen - - do_strlen = _new_do_len(rstr.STR) - do_unicodelen = _new_do_len(rstr.UNICODE) - - def do_strgetitem(self, args, descr=None): - basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR, - self.translate_support_code) - gcref = args[0].getref(llmemory.GCREF) - i = args[1].getint() - v = rffi.cast(rffi.CArrayPtr(lltype.Char), gcref)[basesize + i] - return BoxInt(ord(v)) - - def do_unicodegetitem(self, args, descr=None): - basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE, - self.translate_support_code) - gcref = args[0].getref(llmemory.GCREF) - i = args[1].getint() - basesize = basesize // itemsize - v = rffi.cast(rffi.CArrayPtr(lltype.UniChar), gcref)[basesize + i] - return BoxInt(ord(v)) - - @specialize.argtype(1) - def _base_do_getfield(self, gcref, fielddescr): - ofs, size, ptr = self.unpack_fielddescr(fielddescr) - if size == 1: - v = ord(rffi.cast(rffi.CArrayPtr(lltype.Char), gcref)[ofs]) - elif size == 2: - v = rffi.cast(rffi.CArrayPtr(rffi.USHORT), gcref)[ofs/2] - v = rffi.cast(lltype.Signed, v) - elif size == WORD: - v = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref)[ofs/WORD] - if ptr: - return BoxPtr(self.cast_int_to_gcref(v)) - else: - raise NotImplementedError("size = %d" % size) - return BoxInt(v) - - def do_getfield_gc(self, args, fielddescr): - gcref = args[0].getref(llmemory.GCREF) - return self._base_do_getfield(gcref, fielddescr) - - def do_getfield_raw(self, args, fielddescr): - return self._base_do_getfield(args[0].getint(), fielddescr) - - @specialize.argtype(2) - def _base_do_setfield(self, fielddescr, gcref, vbox): - ofs, size, ptr = self.unpack_fielddescr(fielddescr) - if size == 1: - v = vbox.getint() - rffi.cast(rffi.CArrayPtr(lltype.Char), gcref)[ofs] = chr(v) - elif size == 2: - v = rffi.cast(rffi.USHORT, vbox.getint()) - rffi.cast(rffi.CArrayPtr(rffi.USHORT), gcref)[ofs/2] = v - elif size == WORD: - if ptr: - assert lltype.typeOf(gcref) is not lltype.Signed, ( - "can't handle write barriers for setfield_raw") - ptr = vbox.getref(llmemory.GCREF) - self.gc_ll_descr.do_write_barrier(gcref, ptr) - a = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref) - a[ofs/WORD] = self.cast_gcref_to_int(ptr) - else: - a = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref) - a[ofs/WORD] = vbox.getint() - else: - raise NotImplementedError("size = %d" % size) - - def do_setfield_gc(self, args, fielddescr): - gcref = args[0].getref(llmemory.GCREF) - self._base_do_setfield(fielddescr, gcref, args[1]) - - def do_setfield_raw(self, args, fielddescr): - self._base_do_setfield(fielddescr, args[0].getint(), args[1]) - - def do_new(self, args, descrsize): - res = self.gc_ll_descr.gc_malloc(descrsize) - return BoxPtr(res) - - def do_new_with_vtable(self, args, descr=None): - assert descr is None - classint = args[0].getint() - descrsize = self.class_sizes[classint] - res = self.gc_ll_descr.gc_malloc(descrsize) - as_array = rffi.cast(rffi.CArrayPtr(lltype.Signed), res) - as_array[self.vtable_offset/WORD] = classint - return BoxPtr(res) - - def do_new_array(self, args, arraydescr): - num_elem = args[0].getint() - res = self.gc_ll_descr.gc_malloc_array(arraydescr, num_elem) - return BoxPtr(self.cast_adr_to_gcref(res)) - - def do_newstr(self, args, descr=None): - num_elem = args[0].getint() - tsc = self.translate_support_code - res = self.gc_ll_descr.gc_malloc_str(num_elem, tsc) - return BoxPtr(self.cast_adr_to_gcref(res)) - - def do_newunicode(self, args, descr=None): - num_elem = args[0].getint() - tsc = self.translate_support_code - res = self.gc_ll_descr.gc_malloc_unicode(num_elem, tsc) - return BoxPtr(self.cast_adr_to_gcref(res)) - - def do_strsetitem(self, args, descr=None): - basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR, - self.translate_support_code) - index = args[1].getint() - v = args[2].getint() - a = args[0].getref(llmemory.GCREF) - rffi.cast(rffi.CArrayPtr(lltype.Char), a)[index + basesize] = chr(v) - - def do_unicodesetitem(self, args, descr=None): - basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE, - self.translate_support_code) - index = args[1].getint() - v = args[2].getint() - a = args[0].getref(llmemory.GCREF) - basesize = basesize // itemsize - rffi.cast(rffi.CArrayPtr(lltype.UniChar), a)[index + basesize] = unichr(v) - - def do_call(self, args, calldescr): - assert isinstance(calldescr, ConstDescr3) - num_args, size, ptr = self.unpack_calldescr(calldescr) - assert num_args == len(args) - 1 - loop = self._get_loop_for_call(args, calldescr, ptr) - history.set_future_values(self, args) - self.execute_operations(loop, verbose=False) - # Note: if an exception is set, the rest of the code does a bit of - # nonsense but nothing wrong (the return value should be ignored) - if size == 0: - return None - elif ptr: - return BoxPtr(self.get_latest_value_ref(0)) - else: - return BoxInt(self.get_latest_value_int(0)) - - def do_cast_ptr_to_int(self, args, descr=None): - return BoxInt(self.cast_gcref_to_int(args[0].getref_base())) - - def do_cast_int_to_ptr(self, args, descr=None): - return BoxPtr(self.cast_int_to_gcref(args[0].getint())) - - # ------------------- helpers and descriptions -------------------- - - @staticmethod - def cast_adr_to_int(x): - res = rffi.cast(lltype.Signed, x) - return res - @staticmethod def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return CPU386.cast_adr_to_int(adr) - def arraydescrof(self, A): - try: - return self._descr_caches['array', A] - except KeyError: - pass - assert isinstance(A, lltype.GcArray) - descr = self.gc_ll_descr.arraydescrof(A, self.translate_support_code) - self._descr_caches['array', A] = descr - return descr - - @staticmethod - def unpack_arraydescr(arraydescr): - assert isinstance(arraydescr, ConstDescr3) - basesize = arraydescr.v0 - itemsize = arraydescr.v1 - ptr = arraydescr.flag2 - counter = 0 - while itemsize != 1: - itemsize >>= 1 - counter += 1 - return counter, basesize, ptr - - @staticmethod - def _is_ptr(TP): - if isinstance(TP, lltype.Ptr) and TP.TO._gckind == 'gc': - return True - else: - return False - - def calldescrof(self, functype, argtypes, resulttype): - cachekey = ('call', functype, tuple(argtypes), resulttype) - try: - return self._descr_caches[cachekey] - except KeyError: - pass - for argtype in argtypes: - if rffi.sizeof(argtype) > WORD: - raise NotImplementedError("bigger than lltype.Signed") - if resulttype is not lltype.Void and rffi.sizeof(resulttype) > WORD: - raise NotImplementedError("bigger than lltype.Signed") - if resulttype is lltype.Void: - size = 0 - else: - size = symbolic.get_size(resulttype, self.translate_support_code) - ptr = self._is_ptr(resulttype) - descr = ConstDescr3(len(argtypes), size, ptr) - shape = ([self._is_ptr(arg) for arg in argtypes], ptr) - self._descr_caches[cachekey] = descr - descr.shape = shape - return descr - - @staticmethod - def unpack_calldescr(calldescr): - assert isinstance(calldescr, ConstDescr3) - return calldescr.v0, calldescr.v1, calldescr.flag2 - - def fielddescrof(self, S, fieldname): - try: - return self._descr_caches['field', S, fieldname] - except KeyError: - pass - ofs, size = symbolic.get_field_token(S, fieldname, - self.translate_support_code) - exp_size = rffi.sizeof(getattr(S, fieldname)) - if type(exp_size) is int: - assert exp_size in [1, 2, WORD] - if (isinstance(getattr(S, fieldname), lltype.Ptr) and - getattr(S, fieldname).TO._gckind == 'gc'): - ptr = True - else: - ptr = False - descr = ConstDescr3(ofs, size, ptr) - self._descr_caches['field', S, fieldname] = descr - return descr - - @staticmethod - def unpack_fielddescr(fielddescr): - assert isinstance(fielddescr, ConstDescr3) - return fielddescr.v0, fielddescr.v1, fielddescr.flag2 - - @staticmethod - def cast_int_to_adr(x): - if not we_are_translated(): - _check_addr_range(x) - return rffi.cast(llmemory.Address, x) - - def cast_gcref_to_int(self, x): - return rffi.cast(lltype.Signed, x) - - def cast_int_to_gcref(self, x): - if not we_are_translated(): - _check_addr_range(x) - return rffi.cast(llmemory.GCREF, x) - - def cast_adr_to_gcref(self, x): - return rffi.cast(llmemory.GCREF, x) CPU = CPU386 From arigo at codespeak.net Tue Sep 1 16:13:53 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:13:53 +0200 (CEST) Subject: [pypy-svn] r67399 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86 Message-ID: <20090901141353.D3B4B168038@codespeak.net> Author: arigo Date: Tue Sep 1 16:13:52 2009 New Revision: 67399 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/assembler.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67387 | arigo | 2009-09-01 14:57:32 +0200 (Tue, 01 Sep 2009) | 6 lines Tests and implementation in the x86 backend of proper gcrootmap support, marking which registers and stack locations contain GC pointers. This also fixes a bug existing in 'trunk', where stack locations were marked but not the ebx, esi and edi registers. ------------------------------------------------------------------------ r67357 | arigo | 2009-08-31 14:49:25 +0200 (Mon, 31 Aug 2009) | 2 lines Small changes. The x86 tests pass up to 'y'; now trying the 'z' tests... ------------------------------------------------------------------------ r67356 | arigo | 2009-08-31 14:28:28 +0200 (Mon, 31 Aug 2009) | 2 lines Fix the x86 backend. ------------------------------------------------------------------------ r67344 | arigo | 2009-08-30 17:34:28 +0200 (Sun, 30 Aug 2009) | 2 lines Add a comment. ------------------------------------------------------------------------ r67343 | arigo | 2009-08-30 17:33:25 +0200 (Sun, 30 Aug 2009) | 3 lines Add COND_CALL and implement it in the backend. Meant to be used only for calls to helpers like malloc. ------------------------------------------------------------------------ r67330 | arigo | 2009-08-29 18:58:55 +0200 (Sat, 29 Aug 2009) | 2 lines Fix. ------------------------------------------------------------------------ r67329 | arigo | 2009-08-29 18:42:08 +0200 (Sat, 29 Aug 2009) | 3 lines Skip tests running on a moving GC. The rest of the tests pass (at least the non-translation ones). ------------------------------------------------------------------------ r67322 | arigo | 2009-08-29 17:02:58 +0200 (Sat, 29 Aug 2009) | 2 lines A few tests start to pass again. ------------------------------------------------------------------------ r67321 | arigo | 2009-08-29 16:47:35 +0200 (Sat, 29 Aug 2009) | 2 lines In-progress. Attach the repr_of_descr() method to Descrs. ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py.merge.tmp Tue Sep 1 16:13:52 2009 @@ -1,6 +1,6 @@ import sys, os import ctypes -from pypy.jit.backend.x86 import symbolic +from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.history import Const, Box, BoxPtr, REF from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory from pypy.rpython.lltypesystem.rclass import OBJECT @@ -13,7 +13,6 @@ from pypy.jit.backend.x86 import codebuf from pypy.jit.backend.x86.ri386 import * from pypy.jit.metainterp.resoperation import rop -from pypy.jit.backend.logger import AbstractLogger # our calling convention - we pass three first args as edx, ecx and eax # and the rest stays on the stack @@ -29,16 +28,6 @@ def align_stack_words(words): return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) -class x86Logger(AbstractLogger): - - def repr_of_descr(self, descr): - from pypy.jit.backend.x86.runner import ConstDescr3 - if isinstance(descr, ConstDescr3): - return (str(descr.v0) + "," + str(descr.v1) + - "," + str(descr.flag2)) - return AbstractLogger.repr_of_descr(self, descr) - - class MachineCodeBlockWrapper(object): MC_SIZE = 1024*1024 @@ -105,7 +94,7 @@ self._exception_data = lltype.nullptr(rffi.CArray(lltype.Signed)) self._exception_addr = 0 self.mcstack = MachineCodeStack() - self.logger = x86Logger(cpu.ts) + self.logger = cpu.logger_cls() self.fail_boxes_int = lltype.malloc(lltype.GcArray(lltype.Signed), MAX_FAIL_BOXES, zero=True) self.fail_boxes_ptr = lltype.malloc(lltype.GcArray(llmemory.GCREF), @@ -113,8 +102,6 @@ def make_sure_mc_exists(self): if self.mc is None: - from pypy.jit.backend.x86.runner import ConstDescr3 - rffi.cast(lltype.Signed, self.fail_boxes_int) # workaround rffi.cast(lltype.Signed, self.fail_boxes_ptr) # workaround self.fail_box_int_addr = rffi.cast(lltype.Signed, @@ -139,10 +126,9 @@ zero=True, flavor='raw') self._exception_bck_addr = self.cpu.cast_ptr_to_int( self._exception_bck) - self.mc = self.mcstack.next_mc() - self.mc2 = self.mcstack.next_mc() # the address of the function called by 'new' gc_ll_descr = self.cpu.gc_ll_descr + gc_ll_descr.initialize() ll_new = gc_ll_descr.get_funcptr_for_new() self.malloc_func_addr = rffi.cast(lltype.Signed, ll_new) if gc_ll_descr.get_funcptr_for_newarray is not None: @@ -157,16 +143,9 @@ ll_new_unicode = gc_ll_descr.get_funcptr_for_newunicode() self.malloc_unicode_func_addr = rffi.cast(lltype.Signed, ll_new_unicode) - # for moving GCs, the array used to hold the address of GC objects - # that appear as ConstPtr. - if gc_ll_descr.moving_gc: - self.gcrefs = gc_ll_descr.GcRefList() - self.single_gcref_descr = ConstDescr3(0, WORD, True) - else: - self.gcrefs = None - self.gcrootmap = gc_ll_descr.gcrootmap - if self.gcrootmap: - self.gcrootmap.initialize() + # done + self.mc2 = self.mcstack.next_mc() + self.mc = self.mcstack.next_mc() def _compute_longest_fail_op(self, ops): @@ -580,6 +559,7 @@ assert 0, itemsize genop_discard_setfield_raw = genop_discard_setfield_gc + genop_discard_setarrayitem_raw = genop_discard_setarrayitem_gc def genop_strlen(self, op, arglocs, resloc): base_loc = arglocs[0] @@ -594,9 +574,9 @@ self.mc.MOV(resloc, addr_add_const(base_loc, ofs_length)) def genop_arraylen_gc(self, op, arglocs, resloc): - ofs = self.cpu.gc_ll_descr.array_length_ofs base_loc, ofs_loc = arglocs - self.mc.MOV(resloc, addr_add_const(base_loc, ofs)) + assert isinstance(ofs_loc, IMM32) + self.mc.MOV(resloc, addr_add_const(base_loc, ofs_loc.value)) def genop_strgetitem(self, op, arglocs, resloc): base_loc, ofs_loc = arglocs @@ -766,17 +746,14 @@ sizeloc = arglocs[0] assert isinstance(sizeloc, IMM32) size = sizeloc.value - arglocs = arglocs[1:] nargs = len(op.args)-1 extra_on_stack = self.align_stack_for_call(nargs) - for i in range(nargs, 0, -1): - v = op.args[i] - loc = arglocs[i] - self.mc.PUSH(loc) + for i in range(nargs+1, 1, -1): + self.mc.PUSH(arglocs[i]) if isinstance(op.args[0], Const): x = rel32(op.args[0].getint()) else: - x = arglocs[0] + x = arglocs[1] self.mc.CALL(x) self.mark_gc_roots() self.mc.ADD(esp, imm(WORD * extra_on_stack)) @@ -787,6 +764,35 @@ genop_call_pure = genop_call + def genop_discard_cond_call_gc_wb(self, op, arglocs): + # use 'mc._mc' directly instead of 'mc', to avoid + # bad surprizes if the code buffer is mostly full + loc_cond = arglocs[0] + loc_mask = arglocs[1] + mc = self.mc._mc + mc.TEST(loc_cond, loc_mask) + mc.write('\x74\x00') # JZ after_the_call + jz_location = mc.get_relative_pos() + # the following is supposed to be the slow path, so whenever possible + # we choose the most compact encoding over the most efficient one. + for i in range(len(arglocs)-1, 2, -1): + mc.PUSH(arglocs[i]) + mc.CALL(rel32(op.args[2].getint())) + pop_count = 0 + for i in range(3, len(arglocs)): + loc = arglocs[i] + pop_count += 1 + if isinstance(loc, REG): + while pop_count > 0: + mc.POP(loc) + pop_count -= 1 + if pop_count: + mc.ADD(esp, imm(WORD * pop_count)) + # patch the JZ above + offset = mc.get_relative_pos() - jz_location + assert 0 < offset <= 127 + mc.overwrite(jz_location-1, chr(offset)) + def not_implemented_op_discard(self, op, arglocs): print "not implemented operation: %s" % op.getopname() raise NotImplementedError @@ -809,22 +815,11 @@ # self.mc.MOVZX(eax, eax) def mark_gc_roots(self): - if self.gcrootmap: - gclocs = [] - regalloc = self._regalloc - for v, val in regalloc.stack_bindings.items(): - if (isinstance(v, BoxPtr) and - regalloc.longevity[v][1] > regalloc.position): - gclocs.append(val) - #alllocs = [] - #for loc in gclocs: - # assert isinstance(loc, MODRM) - # alllocs.append(str(loc.position)) - #print self.mc.tell() - #print ", ".join(alllocs) - shape = self.gcrootmap.encode_callshape(gclocs) - self.gcrootmap.put(rffi.cast(llmemory.Address, self.mc.tell()), - shape) + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + if gcrootmap: + mark = self._regalloc.get_mark_gc_roots(gcrootmap) + gcrootmap.put(rffi.cast(llmemory.Address, self.mc.tell()), mark) + genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST genop_list = [Assembler386.not_implemented_op] * rop._LAST From arigo at codespeak.net Tue Sep 1 16:13:57 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:13:57 +0200 (CEST) Subject: [pypy-svn] r67400 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph Message-ID: <20090901141357.45AC7168038@codespeak.net> Author: arigo Date: Tue Sep 1 16:13:56 2009 New Revision: 67400 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph/llimpl.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph/llimpl.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llgraph/llimpl.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67353 | arigo | 2009-08-31 14:06:02 +0200 (Mon, 31 Aug 2009) | 2 lines Write test_cond_call_gc_wb and make it pass on the llgraph backend. ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph/llimpl.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph/llimpl.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph/llimpl.py.merge.tmp Tue Sep 1 16:13:56 2009 @@ -104,6 +104,7 @@ 'arraylen_gc' : (('ref',), 'int'), 'call' : (('ref', 'varargs'), 'intorptr'), 'call_pure' : (('ref', 'varargs'), 'intorptr'), + 'cond_call_gc_wb' : (('int', 'int', 'ptr', 'varargs'), None), 'oosend' : (('varargs',), 'intorptr'), 'oosend_pure' : (('varargs',), 'intorptr'), 'guard_true' : (('bool',), None), @@ -680,6 +681,10 @@ op_call_pure = op_call + def op_cond_call_gc_wb(self, calldescr, a, b, func, *args): + if a & b: + self.op_call(calldescr, func, *args) + def op_oosend(self, descr, obj, *args): raise NotImplementedError("oosend for lltype backend??") From arigo at codespeak.net Tue Sep 1 16:14:00 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:14:00 +0200 (CEST) Subject: [pypy-svn] r67401 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test Message-ID: <20090901141400.DC2CE168052@codespeak.net> Author: arigo Date: Tue Sep 1 16:14:00 2009 New Revision: 67401 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_runner.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_runner.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_runner.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67321 | arigo | 2009-08-29 16:47:35 +0200 (Sat, 29 Aug 2009) | 2 lines In-progress. Attach the repr_of_descr() method to Descrs. ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_runner.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_runner.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_runner.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_runner.py.merge.tmp Tue Sep 1 16:14:00 2009 @@ -5,7 +5,7 @@ Box) from pypy.jit.backend.x86.runner import CPU from pypy.jit.backend.x86.regalloc import WORD -from pypy.jit.backend.x86 import symbolic +from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import execute from pypy.jit.backend.test.runner_test import LLtypeBackendTest From arigo at codespeak.net Tue Sep 1 16:14:04 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:14:04 +0200 (CEST) Subject: [pypy-svn] r67402 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test Message-ID: <20090901141404.1AD82168058@codespeak.net> Author: arigo Date: Tue Sep 1 16:14:03 2009 New Revision: 67402 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_regalloc.py.merge.tmp - copied, changed from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_regalloc.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_regalloc.py revisions 67298 to 67389: ------------------------------------------------------------------------ r67387 | arigo | 2009-09-01 14:57:32 +0200 (Tue, 01 Sep 2009) | 6 lines Tests and implementation in the x86 backend of proper gcrootmap support, marking which registers and stack locations contain GC pointers. This also fixes a bug existing in 'trunk', where stack locations were marked but not the ebx, esi and edi registers. ------------------------------------------------------------------------ r67357 | arigo | 2009-08-31 14:49:25 +0200 (Mon, 31 Aug 2009) | 2 lines Small changes. The x86 tests pass up to 'y'; now trying the 'z' tests... ------------------------------------------------------------------------ r67299 | arigo | 2009-08-29 11:56:39 +0200 (Sat, 29 Aug 2009) | 3 lines A branch to try to extract as much of the x86 backend as possible into generic code for LL backends. ------------------------------------------------------------------------ Copied: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_regalloc.py.merge.tmp (from r67389, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_regalloc.py) ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_regalloc.py.merge.tmp Tue Sep 1 16:14:03 2009 @@ -5,6 +5,7 @@ from pypy.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ BoxPtr, ConstPtr, TreeLoop from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.backend.llsupport.descr import GcCache from pypy.jit.backend.x86.runner import CPU from pypy.jit.backend.x86.regalloc import RegAlloc, REGS, WORD from pypy.jit.metainterp.test.oparser import parse @@ -20,11 +21,13 @@ class MockAssembler(object): gcrefs = None - def __init__(self): + def __init__(self, cpu=None): self.loads = [] self.stores = [] self.performs = [] self.lea = [] + self.cpu = cpu or CPU(None, None) + self.cpu.gc_ll_descr = MockGcDescr(False) def dump(self, *args): pass @@ -44,16 +47,47 @@ def load_effective_addr(self, *args): self.lea.append(args) +class MockGcRootMap(object): + def get_basic_shape(self): + return ['shape'] + def add_ebp_offset(self, shape, offset): + shape.append(offset) + def add_ebx(self, shape): + shape.append('ebx') + def add_esi(self, shape): + shape.append('esi') + def add_edi(self, shape): + shape.append('edi') + def compress_callshape(self, shape): + assert shape[0] == 'shape' + return ['compressed'] + shape[1:] + +class MockGcDescr(GcCache): + def get_funcptr_for_new(self): + return 123 + get_funcptr_for_newarray = get_funcptr_for_new + get_funcptr_for_newstr = get_funcptr_for_new + get_funcptr_for_newunicode = get_funcptr_for_new + + moving_gc = True + gcrootmap = MockGcRootMap() + + def initialize(self): + pass + def rewrite_assembler(self, cpu, operations): + pass + + class RegAllocForTests(RegAlloc): position = 0 def _compute_next_usage(self, v, _): return -1 class TestRegallocDirect(object): - def fill_regs(self, regalloc): + def fill_regs(self, regalloc, cls=BoxInt): allboxes = [] for reg in REGS: - box = BoxInt() + box = cls() allboxes.append(box) regalloc.reg_bindings[box] = reg regalloc.free_regs = [] @@ -101,24 +135,44 @@ def test_registers_around_call(self): cpu = CPU(None, None) - regalloc = RegAlloc(MockAssembler(), DummyTree()) + regalloc = RegAlloc(MockAssembler(cpu), DummyTree()) boxes = self.fill_regs(regalloc) TP = lltype.FuncType([], lltype.Void) calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) regalloc._check_invariants() - box = boxes[0] for box in boxes: regalloc.longevity[box] = (0, 1) + box = boxes[0] regalloc.position = 0 regalloc.consider_call(ResOperation(rop.CALL, [box], None, calldescr), None) assert len(regalloc.assembler.stores) == 3 regalloc._check_invariants() + def test_mark_gc_roots(self): + cpu = CPU(None, None) + regalloc = RegAlloc(MockAssembler(cpu), DummyTree()) + cpu = regalloc.assembler.cpu + boxes = self.fill_regs(regalloc, cls=BoxPtr) + TP = lltype.FuncType([], lltype.Signed) + calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) + regalloc._check_invariants() + for box in boxes: + regalloc.longevity[box] = (0, 1) + box = boxes[0] + regalloc.position = 0 + regalloc.consider_call(ResOperation(rop.CALL, [box], BoxInt(), + calldescr), None) + assert len(regalloc.assembler.stores) == 3 + # + mark = regalloc.get_mark_gc_roots(cpu.gc_ll_descr.gcrootmap) + assert mark[0] == 'compressed' + expected = ['ebx', 'esi', 'edi', -16, -20, -24] + assert dict.fromkeys(mark[1:]) == dict.fromkeys(expected) + def test_registers_around_newstr(self): cpu = CPU(None, None) - regalloc = RegAllocForTests(MockAssembler(), DummyTree()) - regalloc.assembler.cpu = cpu + regalloc = RegAllocForTests(MockAssembler(cpu), DummyTree()) boxes = self.fill_regs(regalloc) regalloc._check_invariants() for box in boxes: @@ -522,42 +576,10 @@ assert s[1] == 'a' -class GcRootMap(object): - def initialize(self): - pass - -class MockGcDescr(object): - def get_funcptr_for_new(self): - return 123 - get_funcptr_for_newarray = get_funcptr_for_new - get_funcptr_for_newstr = get_funcptr_for_new - get_funcptr_for_newunicode = get_funcptr_for_new - - moving_gc = True - class GcRefList(object): - MAXLEN = 1000 - - def __init__(self): - TP = rffi.CArray(llmemory.GCREF) - self.l = lltype.malloc(TP, self.MAXLEN, flavor='raw') - self.size = 0 - - def get_address_of_gcref(self, addr): - baseaddr = rffi.cast(lltype.Signed, self.l) - for i in range(self.size): - if self.l[i] == addr: - return baseaddr + i * WORD - self.l[self.size] = addr - self.size += 1 - return baseaddr + (self.size - 1) * WORD - - gcrootmap = GcRootMap() - class TestRegallocGc(BaseTestRegalloc): cpu = CPU(None, None) - cpu.gc_ll_descr = MockGcDescr() - cpu.gcrefs = cpu.gc_ll_descr.GcRefList() - + cpu.gc_ll_descr = MockGcDescr(False) + S = lltype.GcForwardReference() S.become(lltype.GcStruct('S', ('field', lltype.Ptr(S)), ('int', lltype.Signed))) @@ -604,15 +626,6 @@ self.interpret(ops, [0]) assert not self.getptr(0, lltype.Ptr(self.S)) - def test_get_rid_of_debug_merge_point(self): - ops = ''' - [] - debug_merge_point() - fail() - ''' - loop = self.interpret(ops, [], run=False) - assert len(loop.operations) == 1 - def test_bug_0(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] From arigo at codespeak.net Tue Sep 1 16:20:11 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:20:11 +0200 (CEST) Subject: [pypy-svn] r67403 - in pypy/branch/pyjitpl5-llmodel-merge/pypy: jit/backend jit/backend/llgraph jit/backend/llsupport jit/backend/test jit/backend/x86 jit/backend/x86/test jit/metainterp rpython/memory/gctransform Message-ID: <20090901142011.20D1A168056@codespeak.net> Author: arigo Date: Tue Sep 1 16:20:10 2009 New Revision: 67403 Added: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph/llimpl.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph/llimpl.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/ - copied from r67402, pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/llsupport/ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test/runner_test.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test/runner_test.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/codebuf.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/codebuf.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/regalloc.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/regalloc.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_regalloc.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_regalloc.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_runner.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_runner.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_symbolic.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_symbolic.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_zrpy_gc.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel/pypy/jit/backend/x86/test/test_zrpy_gc.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/executor.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/executor.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/history.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/history.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/resoperation.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel/pypy/jit/metainterp/resoperation.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/warmspot.py - copied unchanged from r67402, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/warmspot.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/rpython/memory/gctransform/ - copied from r67402, pypy/branch/pyjitpl5-llmodel/pypy/rpython/memory/gctransform/ Removed: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph/llimpl.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test/runner_test.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/gc.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/symbolic.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_regalloc.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/test/test_runner.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/executor.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/history.py.merge.tmp pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/warmspot.py.merge.tmp Log: Merge pyjitpl5-llmodel into a copy of trunk. From arigo at codespeak.net Tue Sep 1 16:26:13 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 16:26:13 +0200 (CEST) Subject: [pypy-svn] r67404 - pypy/trunk/pypy/jit/backend Message-ID: <20090901142613.1F82F16805A@codespeak.net> Author: arigo Date: Tue Sep 1 16:26:11 2009 New Revision: 67404 Modified: pypy/trunk/pypy/jit/backend/loopparser.py Log: Accept LOOP with zero input argument too. Modified: pypy/trunk/pypy/jit/backend/loopparser.py ============================================================================== --- pypy/trunk/pypy/jit/backend/loopparser.py (original) +++ pypy/trunk/pypy/jit/backend/loopparser.py Tue Sep 1 16:26:11 2009 @@ -214,7 +214,10 @@ if line.startswith('LOOP END'): raise EndOfBlock() if line.startswith('LOOP'): - _, inputargs = line.split(" ") + if " " in line: + _, inputargs = line.split(" ") + else: + inputargs = "" self.current_block.inputargs = self._parse_boxes(inputargs) return i + 1 if line.startswith('END'): From arigo at codespeak.net Tue Sep 1 17:05:53 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 17:05:53 +0200 (CEST) Subject: [pypy-svn] r67405 - in pypy/trunk/pypy: interpreter objspace/flow Message-ID: <20090901150553.C9E4E168066@codespeak.net> Author: arigo Date: Tue Sep 1 17:05:53 2009 New Revision: 67405 Modified: pypy/trunk/pypy/interpreter/pyframe.py pypy/trunk/pypy/interpreter/pyopcode.py pypy/trunk/pypy/objspace/flow/objspace.py Log: Replace space.unpackiterable() in UNPACK_SEQUENCE with space.viewiterable(). Fix in the flow space. Modified: pypy/trunk/pypy/interpreter/pyframe.py ============================================================================== --- pypy/trunk/pypy/interpreter/pyframe.py (original) +++ pypy/trunk/pypy/interpreter/pyframe.py Tue Sep 1 17:05:53 2009 @@ -202,6 +202,7 @@ self.valuestackdepth = finaldepth def pushrevvalues(self, n, values_w): # n should be len(values_w) + make_sure_not_resized(values_w) while True: n -= 1 if n < 0: Modified: pypy/trunk/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/pypy/interpreter/pyopcode.py Tue Sep 1 17:05:53 2009 @@ -636,7 +636,7 @@ def UNPACK_SEQUENCE(f, itemcount, *ignored): w_iterable = f.popvalue() try: - items = f.space.unpackiterable(w_iterable, itemcount) + items = f.space.viewiterable(w_iterable, itemcount) except UnpackValueError, e: raise OperationError(f.space.w_ValueError, f.space.wrap(e.msg)) f.pushrevvalues(itemcount, items) Modified: pypy/trunk/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/pypy/objspace/flow/objspace.py Tue Sep 1 17:05:53 2009 @@ -264,12 +264,7 @@ return graph def viewiterable(self, w_tuple, expected_length=None): - unwrapped = self.unwrap(w_tuple) - result = tuple([Constant(x) for x in unwrapped]) - if expected_length is not None and len(result) != expected_length: - raise ValueError, "got a tuple of length %d instead of %d" % ( - len(result), expected_length) - return result + return self.unpackiterable(w_tuple, expected_length) def unpackiterable(self, w_iterable, expected_length=None): if not isinstance(w_iterable, Variable): From arigo at codespeak.net Tue Sep 1 17:06:27 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 17:06:27 +0200 (CEST) Subject: [pypy-svn] r67406 - in pypy/branch/pyjitpl5-llmodel-merge/pypy/jit: backend backend/cli backend/llsupport backend/llsupport/test backend/llvm backend/x86 metainterp Message-ID: <20090901150627.44F75168066@codespeak.net> Author: arigo Date: Tue Sep 1 17:06:26 2009 New Revision: 67406 Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/cli/method.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/cli/runner.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/descr.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/llmodel.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/test/test_descr.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llvm/runner.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/pyjitpl.py Log: Lots of small fixes needed after the merge. Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/cli/method.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/cli/method.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/cli/method.py Tue Sep 1 17:06:26 2009 @@ -10,7 +10,6 @@ ConstObj, BoxInt) from pypy.jit.metainterp.resoperation import rop, opname from pypy.jit.metainterp.typesystem import oohelper -from pypy.jit.backend.logger import AbstractLogger from pypy.jit.backend.cli import runner from pypy.jit.backend.cli.methodfactory import get_method_wrapper @@ -24,16 +23,6 @@ cVoid = ootype.nullruntimeclass -class CliLogger(AbstractLogger): - - def repr_of_descr(self, descr): - from pypy.jit.backend.cli.runner import DescrWithKey - if isinstance(descr, DescrWithKey): - return descr.short_repr() - return AbstractLogger.repr_of_descr(self, descr) - -logger = CliLogger(oohelper) -runner.CliCPU.logger_cls = CliLogger # xxx hack class __extend__(AbstractValue): __metaclass__ = extendabletype @@ -162,8 +151,8 @@ self.av_ZeroDivisionError = None # ---- - logger.create_log() - logger.eventually_log_loop(loop) + cpu.logger.create_log() + cpu.logger.eventually_log_loop(loop) # ---- self.box2type = {} if self.nocast: Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/cli/runner.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/cli/runner.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/cli/runner.py Tue Sep 1 17:06:26 2009 @@ -8,6 +8,7 @@ from pypy.jit.metainterp import executor from pypy.jit.metainterp.resoperation import rop, opname from pypy.jit.backend import model +from pypy.jit.backend.logger import Logger from pypy.jit.backend.llgraph.runner import KeyManager from pypy.translator.cli import dotnet from pypy.translator.cli.dotnet import CLR @@ -44,6 +45,7 @@ self.failing_ops = [] # index --> op self.ll_ovf_exc = self._get_prebuilt_exc(OverflowError) self.ll_zero_exc = self._get_prebuilt_exc(ZeroDivisionError) + self.logger = Logger(self.ts) def _get_prebuilt_exc(self, cls): if self.rtyper is None: @@ -261,6 +263,9 @@ def short_repr(self): return '' + def repr_of_descr(self): + return self.short_repr() + def get_class_for_type(T): if T is ootype.Void: Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/descr.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/descr.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/descr.py Tue Sep 1 17:06:26 2009 @@ -169,7 +169,7 @@ arg_classes = '' # <-- annotation hack def __init__(self, arg_classes): - self.arg_classes = arg_classes # string of "p" and "i" (ptr/int) + self.arg_classes = arg_classes # string of "r" and "i" (ref/int) def instantiate_arg_classes(self): result = [] @@ -240,7 +240,7 @@ for ARG in ARGS: kind = getkind(ARG) if kind == 'int': arg_classes.append('i') - elif kind == 'ptr': arg_classes.append('p') + elif kind == 'ref': arg_classes.append('r') else: raise NotImplementedError('ARG = %r' % (ARG,)) arg_classes = ''.join(arg_classes) Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/llmodel.py Tue Sep 1 17:06:26 2009 @@ -2,8 +2,8 @@ from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.jit.metainterp.history import BoxInt, BoxPtr, set_future_values +from pypy.jit.metainterp.typesystem import llhelper from pypy.jit.backend.model import AbstractCPU -from pypy.jit.backend.logger import LLLogger from pypy.jit.backend.llsupport import symbolic from pypy.jit.backend.llsupport.symbolic import WORD, unroll_basic_sizes from pypy.jit.backend.llsupport.descr import get_size_descr, BaseSizeDescr @@ -19,8 +19,7 @@ class AbstractLLCPU(AbstractCPU): - is_oo = False - logger_cls = LLLogger + ts = llhelper def __init__(self, rtyper, stats, translate_support_code=False, gcdescr=None): @@ -125,13 +124,13 @@ def do_arraylen_gc(self, args, arraydescr): assert isinstance(arraydescr, BaseArrayDescr) ofs = arraydescr.get_ofs_length(self.translate_support_code) - gcref = args[0].getptr_base() + gcref = args[0].getref_base() length = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref)[ofs/WORD] return BoxInt(length) def do_getarrayitem_gc(self, args, arraydescr): itemindex = args[1].getint() - gcref = args[0].getptr_base() + gcref = args[0].getref_base() ofs, size, ptr = self.unpack_arraydescr(arraydescr) # for TYPE, itemsize in unroll_basic_sizes: @@ -149,12 +148,12 @@ def do_setarrayitem_gc(self, args, arraydescr): itemindex = args[1].getint() - gcref = args[0].getptr_base() + gcref = args[0].getref_base() ofs, size, ptr = self.unpack_arraydescr(arraydescr) vbox = args[2] # if ptr: - vboxptr = vbox.getptr_base() + vboxptr = vbox.getref_base() self.gc_ll_descr.do_write_barrier(gcref, vboxptr) a = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref) a[ofs/WORD + itemindex] = self.cast_gcref_to_int(vboxptr) @@ -172,7 +171,7 @@ def do_strlen(self, args, descr=None): basesize, itemsize, ofs_length = symbolic.get_array_token(TP, self.translate_support_code) - gcref = args[0].getptr_base() + gcref = args[0].getref_base() v = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref)[ofs_length/WORD] return BoxInt(v) return do_strlen @@ -183,7 +182,7 @@ def do_strgetitem(self, args, descr=None): basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR, self.translate_support_code) - gcref = args[0].getptr_base() + gcref = args[0].getref_base() i = args[1].getint() v = rffi.cast(rffi.CArrayPtr(lltype.Char), gcref)[basesize + i] return BoxInt(ord(v)) @@ -191,7 +190,7 @@ def do_unicodegetitem(self, args, descr=None): basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE, self.translate_support_code) - gcref = args[0].getptr_base() + gcref = args[0].getref_base() i = args[1].getint() basesize = basesize // itemsize v = rffi.cast(rffi.CArrayPtr(lltype.UniChar), gcref)[basesize + i] @@ -213,7 +212,7 @@ return BoxInt(val) def do_getfield_gc(self, args, fielddescr): - gcref = args[0].getptr_base() + gcref = args[0].getref_base() return self._base_do_getfield(gcref, fielddescr) def do_getfield_raw(self, args, fielddescr): @@ -225,7 +224,7 @@ if ptr: assert lltype.typeOf(gcref) is not lltype.Signed, ( "can't handle write barriers for setfield_raw") - ptr = vbox.getptr_base() + ptr = vbox.getref_base() self.gc_ll_descr.do_write_barrier(gcref, ptr) a = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref) a[ofs/WORD] = self.cast_gcref_to_int(ptr) @@ -240,7 +239,7 @@ raise NotImplementedError("size = %d" % size) def do_setfield_gc(self, args, fielddescr): - gcref = args[0].getptr_base() + gcref = args[0].getref_base() self._base_do_setfield(gcref, args[1], fielddescr) def do_setfield_raw(self, args, fielddescr): @@ -279,7 +278,7 @@ self.translate_support_code) index = args[1].getint() v = args[2].getint() - a = args[0].getptr_base() + a = args[0].getref_base() rffi.cast(rffi.CArrayPtr(lltype.Char), a)[index + basesize] = chr(v) def do_unicodesetitem(self, args, descr=None): @@ -287,7 +286,7 @@ self.translate_support_code) index = args[1].getint() v = args[2].getint() - a = args[0].getptr_base() + a = args[0].getref_base() basesize = basesize // itemsize rffi.cast(rffi.CArrayPtr(lltype.UniChar), a)[index + basesize] = unichr(v) @@ -303,14 +302,14 @@ # Note: if an exception is set, the rest of the code does a bit of # nonsense but nothing wrong (the return value should be ignored) if calldescr.returns_a_pointer(): - return BoxPtr(self.get_latest_value_ptr(0)) + return BoxPtr(self.get_latest_value_ref(0)) elif calldescr.get_result_size(self.translate_support_code) != 0: return BoxInt(self.get_latest_value_int(0)) else: return None def do_cast_ptr_to_int(self, args, descr=None): - return BoxInt(self.cast_gcref_to_int(args[0].getptr_base())) + return BoxInt(self.cast_gcref_to_int(args[0].getref_base())) def do_cast_int_to_ptr(self, args, descr=None): return BoxPtr(self.cast_int_to_gcref(args[0].getint())) Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/test/test_descr.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/test/test_descr.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/test/test_descr.py Tue Sep 1 17:06:26 2009 @@ -120,7 +120,7 @@ descr2 = get_call_descr(c0, [lltype.Ptr(T)], lltype.Ptr(T)) assert descr2.get_result_size(False) == rffi.sizeof(lltype.Ptr(T)) assert descr2.returns_a_pointer() - assert descr2.arg_classes == "p" + assert descr2.arg_classes == "r" # U = lltype.GcStruct('U', ('x', lltype.Signed)) assert descr2 == get_call_descr(c0, [lltype.Ptr(U)], lltype.Ptr(U)) @@ -129,7 +129,7 @@ descr3 = get_call_descr(c1, [lltype.Ptr(T)], lltype.Ptr(U)) assert isinstance(descr3.get_result_size(True), Symbolic) assert descr3.returns_a_pointer() - assert descr3.arg_classes == "p" + assert descr3.arg_classes == "r" def test_repr_of_descr(): Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llvm/runner.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llvm/runner.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llvm/runner.py Tue Sep 1 17:06:26 2009 @@ -17,7 +17,6 @@ class LLVMCPU(object): ts = llhelper - logger_cls = None RAW_VALUE = rffi.CFixedArray(rffi.ULONGLONG, 1) SIGNED_VALUE = rffi.CFixedArray(lltype.Signed, 1) POINTER_VALUE = rffi.CFixedArray(llmemory.GCREF, 1) Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py Tue Sep 1 17:06:26 2009 @@ -4,7 +4,7 @@ from pypy.jit.metainterp.history import Const, ConstInt, Box, \ BoxInt, ConstAddr -class AbstractLogger(object): +class Logger(object): def __init__(self, ts): self._log_fd = -1 @@ -119,10 +119,3 @@ args_s = ','.join([self.repr_of_arg(memo, box) for box in valueboxes]) os.write(self._log_fd, "CALL\n") os.write(self._log_fd, "%s %s\n" % (name, args_s)) - - -class LLLogger(AbstractLogger): - is_oo = False - -class OOLogger(AbstractLogger): - is_oo = True Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py Tue Sep 1 17:06:26 2009 @@ -1,5 +1,4 @@ class AbstractCPU(object): - logger_cls = None def set_class_sizes(self, class_sizes): self.class_sizes = class_sizes Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py Tue Sep 1 17:06:26 2009 @@ -7,6 +7,7 @@ from pypy.rpython.lltypesystem.lloperation import llop from pypy.annotation import model as annmodel from pypy.tool.uid import fixid +from pypy.jit.backend.logger import Logger from pypy.jit.backend.x86.regalloc import (RegAlloc, WORD, REGS, TempBox, lower_byte, stack_pos) from pypy.rlib.objectmodel import we_are_translated, specialize @@ -94,7 +95,7 @@ self._exception_data = lltype.nullptr(rffi.CArray(lltype.Signed)) self._exception_addr = 0 self.mcstack = MachineCodeStack() - self.logger = cpu.logger_cls() + self.logger = Logger(cpu.ts) self.fail_boxes_int = lltype.malloc(lltype.GcArray(lltype.Signed), MAX_FAIL_BOXES, zero=True) self.fail_boxes_ptr = lltype.malloc(lltype.GcArray(llmemory.GCREF), Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/runner.py Tue Sep 1 17:06:26 2009 @@ -7,7 +7,6 @@ from pypy.jit.metainterp import history from pypy.jit.backend.x86.assembler import Assembler386, MAX_FAIL_BOXES from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU -from pypy.jit.metainterp.typesystem import llhelper history.TreeLoop._x86_compiled = 0 history.TreeLoop._x86_bootstrap_code = 0 @@ -15,7 +14,6 @@ class CPU386(AbstractLLCPU): debug = True - ts = llhelper BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/pyjitpl.py Tue Sep 1 17:06:26 2009 @@ -9,6 +9,7 @@ from pypy.jit.metainterp.history import Const, ConstInt, Box from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import codewriter, executor +from pypy.jit.backend.logger import Logger from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize @@ -1004,8 +1005,7 @@ self.cpu = cpu self.stats = stats self.options = options - if cpu.logger_cls is not None: - options.logger_noopt = cpu.logger_cls(cpu.ts) + options.logger_noopt = Logger(cpu.ts) RESULT = portal_graph.getreturnvar().concretetype self.result_type = history.getkind(RESULT) @@ -1057,8 +1057,7 @@ self.profiler.start() self.profiler.initialized = True self.globaldata.initialized = True - if self.options.logger_noopt is not None: - self.options.logger_noopt.create_log('.noopt') + self.options.logger_noopt.create_log('.noopt') def _setup_class_sizes(self): class_sizes = {} From arigo at codespeak.net Tue Sep 1 17:20:29 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 17:20:29 +0200 (CEST) Subject: [pypy-svn] r67407 - pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86 Message-ID: <20090901152029.9E37C16805C@codespeak.net> Author: arigo Date: Tue Sep 1 17:20:28 2009 New Revision: 67407 Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py Log: Fix a couple of rare crashes. Basically, don't use tell() on self.mc directly (as opposed to self.mc._mc.tell()) unless you are sure that you know what you are doing. Modified: pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/assembler.py Tue Sep 1 17:20:28 2009 @@ -206,7 +206,6 @@ def assemble_bootstrap_code(self, jumpaddr, arglocs, args, framesize): self.make_sure_mc_exists() addr = self.mc.tell() - #if self.gcrootmap: self.mc.PUSH(ebp) self.mc.MOV(ebp, esp) self.mc.PUSH(ebx) @@ -625,13 +624,15 @@ def genop_discard_jump(self, op, locs): targetmp = op.jump_target + # don't break the following code sequence! + mc = self.mc._mc if op.jump_target is not self.tree: - self.jumps_to_look_at.append((op, self.mc.tell())) - self.mc.JMP(rel32(targetmp._x86_compiled)) + self.jumps_to_look_at.append((op, mc.tell())) + mc.JMP(rel32(targetmp._x86_compiled)) if op.jump_target is not self.tree: # Reserve 6 bytes for a possible later patch by patch_jump(). # Put them after the JMP by default, as it's not doing anything. - self.mc.SUB(esp, imm32(0)) + mc.SUB(esp, imm32(0)) def genop_guard_guard_true(self, op, ign_1, addr, locs, ign_2): loc = locs[0] @@ -718,16 +719,17 @@ eax) if exc: self.generate_exception_handling(eax) - self.places_to_patch_framesize.append(self.mc.tell()) - self.mc.ADD(esp, imm32(0)) + # don't break the following code sequence! + mc = self.mc._mc + self.places_to_patch_framesize.append(mc.tell()) + mc.ADD(esp, imm32(0)) guard_index = self.cpu.make_guard_index(op) - self.mc.MOV(eax, imm(guard_index)) - #if self.gcrootmap: - self.mc.POP(edi) - self.mc.POP(esi) - self.mc.POP(ebx) - self.mc.POP(ebp) - self.mc.RET() + mc.MOV(eax, imm(guard_index)) + mc.POP(edi) + mc.POP(esi) + mc.POP(ebx) + mc.POP(ebp) + mc.RET() def generate_exception_handling(self, loc): self.mc.MOV(loc, heap(self._exception_addr)) From arigo at codespeak.net Tue Sep 1 17:59:44 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 17:59:44 +0200 (CEST) Subject: [pypy-svn] r67408 - in pypy/trunk/pypy: jit/backend jit/backend/cli jit/backend/llgraph jit/backend/llsupport jit/backend/llvm jit/backend/test jit/backend/x86 jit/metainterp rpython Message-ID: <20090901155944.9FC7816806F@codespeak.net> Author: arigo Date: Tue Sep 1 17:59:41 2009 New Revision: 67408 Added: pypy/trunk/pypy/jit/backend/cli/ - copied from r67407, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/cli/ pypy/trunk/pypy/jit/backend/llgraph/ - copied from r67407, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llgraph/ pypy/trunk/pypy/jit/backend/llsupport/ - copied from r67407, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llsupport/ pypy/trunk/pypy/jit/backend/llvm/ - copied from r67407, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/llvm/ pypy/trunk/pypy/jit/backend/logger.py - copied unchanged from r67407, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/logger.py pypy/trunk/pypy/jit/backend/model.py - copied unchanged from r67407, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/model.py pypy/trunk/pypy/jit/backend/test/ - copied from r67407, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/test/ pypy/trunk/pypy/jit/backend/x86/ - copied from r67407, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/backend/x86/ pypy/trunk/pypy/jit/metainterp/ - copied from r67407, pypy/branch/pyjitpl5-llmodel-merge/pypy/jit/metainterp/ pypy/trunk/pypy/rpython/ - copied from r67407, pypy/branch/pyjitpl5-llmodel-merge/pypy/rpython/ Log: Merge the pyjitpl5-llmodel branch. Summary: move out of the ll backend the details of descrs, of handling the GC, and the implementation of all the direct-running operations in do_xxx(). This is now in pypy.jit.backend.llsupport and the x86 backend only has to worry about generating assembler. From fijal at codespeak.net Tue Sep 1 18:12:44 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 18:12:44 +0200 (CEST) Subject: [pypy-svn] r67409 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090901161244.53A0F168052@codespeak.net> Author: fijal Date: Tue Sep 1 18:12:43 2009 New Revision: 67409 Modified: pypy/trunk/pypy/jit/backend/x86/runner.py Log: Remove dead code (two versions!) Modified: pypy/trunk/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/runner.py (original) +++ pypy/trunk/pypy/jit/backend/x86/runner.py Tue Sep 1 18:12:43 2009 @@ -88,12 +88,6 @@ def execute_operations(self, loop, verbose=False): assert isinstance(verbose, bool) func = self.get_bootstrap_code(loop) - # debug info - #if self.debug and not we_are_translated(): - # values_repr = ", ".join([str(values_as_int[i]) for i in - # range(len(valueboxes))]) - # llop.debug_print(lltype.Void, 'exec:', name, values_repr) - #self.assembler.logger.log_call(valueboxes) --- XXX guard_index = self.execute_call(loop, func, verbose) self._guard_index = guard_index # for tests op = self._guard_list[guard_index] From arigo at codespeak.net Tue Sep 1 18:19:13 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 18:19:13 +0200 (CEST) Subject: [pypy-svn] r67410 - pypy/branch/pyjitpl5-llmodel Message-ID: <20090901161913.3D62F168079@codespeak.net> Author: arigo Date: Tue Sep 1 18:19:12 2009 New Revision: 67410 Removed: pypy/branch/pyjitpl5-llmodel/ Log: Remove a branch. From arigo at codespeak.net Tue Sep 1 18:19:31 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Sep 2009 18:19:31 +0200 (CEST) Subject: [pypy-svn] r67411 - pypy/branch/pyjitpl5-llmodel-merge Message-ID: <20090901161931.99CEF168079@codespeak.net> Author: arigo Date: Tue Sep 1 18:19:31 2009 New Revision: 67411 Removed: pypy/branch/pyjitpl5-llmodel-merge/ Log: Remove the merging branch. From fijal at codespeak.net Tue Sep 1 18:36:43 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 18:36:43 +0200 (CEST) Subject: [pypy-svn] r67412 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090901163643.1F9DC1680B8@codespeak.net> Author: fijal Date: Tue Sep 1 18:36:42 2009 New Revision: 67412 Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py pypy/trunk/pypy/jit/metainterp/test/test_oparser.py Log: A test and support for embedding strings (lltype only since ootype has no tests) Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/oparser.py Tue Sep 1 18:36:42 2009 @@ -9,6 +9,7 @@ from pypy.jit.metainterp.typesystem import llhelper from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.ootypesystem import ootype +from pypy.rpython.annlowlevel import llstr _cache = {} _default_namespace = {'lltype': {}, 'ootype': {}} @@ -99,6 +100,11 @@ try: return ConstInt(int(arg)) except ValueError: + if arg.startswith('"') or arg.startswith("'"): + # XXX ootype + info = arg.strip("'\"") + return ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, + llstr(info))) if arg.startswith('ConstClass('): name = arg[len('ConstClass('):-1] if self.type_system == 'lltype': Modified: pypy/trunk/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_oparser.py Tue Sep 1 18:36:42 2009 @@ -140,3 +140,12 @@ loop = parse(x, jump_targets=[obj, 'self']) assert loop.operations[-1].jump_target is loop assert loop.operations[0].suboperations[0].jump_target is obj + +def test_debug_merge_point(): + x = ''' + [] + debug_merge_point("info") + debug_merge_point('info') + ''' + loop = parse(x) + assert loop.operations[0].args[0]._get_str() == 'info' From fijal at codespeak.net Tue Sep 1 19:11:03 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 19:11:03 +0200 (CEST) Subject: [pypy-svn] r67413 - pypy/trunk/pypy/jit/backend/x86/test Message-ID: <20090901171103.1C3741680AB@codespeak.net> Author: fijal Date: Tue Sep 1 19:11:02 2009 New Revision: 67413 Modified: pypy/trunk/pypy/jit/backend/x86/test/test_virtualizable.py Log: update skips Modified: pypy/trunk/pypy/jit/backend/x86/test/test_virtualizable.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_virtualizable.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_virtualizable.py Tue Sep 1 19:11:02 2009 @@ -4,11 +4,5 @@ from pypy.jit.backend.x86.test.test_basic import Jit386Mixin class TestVirtualizable(Jit386Mixin, ImplicitVirtualizableTests): - def test_pass_always_virtual_to_bridge(self): - py.test.skip("Not implemented nonsense in patch_jump") - - def test_virtual_obj_on_always_virtual(self): - py.test.skip("Widening to trash error") - - def test_virtual_obj_on_always_virtual_more_bridges(self): - py.test.skip("Widening to trash error") + def test_blackhole_should_not_reenter(self): + py.test.skip("Assertion error & llinterp mess") From fijal at codespeak.net Tue Sep 1 19:29:19 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 19:29:19 +0200 (CEST) Subject: [pypy-svn] r67414 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090901172919.914AE168078@codespeak.net> Author: fijal Date: Tue Sep 1 19:29:16 2009 New Revision: 67414 Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py pypy/trunk/pypy/jit/metainterp/test/test_oparser.py Log: Ignore descrs that are printed by x86 backend Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/oparser.py Tue Sep 1 19:29:16 2009 @@ -150,7 +150,10 @@ descr = None poss_descr = allargs[-1].strip() if poss_descr.startswith('descr='): - descr = self.consts[poss_descr[len('descr='):]] + if poss_descr.startswith('descr=<'): + descr = None + else: + descr = self.consts[poss_descr[len('descr='):]] allargs = allargs[:-1] for arg in allargs: arg = arg.strip() Modified: pypy/trunk/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_oparser.py Tue Sep 1 19:29:16 2009 @@ -149,3 +149,12 @@ ''' loop = parse(x) assert loop.operations[0].args[0]._get_str() == 'info' + assert loop.operations[1].args[0]._get_str() == 'info' + +def test_descr_with_obj_print(): + x = ''' + [p0] + setfield_gc(p0, 1, descr=) + ''' + loop = parse(x) + # assert did not explode From fijal at codespeak.net Tue Sep 1 19:41:20 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 19:41:20 +0200 (CEST) Subject: [pypy-svn] r67415 - in pypy/trunk/pypy/jit: backend backend/cli backend/test backend/x86 metainterp Message-ID: <20090901174120.726F91683B8@codespeak.net> Author: fijal Date: Tue Sep 1 19:41:20 2009 New Revision: 67415 Added: pypy/trunk/pypy/jit/backend/loopviewer.py (contents, props changed) pypy/trunk/pypy/jit/backend/test/test_logger.py (contents, props changed) Modified: pypy/trunk/pypy/jit/backend/cli/method.py pypy/trunk/pypy/jit/backend/logger.py pypy/trunk/pypy/jit/backend/x86/assembler.py pypy/trunk/pypy/jit/metainterp/optimize.py Log: Change logger to use oparser storage type. Additionally add a viewer for that and make everyone adapt. Modified: pypy/trunk/pypy/jit/backend/cli/method.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/method.py (original) +++ pypy/trunk/pypy/jit/backend/cli/method.py Tue Sep 1 19:41:20 2009 @@ -152,7 +152,7 @@ # ---- cpu.logger.create_log() - cpu.logger.eventually_log_loop(loop) + cpu.logger.log_loop(loop) # ---- self.box2type = {} if self.nocast: Modified: pypy/trunk/pypy/jit/backend/logger.py ============================================================================== --- pypy/trunk/pypy/jit/backend/logger.py (original) +++ pypy/trunk/pypy/jit/backend/logger.py Tue Sep 1 19:41:20 2009 @@ -3,31 +3,30 @@ from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.history import Const, ConstInt, Box, \ BoxInt, ConstAddr +from pypy.rlib.streamio import open_file_as_stream class Logger(object): def __init__(self, ts): - self._log_fd = -1 + self.log_stream = None self.ts = ts def create_log(self, extension='.ops'): - if self._log_fd != -1: - return self._log_fd + if self.log_stream is not None: + return self.log_stream s = os.environ.get('PYPYJITLOG') if not s: - return -1 + return None s += extension try: - flags = os.O_WRONLY|os.O_CREAT|os.O_TRUNC - self._log_fd = os.open(s, flags, 0666) + self.log_stream = open_file_as_stream(s, 'w') except OSError: os.write(2, "could not create log file\n") - return -1 - return self._log_fd + return None + return self.log_stream - def eventually_log_loop(self, loop): - self.eventually_log_operations(loop.inputargs, loop.operations, None, - compute_unique_id(loop)) + def log_loop(self, loop): + self.log_operations(loop.inputargs, loop.operations, {}) def repr_of_descr(self, descr): return descr.repr_of_descr() @@ -39,83 +38,41 @@ mv = len(memo) memo[arg] = mv if isinstance(arg, ConstInt): - return "ci(%d,%d)" % (mv, arg.value) + return str(arg.value) elif isinstance(arg, BoxInt): - return "bi(%d,%d)" % (mv, arg.value) + return 'i' + str(mv) elif isinstance(arg, self.ts.ConstRef): - return "cr(%d,%d)" % (mv, arg.get_()) + return 'ConstPtr(ptr' + str(mv) + ')' elif isinstance(arg, self.ts.BoxRef): - return "br(%d,%d)" % (mv, arg.get_()) + return 'p' + str(mv) elif isinstance(arg, self.ts.ConstAddr): - return "ca(%d,%d)" % (mv, arg.get_()) + return 'ConstClass(cls' + str(mv) + ')' else: - #raise NotImplementedError - return "?%r" % (arg,) + raise NotImplementedError - def eventually_log_operations(self, inputargs, operations, memo=None, - myid=0, indent=0): - if self._log_fd == -1: + def log_operations(self, inputargs, operations, memo, indent=0): + if self.log_stream is None: return pre = " " * indent - if memo is None: - memo = {} - if inputargs is None: - os.write(self._log_fd, pre + "BEGIN(%s)\n" % myid) - else: - args = ",".join([self.repr_of_arg(memo, arg) for arg in inputargs]) - os.write(self._log_fd, pre + "LOOP %s\n" % args) + if inputargs is not None: + args = ", ".join([self.repr_of_arg(memo, arg) for arg in inputargs]) + self.log_stream.write(pre + '[' + args + ']\n') for i in range(len(operations)): op = operations[i] if op.opnum == rop.DEBUG_MERGE_POINT: loc = op.args[0]._get_str() - os.write(self._log_fd, pre + "#%s\n" % (loc,)) + self.log_stream.write(pre + "debug_merge_point('%s')\n" % (loc,)) continue - args = ",".join([self.repr_of_arg(memo, arg) for arg in op.args]) - if op.descr is not None: - descr = self.repr_of_descr(op.descr) - os.write(self._log_fd, pre + "%d:%s %s[%s]\n" % - (i, op.getopname(), args, descr)) - else: - os.write(self._log_fd, pre + "%d:%s %s\n" % - (i, op.getopname(), args)) + args = ", ".join([self.repr_of_arg(memo, arg) for arg in op.args]) if op.result is not None: - os.write(self._log_fd, pre + " => %s\n" % - self.repr_of_arg(memo, op.result)) + res = self.repr_of_arg(memo, op.result) + " = " + else: + res = "" + if op.descr is not None: + args += ', descr=' + self.repr_of_descr(op.descr) + self.log_stream.write(pre + res + op.getopname() + + '(' + args + ')\n') if op.is_guard(): - self.eventually_log_operations(None, op.suboperations, memo, - indent=indent+2) -# if operations[-1].opnum == rop.JUMP: -# if operations[-1].jump_target is not None: - -# else: -# # XXX hack for the annotator -# jump_target = 13 -# os.write(self._log_fd, pre + 'JUMPTO:%s\n' % jump_target) - if inputargs is None: - os.write(self._log_fd, pre + "END\n") - else: - os.write(self._log_fd, pre + "LOOP END\n") - - def log_failure_recovery(self, gf, guard_index): - if self._log_fd == -1: - return - return # XXX - os.write(self._log_fd, 'xxxxxxxxxx\n') - memo = {} - reprs = [] - for j in range(len(gf.guard_op.liveboxes)): - valuebox = gf.cpu.getvaluebox(gf.frame, gf.guard_op, j) - reprs.append(self.repr_of_arg(memo, valuebox)) - jmp = gf.guard_op._jmp_from - os.write(self._log_fd, "%d %d %s\n" % (guard_index, jmp, - ",".join(reprs))) - os.write(self._log_fd, 'xxxxxxxxxx\n') - - def log_call(self, valueboxes): - if self._log_fd == -1: - return - return # XXX - memo = {} - args_s = ','.join([self.repr_of_arg(memo, box) for box in valueboxes]) - os.write(self._log_fd, "CALL\n") - os.write(self._log_fd, "%s %s\n" % (name, args_s)) + self.log_operations(None, op.suboperations, memo, + indent=indent+2) + self.log_stream.flush() Added: pypy/trunk/pypy/jit/backend/loopviewer.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/jit/backend/loopviewer.py Tue Sep 1 19:41:20 2009 @@ -0,0 +1,26 @@ +#!/usr/bin/env python +""" Usage: loopviewer.py [loopnum] loopfile +""" + +import py +import sys +from pypy.jit.metainterp.test.oparser import parse + +def main(loopnum, loopfile): + data = py.path.local(loopfile).read() + loops = [i for i in data.split("[") if i] + inp = "[" + loops[loopnum] + loop = parse(inp) + loop.show() + +if __name__ == '__main__': + if len(sys.argv) == 2: + loopnum = -1 + loopfile = sys.argv[1] + elif len(sys.argv) == 3: + loopnum = int(sys.argv[1]) + loopfile = sys.argv[2] + else: + print __doc__ + sys.exit(1) + main(loopnum, loopfile) Added: pypy/trunk/pypy/jit/backend/test/test_logger.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/jit/backend/test/test_logger.py Tue Sep 1 19:41:20 2009 @@ -0,0 +1,78 @@ + +from pypy.jit.metainterp.test.oparser import parse +from pypy.jit.backend import logger +from pypy.jit.metainterp.typesystem import llhelper +from StringIO import StringIO +from pypy.jit.metainterp.test.test_optimizeopt import equaloplists +from pypy.jit.metainterp.history import AbstractDescr + +class Descr(AbstractDescr): + pass + +class Logger(logger.Logger): + def log_loop(self, loop, namespace={}): + self.log_stream = StringIO() + self.namespace = namespace + logger.Logger.log_loop(self, loop) + return self.log_stream.getvalue() + + def repr_of_descr(self, descr): + for k, v in self.namespace.items(): + if v == descr: + return k + return "???" + +class TestLogger(object): + ts = llhelper + + def reparse(self, inp, namespace=None): + """ parse loop once, then log it and parse again, + return both + """ + loop = parse(inp, namespace=namespace) + logger = Logger(self.ts) + output = logger.log_loop(loop, namespace) + oloop = parse(output, namespace=namespace) + return loop, oloop + + def test_simple(self): + inp = ''' + [i0, i1, i2, p3, p4, p5] + i6 = int_add(i1, i2) + i8 = int_add(i6, 3) + jump(i0, i8, i6, p3, p4, p5) + ''' + loop, oloop = self.reparse(inp) + equaloplists(oloop.operations, loop.operations) + assert oloop.inputargs == loop.inputargs + + def test_descr(self): + inp = ''' + [p0] + setfield_gc(p0, 3, descr=somedescr) + ''' + somedescr = Descr() + loop, oloop = self.reparse(inp, namespace=locals()) + equaloplists(loop.operations, oloop.operations) + + def test_guard(self): + inp = ''' + [i0] + guard_true(i0) + i1 = int_add(i0, 1) + guard_true(i1) + fail(i1) + fail(i1) + fail(i0) + ''' + loop, oloop = self.reparse(inp) + equaloplists(loop.operations, oloop.operations) + + def test_debug_merge_point(self): + inp = ''' + [] + debug_merge_point("info") + ''' + loop, oloop = self.reparse(inp) + assert oloop.operations[0].args[0]._get_str() == 'info' + Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py Tue Sep 1 19:41:20 2009 @@ -170,7 +170,7 @@ self.tree = tree self.make_sure_mc_exists() inputargs = tree.inputargs - self.logger.eventually_log_loop(tree) + self.logger.log_loop(tree) regalloc = RegAlloc(self, tree, self.cpu.translate_support_code) self._regalloc = regalloc regalloc.walk_operations(tree) Modified: pypy/trunk/pypy/jit/metainterp/optimize.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimize.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimize.py Tue Sep 1 19:41:20 2009 @@ -11,7 +11,7 @@ else: return None if options.logger_noopt is not None: - options.logger_noopt.eventually_log_loop(loop) + options.logger_noopt.log_loop(loop) finder = PerfectSpecializationFinder() finder.find_nodes_loop(loop) for old_loop in old_loops: @@ -29,7 +29,7 @@ if not options.specialize: # for tests only return old_loops[0] if options.logger_noopt is not None: - options.logger_noopt.eventually_log_loop(bridge) + options.logger_noopt.log_loop(bridge) finder = BridgeSpecializationFinder() finder.find_nodes_bridge(bridge) for old_loop in old_loops: From fijal at codespeak.net Tue Sep 1 19:44:44 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 19:44:44 +0200 (CEST) Subject: [pypy-svn] r67416 - in pypy/trunk/pypy/jit/backend: . test test/loopdata Message-ID: <20090901174444.9769C1683BE@codespeak.net> Author: fijal Date: Tue Sep 1 19:44:44 2009 New Revision: 67416 Removed: pypy/trunk/pypy/jit/backend/loopparser.py pypy/trunk/pypy/jit/backend/test/loopdata/ pypy/trunk/pypy/jit/backend/test/test_loopparser.py Log: remove loopparser as it's no longer necessary From fijal at codespeak.net Tue Sep 1 19:49:14 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 19:49:14 +0200 (CEST) Subject: [pypy-svn] r67417 - pypy/branch/no-recompilation Message-ID: <20090901174914.EFB0D1683BB@codespeak.net> Author: fijal Date: Tue Sep 1 19:49:14 2009 New Revision: 67417 Added: pypy/branch/no-recompilation/ - copied from r67416, pypy/trunk/ Log: A branch to get away from constant recompilation of code From fijal at codespeak.net Tue Sep 1 20:08:27 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 20:08:27 +0200 (CEST) Subject: [pypy-svn] r67418 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090901180827.D53631683CE@codespeak.net> Author: fijal Date: Tue Sep 1 20:08:26 2009 New Revision: 67418 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py Log: typo Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py Tue Sep 1 20:08:26 2009 @@ -58,7 +58,7 @@ self.assembler._exception_bck[0] = 0 self.assembler._exception_bck[1] = 0 - def compile_operations(self, tree, bridge=None): + def compile_operations(self, tree, guard_op=None): old_loop = tree._x86_compiled if old_loop: olddepth = tree._x86_stack_depth From fijal at codespeak.net Tue Sep 1 20:15:49 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 20:15:49 +0200 (CEST) Subject: [pypy-svn] r67419 - pypy/branch/no-recompilation/pypy/jit/backend/x86/test Message-ID: <20090901181549.324FB1683C6@codespeak.net> Author: fijal Date: Tue Sep 1 20:15:48 2009 New Revision: 67419 Added: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py (contents, props changed) Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Log: Start a new test file for recompilation tests. Since those should work whether we do recompilation or no, they're just passing. More to come. Added: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py ============================================================================== --- (empty file) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py Tue Sep 1 20:15:48 2009 @@ -0,0 +1,57 @@ + +from pypy.jit.backend.x86.runner import CPU +from pypy.jit.backend.x86.test.test_regalloc import BaseTestRegalloc + +class TestRecompilation(BaseTestRegalloc): + def test_compile_bridge_not_deeper(self): + ops = ''' + [i0] + i1 = int_add(i0, 1) + i2 = int_lt(i1, 20) + guard_true(i2) + fail(i1) + jump(i1) + ''' + loop = self.interpret(ops, [0]) + assert self.getint(0) == 20 + ops = ''' + [i1] + i3 = int_add(i1, 1) + fail(i3) + ''' + bridge = self.attach_bridge(ops, loop, loop.operations[-2]) + self.cpu.set_future_value_int(0, 0) + op = self.cpu.execute_operations(loop) + assert op is bridge.operations[-1] + assert self.getint(0) == 21 + + def test_compile_bridge_deeper(self): + ops = ''' + [i0] + i1 = int_add(i0, 1) + i2 = int_lt(i1, 20) + guard_true(i2) + fail(i1) + jump(i1) + ''' + loop = self.interpret(ops, [0]) + assert self.getint(0) == 20 + ops = ''' + [i1] + i3 = int_add(i1, 1) + i4 = int_add(i3, 1) + i5 = int_add(i4, 1) + i6 = int_add(i5, 1) + fail(i3, i4, i5, i6) + ''' + bridge = self.attach_bridge(ops, loop, loop.operations[-2]) + self.cpu.set_future_value_int(0, 0) + op = self.cpu.execute_operations(loop) + assert op is bridge.operations[-1] + assert self.getint(0) == 21 + assert self.getint(1) == 22 + assert self.getint(2) == 23 + assert self.getint(3) == 24 + +# def test_bridge_jump_to_other_loop(self): +# xxx Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Tue Sep 1 20:15:48 2009 @@ -268,34 +268,6 @@ self.interpret(ops, [0]) assert self.getint(0) == 20 - def test_compile_and_recompile(self): - ops = ''' - [i0] - i1 = int_add(i0, 1) - i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) - jump(i1) - ''' - loop = self.interpret(ops, [0]) - assert self.getint(0) == 20 - ops = ''' - [i1] - i3 = int_add(i1, 1) - i4 = int_add(i3, 1) - i5 = int_add(i4, 1) - i6 = int_add(i5, 1) - fail(i3, i4, i5, i6) - ''' - bridge = self.attach_bridge(ops, loop, loop.operations[-2]) - self.cpu.set_future_value_int(0, 0) - op = self.cpu.execute_operations(loop) - assert op is bridge.operations[-1] - assert self.getint(0) == 21 - assert self.getint(1) == 22 - assert self.getint(2) == 23 - assert self.getint(3) == 24 - def test_two_loops_and_a_bridge(self): ops = ''' [i0, i1, i2, i3] @@ -615,7 +587,7 @@ self.interpret(ops, []) assert not self.getptr(0, lltype.Ptr(self.S)) - def test_rewrite_constptr_in_brdige(self): + def test_rewrite_constptr_in_bridge(self): ops = ''' [i0] guard_true(i0) From fijal at codespeak.net Tue Sep 1 21:06:37 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 21:06:37 +0200 (CEST) Subject: [pypy-svn] r67420 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090901190637.3A4211680AB@codespeak.net> Author: fijal Date: Tue Sep 1 21:06:34 2009 New Revision: 67420 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py Log: kill this debug print Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py Tue Sep 1 21:06:34 2009 @@ -171,7 +171,7 @@ return False if (self.longevity[op.result][1] > i + 1 or op.result in operations[i + 1].inputargs): - print "!!!! boolean flag not optimized away !!!!" + #print "!!!! boolean flag not optimized away !!!!" return False return True From fijal at codespeak.net Tue Sep 1 21:15:08 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 1 Sep 2009 21:15:08 +0200 (CEST) Subject: [pypy-svn] r67421 - pypy/branch/no-recompilation/pypy/jit/backend/x86/test Message-ID: <20090901191508.5CA4D1683D3@codespeak.net> Author: fijal Date: Tue Sep 1 21:15:05 2009 New Revision: 67421 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Log: Add more tests Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py Tue Sep 1 21:15:05 2009 @@ -53,5 +53,86 @@ assert self.getint(2) == 23 assert self.getint(3) == 24 -# def test_bridge_jump_to_other_loop(self): -# xxx + def test_bridge_jump_to_other_loop(self): + loop = self.interpret(''' + [i0, i10, i11, i12, i13, i14, i15, i16] + i1 = int_add(i0, 1) + i2 = int_lt(i1, 20) + guard_true(i2) + fail(i1) + jump(i1, i10, i11, i12, i13, i14, i15, i16) + ''', [0]) + other_loop = self.interpret(''' + [i3] + guard_false(i3) + fail(i3) + jump(i3) + ''', [1]) + ops = ''' + [i3] + jump(i3, 1, 2, 3, 4, 5, 6, 7) + ''' + bridge = self.attach_bridge(ops, other_loop, other_loop.operations[0], + jump_targets=[loop]) + self.cpu.set_future_value_int(0, 1) + op = self.cpu.execute_operations(other_loop) + assert op is loop.operations[2].suboperations[0] + + def test_bridge_jumps_to_self_deeper(self): + loop = self.interpret(''' + [i0, i1, i2] + i3 = int_add(i0, 1) + i4 = int_and(i3, 1) + guard_false(i4) + fail(0, i3) + i5 = int_lt(i3, 20) + guard_true(i5) + fail(1, i3) + jump(i3, i1, i2) + ''', [0]) + assert self.getint(0) == 0 + assert self.getint(1) == 1 + ops = ''' + [i3] + i10 = int_mul(i3, 2) + i8 = int_add(i3, 1) + i6 = int_add(i8, i10) + i7 = int_add(i3, i6) + jump(i3, i6, i7) + ''' + bridge = self.attach_bridge(ops, loop, loop.operations[2], + jump_targets=[loop]) + self.cpu.set_future_value_int(0, 0) + self.cpu.set_future_value_int(1, 0) + self.cpu.set_future_value_int(2, 0) + self.cpu.execute_operations(loop) + assert self.getint(0) == 1 + assert self.getint(1) == 20 + + def test_bridge_jumps_to_self_shallower(self): + loop = self.interpret(''' + [i0, i1, i2] + i3 = int_add(i0, 1) + i4 = int_and(i3, 1) + guard_false(i4) + fail(0, i3) + i5 = int_lt(i3, 20) + guard_true(i5) + fail(1, i3) + jump(i3, i1, i2) + ''', [0]) + assert self.getint(0) == 0 + assert self.getint(1) == 1 + ops = ''' + [i3] + jump(i3, 0, 1) + ''' + bridge = self.attach_bridge(ops, loop, loop.operations[2], + jump_targets=[loop]) + self.cpu.set_future_value_int(0, 0) + self.cpu.set_future_value_int(1, 0) + self.cpu.set_future_value_int(2, 0) + self.cpu.execute_operations(loop) + assert self.getint(0) == 1 + assert self.getint(1) == 20 + Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Tue Sep 1 21:15:05 2009 @@ -247,9 +247,9 @@ gcref = self.cpu.get_latest_value_ref(index) return lltype.cast_opaque_ptr(T, gcref) - def attach_bridge(self, ops, loop, guard_op): + def attach_bridge(self, ops, loop, guard_op, **kwds): assert guard_op.is_guard() - bridge = self.parse(ops) + bridge = self.parse(ops, **kwds) guard_op.suboperations = bridge.operations self.cpu.compile_operations(loop, guard_op) return bridge From antocuni at codespeak.net Wed Sep 2 11:00:18 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 2 Sep 2009 11:00:18 +0200 (CEST) Subject: [pypy-svn] r67422 - in pypy/trunk/pypy/jit/backend/cli: . test Message-ID: <20090902090018.E517D1680C1@codespeak.net> Author: antocuni Date: Wed Sep 2 11:00:17 2009 New Revision: 67422 Modified: pypy/trunk/pypy/jit/backend/cli/method.py pypy/trunk/pypy/jit/backend/cli/test/test_loop.py pypy/trunk/pypy/jit/backend/cli/test/test_runner.py Log: - ignore some lltype-specific operations - skip a failing test (will fix it later) - skip a direct test that can run only after translation Modified: pypy/trunk/pypy/jit/backend/cli/method.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/method.py (original) +++ pypy/trunk/pypy/jit/backend/cli/method.py Wed Sep 2 11:00:17 2009 @@ -685,6 +685,9 @@ emit_op_newunicode = lltype_only emit_op_unicodelen = lltype_only emit_op_unicodegetitem = lltype_only + emit_op_cond_call_gc_wb = lltype_only + emit_op_cond_call_gc_malloc = lltype_only + emit_op_setarrayitem_raw = lltype_only # -------------------------------------------------------------------- Modified: pypy/trunk/pypy/jit/backend/cli/test/test_loop.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/test/test_loop.py (original) +++ pypy/trunk/pypy/jit/backend/cli/test/test_loop.py Wed Sep 2 11:00:17 2009 @@ -18,4 +18,5 @@ test_path_with_operations_not_from_start_2 = skip test_loop_unicode = skip test_loop_string = skip - + test_loop_with_delayed_setfield = skip + Modified: pypy/trunk/pypy/jit/backend/cli/test/test_runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/test/test_runner.py (original) +++ pypy/trunk/pypy/jit/backend/cli/test/test_runner.py Wed Sep 2 11:00:17 2009 @@ -33,6 +33,9 @@ def test_ovf_operations(self, reversed=False): self.skip() + def test_unicode_basic(self): + py.test.skip('fixme!') + def test_pypycliopt(): import os from pypy.jit.backend.cli.method import Method From pedronis at codespeak.net Wed Sep 2 11:13:05 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 2 Sep 2009 11:13:05 +0200 (CEST) Subject: [pypy-svn] r67423 - pypy/trunk/pypy/module/pypyjit/test Message-ID: <20090902091305.0BC8C1680AB@codespeak.net> Author: pedronis Date: Wed Sep 2 11:13:04 2009 New Revision: 67423 Modified: pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py Log: let's throw away recent new code because we like perturbation Modified: pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py ============================================================================== --- pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py (original) +++ pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py Wed Sep 2 11:13:04 2009 @@ -1,20 +1,8 @@ from pypy.conftest import gettestobjspace, option from pypy.tool.udir import udir -from pypy.jit.backend import loopparser import py import sys, os -def run_source(sourcefile, pypy_executable, tmpdir): - logfilepath = tmpdir.join(sourcefile.basename[:-3] + '.log') - if sys.platform.startswith('win'): - py.test.skip("XXX this is not Windows-friendly") - - result = py.process.cmdexec('PYPYJITLOG="%s" "%s" "%s"' % ( - logfilepath, pypy_executable, sourcefile)) - assert result - assert logfilepath.check() - return result, logfilepath + '.ops' - class PyPyCJITTests(object): def run_source(self, source, testcases): source = py.code.Source(source) @@ -144,35 +132,3 @@ cls.tmpdir.ensure(dir=1) cls.counter = 0 cls.pypy_c = option.pypy_c - - def run_and_compare(self, sourcefile): - fname = py.magic.autopath().dirpath().join('loops', sourcefile) - pypy_out, log = run_source(fname, self.pypy_c, self.tmpdir) - cpy_out = py.process.cmdexec('"%s" "%s"' % ( - sys.executable, fname)) - assert pypy_out == cpy_out - parser = loopparser.Parser() - loops = parser.parse(log) - if option.view: - from pypy.jit.metainterp.graphpage import display_loops - display_loops(loops) - return loops - - def assert_no_op(self, loop, opname): - for operation in loop.iter_operations(): - assert operation.opname != opname - - def test_trivial_add(self): - loops = self.run_and_compare('simple_add.py') - for loop in loops: - # naive way if finding the relevant loop to inspect - if isinstance(loop.operations[0], loopparser.ByteCodeRef): - self.assert_no_op(loop, 'call') - break - else: - assert False - - def test_dict_lookup(self): - py.test.skip('should remove dict lookups') - loops = self.run_and_compare('dict_lookup.py') - self.assert_no_op(loops[1], 'getfield_gc') From fijal at codespeak.net Wed Sep 2 11:43:57 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 2 Sep 2009 11:43:57 +0200 (CEST) Subject: [pypy-svn] r67424 - in pypy/branch/no-recompilation/pypy/module: _ast _ast/test parser parser/test pypyjit/test/loops token token/test Message-ID: <20090902094357.B3D6E1683BA@codespeak.net> Author: fijal Date: Wed Sep 2 11:43:54 2009 New Revision: 67424 Modified: pypy/branch/no-recompilation/pypy/module/_ast/ (props changed) pypy/branch/no-recompilation/pypy/module/_ast/__init__.py (props changed) pypy/branch/no-recompilation/pypy/module/_ast/test/ (props changed) pypy/branch/no-recompilation/pypy/module/_ast/test/__init__.py (props changed) pypy/branch/no-recompilation/pypy/module/_ast/test/test_ast.py (props changed) pypy/branch/no-recompilation/pypy/module/parser/ (props changed) pypy/branch/no-recompilation/pypy/module/parser/test/ (props changed) pypy/branch/no-recompilation/pypy/module/pypyjit/test/loops/ (props changed) pypy/branch/no-recompilation/pypy/module/pypyjit/test/loops/dict_lookup.py (props changed) pypy/branch/no-recompilation/pypy/module/pypyjit/test/loops/simple_add.py (props changed) pypy/branch/no-recompilation/pypy/module/token/ (props changed) pypy/branch/no-recompilation/pypy/module/token/test/ (props changed) Log: fixeol From antocuni at codespeak.net Wed Sep 2 12:27:13 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 2 Sep 2009 12:27:13 +0200 (CEST) Subject: [pypy-svn] r67425 - pypy/trunk/pypy/module/posix Message-ID: <20090902102713.47B6B1683D2@codespeak.net> Author: antocuni Date: Wed Sep 2 12:27:10 2009 New Revision: 67425 Modified: pypy/trunk/pypy/module/posix/__init__.py Log: oups, cli and jvm translations on linux have been broken since r66115 :-/. Fix it Modified: pypy/trunk/pypy/module/posix/__init__.py ============================================================================== --- pypy/trunk/pypy/module/posix/__init__.py (original) +++ pypy/trunk/pypy/module/posix/__init__.py Wed Sep 2 12:27:10 2009 @@ -124,7 +124,7 @@ backend = space.config.translation.backend # the Win32 urandom implementation isn't going to translate on JVM or CLI # so we have to remove it - if backend == 'cli' or backend == 'jvm': + if 'urandom' in self.interpleveldefs and (backend == 'cli' or backend == 'jvm'): del self.interpleveldefs['urandom'] MixedModule.__init__(self, space, w_name) From fijal at codespeak.net Wed Sep 2 12:59:03 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 2 Sep 2009 12:59:03 +0200 (CEST) Subject: [pypy-svn] r67426 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090902105903.CC0E61683CF@codespeak.net> Author: fijal Date: Wed Sep 2 12:59:03 2009 New Revision: 67426 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py Log: Remove support for bridges. test_runner passes Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Wed Sep 2 12:59:03 2009 @@ -15,7 +15,7 @@ from pypy.jit.backend.x86.ri386 import * from pypy.jit.metainterp.resoperation import rop -# our calling convention - we pass three first args as edx, ecx and eax +# our calling convention - we pass first 6 args in registers # and the rest stays on the stack MAX_FAIL_BOXES = 1000 @@ -60,25 +60,6 @@ if name.upper() == name: setattr(MachineCodeBlockWrapper, name, _new_method(name)) -class MachineCodeStack(object): - def __init__(self): - self.mcstack = [] - self.counter = 0 - - def next_mc(self): - if len(self.mcstack) == self.counter: - mc = MachineCodeBlockWrapper() - self.mcstack.append(mc) - else: - mc = self.mcstack[self.counter] - self.counter += 1 - return mc - - def give_mc_back(self, mc): - mc.done() - assert self.mcstack[self.counter - 1] is mc - self.counter -= 1 - class Assembler386(object): mc = None mc2 = None @@ -94,7 +75,6 @@ self.malloc_unicode_func_addr = 0 self._exception_data = lltype.nullptr(rffi.CArray(lltype.Signed)) self._exception_addr = 0 - self.mcstack = MachineCodeStack() self.logger = Logger(cpu.ts) self.fail_boxes_int = lltype.malloc(lltype.GcArray(lltype.Signed), MAX_FAIL_BOXES, zero=True) @@ -145,9 +125,8 @@ self.malloc_unicode_func_addr = rffi.cast(lltype.Signed, ll_new_unicode) # done - self.mc2 = self.mcstack.next_mc() - self.mc = self.mcstack.next_mc() - + self.mc = MachineCodeBlockWrapper() + self.mc2 = MachineCodeBlockWrapper() def _compute_longest_fail_op(self, ops): max_so_far = 0 @@ -160,6 +139,9 @@ assert max_so_far < MAX_FAIL_BOXES return max_so_far + def assemble_loop(self, loop): + self.assemble(loop) + def assemble(self, tree): self.places_to_patch_framesize = [] self.jumps_to_look_at = [] @@ -180,8 +162,8 @@ stack_words = regalloc.max_stack_depth # possibly align, e.g. for Mac OS X RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words - stack_words = align_stack_words(stack_words+RET_BP) - tree._x86_stack_depth = stack_words-RET_BP + stack_words = align_stack_words(stack_words + RET_BP) + tree._x86_stack_depth = stack_words - RET_BP for place in self.places_to_patch_framesize: mc = codebuf.InMemoryCodeBuilder(place, place + 128) mc.ADD(esp, imm32(tree._x86_stack_depth * WORD)) @@ -272,14 +254,14 @@ def regalloc_perform_discard(self, op, arglocs): genop_discard_list[op.opnum](self, op, arglocs) - def regalloc_perform_with_guard(self, op, guard_op, regalloc, + def regalloc_perform_with_guard(self, op, guard_op, faillocs, arglocs, resloc): - addr = self.implement_guard_recovery(guard_op, regalloc) + addr = self.implement_guard_recovery(guard_op, faillocs) genop_guard_list[op.opnum](self, op, guard_op, addr, arglocs, resloc) - def regalloc_perform_guard(self, op, regalloc, arglocs, resloc): - addr = self.implement_guard_recovery(op, regalloc) + def regalloc_perform_guard(self, op, faillocs, arglocs, resloc): + addr = self.implement_guard_recovery(op, faillocs) genop_guard_list[op.opnum](self, op, None, addr, arglocs, resloc) @@ -674,27 +656,17 @@ self.mc.CMP(mem(locs[0], offset), locs[1]) self.implement_guard(addr, op, self.mc.JNE) - def implement_guard_recovery(self, guard_op, regalloc): - oldmc = self.mc - self.mc = self.mc2 - self.mc2 = self.mcstack.next_mc() - addr = self.mc.tell() + def implement_guard_recovery(self, guard_op, fail_locs): + addr = self.mc2.tell() exc = (guard_op.opnum == rop.GUARD_EXCEPTION or guard_op.opnum == rop.GUARD_NO_EXCEPTION) - # XXX this is a heuristics to detect whether we're handling this - # exception or not. We should have a bit better interface to deal - # with that I fear - if (exc and (guard_op.suboperations[0].opnum == rop.GUARD_EXCEPTION or - guard_op.suboperations[0].opnum == rop.GUARD_NO_EXCEPTION)): - exc = False - regalloc.walk_guard_ops(guard_op.inputargs, guard_op.suboperations, exc) - self.mcstack.give_mc_back(self.mc2) - self.mc2 = self.mc - self.mc = oldmc + guard_op._x86_faillocs = fail_locs + self.generate_failure(self.mc2, guard_op.suboperations[0], fail_locs, + exc) return addr - def generate_failure(self, op, locs, exc): - pos = self.mc.tell() + def generate_failure(self, mc, op, locs, exc): + pos = mc.tell() for i in range(len(locs)): loc = locs[i] if isinstance(loc, REG): @@ -702,7 +674,7 @@ base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr - self.mc.MOV(addr_add(imm(base), imm(i*WORD)), loc) + mc.MOV(addr_add(imm(base), imm(i*WORD)), loc) for i in range(len(locs)): loc = locs[i] if not isinstance(loc, REG): @@ -710,17 +682,17 @@ base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr - self.mc.MOV(eax, loc) - self.mc.MOV(addr_add(imm(base), imm(i*WORD)), eax) + mc.MOV(eax, loc) + mc.MOV(addr_add(imm(base), imm(i*WORD)), eax) if self.debug_markers: - self.mc.MOV(eax, imm(pos)) - self.mc.MOV(addr_add(imm(self.fail_box_int_addr), + mc.MOV(eax, imm(pos)) + mc.MOV(addr_add(imm(self.fail_box_int_addr), imm(len(locs) * WORD)), eax) if exc: - self.generate_exception_handling(eax) + self.generate_exception_handling(mc, eax) # don't break the following code sequence! - mc = self.mc._mc + mc = mc._mc self.places_to_patch_framesize.append(mc.tell()) mc.ADD(esp, imm32(0)) guard_index = self.cpu.make_guard_index(op) @@ -731,15 +703,15 @@ mc.POP(ebp) mc.RET() - def generate_exception_handling(self, loc): - self.mc.MOV(loc, heap(self._exception_addr)) - self.mc.MOV(heap(self._exception_bck_addr), loc) - self.mc.MOV(loc, addr_add(imm(self._exception_addr), imm(WORD))) - self.mc.MOV(addr_add(imm(self._exception_bck_addr), imm(WORD)), loc) + def generate_exception_handling(self, mc, loc): + mc.MOV(loc, heap(self._exception_addr)) + mc.MOV(heap(self._exception_bck_addr), loc) + mc.MOV(loc, addr_add(imm(self._exception_addr), imm(WORD))) + mc.MOV(addr_add(imm(self._exception_bck_addr), imm(WORD)), loc) # clean up the original exception, we don't want # to enter more rpython code with exc set - self.mc.MOV(heap(self._exception_addr), imm(0)) - self.mc.MOV(addr_add(imm(self._exception_addr), imm(WORD)), imm(0)) + mc.MOV(heap(self._exception_addr), imm(0)) + mc.MOV(addr_add(imm(self._exception_addr), imm(WORD)), imm(0)) @specialize.arg(3) def implement_guard(self, addr, guard_op, emit_jump): Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py Wed Sep 2 12:59:03 2009 @@ -58,42 +58,19 @@ # variables that have place in register self.assembler = assembler self.translate_support_code = translate_support_code - if regalloc is None: - cpu = self.assembler.cpu - cpu.gc_ll_descr.rewrite_assembler(cpu, tree.operations) - self.tree = tree - self.reg_bindings = newcheckdict() - self.stack_bindings = newcheckdict() - # compute longevity of variables - self._compute_vars_longevity(tree.inputargs, tree.operations) - self.free_regs = REGS[:] - jump = tree.operations[-1] - loop_consts = self._compute_loop_consts(tree.inputargs, jump) - self.loop_consts = loop_consts - self.current_stack_depth = 0 - else: - inp = guard_op.inputargs - assert inp is not None - self.reg_bindings = {} - self.stack_bindings = {} - for arg in inp: - if arg in regalloc.reg_bindings: - self.reg_bindings[arg] = regalloc.reg_bindings[arg] - if arg in regalloc.stack_bindings: - self.stack_bindings[arg] = regalloc.stack_bindings[arg] - else: - assert arg in regalloc.reg_bindings - allocated_regs = self.reg_bindings.values() - self.free_regs = [v for v in REGS if v not in allocated_regs] - self.current_stack_depth = regalloc.current_stack_depth - self.longevity = guard_op.longevity - jump_or_fail = guard_op.suboperations[-1] - self.loop_consts = {} - self.tree = regalloc.tree - - def regalloc_for_guard(self, guard_op): - return RegAlloc(self.assembler, None, self.translate_support_code, - self, guard_op) + assert regalloc is None + cpu = self.assembler.cpu + cpu.gc_ll_descr.rewrite_assembler(cpu, tree.operations) + self.tree = tree + self.reg_bindings = newcheckdict() + self.stack_bindings = newcheckdict() + # compute longevity of variables + self._compute_vars_longevity(tree.inputargs, tree.operations) + self.free_regs = REGS[:] + jump = tree.operations[-1] + loop_consts = self._compute_loop_consts(tree.inputargs, jump) + self.loop_consts = loop_consts + self.current_stack_depth = 0 def _compute_loop_consts(self, inputargs, jump): if jump.opnum != rop.JUMP or jump.jump_target is not self.tree: @@ -136,24 +113,20 @@ self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) self.assembler.regalloc_perform(op, arglocs, result_loc) - def perform_with_guard(self, op, guard_op, regalloc, arglocs, result_loc): + def perform_with_guard(self, op, guard_op, locs, arglocs, result_loc): if not we_are_translated(): self.assembler.dump('%s <- %s(%s) [GUARDED]' % (result_loc, op, arglocs)) - self.assembler.regalloc_perform_with_guard(op, guard_op, regalloc, + self.assembler.regalloc_perform_with_guard(op, guard_op, locs, arglocs, result_loc) - self.max_stack_depth = max(self.max_stack_depth, - regalloc.max_stack_depth) - def perform_guard(self, op, regalloc, arglocs, result_loc): + def perform_guard(self, op, locs, arglocs, result_loc): if not we_are_translated(): if result_loc is not None: self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) else: self.assembler.dump('%s(%s)' % (op, arglocs)) - self.assembler.regalloc_perform_guard(op, regalloc, arglocs, result_loc) - self.max_stack_depth = max(self.max_stack_depth, - regalloc.max_stack_depth) + self.assembler.regalloc_perform_guard(op, locs, arglocs, result_loc) def PerformDiscard(self, op, arglocs): if not we_are_translated(): @@ -183,12 +156,12 @@ self.process_inputargs(tree) self._walk_operations(operations) - def walk_guard_ops(self, inputargs, operations, exc): - self.exc = exc - old_regalloc = self.assembler._regalloc - self.assembler._regalloc = self - self._walk_operations(operations) - self.assembler._regalloc = old_regalloc + #def walk_guard_ops(self, inputargs, operations, exc): + # self.exc = exc + # old_regalloc = self.assembler._regalloc + # self.assembler._regalloc = self + # self._walk_operations(operations) + # self.assembler._regalloc = old_regalloc def _walk_operations(self, operations): i = 0 @@ -482,6 +455,10 @@ loc = self.reg_bindings[result_v] return loc + def locs_for_fail(self, guard_op): + assert len(guard_op.suboperations) == 1 + return [self.loc(v) for v in guard_op.suboperations[0].args] + def process_inputargs(self, tree): # XXX we can sort out here by longevity if we need something # more optimal @@ -510,8 +487,8 @@ def _consider_guard(self, op, ignored): loc = self.make_sure_var_in_reg(op.args[0], []) - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [loc], None) + locs = self.locs_for_fail(op) + self.perform_guard(op, locs, [loc], None) self.eventually_free_var(op.args[0]) self.eventually_free_vars(op.inputargs) @@ -521,12 +498,12 @@ def consider_fail(self, op, ignored): # make sure all vars are on stack locs = [self.loc(arg) for arg in op.args] - self.assembler.generate_failure(op, locs, self.exc) + self.assembler.generate_failure(self.assembler.mc, op, locs, self.exc) self.eventually_free_vars(op.args) def consider_guard_no_exception(self, op, ignored): - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [], None) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [], None) self.eventually_free_vars(op.inputargs) def consider_guard_exception(self, op, ignored): @@ -538,8 +515,8 @@ resloc = self.force_allocate_reg(op.result, op.args + [box]) else: resloc = None - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [loc, loc1], resloc) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [loc, loc1], resloc) self.eventually_free_vars(op.inputargs) self.eventually_free_vars(op.args) self.eventually_free_var(box) @@ -550,8 +527,8 @@ def consider_guard_value(self, op, ignored): x = self.make_sure_var_in_reg(op.args[0], []) y = self.loc(op.args[1]) - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [x, y], None) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [x, y], None) self.eventually_free_vars(op.inputargs) self.eventually_free_vars(op.args) @@ -559,8 +536,8 @@ assert isinstance(op.args[0], Box) x = self.make_sure_var_in_reg(op.args[0], []) y = self.loc(op.args[1]) - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [x, y], None) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [x, y], None) self.eventually_free_vars(op.inputargs) self.eventually_free_vars(op.args) @@ -640,9 +617,9 @@ need_lower_byte=True) self.Perform(op, arglocs, loc) else: - regalloc = self.regalloc_for_guard(guard_op) + faillocs = self.locs_for_fail(guard_op) self.position += 1 - self.perform_with_guard(op, guard_op, regalloc, arglocs, None) + self.perform_with_guard(op, guard_op, faillocs, arglocs, None) self.eventually_free_var(op.result) self.eventually_free_vars(guard_op.inputargs) @@ -864,9 +841,9 @@ if guard_op is not None: argloc = self.make_sure_var_in_reg(op.args[0], []) self.eventually_free_var(op.args[0]) - regalloc = self.regalloc_for_guard(guard_op) + faillocs = self.locs_for_fail(guard_op) self.position += 1 - self.perform_with_guard(op, guard_op, regalloc, [argloc], None) + self.perform_with_guard(op, guard_op, faillocs, [argloc], None) self.eventually_free_var(op.result) self.eventually_free_vars(guard_op.inputargs) else: Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py Wed Sep 2 12:59:03 2009 @@ -59,20 +59,10 @@ self.assembler._exception_bck[1] = 0 def compile_operations(self, tree, guard_op=None): - old_loop = tree._x86_compiled - if old_loop: - olddepth = tree._x86_stack_depth - oldlocs = tree.arglocs - else: - oldlocs = None - olddepth = 0 - stack_depth = self.assembler.assemble(tree) - newlocs = tree.arglocs - if old_loop != 0: - self.assembler.patch_jump(old_loop, tree._x86_compiled, - oldlocs, newlocs, olddepth, - tree._x86_stack_depth) - + if guard_op is not None: + self.assembler.assemble_from_guard(guard_op) + self.assembler.assemble_loop(tree) + def get_bootstrap_code(self, loop): addr = loop._x86_bootstrap_code if not addr: From pedronis at codespeak.net Wed Sep 2 13:27:07 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 2 Sep 2009 13:27:07 +0200 (CEST) Subject: [pypy-svn] r67427 - in pypy/trunk/pypy: config doc/config interpreter/test module/_testing Message-ID: <20090902112707.A6B841680AB@codespeak.net> Author: pedronis Date: Wed Sep 2 13:27:04 2009 New Revision: 67427 Added: pypy/trunk/pypy/doc/config/objspace.usemodules._testing.txt (contents, props changed) pypy/trunk/pypy/module/_testing/ pypy/trunk/pypy/module/_testing/__init__.py (contents, props changed) pypy/trunk/pypy/module/_testing/app_notrpython.py (contents, props changed) Modified: pypy/trunk/pypy/config/pypyoption.py pypy/trunk/pypy/interpreter/test/test_pyframe.py Log: (micke, pedronis) rewrite the hidden frame test to be less fragile at the price of introducing a testing only module, cpython has those too, such is life Modified: pypy/trunk/pypy/config/pypyoption.py ============================================================================== --- pypy/trunk/pypy/config/pypyoption.py (original) +++ pypy/trunk/pypy/config/pypyoption.py Wed Sep 2 13:27:04 2009 @@ -18,7 +18,8 @@ default_modules.update(dict.fromkeys( ["_codecs", "gc", "_weakref", "marshal", "errno", "math", "_sre", "_pickle_support", "operator", - "parser", "symbol", "token", "_ast", "_random", "__pypy__"])) + "parser", "symbol", "token", "_ast", "_random", "__pypy__", + "_testing"])) # --allworkingmodules Added: pypy/trunk/pypy/doc/config/objspace.usemodules._testing.txt ============================================================================== --- (empty file) +++ pypy/trunk/pypy/doc/config/objspace.usemodules._testing.txt Wed Sep 2 13:27:04 2009 @@ -0,0 +1,3 @@ +Use the '_testing' module. This module exists only for PyPy own testing purposes. + +This module is expected to be working and is included by default. Modified: pypy/trunk/pypy/interpreter/test/test_pyframe.py ============================================================================== --- pypy/trunk/pypy/interpreter/test/test_pyframe.py (original) +++ pypy/trunk/pypy/interpreter/test/test_pyframe.py Wed Sep 2 13:27:04 2009 @@ -140,20 +140,25 @@ assert len(l) == 1 assert isinstance(l[0][1], Exception) - def test_trace_print_hidden(self): + def test_trace_ignore_hidden(self): import sys + import _testing + l = [] def trace(a,b,c): l.append((a,b,c)) def f(): - print 'foo!' + h = _testing.Hidden() + r = h.meth() + return r sys.settrace(trace) - f() + res = f() sys.settrace(None) assert len(l) == 1 assert l[0][1] == 'call' + assert res == 'hidden' # sanity def test_trace_return_exc(self): import sys Added: pypy/trunk/pypy/module/_testing/__init__.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/module/_testing/__init__.py Wed Sep 2 13:27:04 2009 @@ -0,0 +1,17 @@ + +""" +Mixed-module definition for pypy own testing purposes +""" + +from pypy.interpreter.mixedmodule import MixedModule + + +class Module(MixedModule): + """PyPy own testing""" + + interpleveldefs = { + } + + appleveldefs = { + 'Hidden': 'app_notrpython.Hidden', + } Added: pypy/trunk/pypy/module/_testing/app_notrpython.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/module/_testing/app_notrpython.py Wed Sep 2 13:27:04 2009 @@ -0,0 +1,6 @@ +# NOT_RPYTHON + +class Hidden(object): + + def meth(self): + return 'hidden' From cfbolz at codespeak.net Wed Sep 2 14:03:11 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 2 Sep 2009 14:03:11 +0200 (CEST) Subject: [pypy-svn] r67428 - pypy/trunk/pypy/jit/tl Message-ID: <20090902120311.6A9971683D1@codespeak.net> Author: cfbolz Date: Wed Sep 2 14:03:10 2009 New Revision: 67428 Modified: pypy/trunk/pypy/jit/tl/pypyjit_demo.py Log: An example loop that shows behaviour that I think is one of the next problems in richards (apart from recompilation). Modified: pypy/trunk/pypy/jit/tl/pypyjit_demo.py ============================================================================== --- pypy/trunk/pypy/jit/tl/pypyjit_demo.py (original) +++ pypy/trunk/pypy/jit/tl/pypyjit_demo.py Wed Sep 2 14:03:10 2009 @@ -5,16 +5,50 @@ __import__('test.' + TESTNAME) print "---ending 1---" +class A(object): + def __init__(self, x): + self.x = x + self.y = x + self.count = 0 + + def increment(self): + self.count += 1 + count = self.count + self.reset(self.count) + self.count += count + + def reset(self, howmuch): + for i in range(howmuch): + self.count -= 1 + + def f(self): + self.increment() + return self.x + self.y + 1 + def simple_loop(): print "simple loop" import time + global a + a = A(10) + a = A(10) + a = A(10) + a = A(10) + a = A(10) + a = A(1) + print a + print a i = 0 - N = 100 + N = 1000 #N = 10000000 step = 3 start = time.clock() + odd = 0 while i < N: - i = i + step + i = i + a.f() + if i % 2: + i += 2 + odd += 1 + print a.count, i, odd end = time.clock() print i print end-start, 'seconds' From cfbolz at codespeak.net Wed Sep 2 15:32:31 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 2 Sep 2009 15:32:31 +0200 (CEST) Subject: [pypy-svn] r67429 - pypy/branch/spine-of-frames Message-ID: <20090902133231.56D80168077@codespeak.net> Author: cfbolz Date: Wed Sep 2 15:32:28 2009 New Revision: 67429 Added: pypy/branch/spine-of-frames/ - copied from r67428, pypy/trunk/ Log: a branch where to try to link frames together differently From arigo at codespeak.net Wed Sep 2 16:52:03 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 2 Sep 2009 16:52:03 +0200 (CEST) Subject: [pypy-svn] r67430 - in pypy/trunk/pypy/jit: backend backend/llgraph backend/llsupport backend/x86 metainterp metainterp/test Message-ID: <20090902145203.E05981683CE@codespeak.net> Author: arigo Date: Wed Sep 2 16:52:02 2009 New Revision: 67430 Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py pypy/trunk/pypy/jit/backend/llgraph/runner.py pypy/trunk/pypy/jit/backend/llsupport/llmodel.py pypy/trunk/pypy/jit/backend/model.py pypy/trunk/pypy/jit/backend/x86/assembler.py pypy/trunk/pypy/jit/backend/x86/regalloc.py pypy/trunk/pypy/jit/backend/x86/runner.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/resoperation.py pypy/trunk/pypy/jit/metainterp/test/test_basic.py Log: Fix the storage of exceptions in the x86 backend (notably by storing the exception object as a real object, not as an int, which can explode on a moving GC). Remove the 'cast_int_to_ptr' operation, which makes a bit no sense at all on moving GCs. Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py Wed Sep 2 16:52:02 2009 @@ -124,7 +124,6 @@ 'unicodegetitem' : (('ref', 'int'), 'int'), 'unicodesetitem' : (('ref', 'int', 'int'), 'int'), 'cast_ptr_to_int' : (('ref',), 'int'), - 'cast_int_to_ptr' : (('int',), 'ref'), 'debug_merge_point': (('ref',), None), #'getitem' : (('void', 'ref', 'int'), 'int'), #'setitem' : (('void', 'ref', 'int', 'int'), None), @@ -696,9 +695,6 @@ def op_cast_ptr_to_int(self, descr, ptr): return cast_to_int(ptr, self.memocast) - def op_cast_int_to_ptr(self, descr, val): - return cast_from_int(llmemory.GCREF, val, self.memocast) - def op_uint_xor(self, descr, arg1, arg2): return arg1 ^ arg2 Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/runner.py Wed Sep 2 16:52:02 2009 @@ -421,12 +421,6 @@ else: # calldescr.typeinfo == 'v' # void llimpl.do_call_void(func, self.memo_cast) - def do_cast_int_to_ptr(self, args, descr=None): - assert descr is None - return history.BoxPtr(llimpl.cast_from_int(llmemory.GCREF, - args[0].getint(), - self.memo_cast)) - def do_cast_ptr_to_int(self, args, descr=None): assert descr is None return history.BoxInt(llimpl.cast_to_int(args[0].getref_base(), Modified: pypy/trunk/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/trunk/pypy/jit/backend/llsupport/llmodel.py Wed Sep 2 16:52:02 2009 @@ -54,13 +54,14 @@ immortal=True) setattr(self, '_%s_error_vtable' % prefix, llmemory.cast_ptr_to_adr(ll_inst.typeptr)) - setattr(self, '_%s_error_inst' % prefix, - llmemory.cast_ptr_to_adr(ll_inst)) + setattr(self, '_%s_error_inst' % prefix, ll_inst) # ------------------- helpers and descriptions -------------------- @staticmethod - def cast_int_to_gcref(x): + def _cast_int_to_gcref(x): + # dangerous! only use if you are sure no collection could occur + # between reading the integer and casting it to a pointer if not we_are_translated(): _check_addr_range(x) return rffi.cast(llmemory.GCREF, x) @@ -109,14 +110,14 @@ def get_overflow_error(self): ovf_vtable = self.cast_adr_to_int(self._ovf_error_vtable) - ovf_inst = self.cast_int_to_gcref( - self.cast_adr_to_int(self._ovf_error_inst)) + ovf_inst = lltype.cast_opaque_ptr(llmemory.GCREF, + self._ovf_error_inst) return ovf_vtable, ovf_inst def get_zero_division_error(self): zer_vtable = self.cast_adr_to_int(self._zer_error_vtable) - zer_inst = self.cast_int_to_gcref( - self.cast_adr_to_int(self._zer_error_inst)) + zer_inst = lltype.cast_opaque_ptr(llmemory.GCREF, + self._zer_error_inst) return zer_vtable, zer_inst # ____________________________________________________________ @@ -142,7 +143,7 @@ else: raise NotImplementedError("size = %d" % size) if ptr: - return BoxPtr(self.cast_int_to_gcref(val)) + return BoxPtr(self._cast_int_to_gcref(val)) else: return BoxInt(val) @@ -207,7 +208,7 @@ else: raise NotImplementedError("size = %d" % size) if ptr: - return BoxPtr(self.cast_int_to_gcref(val)) + return BoxPtr(self._cast_int_to_gcref(val)) else: return BoxInt(val) @@ -311,9 +312,6 @@ def do_cast_ptr_to_int(self, args, descr=None): return BoxInt(self.cast_gcref_to_int(args[0].getref_base())) - def do_cast_int_to_ptr(self, args, descr=None): - return BoxPtr(self.cast_int_to_gcref(args[0].getint())) - import pypy.jit.metainterp.executor pypy.jit.metainterp.executor.make_execute_list(AbstractLLCPU) Modified: pypy/trunk/pypy/jit/backend/model.py ============================================================================== --- pypy/trunk/pypy/jit/backend/model.py (original) +++ pypy/trunk/pypy/jit/backend/model.py Wed Sep 2 16:52:02 2009 @@ -160,9 +160,6 @@ def do_cond_call_gc_malloc(self, args, calldescr): xxx - def do_cast_int_to_ptr(self, args, descr=None): - raise NotImplementedError - def do_cast_ptr_to_int(self, args, descr=None): raise NotImplementedError Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py Wed Sep 2 16:52:02 2009 @@ -79,6 +79,11 @@ assert self.mcstack[self.counter - 1] is mc self.counter -= 1 +EXCEPTION_STORAGE = lltype.GcStruct('EXCEPTION_STORAGE', + ('type', lltype.Signed), + ('value', llmemory.GCREF)) + + class Assembler386(object): mc = None mc2 = None @@ -92,8 +97,10 @@ self.malloc_array_func_addr = 0 self.malloc_str_func_addr = 0 self.malloc_unicode_func_addr = 0 - self._exception_data = lltype.nullptr(rffi.CArray(lltype.Signed)) - self._exception_addr = 0 + # The '_exception_emulator' is only used when non-translated. + # The '_exception_copy' is preallocated, so non-moving. + self._exception_emulator = lltype.malloc(EXCEPTION_STORAGE, zero=True) + self._exception_copy = lltype.malloc(EXCEPTION_STORAGE, zero=True) self.mcstack = MachineCodeStack() self.logger = Logger(cpu.ts) self.fail_boxes_int = lltype.malloc(lltype.GcArray(lltype.Signed), @@ -111,22 +118,6 @@ lltype.direct_arrayitems(self.fail_boxes_ptr)) self.logger.create_log() - # we generate the loop body in 'mc' - # 'mc2' is for guard recovery code - if we_are_translated(): - addr = llop.get_exception_addr(llmemory.Address) - self._exception_data = llmemory.cast_adr_to_ptr(addr, rffi.CArrayPtr(lltype.Signed)) - else: - self._exception_data = lltype.malloc(rffi.CArray(lltype.Signed), 2, - zero=True, flavor='raw') - self._exception_addr = self.cpu.cast_ptr_to_int( - self._exception_data) - # a backup, in case our exception can be somehow mangled, - # by a handling code - self._exception_bck = lltype.malloc(rffi.CArray(lltype.Signed), 2, - zero=True, flavor='raw') - self._exception_bck_addr = self.cpu.cast_ptr_to_int( - self._exception_bck) # the address of the function called by 'new' gc_ll_descr = self.cpu.gc_ll_descr gc_ll_descr.initialize() @@ -145,6 +136,8 @@ self.malloc_unicode_func_addr = rffi.cast(lltype.Signed, ll_new_unicode) # done + # we generate the loop body in 'mc' + # 'mc2' is for guard recovery code self.mc2 = self.mcstack.next_mc() self.mc = self.mcstack.next_mc() @@ -444,7 +437,6 @@ def genop_same_as(self, op, arglocs, resloc): self.mc.MOV(resloc, arglocs[0]) - genop_cast_int_to_ptr = genop_same_as genop_cast_ptr_to_int = genop_same_as def genop_int_mod(self, op, arglocs, resloc): @@ -639,20 +631,50 @@ self.mc.TEST(loc, loc) self.implement_guard(addr, op, self.mc.JZ) + def pos_exception(self): + if we_are_translated(): + addr = llop.get_exception_addr(llmemory.Address) + return llmemory.cast_adr_to_int(addr) + else: + i = rffi.cast(lltype.Signed, self._exception_emulator) + return i + 0 # xxx hard-coded offset of 'type' when non-translated + + def pos_exc_value(self): + if we_are_translated(): + addr = llop.get_exc_value_addr(llmemory.Address) + return llmemory.cast_adr_to_int(addr) + else: + i = rffi.cast(lltype.Signed, self._exception_emulator) + return i + 4 # xxx hard-coded offset of 'value' when non-translated + + def pos_exception_copy(self): + i = rffi.cast(lltype.Signed, self._exception_copy) + if we_are_translated(): + return i + llmemory.offsetof(EXCEPTION_STORAGE, 'type') + else: + return i + 0 # xxx hard-coded offset of 'type' when non-translated + + def pos_exc_value_copy(self): + i = rffi.cast(lltype.Signed, self._exception_copy) + if we_are_translated(): + return i + llmemory.offsetof(EXCEPTION_STORAGE, 'value') + else: + return i + 4 # xxx hard-coded offset of 'value' when non-translated + def genop_guard_guard_no_exception(self, op, ign_1, addr, locs, ign_2): - self.mc.CMP(heap(self._exception_addr), imm(0)) + self.mc.CMP(heap(self.pos_exception()), imm(0)) self.implement_guard(addr, op, self.mc.JNZ) def genop_guard_guard_exception(self, op, ign_1, addr, locs, resloc): loc = locs[0] loc1 = locs[1] - self.mc.MOV(loc1, heap(self._exception_addr)) + self.mc.MOV(loc1, heap(self.pos_exception())) self.mc.CMP(loc1, loc) self.implement_guard(addr, op, self.mc.JNE) if resloc is not None: - self.mc.MOV(resloc, addr_add(imm(self._exception_addr), imm(WORD))) - self.mc.MOV(heap(self._exception_addr), imm(0)) - self.mc.MOV(addr_add(imm(self._exception_addr), imm(WORD)), imm(0)) + self.mc.MOV(resloc, heap(self.pos_exc_value())) + self.mc.MOV(heap(self.pos_exception()), imm(0)) + self.mc.MOV(heap(self.pos_exc_value()), imm(0)) def genop_guard_guard_no_overflow(self, op, ign_1, addr, locs, resloc): self.implement_guard(addr, op, self.mc.JO) @@ -732,14 +754,14 @@ mc.RET() def generate_exception_handling(self, loc): - self.mc.MOV(loc, heap(self._exception_addr)) - self.mc.MOV(heap(self._exception_bck_addr), loc) - self.mc.MOV(loc, addr_add(imm(self._exception_addr), imm(WORD))) - self.mc.MOV(addr_add(imm(self._exception_bck_addr), imm(WORD)), loc) + self.mc.MOV(loc, heap(self.pos_exception())) + self.mc.MOV(heap(self.pos_exception_copy()), loc) + self.mc.MOV(loc, heap(self.pos_exc_value())) + self.mc.MOV(heap(self.pos_exc_value_copy()), loc) # clean up the original exception, we don't want # to enter more rpython code with exc set - self.mc.MOV(heap(self._exception_addr), imm(0)) - self.mc.MOV(addr_add(imm(self._exception_addr), imm(WORD)), imm(0)) + self.mc.MOV(heap(self.pos_exception()), imm(0)) + self.mc.MOV(heap(self.pos_exc_value()), imm(0)) @specialize.arg(3) def implement_guard(self, addr, guard_op, emit_jump): Modified: pypy/trunk/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/regalloc.py Wed Sep 2 16:52:02 2009 @@ -885,7 +885,6 @@ self.eventually_free_var(op.args[0]) resloc = self.force_allocate_reg(op.result, []) self.Perform(op, [argloc], resloc) - consider_cast_int_to_ptr = consider_same_as consider_cast_ptr_to_int = consider_same_as def consider_strlen(self, op, ignored): Modified: pypy/trunk/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/runner.py (original) +++ pypy/trunk/pypy/jit/backend/x86/runner.py Wed Sep 2 16:52:02 2009 @@ -26,9 +26,9 @@ def _store_exception(lle): tp_i = self.cast_ptr_to_int(lle.args[0]) - v_i = self.cast_gcref_to_int(lle.args[1]) - self.assembler._exception_data[0] = tp_i - self.assembler._exception_data[1] = v_i + v_i = lltype.cast_opaque_ptr(llmemory.GCREF, lle.args[1]) + self.assembler._exception_emulator.type = tp_i + self.assembler._exception_emulator.value = v_i self.current_interpreter._store_exception = _store_exception TP = lltype.GcArray(llmemory.GCREF) @@ -46,17 +46,14 @@ pass def get_exception(self): - self.assembler.make_sure_mc_exists() - return self.assembler._exception_bck[0] + return self.assembler._exception_copy.type def get_exc_value(self): - self.assembler.make_sure_mc_exists() - return self.cast_int_to_gcref(self.assembler._exception_bck[1]) + return self.assembler._exception_copy.value def clear_exception(self): - self.assembler.make_sure_mc_exists() - self.assembler._exception_bck[0] = 0 - self.assembler._exception_bck[1] = 0 + self.assembler._exception_copy.type = 0 + self.assembler._exception_copy.value= lltype.nullptr(llmemory.GCREF.TO) def compile_operations(self, tree, bridge=None): old_loop = tree._x86_compiled Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Wed Sep 2 16:52:02 2009 @@ -243,7 +243,7 @@ ''' % (_opimpl, _opimpl.upper())).compile() for _opimpl in ['int_is_true', 'int_neg', 'int_invert', 'bool_not', - 'cast_ptr_to_int', 'cast_int_to_ptr', + 'cast_ptr_to_int', ]: exec py.code.Source(''' @arguments("box") Modified: pypy/trunk/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resoperation.py (original) +++ pypy/trunk/pypy/jit/metainterp/resoperation.py Wed Sep 2 16:52:02 2009 @@ -126,7 +126,6 @@ 'OOSEND_PURE', # ootype operation 'CALL_PURE', # - 'CAST_INT_TO_PTR', 'CAST_PTR_TO_INT', 'INT_ADD', 'INT_SUB', Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Wed Sep 2 16:52:02 2009 @@ -915,16 +915,21 @@ lltype.free(x, flavor='raw') def test_casts(self): + if not self.basic: + py.test.skip("test written in a style that " + "means it's frontend only") from pypy.rpython.lltypesystem import lltype, llmemory TP = lltype.GcStruct('x') def f(p): n = lltype.cast_ptr_to_int(p) - return lltype.cast_int_to_ptr(lltype.Ptr(TP), n) + return n x = lltype.malloc(TP) - expected = lltype.cast_opaque_ptr(llmemory.GCREF, x) - assert self.interp_operations(f, [x]) == expected + res = self.interp_operations(f, [x]) + expected = self.metainterp.cpu.do_cast_ptr_to_int( + [history.BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, x))]).value + assert res == expected class TestLLtype(BaseLLtypeTests, LLJitMixin): pass From arigo at codespeak.net Wed Sep 2 17:04:16 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 2 Sep 2009 17:04:16 +0200 (CEST) Subject: [pypy-svn] r67431 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090902150416.DF5AA1683D3@codespeak.net> Author: arigo Date: Wed Sep 2 17:04:16 2009 New Revision: 67431 Modified: pypy/trunk/pypy/jit/metainterp/policy.py Log: Fix the policy to avoid printing "graph contains Float!" if the graph is anyway disabled by the look_inside_function() method. Modified: pypy/trunk/pypy/jit/metainterp/policy.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/policy.py (original) +++ pypy/trunk/pypy/jit/metainterp/policy.py Wed Sep 2 17:04:16 2009 @@ -17,13 +17,13 @@ return True def look_inside_graph(self, graph): - if contains_unsupported_variable_type(graph): - return False try: func = graph.func except AttributeError: - return True - return self.look_inside_function(func) + see_function = True + else: + see_function = self.look_inside_function(func) + return see_function and not contains_unsupported_variable_type(graph) def graphs_from(self, op): if op.opname == 'direct_call': From pedronis at codespeak.net Wed Sep 2 17:28:35 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 2 Sep 2009 17:28:35 +0200 (CEST) Subject: [pypy-svn] r67432 - in pypy/trunk/pypy/annotation: . test Message-ID: <20090902152835.320F91683DB@codespeak.net> Author: pedronis Date: Wed Sep 2 17:28:33 2009 New Revision: 67432 Modified: pypy/trunk/pypy/annotation/bookkeeper.py pypy/trunk/pypy/annotation/test/test_annrpython.py Log: (micke, pedronis) before we sprinkle more access_direcly/fresh_virtualizable add a sanity check that annotations with flags don't escape to the heap Modified: pypy/trunk/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/trunk/pypy/annotation/bookkeeper.py (original) +++ pypy/trunk/pypy/annotation/bookkeeper.py Wed Sep 2 17:28:33 2009 @@ -11,8 +11,8 @@ SomeLLADTMeth, SomeBool, SomeTuple, SomeOOClass, SomeImpossibleValue, \ SomeUnicodeString, SomeList, SomeObject, HarmlesslyBlocked, \ SomeWeakRef, lltype_to_annotation -from pypy.annotation.classdef import InstanceSource -from pypy.annotation.listdef import ListDef +from pypy.annotation.classdef import InstanceSource, ClassDef +from pypy.annotation.listdef import ListDef, ListItem from pypy.annotation.dictdef import DictDef from pypy.annotation import description from pypy.annotation.signature import annotationoftype @@ -228,6 +228,38 @@ finally: self.leave() + # sanity check: no flags attached to heap stored instances + + seen = set() + + def check_no_flags(s_value_or_def): + if isinstance(s_value_or_def, SomeInstance): + assert not s_value_or_def.flags, "instance annotation with flags escaped to the heap" + check_no_flags(s_value_or_def.classdef) + elif isinstance(s_value_or_def, SomeList): + check_no_flags(s_value_or_def.listdef.listitem) + elif isinstance(s_value_or_def, SomeDict): + check_no_flags(s_value_or_def.dictdef.dictkey) + check_no_flags(s_value_or_def.dictdef.dictvalue) + elif isinstance(s_value_or_def, SomeTuple): + for s_item in s_value_or_def.items: + check_no_flags(s_item) + elif isinstance(s_value_or_def, ClassDef): + if s_value_or_def in seen: + return + seen.add(s_value_or_def) + for attr in s_value_or_def.attrs.values(): + s_attr = attr.s_value + check_no_flags(s_attr) + elif isinstance(s_value_or_def, ListItem): + if s_value_or_def in seen: + return + seen.add(s_value_or_def) + check_no_flags(s_value_or_def.s_value) + + for clsdef in self.classdefs: + check_no_flags(clsdef) + def consider_call_site(self, call_op): binding = self.annotator.binding s_callable = binding(call_op.args[0]) Modified: pypy/trunk/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/trunk/pypy/annotation/test/test_annrpython.py (original) +++ pypy/trunk/pypy/annotation/test/test_annrpython.py Wed Sep 2 17:28:33 2009 @@ -2785,6 +2785,64 @@ assert isinstance(s.items[2], annmodel.SomeInstance) assert s.items[2].flags == {} + def test_no_access_directly_on_heap(self): + from pypy.rlib.jit import hint + + class A: + _virtualizable2_ = [] + + class I: + pass + + def f(): + x = A() + x = hint(x, access_directly=True) + i = I() + i.x = x + + a = self.RPythonAnnotator() + py.test.raises(Exception, a.build_types, f, []) + + + class M: + def __init__(self): + self.l = [] + self.d = {} + + class C: + def _freeze_(self): + return True + + def __init__(self): + self.m = M() + self.l2 = [] + + c = C() + + def f(): + x = A() + x = hint(x, access_directly=True) + c.m.l.append(x) + + a = self.RPythonAnnotator() + py.test.raises(AssertionError, a.build_types, f, []) + + def f(): + x = A() + x = hint(x, access_directly=True) + c.m.d[None] = x + + a = self.RPythonAnnotator() + py.test.raises(AssertionError, a.build_types, f, []) + + def f(): + x = A() + x = hint(x, access_directly=True) + c.m.d[x] = None + + a = self.RPythonAnnotator() + py.test.raises(AssertionError, a.build_types, f, []) + def test_ctr_location(self): from pypy.rlib.jit import hint From cfbolz at codespeak.net Wed Sep 2 17:53:35 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 2 Sep 2009 17:53:35 +0200 (CEST) Subject: [pypy-svn] r67433 - in pypy/branch/spine-of-frames/pypy: interpreter interpreter/test module/sys module/sys/test Message-ID: <20090902155335.AB58F1683D3@codespeak.net> Author: cfbolz Date: Wed Sep 2 17:53:35 2009 New Revision: 67433 Modified: pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py pypy/branch/spine-of-frames/pypy/interpreter/generator.py pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py pypy/branch/spine-of-frames/pypy/interpreter/pytraceback.py pypy/branch/spine-of-frames/pypy/interpreter/test/test_zzpickle_and_slow.py pypy/branch/spine-of-frames/pypy/module/sys/test/test_sysmodule.py pypy/branch/spine-of-frames/pypy/module/sys/vm.py Log: try to have frames not escape via the f_backs of the next "real" frame. Modified: pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py Wed Sep 2 17:53:35 2009 @@ -40,13 +40,13 @@ def gettopframe_nohidden(self): frame = self.gettopframe() while frame and frame.hide(): - frame = frame.f_back + frame = frame.f_back() return frame def getnextframe_nohidden(frame): - frame = frame.f_back + frame = frame.f_back() while frame and frame.hide(): - frame = frame.f_back + frame = frame.f_back() return frame getnextframe_nohidden = staticmethod(getnextframe_nohidden) @@ -56,8 +56,8 @@ self.space.wrap("maximum recursion depth exceeded")) self.framestackdepth += 1 # + frame.f_back_some = self.some_frame curtopframe = self.gettopframe() - frame.f_back = curtopframe if curtopframe is not None: curtopframe.f_forward = frame if not we_are_jitted(): @@ -68,11 +68,11 @@ self._trace(frame, 'leaveframe', self.space.w_None) #assert frame is self.gettopframe() --- slowish - f_back = frame.f_back + f_back = frame.f_back() if f_back is not None: f_back.f_forward = None if not we_are_jitted() or self.some_frame is frame: - self.some_frame = f_back + self.some_frame = frame.f_back_some self.framestackdepth -= 1 if self.w_tracefunc is not None and not frame.hide(): @@ -134,7 +134,7 @@ while index > 0: index -= 1 lst[index] = f - f = f.f_back + f = f.f_back() assert f is None return lst # coroutine: I think this is all, folks! Modified: pypy/branch/spine-of-frames/pypy/interpreter/generator.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/generator.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/generator.py Wed Sep 2 17:53:35 2009 @@ -64,7 +64,7 @@ else: return w_result # YIELDed finally: - self.frame.f_back = None + self.frame.f_back_some = None self.running = False def descr_throw(self, w_type, w_val=None, w_tb=None): Modified: pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py Wed Sep 2 17:53:35 2009 @@ -33,14 +33,49 @@ * 'builtin' is the attached built-in module * 'valuestack_w', 'blockstack', control the interpretation """ + + """ + explanation of the f_back handling: + ----------------------------------- + + in the non-JIT case, the frames simply form a doubly linked list via the + attributes f_back_some and f_forward. + + When the JIT is used, things become more complex, as functions can be + inlined into each other. In this case a frame chain can look like this: + + +---------------+ + | real_frame | + +---------------+ + | ^ + | f_back_some + | | + | | f_forward + | +--------------+ + | | virtual frame| + | +--------------+ + | ^ + | | f_forward + | +--------------+ + | | virtual frame| + | +--------------+ + | ^ + | | + v | f_forward + +---------------+ + | real_frame | + +---------------+ + + """ __metaclass__ = extendabletype frame_finished_execution = False last_instr = -1 last_exception = None - f_back = None # these two should be modified together - f_forward = None # they make a doubly-linked list + f_back_some = None # these two should be modified together + f_forward = None # they make a sort of doubly-linked list + f_back_forced = False w_f_trace = None # For tracing instr_lb = 0 @@ -286,7 +321,7 @@ w_tb = w(self.last_exception.application_traceback) tup_state = [ - w(self.f_back), + w(self.f_back()), w(self.get_builtin()), w(self.pycode), w_valuestack, @@ -338,7 +373,9 @@ # do not use the instance's __init__ but the base's, because we set # everything like cells from here PyFrame.__init__(self, space, pycode, w_globals, closure) - new_frame.f_back = space.interp_w(PyFrame, w_f_back, can_be_None=True) + new_frame.f_back_some = space.interp_w(PyFrame, w_f_back, can_be_None=True) + new_frame.f_back_forced = True + new_frame.builtin = space.interp_w(Module, w_builtin) new_frame.blockstack = [unpickle_block(space, w_blk) for w_blk in space.unpackiterable(w_blockstack)] @@ -407,6 +444,25 @@ def _setcellvars(self, cellvars): pass + def f_back(self): + back_some = self.f_back_some + if self.f_back_forced: + # don't check back_some.f_forward in this case + return back_some + if back_some is None: + return None + while back_some.f_forward is not self: + back_some = back_some.f_forward + return back_some + + def force_f_back(self): + self.f_back_some = f_back = self.f_back() + self.f_back_forced = True + if f_back is not None: + f_back.force_f_back() + return f_back + + ### line numbers ### # for f*_f_* unwrapping through unwrap_spec in typedef.py @@ -550,7 +606,7 @@ return self.get_builtin().getdict() def fget_f_back(space, self): - return self.space.wrap(self.f_back) + return self.space.wrap(self.f_back()) def fget_f_lasti(space, self): return self.space.wrap(self.last_instr) @@ -571,27 +627,27 @@ def fget_f_exc_type(space, self): if self.last_exception is not None: - f = self.f_back + f = self.f_back() while f is not None and f.last_exception is None: - f = f.f_back + f = f.f_back() if f is not None: return f.last_exception.w_type return space.w_None def fget_f_exc_value(space, self): if self.last_exception is not None: - f = self.f_back + f = self.f_back() while f is not None and f.last_exception is None: - f = f.f_back + f = f.f_back() if f is not None: return f.last_exception.w_value return space.w_None def fget_f_exc_traceback(space, self): if self.last_exception is not None: - f = self.f_back + f = self.f_back() while f is not None and f.last_exception is None: - f = f.f_back + f = f.f_back() if f is not None: return space.wrap(f.last_exception.application_traceback) return space.w_None Modified: pypy/branch/spine-of-frames/pypy/interpreter/pytraceback.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/pytraceback.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/pytraceback.py Wed Sep 2 17:53:35 2009 @@ -46,6 +46,7 @@ self.next = space.interp_w(PyTraceback, w_next, can_be_None=True) def record_application_traceback(space, operror, frame, last_instruction): + frame.force_f_back() if frame.pycode.hidden_applevel: return lineno = offset2lineno(frame.pycode, last_instruction) Modified: pypy/branch/spine-of-frames/pypy/interpreter/test/test_zzpickle_and_slow.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/test/test_zzpickle_and_slow.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/test/test_zzpickle_and_slow.py Wed Sep 2 17:53:35 2009 @@ -30,18 +30,23 @@ from pypy.interpreter import pytraceback def hide_top_frame(space, w_frame): w_last = None - while w_frame.f_back: + while w_frame.f_back(): + # should have been forced by traceback capturing + assert w_frame.f_back_forced w_last = w_frame - w_frame = w_frame.f_back + w_frame = w_frame.f_back() assert w_last - w_saved = w_last.f_back - w_last.f_back = None + w_saved = w_last.f_back() + w_last.f_back_some = None + w_saved.f_forward = None return w_saved def restore_top_frame(space, w_frame, w_saved): - while w_frame.f_back: - w_frame = w_frame.f_back - w_frame.f_back = w_saved + while w_frame.f_back(): + assert w_frame.f_back_forced + w_frame = w_frame.f_back() + w_frame.f_back_some = w_saved + w_saved.f_forward = w_frame def read_exc_type(space, w_frame): if w_frame.last_exception is None: Modified: pypy/branch/spine-of-frames/pypy/module/sys/test/test_sysmodule.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/sys/test/test_sysmodule.py (original) +++ pypy/branch/spine-of-frames/pypy/module/sys/test/test_sysmodule.py Wed Sep 2 17:53:35 2009 @@ -337,6 +337,16 @@ # is sys._getframe().f_code #) + def test_getframe_in_returned_func(self): + def f(): + return g() + def g(): + return sys._getframe(0) + frame = f() + assert frame.f_code.co_name == 'g' + assert frame.f_back.f_code.co_name == 'f' + assert frame.f_back.f_back.f_code.co_name == 'test_getframe_in_returned_func' + def test_attributes(self): assert sys.__name__ == 'sys' assert isinstance(sys.modules, dict) Modified: pypy/branch/spine-of-frames/pypy/module/sys/vm.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/sys/vm.py (original) +++ pypy/branch/spine-of-frames/pypy/module/sys/vm.py Wed Sep 2 17:53:35 2009 @@ -31,6 +31,7 @@ space.wrap("frame index must not be negative")) ec = space.getexecutioncontext() f = ec.gettopframe_nohidden() + f.force_f_back() while True: if f is None: raise OperationError(space.w_ValueError, From cfbolz at codespeak.net Wed Sep 2 17:57:55 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 2 Sep 2009 17:57:55 +0200 (CEST) Subject: [pypy-svn] r67434 - pypy/branch/spine-of-frames/pypy/interpreter Message-ID: <20090902155755.198D71683DA@codespeak.net> Author: cfbolz Date: Wed Sep 2 17:57:54 2009 New Revision: 67434 Modified: pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py Log: some more text describing what happens Modified: pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py Wed Sep 2 17:57:54 2009 @@ -65,6 +65,18 @@ +---------------+ | real_frame | +---------------+ + | + | + v + ... + + This ensures that the virtual frames don't escape via the f_back of the + real frames. For the same reason, the executioncontext's some_frame + attribute should only point to real frames. + + All places where a frame can become accessed from applevel-code (like + sys._getframe and traceback catching) need to call force_f_back to ensure + that the intermediate virtual frames are forced to be real ones. """ From arigo at codespeak.net Wed Sep 2 18:04:57 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 2 Sep 2009 18:04:57 +0200 (CEST) Subject: [pypy-svn] r67435 - pypy/trunk/pypy/rpython/lltypesystem Message-ID: <20090902160457.6A4EF1683DF@codespeak.net> Author: arigo Date: Wed Sep 2 18:04:57 2009 New Revision: 67435 Modified: pypy/trunk/pypy/rpython/lltypesystem/rdict.py Log: Minor simplification here. Modified: pypy/trunk/pypy/rpython/lltypesystem/rdict.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/rdict.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/rdict.py Wed Sep 2 18:04:57 2009 @@ -507,7 +507,6 @@ PERTURB_SHIFT = 5 def ll_dict_lookup(d, key, hash): - DICT = lltype.typeOf(d).TO entries = d.entries mask = len(entries) - 1 i = hash & mask @@ -520,7 +519,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if DICT.paranoia: + if d.paranoia: if (entries != d.entries or not entries.valid(i) or entries[i].key != checkingkey): # the compare did major nasty stuff to the dict: start over @@ -555,7 +554,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if DICT.paranoia: + if d.paranoia: if (entries != d.entries or not entries.valid(i) or entries[i].key != checkingkey): # the compare did major nasty stuff to the dict: From arigo at codespeak.net Thu Sep 3 11:20:01 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 11:20:01 +0200 (CEST) Subject: [pypy-svn] r67436 - pypy/trunk/pypy/rpython/lltypesystem Message-ID: <20090903092001.E1C17168022@codespeak.net> Author: arigo Date: Thu Sep 3 11:20:00 2009 New Revision: 67436 Modified: pypy/trunk/pypy/rpython/lltypesystem/rdict.py Log: Gr gr gr. Life is hard. Going in a branch now to fix this mess... Modified: pypy/trunk/pypy/rpython/lltypesystem/rdict.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/rdict.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/rdict.py Thu Sep 3 11:20:00 2009 @@ -507,6 +507,7 @@ PERTURB_SHIFT = 5 def ll_dict_lookup(d, key, hash): + DICT = lltype.typeOf(d).TO entries = d.entries mask = len(entries) - 1 i = hash & mask @@ -519,7 +520,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if d.paranoia: + if DICT.paranoia: if (entries != d.entries or not entries.valid(i) or entries[i].key != checkingkey): # the compare did major nasty stuff to the dict: start over @@ -554,7 +555,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if d.paranoia: + if DICT.paranoia: if (entries != d.entries or not entries.valid(i) or entries[i].key != checkingkey): # the compare did major nasty stuff to the dict: From arigo at codespeak.net Thu Sep 3 11:22:20 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 11:22:20 +0200 (CEST) Subject: [pypy-svn] r67437 - pypy/branch/adtmembers-fun Message-ID: <20090903092220.09BC9168022@codespeak.net> Author: arigo Date: Thu Sep 3 11:22:18 2009 New Revision: 67437 Added: pypy/branch/adtmembers-fun/ - copied from r67436, pypy/trunk/ Log: A branch in which trying to make "p.adtmember" work. From arigo at codespeak.net Thu Sep 3 11:32:08 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 11:32:08 +0200 (CEST) Subject: [pypy-svn] r67438 - in pypy/branch/adtmembers-fun/pypy: annotation rpython/lltypesystem rpython/lltypesystem/test rpython/test Message-ID: <20090903093208.C35B6168022@codespeak.net> Author: arigo Date: Thu Sep 3 11:32:07 2009 New Revision: 67438 Modified: pypy/branch/adtmembers-fun/pypy/annotation/model.py pypy/branch/adtmembers-fun/pypy/annotation/unaryop.py pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/lltype.py pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/test/test_lltype.py pypy/branch/adtmembers-fun/pypy/rpython/test/test_llann.py Log: Refactor the logic that reads adtmethods from pointers (as opposed to from types). Modified: pypy/branch/adtmembers-fun/pypy/annotation/model.py ============================================================================== --- pypy/branch/adtmembers-fun/pypy/annotation/model.py (original) +++ pypy/branch/adtmembers-fun/pypy/annotation/model.py Thu Sep 3 11:32:07 2009 @@ -632,15 +632,6 @@ # i think we can only get here in the case of void-returning # functions return s_None - if isinstance(v, MethodType): - ll_ptrtype = lltype.typeOf(v.im_self) - assert isinstance(ll_ptrtype, (lltype.Ptr, lltype.InteriorPtr)) - return SomeLLADTMeth(ll_ptrtype, v.im_func) - if isinstance(v, FunctionType): - # this case should only be for staticmethod instances used in - # adtmeths: the getattr() result is then a plain FunctionType object. - from pypy.annotation.bookkeeper import getbookkeeper - return getbookkeeper().immutablevalue(v) if isinstance(v, lltype._interior_ptr): ob = v._parent if ob is None: Modified: pypy/branch/adtmembers-fun/pypy/annotation/unaryop.py ============================================================================== --- pypy/branch/adtmembers-fun/pypy/annotation/unaryop.py (original) +++ pypy/branch/adtmembers-fun/pypy/annotation/unaryop.py Thu Sep 3 11:32:07 2009 @@ -2,6 +2,7 @@ Unary operations on SomeValues. """ +from types import MethodType from pypy.annotation.model import \ SomeObject, SomeInteger, SomeBool, SomeString, SomeChar, SomeList, \ SomeDict, SomeTuple, SomeImpossibleValue, \ @@ -727,8 +728,19 @@ def getattr(p, s_attr): assert s_attr.is_constant(), "getattr on ptr %r with non-constant field-name" % p.ll_ptrtype - v = getattr(p.ll_ptrtype._example(), s_attr.const) - return ll_to_annotation(v) + example = p.ll_ptrtype._example() + try: + v = example._lookup_adtmeth(s_attr.const) + except AttributeError: + v = getattr(example, s_attr.const) + return ll_to_annotation(v) + else: + if isinstance(v, MethodType): + from pypy.rpython.lltypesystem import lltype + ll_ptrtype = lltype.typeOf(v.im_self) + assert isinstance(ll_ptrtype, (lltype.Ptr, lltype.InteriorPtr)) + return SomeLLADTMeth(ll_ptrtype, v.im_func) + return getbookkeeper().immutablevalue(v) getattr.can_only_throw = [] def len(p): Modified: pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/lltype.py Thu Sep 3 11:32:07 2009 @@ -994,25 +994,31 @@ return (type(self._obj0) not in (type(None), int) and self._getobj(check=False)._was_freed()) - def __getattr__(self, field_name): # ! can only return basic or ptr ! - if isinstance(self._T, Struct): - if field_name in self._T._flds: - o = self._obj._getattr(field_name) - return self._expose(field_name, o) + def _lookup_adtmeth(self, member_name): if isinstance(self._T, ContainerType): try: - adtmeth = self._T._adtmeths[field_name] + adtmember = self._T._adtmeths[member_name] except KeyError: pass else: try: - getter = adtmeth.__get__ + getter = adtmember.__get__ except AttributeError: - return adtmeth + return adtmember else: return getter(self) - raise AttributeError("%r instance has no field %r" % (self._T, - field_name)) + raise AttributeError + + def __getattr__(self, field_name): # ! can only return basic or ptr ! + if isinstance(self._T, Struct): + if field_name in self._T._flds: + o = self._obj._getattr(field_name) + return self._expose(field_name, o) + try: + return self._lookup_adtmeth(field_name) + except AttributeError: + raise AttributeError("%r instance has no field %r" % (self._T, + field_name)) def __setattr__(self, field_name, val): if isinstance(self._T, Struct): Modified: pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/test/test_lltype.py ============================================================================== --- pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/test/test_lltype.py (original) +++ pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/test/test_lltype.py Thu Sep 3 11:32:07 2009 @@ -528,7 +528,8 @@ A = GcArray(Signed, adtmeths={"h_alloc": h_alloc, - "h_length": h_length}) + "h_length": h_length, + "stuff": 12}) a = A.h_alloc(10) @@ -536,6 +537,9 @@ assert len(a) == 10 assert a.h_length() == 10 + assert a._lookup_adtmeth("h_length")() == 10 + assert a.stuff == 12 + assert a._lookup_adtmeth("stuff") == 12 def test_adt_typemethod(): def h_newstruct(S): Modified: pypy/branch/adtmembers-fun/pypy/rpython/test/test_llann.py ============================================================================== --- pypy/branch/adtmembers-fun/pypy/rpython/test/test_llann.py (original) +++ pypy/branch/adtmembers-fun/pypy/rpython/test/test_llann.py Thu Sep 3 11:32:07 2009 @@ -389,6 +389,26 @@ lst.append(6) self.annotate(llf, []) + def test_adtmeths(self): + def h_length(s): + return s.foo + S = GcStruct("S", ('foo', Signed), + adtmeths={"h_length": h_length, + "stuff": 12}) + def llf(): + s = malloc(S) + s.foo = 321 + return s.h_length() + s = self.annotate(llf, []) + assert s.knowntype == int and not s.is_constant() + + def llf(): + s = malloc(S) + return s.stuff + s = self.annotate(llf, []) + assert s.is_constant() and s.const == 12 + + def test_pseudohighlevelcallable(): t = TranslationContext() t.buildannotator() From arigo at codespeak.net Thu Sep 3 11:32:18 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 11:32:18 +0200 (CEST) Subject: [pypy-svn] r67439 - pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem Message-ID: <20090903093218.79900168022@codespeak.net> Author: arigo Date: Thu Sep 3 11:32:17 2009 New Revision: 67439 Modified: pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/rdict.py Log: Now this should work. Modified: pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/rdict.py ============================================================================== --- pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/rdict.py (original) +++ pypy/branch/adtmembers-fun/pypy/rpython/lltypesystem/rdict.py Thu Sep 3 11:32:17 2009 @@ -507,7 +507,6 @@ PERTURB_SHIFT = 5 def ll_dict_lookup(d, key, hash): - DICT = lltype.typeOf(d).TO entries = d.entries mask = len(entries) - 1 i = hash & mask @@ -520,7 +519,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if DICT.paranoia: + if d.paranoia: if (entries != d.entries or not entries.valid(i) or entries[i].key != checkingkey): # the compare did major nasty stuff to the dict: start over @@ -555,7 +554,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if DICT.paranoia: + if d.paranoia: if (entries != d.entries or not entries.valid(i) or entries[i].key != checkingkey): # the compare did major nasty stuff to the dict: From arigo at codespeak.net Thu Sep 3 11:50:26 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 11:50:26 +0200 (CEST) Subject: [pypy-svn] r67440 - in pypy/trunk/pypy/jit/backend: llgraph test Message-ID: <20090903095026.D7F07168009@codespeak.net> Author: arigo Date: Thu Sep 3 11:50:26 2009 New Revision: 67440 Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py pypy/trunk/pypy/jit/backend/test/runner_test.py Log: Oups. Fix runner_test: we no longer have CAST_INT_TO_PTR. Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/runner.py Thu Sep 3 11:50:26 2009 @@ -228,6 +228,9 @@ def cast_int_to_adr(self, int): return llimpl.cast_int_to_adr(self.memo_cast, int) + def cast_gcref_to_int(self, gcref): + return self.cast_adr_to_int(llmemory.cast_ptr_to_adr(gcref)) + class LLtypeCPU(BaseCPU): Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/runner_test.py (original) +++ pypy/trunk/pypy/jit/backend/test/runner_test.py Thu Sep 3 11:50:26 2009 @@ -620,14 +620,10 @@ x = lltype.cast_opaque_ptr(llmemory.GCREF, x) res = self.execute_operation(rop.CAST_PTR_TO_INT, [BoxPtr(x)], 'int').value - res2 = self.execute_operation(rop.CAST_INT_TO_PTR, - [BoxInt(res)], 'ref').value - x = lltype.cast_opaque_ptr(llmemory.GCREF, x) + assert res == self.cpu.cast_gcref_to_int(x) res = self.execute_operation(rop.CAST_PTR_TO_INT, [ConstPtr(x)], 'int').value - res2 = self.execute_operation(rop.CAST_INT_TO_PTR, - [ConstInt(res)], 'ref').value - assert res2 == x + assert res == self.cpu.cast_gcref_to_int(x) def test_ooops_non_gc(self): x = lltype.malloc(lltype.Struct('x'), flavor='raw') @@ -851,9 +847,7 @@ x = cpu.do_newstr([BoxInt(5)]) y = cpu.do_cast_ptr_to_int([x]) assert isinstance(y, BoxInt) - z = cpu.do_cast_int_to_ptr([y]) - assert isinstance(z, BoxPtr) - assert z.value == x.value + assert y.value == cpu.cast_gcref_to_int(x.value) def test_sorting_of_fields(self): S = self.S From fijal at codespeak.net Thu Sep 3 12:37:36 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 12:37:36 +0200 (CEST) Subject: [pypy-svn] r67441 - pypy/branch/no-recompilation/pypy/jit/backend/x86/test Message-ID: <20090903103736.DD25A16801B@codespeak.net> Author: fijal Date: Thu Sep 3 12:37:34 2009 New Revision: 67441 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Log: this test makes no longer sense, since we removed support for bridges Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Thu Sep 3 12:37:34 2009 @@ -586,18 +586,7 @@ ''' self.interpret(ops, []) assert not self.getptr(0, lltype.Ptr(self.S)) - - def test_rewrite_constptr_in_bridge(self): - ops = ''' - [i0] - guard_true(i0) - p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) - fail(p1) - fail(0) - ''' - self.interpret(ops, [0]) - assert not self.getptr(0, lltype.Ptr(self.S)) - + def test_bug_0(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] From fijal at codespeak.net Thu Sep 3 12:44:16 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 12:44:16 +0200 (CEST) Subject: [pypy-svn] r67442 - pypy/branch/no-recompilation/pypy/jit/backend/x86/test Message-ID: <20090903104416.C5E7216801D@codespeak.net> Author: fijal Date: Thu Sep 3 12:44:15 2009 New Revision: 67442 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Log: skip rest of tests that need support for bridges (also rewrite) Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Thu Sep 3 12:44:15 2009 @@ -2,6 +2,7 @@ """ Tests for register allocation for common constructs """ +import py from pypy.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ BoxPtr, ConstPtr, TreeLoop from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -269,6 +270,7 @@ assert self.getint(0) == 20 def test_two_loops_and_a_bridge(self): + py.test.skip("bridge support needed") ops = ''' [i0, i1, i2, i3] i4 = int_add(i0, 1) @@ -285,10 +287,17 @@ i4 = int_add(i3, 1) i2 = int_lt(i4, 30) guard_true(i2) - jump(i4, i4, i4, i4) + fail(i2) jump(i4) ''' loop2 = self.interpret(ops2, [0], jump_targets=[loop, 'self']) + bridge_ops = ''' + [i4] + jump(i4, i4, i4, i4) + ''' + xxx + bridge = self.attach_bridge(xxx) + assert self.getint(0) == 31 assert self.getint(1) == 30 assert self.getint(2) == 30 @@ -311,7 +320,7 @@ assert not self.cpu.assembler.fail_boxes_ptr[1] def test_exception_bridge_no_exception(self): - + py.test.skip("rewrite") ops = ''' [i0] @@ -334,6 +343,7 @@ # assert did not explode def test_nested_guards(self): + py.test.skip("rewrite") ops = ''' [i0, i1] guard_true(i0) From arigo at codespeak.net Thu Sep 3 13:03:51 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 13:03:51 +0200 (CEST) Subject: [pypy-svn] r67443 - in pypy/trunk/pypy: interpreter/astcompiler/tools module/_ast module/_ast/test module/parser module/parser/test module/token module/token/test Message-ID: <20090903110351.574B3168024@codespeak.net> Author: arigo Date: Thu Sep 3 13:03:50 2009 New Revision: 67443 Modified: pypy/trunk/pypy/interpreter/astcompiler/tools/ (props changed) pypy/trunk/pypy/module/_ast/ (props changed) pypy/trunk/pypy/module/_ast/__init__.py (props changed) pypy/trunk/pypy/module/_ast/test/ (props changed) pypy/trunk/pypy/module/_ast/test/__init__.py (props changed) pypy/trunk/pypy/module/_ast/test/test_ast.py (props changed) pypy/trunk/pypy/module/parser/ (props changed) pypy/trunk/pypy/module/parser/test/ (props changed) pypy/trunk/pypy/module/token/ (props changed) pypy/trunk/pypy/module/token/test/ (props changed) Log: fixeol From arigo at codespeak.net Thu Sep 3 13:08:34 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 13:08:34 +0200 (CEST) Subject: [pypy-svn] r67444 - in pypy/trunk/pypy/jit/backend: llsupport x86 Message-ID: <20090903110834.02C68168024@codespeak.net> Author: arigo Date: Thu Sep 3 13:08:34 2009 New Revision: 67444 Modified: pypy/trunk/pypy/jit/backend/llsupport/llmodel.py pypy/trunk/pypy/jit/backend/x86/assembler.py pypy/trunk/pypy/jit/backend/x86/runner.py Log: Move most of the support for exception out of the x86 backend, into llsupport. This is also needed to handle correctly the write barrier case mentioned in llmodel.py. Modified: pypy/trunk/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/trunk/pypy/jit/backend/llsupport/llmodel.py Thu Sep 3 13:08:34 2009 @@ -1,8 +1,10 @@ import sys from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr +from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.llinterp import LLInterpreter +from pypy.rpython.annlowlevel import llhelper from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.jit.metainterp.history import BoxInt, BoxPtr, set_future_values -from pypy.jit.metainterp.typesystem import llhelper from pypy.jit.backend.model import AbstractCPU from pypy.jit.backend.llsupport import symbolic from pypy.jit.backend.llsupport.symbolic import WORD, unroll_basic_sizes @@ -19,7 +21,7 @@ class AbstractLLCPU(AbstractCPU): - ts = llhelper + from pypy.jit.metainterp.typesystem import llhelper as ts def __init__(self, rtyper, stats, translate_support_code=False, gcdescr=None): @@ -37,6 +39,11 @@ translate_support_code) self._setup_prebuilt_error('ovf', OverflowError) self._setup_prebuilt_error('zer', ZeroDivisionError) + if translate_support_code: + self._setup_exception_handling_translated() + else: + self._setup_exception_handling_untranslated() + self.clear_exception() def set_class_sizes(self, class_sizes): self.class_sizes = class_sizes @@ -56,6 +63,91 @@ llmemory.cast_ptr_to_adr(ll_inst.typeptr)) setattr(self, '_%s_error_inst' % prefix, ll_inst) + + def _setup_exception_handling_untranslated(self): + # for running un-translated only, all exceptions occurring in the + # llinterpreter are stored in '_exception_emulator', which is then + # read back by the machine code reading at the address given by + # pos_exception() and pos_exc_value(). + _exception_emulator = lltype.malloc(rffi.CArray(lltype.Signed), 2, + zero=True, flavor='raw') + self._exception_emulator = _exception_emulator + + def _store_exception(lle): + self._last_exception = lle # keepalive + tp_i = rffi.cast(lltype.Signed, lle.args[0]) + v_i = rffi.cast(lltype.Signed, lle.args[1]) + _exception_emulator[0] = tp_i + _exception_emulator[1] = v_i + + self.debug_ll_interpreter = LLInterpreter(self.rtyper) + self.debug_ll_interpreter._store_exception = _store_exception + + def pos_exception(): + return rffi.cast(lltype.Signed, _exception_emulator) + + def pos_exc_value(): + return (rffi.cast(lltype.Signed, _exception_emulator) + + rffi.sizeof(lltype.Signed)) + + def save_exception(): + # copy from _exception_emulator to the real attributes on self + tp_i = _exception_emulator[0] + v_i = _exception_emulator[1] + _exception_emulator[0] = 0 + _exception_emulator[1] = 0 + self.saved_exception = tp_i + self.saved_exc_value = self._cast_int_to_gcref(v_i) + + self.pos_exception = pos_exception + self.pos_exc_value = pos_exc_value + self.save_exception = save_exception + + + def _setup_exception_handling_translated(self): + + def pos_exception(): + addr = llop.get_exception_addr(llmemory.Address) + return llmemory.cast_adr_to_int(addr) + + def pos_exc_value(): + addr = llop.get_exc_value_addr(llmemory.Address) + return llmemory.cast_adr_to_int(addr) + + def save_exception(): + addr = llop.get_exception_addr(llmemory.Address) + exception = rffi.cast(lltype.Signed, addr.address[0]) + addr.address[0] = llmemory.NULL + addr = llop.get_exc_value_addr(llmemory.Address) + exc_value = rffi.cast(llmemory.GCREF, addr.address[0]) + addr.address[0] = llmemory.NULL + # from now on, the state is again consistent -- no more RPython + # exception is set. The following code produces a write barrier + # in the assignment to self.saved_exc_value, as needed. + self.saved_exception = exception + self.saved_exc_value = exc_value + + self.pos_exception = pos_exception + self.pos_exc_value = pos_exc_value + self.save_exception = save_exception + + _SAVE_EXCEPTION_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) + + def get_save_exception_int(self): + f = llhelper(self._SAVE_EXCEPTION_FUNC, self.save_exception) + return rffi.cast(lltype.Signed, f) + + def get_exception(self): + return self.saved_exception + + def get_exc_value(self): + return self.saved_exc_value + + def clear_exception(self): + self.saved_exception = 0 + self.saved_exc_value = lltype.nullptr(llmemory.GCREF.TO) + + # ------------------- helpers and descriptions -------------------- @staticmethod Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py Thu Sep 3 13:08:34 2009 @@ -5,7 +5,6 @@ from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory from pypy.rpython.lltypesystem.rclass import OBJECT from pypy.rpython.lltypesystem.lloperation import llop -from pypy.annotation import model as annmodel from pypy.tool.uid import fixid from pypy.jit.backend.logger import Logger from pypy.jit.backend.x86.regalloc import (RegAlloc, WORD, REGS, TempBox, @@ -79,10 +78,6 @@ assert self.mcstack[self.counter - 1] is mc self.counter -= 1 -EXCEPTION_STORAGE = lltype.GcStruct('EXCEPTION_STORAGE', - ('type', lltype.Signed), - ('value', llmemory.GCREF)) - class Assembler386(object): mc = None @@ -97,10 +92,6 @@ self.malloc_array_func_addr = 0 self.malloc_str_func_addr = 0 self.malloc_unicode_func_addr = 0 - # The '_exception_emulator' is only used when non-translated. - # The '_exception_copy' is preallocated, so non-moving. - self._exception_emulator = lltype.malloc(EXCEPTION_STORAGE, zero=True) - self._exception_copy = lltype.malloc(EXCEPTION_STORAGE, zero=True) self.mcstack = MachineCodeStack() self.logger = Logger(cpu.ts) self.fail_boxes_int = lltype.malloc(lltype.GcArray(lltype.Signed), @@ -631,50 +622,20 @@ self.mc.TEST(loc, loc) self.implement_guard(addr, op, self.mc.JZ) - def pos_exception(self): - if we_are_translated(): - addr = llop.get_exception_addr(llmemory.Address) - return llmemory.cast_adr_to_int(addr) - else: - i = rffi.cast(lltype.Signed, self._exception_emulator) - return i + 0 # xxx hard-coded offset of 'type' when non-translated - - def pos_exc_value(self): - if we_are_translated(): - addr = llop.get_exc_value_addr(llmemory.Address) - return llmemory.cast_adr_to_int(addr) - else: - i = rffi.cast(lltype.Signed, self._exception_emulator) - return i + 4 # xxx hard-coded offset of 'value' when non-translated - - def pos_exception_copy(self): - i = rffi.cast(lltype.Signed, self._exception_copy) - if we_are_translated(): - return i + llmemory.offsetof(EXCEPTION_STORAGE, 'type') - else: - return i + 0 # xxx hard-coded offset of 'type' when non-translated - - def pos_exc_value_copy(self): - i = rffi.cast(lltype.Signed, self._exception_copy) - if we_are_translated(): - return i + llmemory.offsetof(EXCEPTION_STORAGE, 'value') - else: - return i + 4 # xxx hard-coded offset of 'value' when non-translated - def genop_guard_guard_no_exception(self, op, ign_1, addr, locs, ign_2): - self.mc.CMP(heap(self.pos_exception()), imm(0)) + self.mc.CMP(heap(self.cpu.pos_exception()), imm(0)) self.implement_guard(addr, op, self.mc.JNZ) def genop_guard_guard_exception(self, op, ign_1, addr, locs, resloc): loc = locs[0] loc1 = locs[1] - self.mc.MOV(loc1, heap(self.pos_exception())) + self.mc.MOV(loc1, heap(self.cpu.pos_exception())) self.mc.CMP(loc1, loc) self.implement_guard(addr, op, self.mc.JNE) if resloc is not None: - self.mc.MOV(resloc, heap(self.pos_exc_value())) - self.mc.MOV(heap(self.pos_exception()), imm(0)) - self.mc.MOV(heap(self.pos_exc_value()), imm(0)) + self.mc.MOV(resloc, heap(self.cpu.pos_exc_value())) + self.mc.MOV(heap(self.cpu.pos_exception()), imm(0)) + self.mc.MOV(heap(self.cpu.pos_exc_value()), imm(0)) def genop_guard_guard_no_overflow(self, op, ign_1, addr, locs, resloc): self.implement_guard(addr, op, self.mc.JO) @@ -740,7 +701,9 @@ imm(len(locs) * WORD)), eax) if exc: - self.generate_exception_handling(eax) + # note that we don't have to save and restore eax, ecx and edx here + addr = self.cpu.get_save_exception_int() + self.mc.CALL(rel32(addr)) # don't break the following code sequence! mc = self.mc._mc self.places_to_patch_framesize.append(mc.tell()) @@ -753,16 +716,6 @@ mc.POP(ebp) mc.RET() - def generate_exception_handling(self, loc): - self.mc.MOV(loc, heap(self.pos_exception())) - self.mc.MOV(heap(self.pos_exception_copy()), loc) - self.mc.MOV(loc, heap(self.pos_exc_value())) - self.mc.MOV(heap(self.pos_exc_value_copy()), loc) - # clean up the original exception, we don't want - # to enter more rpython code with exc set - self.mc.MOV(heap(self.pos_exception()), imm(0)) - self.mc.MOV(heap(self.pos_exc_value()), imm(0)) - @specialize.arg(3) def implement_guard(self, addr, guard_op, emit_jump): emit_jump(rel32(addr)) Modified: pypy/trunk/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/runner.py (original) +++ pypy/trunk/pypy/jit/backend/x86/runner.py Thu Sep 3 13:08:34 2009 @@ -21,16 +21,6 @@ gcdescr=None): AbstractLLCPU.__init__(self, rtyper, stats, translate_support_code, gcdescr) - if not translate_support_code: - self.current_interpreter = LLInterpreter(self.rtyper) - - def _store_exception(lle): - tp_i = self.cast_ptr_to_int(lle.args[0]) - v_i = lltype.cast_opaque_ptr(llmemory.GCREF, lle.args[1]) - self.assembler._exception_emulator.type = tp_i - self.assembler._exception_emulator.value = v_i - - self.current_interpreter._store_exception = _store_exception TP = lltype.GcArray(llmemory.GCREF) self._bootstrap_cache = {} self._guard_list = [] @@ -45,16 +35,6 @@ def setup_once(self): pass - def get_exception(self): - return self.assembler._exception_copy.type - - def get_exc_value(self): - return self.assembler._exception_copy.value - - def clear_exception(self): - self.assembler._exception_copy.type = 0 - self.assembler._exception_copy.value= lltype.nullptr(llmemory.GCREF.TO) - def compile_operations(self, tree, bridge=None): old_loop = tree._x86_compiled if old_loop: @@ -116,7 +96,7 @@ prev_interpreter = None if not self.translate_support_code: prev_interpreter = LLInterpreter.current_interpreter - LLInterpreter.current_interpreter = self.current_interpreter + LLInterpreter.current_interpreter = self.debug_ll_interpreter res = 0 try: self.caught_exception = None From fijal at codespeak.net Thu Sep 3 14:12:12 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 14:12:12 +0200 (CEST) Subject: [pypy-svn] r67445 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090903121212.4617816801B@codespeak.net> Author: fijal Date: Thu Sep 3 14:12:11 2009 New Revision: 67445 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py Log: Good, this is enough to pass the first test of recompilation series. Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Thu Sep 3 14:12:11 2009 @@ -140,50 +140,60 @@ return max_so_far def assemble_loop(self, loop): - self.assemble(loop) + self.assemble(loop, loop.operations, None) - def assemble(self, tree): + def assemble_from_guard(self, tree, guard_op): + newaddr = self.assemble(tree, guard_op.suboperations, guard_op) + # patch the jump from original guard + addr = guard_op._x86_addr + mc = codebuf.InMemoryCodeBuilder(addr, addr + 128) + mc.write(packimm32(newaddr - addr - 4)) + mc.done() + + def assemble(self, tree, operations, guard_op): self.places_to_patch_framesize = [] - self.jumps_to_look_at = [] + #self.jumps_to_look_at = [] # the last operation can be 'jump', 'return' or 'guard_pause'; # a 'jump' can either close a loop, or end a bridge to some # previously-compiled code. - self._compute_longest_fail_op(tree.operations) + self._compute_longest_fail_op(operations) self.tree = tree self.make_sure_mc_exists() - inputargs = tree.inputargs - self.logger.log_loop(tree) - regalloc = RegAlloc(self, tree, self.cpu.translate_support_code) + newpos = self.mc.tell() + regalloc = RegAlloc(self, tree, self.cpu.translate_support_code, + guard_op) self._regalloc = regalloc - regalloc.walk_operations(tree) - self.sanitize_tree(tree.operations) + if guard_op is None: + inputargs = tree.inputargs + self.logger.log_loop(tree) + regalloc.walk_operations(tree) + stack_words = regalloc.max_stack_depth + else: + inputargs = regalloc.inputargs + self.logger.log_operations + regalloc._walk_operations(operations) + stack_words = max(regalloc.max_stack_depth, + tree._x86_stack_depth) self.mc.done() self.mc2.done() - stack_words = regalloc.max_stack_depth # possibly align, e.g. for Mac OS X RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words stack_words = align_stack_words(stack_words + RET_BP) - tree._x86_stack_depth = stack_words - RET_BP + stack_depth = stack_words - RET_BP + if guard_op is None: + tree._x86_stack_depth = stack_words - RET_BP for place in self.places_to_patch_framesize: mc = codebuf.InMemoryCodeBuilder(place, place + 128) - mc.ADD(esp, imm32(tree._x86_stack_depth * WORD)) + mc.ADD(esp, imm32(stack_depth * WORD)) mc.done() - for op, pos in self.jumps_to_look_at: - if op.jump_target._x86_stack_depth != tree._x86_stack_depth: - tl = op.jump_target - self.patch_jump(pos, tl._x86_compiled, tl.arglocs, tl.arglocs, - tree._x86_stack_depth, tl._x86_stack_depth) + #for op, pos in self.jumps_to_look_at: + # if op.jump_target._x86_stack_depth != tree._x86_stack_depth: + # tl = op.jump_target + # self.patch_jump(pos, tl._x86_compiled, tl.arglocs, tl.arglocs, + # tree._x86_stack_depth, tl._x86_stack_depth) if we_are_translated(): self._regalloc = None # else keep it around for debugging - - def sanitize_tree(self, operations): - """ Cleans up all attributes attached by regalloc and backend - """ - for op in operations: - if op.is_guard(): - op.inputargs = None - op.longevity = None - self.sanitize_tree(op.suboperations) + return newpos def assemble_bootstrap_code(self, jumpaddr, arglocs, args, framesize): self.make_sure_mc_exists() @@ -609,6 +619,7 @@ # don't break the following code sequence! mc = self.mc._mc if op.jump_target is not self.tree: + xxx self.jumps_to_look_at.append((op, mc.tell())) mc.JMP(rel32(targetmp._x86_compiled)) if op.jump_target is not self.tree: @@ -666,6 +677,7 @@ return addr def generate_failure(self, mc, op, locs, exc): + assert op.opnum == rop.FAIL pos = mc.tell() for i in range(len(locs)): loc = locs[i] @@ -716,6 +728,7 @@ @specialize.arg(3) def implement_guard(self, addr, guard_op, emit_jump): emit_jump(rel32(addr)) + guard_op._x86_addr = self.mc.tell() - 4 def genop_call(self, op, arglocs, resloc): sizeloc = arglocs[0] Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py Thu Sep 3 14:12:11 2009 @@ -54,23 +54,50 @@ exc = False def __init__(self, assembler, tree, translate_support_code=False, - regalloc=None, guard_op=None): + guard_op=None): # variables that have place in register self.assembler = assembler self.translate_support_code = translate_support_code - assert regalloc is None cpu = self.assembler.cpu - cpu.gc_ll_descr.rewrite_assembler(cpu, tree.operations) - self.tree = tree self.reg_bindings = newcheckdict() self.stack_bindings = newcheckdict() - # compute longevity of variables - self._compute_vars_longevity(tree.inputargs, tree.operations) - self.free_regs = REGS[:] - jump = tree.operations[-1] - loop_consts = self._compute_loop_consts(tree.inputargs, jump) - self.loop_consts = loop_consts - self.current_stack_depth = 0 + self.tree = tree + if guard_op is not None: + locs = guard_op._x86_faillocs + inpargs, longevity = self._compute_inpargs(guard_op) + self.inputargs = inpargs + self.longevity = longevity + self.position = -1 + self._update_bindings(locs, inpargs) + self.current_stack_depth = guard_op._x86_stack_depth + cpu.gc_ll_descr.rewrite_assembler(cpu, guard_op.suboperations) + self.loop_consts = {} + else: + cpu.gc_ll_descr.rewrite_assembler(cpu, tree.operations) + self._compute_vars_longevity(tree.inputargs, tree.operations) + # compute longevity of variables + jump = tree.operations[-1] + loop_consts = self._compute_loop_consts(tree.inputargs, jump) + self.loop_consts = loop_consts + self.current_stack_depth = 0 + self.free_regs = REGS[:] + + def _update_bindings(self, locs, args): + assert len(locs) == len(args) + used = {} + for i in range(len(locs)): + v = args[i] + loc = locs[i] + if isinstance(loc, REG): + self.reg_bindings[v] = loc + used[loc] = None + else: + self.stack_bindings[v] = loc + self.free_regs = [] + for reg in REGS: + if reg not in used: + self.free_regs.append(reg) + self._check_invariants() def _compute_loop_consts(self, inputargs, jump): if jump.opnum != rop.JUMP or jump.jump_target is not self.tree: @@ -114,6 +141,7 @@ self.assembler.regalloc_perform(op, arglocs, result_loc) def perform_with_guard(self, op, guard_op, locs, arglocs, result_loc): + guard_op._x86_stack_depth = self.current_stack_depth if not we_are_translated(): self.assembler.dump('%s <- %s(%s) [GUARDED]' % (result_loc, op, arglocs)) @@ -121,6 +149,7 @@ arglocs, result_loc) def perform_guard(self, op, locs, arglocs, result_loc): + op._x86_stack_depth = self.current_stack_depth if not we_are_translated(): if result_loc is not None: self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) @@ -143,16 +172,15 @@ if operations[i + 1].args[0] is not op.result: return False if (self.longevity[op.result][1] > i + 1 or - op.result in operations[i + 1].inputargs): - #print "!!!! boolean flag not optimized away !!!!" + op.result in operations[i + 1].suboperations[0].args): return False return True def walk_operations(self, tree): # first pass - walk along the operations in order to find # load/store places - operations = tree.operations self.position = -1 + operations = tree.operations self.process_inputargs(tree) self._walk_operations(operations) @@ -183,11 +211,7 @@ i += 1 assert not self.reg_bindings jmp = operations[-1] - #if jmp.opnum == rop.JUMP and jmp.jump_target is not self.tree: - # self.max_stack_depth = max(jmp.jump_target._x86_stack_depth, - # self.max_stack_depth) - self.max_stack_depth = max(self.max_stack_depth, - self.current_stack_depth + 1) + self.max_stack_depth = self.current_stack_depth def _compute_vars_longevity(self, inputargs, operations): # compute a dictionary that maps variables to index in @@ -207,8 +231,7 @@ raise AssertionError longevity[arg] = (start_live[arg], i) if op.is_guard(): - self._compute_inpargs(op) - for arg in op.inputargs: + for arg in op.suboperations[0].args: if isinstance(arg, Box): if arg not in start_live: print "Bogus arg in guard %d at %d" % (op.opnum, i) @@ -222,16 +245,13 @@ self.longevity = longevity def _compute_inpargs(self, guard): - if guard.inputargs is not None: - return operations = guard.suboperations longevity = {} end = {} for i in range(len(operations)-1, -1, -1): op = operations[i] if op.is_guard(): - self._compute_inpargs(op) - for arg in op.inputargs: + for arg in op.suboperations[0].args: if isinstance(arg, Box) and arg not in end: end[arg] = i for arg in op.args: @@ -244,12 +264,12 @@ # otherwise this var is never ever used for v, e in end.items(): longevity[v] = (0, e) - guard.longevity = longevity - guard.inputargs = end.keys() + inputargs = end.keys() for arg in longevity: assert isinstance(arg, Box) - for arg in guard.inputargs: + for arg in inputargs: assert isinstance(arg, Box) + return inputargs, longevity def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): assert not isinstance(v, Const) @@ -490,7 +510,7 @@ locs = self.locs_for_fail(op) self.perform_guard(op, locs, [loc], None) self.eventually_free_var(op.args[0]) - self.eventually_free_vars(op.inputargs) + self.eventually_free_vars(op.suboperations[0].args) consider_guard_true = _consider_guard consider_guard_false = _consider_guard @@ -504,7 +524,7 @@ def consider_guard_no_exception(self, op, ignored): faillocs = self.locs_for_fail(op) self.perform_guard(op, faillocs, [], None) - self.eventually_free_vars(op.inputargs) + self.eventually_free_vars(op.suboperations[0].args) def consider_guard_exception(self, op, ignored): loc = self.make_sure_var_in_reg(op.args[0], []) @@ -517,7 +537,7 @@ resloc = None faillocs = self.locs_for_fail(op) self.perform_guard(op, faillocs, [loc, loc1], resloc) - self.eventually_free_vars(op.inputargs) + self.eventually_free_vars(op.suboperations[0].args) self.eventually_free_vars(op.args) self.eventually_free_var(box) @@ -529,7 +549,7 @@ y = self.loc(op.args[1]) faillocs = self.locs_for_fail(op) self.perform_guard(op, faillocs, [x, y], None) - self.eventually_free_vars(op.inputargs) + self.eventually_free_vars(op.suboperations[0].args) self.eventually_free_vars(op.args) def consider_guard_class(self, op, ignored): @@ -538,7 +558,7 @@ y = self.loc(op.args[1]) faillocs = self.locs_for_fail(op) self.perform_guard(op, faillocs, [x, y], None) - self.eventually_free_vars(op.inputargs) + self.eventually_free_vars(op.suboperations[0].args) self.eventually_free_vars(op.args) def _consider_binop_part(self, op, ignored): @@ -621,7 +641,7 @@ self.position += 1 self.perform_with_guard(op, guard_op, faillocs, arglocs, None) self.eventually_free_var(op.result) - self.eventually_free_vars(guard_op.inputargs) + self.eventually_free_vars(guard_op.suboperations[0].args) consider_int_lt = _consider_compop consider_int_gt = _consider_compop @@ -845,7 +865,7 @@ self.position += 1 self.perform_with_guard(op, guard_op, faillocs, [argloc], None) self.eventually_free_var(op.result) - self.eventually_free_vars(guard_op.inputargs) + self.eventually_free_vars(guard_op.suboperations[0].args) else: argloc = self.loc(op.args[0]) self.eventually_free_var(op.args[0]) Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py Thu Sep 3 14:12:11 2009 @@ -60,8 +60,9 @@ def compile_operations(self, tree, guard_op=None): if guard_op is not None: - self.assembler.assemble_from_guard(guard_op) - self.assembler.assemble_loop(tree) + self.assembler.assemble_from_guard(tree, guard_op) + else: + self.assembler.assemble_loop(tree) def get_bootstrap_code(self, loop): addr = loop._x86_bootstrap_code From arigo at codespeak.net Thu Sep 3 14:25:08 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 14:25:08 +0200 (CEST) Subject: [pypy-svn] r67446 - in pypy/trunk/pypy: annotation rpython/lltypesystem rpython/lltypesystem/test rpython/test Message-ID: <20090903122508.DD21A16801D@codespeak.net> Author: arigo Date: Thu Sep 3 14:25:03 2009 New Revision: 67446 Modified: pypy/trunk/pypy/annotation/model.py pypy/trunk/pypy/annotation/unaryop.py pypy/trunk/pypy/rpython/lltypesystem/lltype.py pypy/trunk/pypy/rpython/lltypesystem/rdict.py pypy/trunk/pypy/rpython/lltypesystem/test/test_lltype.py pypy/trunk/pypy/rpython/test/test_llann.py Log: Merge branch/adtmembers-fun: fix for the syntax 'p.name', for a low-level pointer p and a name that is an ADT member in the type of p. The issue was that this can run directly or on top of the llinterp, but not when translated to C. Modified: pypy/trunk/pypy/annotation/model.py ============================================================================== --- pypy/trunk/pypy/annotation/model.py (original) +++ pypy/trunk/pypy/annotation/model.py Thu Sep 3 14:25:03 2009 @@ -632,15 +632,6 @@ # i think we can only get here in the case of void-returning # functions return s_None - if isinstance(v, MethodType): - ll_ptrtype = lltype.typeOf(v.im_self) - assert isinstance(ll_ptrtype, (lltype.Ptr, lltype.InteriorPtr)) - return SomeLLADTMeth(ll_ptrtype, v.im_func) - if isinstance(v, FunctionType): - # this case should only be for staticmethod instances used in - # adtmeths: the getattr() result is then a plain FunctionType object. - from pypy.annotation.bookkeeper import getbookkeeper - return getbookkeeper().immutablevalue(v) if isinstance(v, lltype._interior_ptr): ob = v._parent if ob is None: Modified: pypy/trunk/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/pypy/annotation/unaryop.py (original) +++ pypy/trunk/pypy/annotation/unaryop.py Thu Sep 3 14:25:03 2009 @@ -2,6 +2,7 @@ Unary operations on SomeValues. """ +from types import MethodType from pypy.annotation.model import \ SomeObject, SomeInteger, SomeBool, SomeString, SomeChar, SomeList, \ SomeDict, SomeTuple, SomeImpossibleValue, \ @@ -727,8 +728,19 @@ def getattr(p, s_attr): assert s_attr.is_constant(), "getattr on ptr %r with non-constant field-name" % p.ll_ptrtype - v = getattr(p.ll_ptrtype._example(), s_attr.const) - return ll_to_annotation(v) + example = p.ll_ptrtype._example() + try: + v = example._lookup_adtmeth(s_attr.const) + except AttributeError: + v = getattr(example, s_attr.const) + return ll_to_annotation(v) + else: + if isinstance(v, MethodType): + from pypy.rpython.lltypesystem import lltype + ll_ptrtype = lltype.typeOf(v.im_self) + assert isinstance(ll_ptrtype, (lltype.Ptr, lltype.InteriorPtr)) + return SomeLLADTMeth(ll_ptrtype, v.im_func) + return getbookkeeper().immutablevalue(v) getattr.can_only_throw = [] def len(p): Modified: pypy/trunk/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/lltype.py Thu Sep 3 14:25:03 2009 @@ -994,25 +994,31 @@ return (type(self._obj0) not in (type(None), int) and self._getobj(check=False)._was_freed()) - def __getattr__(self, field_name): # ! can only return basic or ptr ! - if isinstance(self._T, Struct): - if field_name in self._T._flds: - o = self._obj._getattr(field_name) - return self._expose(field_name, o) + def _lookup_adtmeth(self, member_name): if isinstance(self._T, ContainerType): try: - adtmeth = self._T._adtmeths[field_name] + adtmember = self._T._adtmeths[member_name] except KeyError: pass else: try: - getter = adtmeth.__get__ + getter = adtmember.__get__ except AttributeError: - return adtmeth + return adtmember else: return getter(self) - raise AttributeError("%r instance has no field %r" % (self._T, - field_name)) + raise AttributeError + + def __getattr__(self, field_name): # ! can only return basic or ptr ! + if isinstance(self._T, Struct): + if field_name in self._T._flds: + o = self._obj._getattr(field_name) + return self._expose(field_name, o) + try: + return self._lookup_adtmeth(field_name) + except AttributeError: + raise AttributeError("%r instance has no field %r" % (self._T, + field_name)) def __setattr__(self, field_name, val): if isinstance(self._T, Struct): Modified: pypy/trunk/pypy/rpython/lltypesystem/rdict.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/rdict.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/rdict.py Thu Sep 3 14:25:03 2009 @@ -507,7 +507,6 @@ PERTURB_SHIFT = 5 def ll_dict_lookup(d, key, hash): - DICT = lltype.typeOf(d).TO entries = d.entries mask = len(entries) - 1 i = hash & mask @@ -520,7 +519,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if DICT.paranoia: + if d.paranoia: if (entries != d.entries or not entries.valid(i) or entries[i].key != checkingkey): # the compare did major nasty stuff to the dict: start over @@ -555,7 +554,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if DICT.paranoia: + if d.paranoia: if (entries != d.entries or not entries.valid(i) or entries[i].key != checkingkey): # the compare did major nasty stuff to the dict: Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_lltype.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/test/test_lltype.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/test/test_lltype.py Thu Sep 3 14:25:03 2009 @@ -528,7 +528,8 @@ A = GcArray(Signed, adtmeths={"h_alloc": h_alloc, - "h_length": h_length}) + "h_length": h_length, + "stuff": 12}) a = A.h_alloc(10) @@ -536,6 +537,9 @@ assert len(a) == 10 assert a.h_length() == 10 + assert a._lookup_adtmeth("h_length")() == 10 + assert a.stuff == 12 + assert a._lookup_adtmeth("stuff") == 12 def test_adt_typemethod(): def h_newstruct(S): Modified: pypy/trunk/pypy/rpython/test/test_llann.py ============================================================================== --- pypy/trunk/pypy/rpython/test/test_llann.py (original) +++ pypy/trunk/pypy/rpython/test/test_llann.py Thu Sep 3 14:25:03 2009 @@ -389,6 +389,26 @@ lst.append(6) self.annotate(llf, []) + def test_adtmeths(self): + def h_length(s): + return s.foo + S = GcStruct("S", ('foo', Signed), + adtmeths={"h_length": h_length, + "stuff": 12}) + def llf(): + s = malloc(S) + s.foo = 321 + return s.h_length() + s = self.annotate(llf, []) + assert s.knowntype == int and not s.is_constant() + + def llf(): + s = malloc(S) + return s.stuff + s = self.annotate(llf, []) + assert s.is_constant() and s.const == 12 + + def test_pseudohighlevelcallable(): t = TranslationContext() t.buildannotator() From arigo at codespeak.net Thu Sep 3 14:25:16 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 14:25:16 +0200 (CEST) Subject: [pypy-svn] r67447 - pypy/branch/adtmembers-fun Message-ID: <20090903122516.35AD4168026@codespeak.net> Author: arigo Date: Thu Sep 3 14:25:14 2009 New Revision: 67447 Removed: pypy/branch/adtmembers-fun/ Log: Remove the merged branch. From fijal at codespeak.net Thu Sep 3 14:33:18 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 14:33:18 +0200 (CEST) Subject: [pypy-svn] r67448 - in pypy/branch/no-recompilation/pypy/jit/backend/x86: . test Message-ID: <20090903123318.568BE16801D@codespeak.net> Author: fijal Date: Thu Sep 3 14:33:17 2009 New Revision: 67448 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py Log: correctly adjust stack depth. Make sure test actually contains bridge that changes stack depth Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Thu Sep 3 14:33:17 2009 @@ -171,6 +171,9 @@ else: inputargs = regalloc.inputargs self.logger.log_operations + mc = self.mc._mc + adr_sub = mc.tell() + mc.SUB(esp, imm32(0)) regalloc._walk_operations(operations) stack_words = max(regalloc.max_stack_depth, tree._x86_stack_depth) @@ -182,6 +185,13 @@ stack_depth = stack_words - RET_BP if guard_op is None: tree._x86_stack_depth = stack_words - RET_BP + else: + guard_op._x86_stack_depth = stack_words + if stack_words - RET_BP != tree._x86_stack_depth: + mc = codebuf.InMemoryCodeBuilder(adr_sub, adr_sub + 128) + mc.SUB(esp, imm32((stack_words - RET_BP - + tree._x86_stack_depth) * WORD)) + mc.done() for place in self.places_to_patch_framesize: mc = codebuf.InMemoryCodeBuilder(place, place + 128) mc.ADD(esp, imm32(stack_depth * WORD)) Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py Thu Sep 3 14:33:17 2009 @@ -35,6 +35,7 @@ jump(i1) ''' loop = self.interpret(ops, [0]) + previous = loop._x86_stack_depth assert self.getint(0) == 20 ops = ''' [i1] @@ -42,9 +43,14 @@ i4 = int_add(i3, 1) i5 = int_add(i4, 1) i6 = int_add(i5, 1) - fail(i3, i4, i5, i6) + i7 = int_add(i5, i4) + i8 = int_add(i7, 1) + i9 = int_add(i8, 1) + fail(i3, i4, i5, i6, i7, i8, i9) ''' bridge = self.attach_bridge(ops, loop, loop.operations[-2]) + new = loop.operations[2]._x86_stack_depth + assert new > previous self.cpu.set_future_value_int(0, 0) op = self.cpu.execute_operations(loop) assert op is bridge.operations[-1] From arigo at codespeak.net Thu Sep 3 16:22:31 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 16:22:31 +0200 (CEST) Subject: [pypy-svn] r67449 - pypy/branch/weakdict Message-ID: <20090903142231.053F216801B@codespeak.net> Author: arigo Date: Thu Sep 3 16:22:27 2009 New Revision: 67449 Added: pypy/branch/weakdict/ - copied from r67448, pypy/trunk/ Log: A branch in which to try to implement RPythonic weak-valued dicts. From arigo at codespeak.net Thu Sep 3 16:23:17 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 16:23:17 +0200 (CEST) Subject: [pypy-svn] r67450 - pypy/trunk/pypy/rlib Message-ID: <20090903142317.A51F7168013@codespeak.net> Author: arigo Date: Thu Sep 3 16:23:17 2009 New Revision: 67450 Modified: pypy/trunk/pypy/rlib/objectmodel.py Log: Avoid extreme confusion when we write e.g. @specialize.memo instead of @specialize.memo() Modified: pypy/trunk/pypy/rlib/objectmodel.py ============================================================================== --- pypy/trunk/pypy/rlib/objectmodel.py (original) +++ pypy/trunk/pypy/rlib/objectmodel.py Thu Sep 3 16:23:17 2009 @@ -31,6 +31,7 @@ specialcase = "specialize:%s%s" % (self.tag, args) def specialize_decorator(func): + "NOT_RPYTHON" func._annspecialcase_ = specialcase return func From arigo at codespeak.net Thu Sep 3 16:25:28 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 16:25:28 +0200 (CEST) Subject: [pypy-svn] r67451 - in pypy/branch/weakdict/pypy/rlib: . test Message-ID: <20090903142528.C7153168013@codespeak.net> Author: arigo Date: Thu Sep 3 16:25:27 2009 New Revision: 67451 Added: pypy/branch/weakdict/pypy/rlib/rweakref.py (contents, props changed) pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py (contents, props changed) pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py (contents, props changed) Log: Start an implementation of RWeakValueDictionary using the controller mechanism for RTyping it. Added: pypy/branch/weakdict/pypy/rlib/rweakref.py ============================================================================== --- (empty file) +++ pypy/branch/weakdict/pypy/rlib/rweakref.py Thu Sep 3 16:25:27 2009 @@ -0,0 +1,45 @@ +""" +Weakref support in RPython. Supports ref() without callbacks, +and a limited version of WeakValueDictionary. LLType only for now! +""" + +import weakref +from weakref import ref + + +class RWeakValueDictionary(object): + """A limited dictionary containing weak values. + Only supports string keys. + """ + + def __init__(self, valueclass): + self._dict = weakref.WeakValueDictionary() + self._valueclass = valueclass + + def get(self, key): + return self._dict.get(key, None) + + def set(self, key, value): + if value is None: + self._dict.pop(key, None) + else: + assert isinstance(value, self._valueclass) + self._dict[key] = value + + +# ____________________________________________________________ + +from pypy.rpython import controllerentry + + at staticmethod +def _get_controller(): + from pypy.rlib.rweakrefimpl import WeakDictController + return WeakDictController() + +class Entry(controllerentry.ControllerEntry): + _about_ = RWeakValueDictionary + _controller_ = _get_controller + +class Entry(controllerentry.ControllerEntryForPrebuilt): + _type_ = RWeakValueDictionary + _controller_ = _get_controller Added: pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py ============================================================================== --- (empty file) +++ pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py Thu Sep 3 16:25:27 2009 @@ -0,0 +1,77 @@ +from pypy.rpython.lltypesystem import lltype, rstr, rclass, rdict +from pypy.rpython.controllerentry import Controller +from pypy.rpython.annlowlevel import llstr, cast_base_ptr_to_instance +from pypy.rpython.annlowlevel import cast_instance_to_base_ptr +from pypy.rlib.objectmodel import specialize +from pypy.rlib.rweakref import RWeakValueDictionary + + +class WeakDictController(Controller): + knowntype = RWeakValueDictionary + + @specialize.arg(1) + def new(self, valueclass): + d = lltype.malloc(get_WEAKDICT(valueclass)) + entries = lltype.malloc(WEAKDICTENTRYARRAY, DICT_INITSIZE) + for i in range(DICT_INITSIZE): + entries[i].key = pristine_marker + d.entries = entries + return d + + def get_get(self, d): + return d.ll_get + + def get_set(self, d): + return d.ll_set + + +pristine_marker = lltype.malloc(rstr.STR, 0) +DICT_INITSIZE = 8 + +WEAKDICTENTRY = lltype.Struct("weakdictentry", + ("key", lltype.Ptr(rstr.STR)), + ("value", rclass.OBJECTPTR)) + +def ll_valid(entries, i): + key = entries[i].key + return key != pristine_marker and bool(key) + +def ll_everused(entries, i): + key = entries[i].key + return key != pristine_marker + +entrymeths = { + 'valid': ll_valid, + 'everused': ll_everused, + } +WEAKDICTENTRYARRAY = lltype.GcArray(WEAKDICTENTRY, + adtmeths=entrymeths, + hints={'weakarray': 'value'}) + +def ll_get(d, key): + llkey = llstr(key) + i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) + llvalue = d.entries[i].value + return cast_base_ptr_to_instance(d.valueclass, llvalue) + +def ll_set(d, key, value): + llkey = llstr(key) + llvalue = cast_instance_to_base_ptr(value) + i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) + d.entries[i].key = llkey + d.entries[i].value = llvalue + +dictmeths = { + 'll_get': ll_get, + 'll_set': ll_set, + 'keyeq': None, + } + + at specialize.memo() +def get_WEAKDICT(valueclass): + adtmeths = dictmeths.copy() + adtmeths['valueclass'] = valueclass + WEAKDICT = lltype.GcStruct("weakdict", + ("entries", lltype.Ptr(WEAKDICTENTRYARRAY)), + adtmeths=adtmeths) + return WEAKDICT Added: pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py ============================================================================== --- (empty file) +++ pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py Thu Sep 3 16:25:27 2009 @@ -0,0 +1,42 @@ +from pypy.rlib import rgc +from pypy.rlib.rweakref import RWeakValueDictionary +from pypy.rpython.test.test_llinterp import interpret + +class X(object): + pass + + +def test_RWeakValueDictionary(): + d = RWeakValueDictionary(X) + assert d.get("hello") is None + x1 = X(); x2 = X(); x3 = X() + d.set("abc", x1) + d.set("def", x2) + d.set("ghi", x3) + assert d.get("abc") is x1 + assert d.get("def") is x2 + assert d.get("ghi") is x3 + assert d.get("hello") is None + x2 = None + rgc.collect(); rgc.collect() + assert d.get("abc") is x1 + assert d.get("def") is None + assert d.get("ghi") is x3 + assert d.get("hello") is None + d.set("abc", None) + assert d.get("abc") is None + assert d.get("def") is None + assert d.get("ghi") is x3 + assert d.get("hello") is None + # resizing should also work + for i in range(100): + d.set(str(i), x1) + for i in range(100): + assert d.get(str(i)) is x1 + assert d.get("abc") is None + assert d.get("def") is None + assert d.get("ghi") is x3 + assert d.get("hello") is None + +#def test_rpython_RWeakValueDictionary(): +# interpret(test_RWeakValueDictionary, []) From arigo at codespeak.net Thu Sep 3 17:24:49 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 17:24:49 +0200 (CEST) Subject: [pypy-svn] r67452 - in pypy/branch/weakdict/pypy/rlib: . test Message-ID: <20090903152449.264DB168013@codespeak.net> Author: arigo Date: Thu Sep 3 17:24:47 2009 New Revision: 67452 Modified: pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py Log: Finish and test rweakrefimpl.py. Modified: pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py ============================================================================== --- pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py (original) +++ pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py Thu Sep 3 17:24:47 2009 @@ -1,7 +1,7 @@ from pypy.rpython.lltypesystem import lltype, rstr, rclass, rdict from pypy.rpython.controllerentry import Controller -from pypy.rpython.annlowlevel import llstr, cast_base_ptr_to_instance -from pypy.rpython.annlowlevel import cast_instance_to_base_ptr +from pypy.rpython.annlowlevel import cast_base_ptr_to_instance +from pypy.rpython.annlowlevel import cast_instance_to_base_ptr, llstr from pypy.rlib.objectmodel import specialize from pypy.rlib.rweakref import RWeakValueDictionary @@ -11,11 +11,10 @@ @specialize.arg(1) def new(self, valueclass): - d = lltype.malloc(get_WEAKDICT(valueclass)) - entries = lltype.malloc(WEAKDICTENTRYARRAY, DICT_INITSIZE) - for i in range(DICT_INITSIZE): - entries[i].key = pristine_marker - d.entries = entries + WEAKDICT = get_WEAKDICT(valueclass) + d = lltype.malloc(WEAKDICT) + d.entries = WEAKDICT.entries.TO.allocate(DICT_INITSIZE) + d.num_pristine_entries = DICT_INITSIZE return d def get_get(self, d): @@ -40,9 +39,23 @@ key = entries[i].key return key != pristine_marker +str_fasthashfn = rstr.string_repr.get_ll_fasthash_function() + +def ll_hash(entries, i): + return str_fasthashfn(entries[i].key) + +def ll_malloc_entries_and_initialize(ENTRIES, n): + entries = lltype.malloc(ENTRIES, n, zero=True) + for i in range(n): + entries[i].key = pristine_marker + return entries + entrymeths = { + 'allocate': lltype.typeMethod(ll_malloc_entries_and_initialize), + 'delete': rdict._ll_free_entries, 'valid': ll_valid, 'everused': ll_everused, + 'hash': ll_hash, } WEAKDICTENTRYARRAY = lltype.GcArray(WEAKDICTENTRY, adtmeths=entrymeths, @@ -50,21 +63,49 @@ def ll_get(d, key): llkey = llstr(key) - i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) + hash = llkey.gethash() + i = rdict.ll_dict_lookup(d, llkey, hash) llvalue = d.entries[i].value + #print 'get', i, key, hash, llvalue return cast_base_ptr_to_instance(d.valueclass, llvalue) def ll_set(d, key, value): llkey = llstr(key) llvalue = cast_instance_to_base_ptr(value) - i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) + hash = llkey.gethash() + i = rdict.ll_dict_lookup(d, llkey, hash) + everused = d.entries.everused(i) + #print 'set', i, key, hash, llvalue d.entries[i].key = llkey d.entries[i].value = llvalue + if not everused: + d.num_pristine_entries -= 1 + #print 'num_pristine_entries:', d.num_pristine_entries + if d.num_pristine_entries <= len(d.entries) / 3: + ll_weakdict_resize(d) + else: + pass #print 'entry reused' + +def ll_weakdict_resize(d): + # first set num_items to its correct, up-to-date value + #print 'in ll_weakdict_resize' + entries = d.entries + num_items = 0 + for i in range(len(entries)): + if entries.valid(i): + num_items += 1 + d.num_items = num_items + #print 'num_items:', num_items + rdict.ll_dict_resize(d) + #print 'resized.' + +str_keyeq = lltype.staticAdtMethod(rstr.string_repr.get_ll_eq_function()) dictmeths = { 'll_get': ll_get, 'll_set': ll_set, - 'keyeq': None, + 'keyeq': str_keyeq, + 'paranoia': False, } @specialize.memo() @@ -72,6 +113,8 @@ adtmeths = dictmeths.copy() adtmeths['valueclass'] = valueclass WEAKDICT = lltype.GcStruct("weakdict", + ("num_items", lltype.Signed), + ("num_pristine_entries", lltype.Signed), ("entries", lltype.Ptr(WEAKDICTENTRYARRAY)), adtmeths=adtmeths) return WEAKDICT Modified: pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py ============================================================================== --- pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py (original) +++ pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py Thu Sep 3 17:24:47 2009 @@ -6,37 +6,45 @@ pass +def make_test(go_away=True, loop=100): + def f(): + d = RWeakValueDictionary(X) + assert d.get("hello") is None + x1 = X(); x2 = X(); x3 = X() + d.set("abc", x1) + d.set("def", x2) + d.set("ghi", x3) + assert d.get("abc") is x1 + assert d.get("def") is x2 + assert d.get("ghi") is x3 + assert d.get("hello") is None + if go_away: + x2 = None + rgc.collect(); rgc.collect() + assert d.get("abc") is x1 + assert d.get("def") is x2 + assert d.get("ghi") is x3 + assert d.get("hello") is None + d.set("abc", None) + assert d.get("abc") is None + assert d.get("def") is x2 + assert d.get("ghi") is x3 + assert d.get("hello") is None + # resizing should also work + for i in range(loop): + d.set(str(i), x1) + for i in range(loop): + assert d.get(str(i)) is x1 + assert d.get("abc") is None + assert d.get("def") is x2 + assert d.get("ghi") is x3 + assert d.get("hello") is None + return f + def test_RWeakValueDictionary(): - d = RWeakValueDictionary(X) - assert d.get("hello") is None - x1 = X(); x2 = X(); x3 = X() - d.set("abc", x1) - d.set("def", x2) - d.set("ghi", x3) - assert d.get("abc") is x1 - assert d.get("def") is x2 - assert d.get("ghi") is x3 - assert d.get("hello") is None - x2 = None - rgc.collect(); rgc.collect() - assert d.get("abc") is x1 - assert d.get("def") is None - assert d.get("ghi") is x3 - assert d.get("hello") is None - d.set("abc", None) - assert d.get("abc") is None - assert d.get("def") is None - assert d.get("ghi") is x3 - assert d.get("hello") is None - # resizing should also work - for i in range(100): - d.set(str(i), x1) - for i in range(100): - assert d.get(str(i)) is x1 - assert d.get("abc") is None - assert d.get("def") is None - assert d.get("ghi") is x3 - assert d.get("hello") is None + make_test()() -#def test_rpython_RWeakValueDictionary(): -# interpret(test_RWeakValueDictionary, []) +def test_rpython_RWeakValueDictionary(): + # we don't implement the correct weakref behavior in lltype when + # directly interpreted, but we can still test that the rest works. + interpret(make_test(go_away=False, loop=12), []) From iko at codespeak.net Thu Sep 3 17:43:50 2009 From: iko at codespeak.net (iko at codespeak.net) Date: Thu, 3 Sep 2009 17:43:50 +0200 (CEST) Subject: [pypy-svn] r67453 - pypy/extradoc/planning Message-ID: <20090903154350.85DAC168013@codespeak.net> Author: iko Date: Thu Sep 3 17:43:49 2009 New Revision: 67453 Modified: pypy/extradoc/planning/jit.txt Log: benchmarking infrastructure Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Thu Sep 3 17:43:49 2009 @@ -7,7 +7,9 @@ - upgrade python on wyvern - improve test running, compile only once -- sort out a benchmark infrastructure. graphs!!! + +- sort out a benchmark infrastructure. graphs!!! (iko is going to do + some sorting) - nightly run of checks on output of pypy-c-jit: we need tests for pypy-jit behaviour that explicitely check whether the loops make From fijal at codespeak.net Thu Sep 3 18:43:39 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 18:43:39 +0200 (CEST) Subject: [pypy-svn] r67454 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090903164339.C86BD16802F@codespeak.net> Author: fijal Date: Thu Sep 3 18:43:38 2009 New Revision: 67454 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Log: Simplification - kill places_to_patch_framesizes and use lea instead for failures Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Thu Sep 3 18:43:38 2009 @@ -151,8 +151,6 @@ mc.done() def assemble(self, tree, operations, guard_op): - self.places_to_patch_framesize = [] - #self.jumps_to_look_at = [] # the last operation can be 'jump', 'return' or 'guard_pause'; # a 'jump' can either close a loop, or end a bridge to some # previously-compiled code. @@ -192,15 +190,6 @@ mc.SUB(esp, imm32((stack_words - RET_BP - tree._x86_stack_depth) * WORD)) mc.done() - for place in self.places_to_patch_framesize: - mc = codebuf.InMemoryCodeBuilder(place, place + 128) - mc.ADD(esp, imm32(stack_depth * WORD)) - mc.done() - #for op, pos in self.jumps_to_look_at: - # if op.jump_target._x86_stack_depth != tree._x86_stack_depth: - # tl = op.jump_target - # self.patch_jump(pos, tl._x86_compiled, tl.arglocs, tl.arglocs, - # tree._x86_stack_depth, tl._x86_stack_depth) if we_are_translated(): self._regalloc = None # else keep it around for debugging return newpos @@ -628,14 +617,8 @@ targetmp = op.jump_target # don't break the following code sequence! mc = self.mc._mc - if op.jump_target is not self.tree: - xxx - self.jumps_to_look_at.append((op, mc.tell())) + #mc.SUB(esp, targetmp._x86_compiled - xxx) mc.JMP(rel32(targetmp._x86_compiled)) - if op.jump_target is not self.tree: - # Reserve 6 bytes for a possible later patch by patch_jump(). - # Put them after the JMP by default, as it's not doing anything. - mc.SUB(esp, imm32(0)) def genop_guard_guard_true(self, op, ign_1, addr, locs, ign_2): loc = locs[0] @@ -715,8 +698,7 @@ self.generate_exception_handling(mc, eax) # don't break the following code sequence! mc = mc._mc - self.places_to_patch_framesize.append(mc.tell()) - mc.ADD(esp, imm32(0)) + mc.LEA(esp, addr_add(imm(0), ebp, -3 * WORD)) guard_index = self.cpu.make_guard_index(op) mc.MOV(eax, imm(guard_index)) mc.POP(edi) From arigo at codespeak.net Thu Sep 3 19:10:40 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 19:10:40 +0200 (CEST) Subject: [pypy-svn] r67455 - in pypy/branch/weakdict/pypy/rlib: . test Message-ID: <20090903171040.F052C16800C@codespeak.net> Author: arigo Date: Thu Sep 3 19:10:40 2009 New Revision: 67455 Modified: pypy/branch/weakdict/pypy/rlib/rweakref.py pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py Log: Pff. Rewrite it "the long and boring way". Indeed, controllerentry is yet again not the right thing -- there is a level mismatch when trying to pass test_rpython_prebuilt. Modified: pypy/branch/weakdict/pypy/rlib/rweakref.py ============================================================================== --- pypy/branch/weakdict/pypy/rlib/rweakref.py (original) +++ pypy/branch/weakdict/pypy/rlib/rweakref.py Thu Sep 3 19:10:40 2009 @@ -29,17 +29,48 @@ # ____________________________________________________________ -from pypy.rpython import controllerentry +from pypy.rpython import extregistry +from pypy.annotation import model as annmodel +from pypy.annotation.bookkeeper import getbookkeeper - at staticmethod -def _get_controller(): - from pypy.rlib.rweakrefimpl import WeakDictController - return WeakDictController() +class SomeWeakValueDict(annmodel.SomeObject): + knowntype = RWeakValueDictionary -class Entry(controllerentry.ControllerEntry): + def __init__(self, valueclassdef): + self.valueclassdef = valueclassdef + + def rtyper_makerepr(self, rtyper): + from pypy.rlib import rweakrefimpl + return rweakrefimpl.WeakValueDictRepr(rtyper) + + def rtyper_makekey_ex(self, rtyper): + return self.__class__, + + def method_get(self, s_key): + assert isinstance(s_key, annmodel.SomeString) + return annmodel.SomeInstance(self.valueclassdef, can_be_None=True) + + def method_set(self, s_key, s_value): + s_oldvalue = self.method_get(s_key) + assert s_oldvalue.contains(s_value) + +class Entry(extregistry.ExtRegistryEntry): _about_ = RWeakValueDictionary - _controller_ = _get_controller -class Entry(controllerentry.ControllerEntryForPrebuilt): + def compute_result_annotation(self, s_valueclass): + assert isinstance(s_valueclass, annmodel.SomePBC) + assert s_valueclass.is_constant() + [desc] = s_valueclass.descriptions + return SomeWeakValueDict(desc.getuniqueclassdef()) + + def specialize_call(self, hop): + from pypy.rlib import rweakrefimpl + return rweakrefimpl.specialize_make_weakdict(hop) + +class Entry(extregistry.ExtRegistryEntry): _type_ = RWeakValueDictionary - _controller_ = _get_controller + + def compute_annotation(self): + bk = self.bookkeeper + x = self.instance + return SomeWeakValueDict(bk.getuniqueclassdef(x._valueclass)) Modified: pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py ============================================================================== --- pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py (original) +++ pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py Thu Sep 3 19:10:40 2009 @@ -1,27 +1,66 @@ +from pypy.objspace.flow.model import Constant from pypy.rpython.lltypesystem import lltype, rstr, rclass, rdict -from pypy.rpython.controllerentry import Controller -from pypy.rpython.annlowlevel import cast_base_ptr_to_instance -from pypy.rpython.annlowlevel import cast_instance_to_base_ptr, llstr -from pypy.rlib.objectmodel import specialize +from pypy.rpython.rclass import getinstancerepr +from pypy.rpython.rmodel import Repr from pypy.rlib.rweakref import RWeakValueDictionary -class WeakDictController(Controller): - knowntype = RWeakValueDictionary +class WeakValueDictRepr(Repr): + def __init__(self, rtyper): + self.rtyper = rtyper + self.lowleveltype = lltype.Ptr(WEAKDICT) + self.dict_cache = {} + + def convert_const(self, weakdict): + if not isinstance(weakdict, RWeakValueDictionary): + raise TyperError("expected an RWeakValueDictionary: %r" % ( + weakdict,)) + try: + key = Constant(weakdict) + return self.dict_cache[key] + except KeyError: + self.setup() + l_dict = ll_new_weakdict() + self.dict_cache[key] = l_dict + bk = self.rtyper.annotator.bookkeeper + classdef = bk.getuniqueclassdef(weakdict._valueclass) + r_key = rstr.string_repr + r_value = getinstancerepr(self.rtyper, classdef) + for dictkey, dictvalue in weakdict._dict.items(): + llkey = r_key.convert_const(dictkey) + llvalue = r_value.convert_const(dictvalue) + if llvalue: + llvalue = lltype.cast_pointer(rclass.OBJECTPTR, llvalue) + ll_set(l_dict, llkey, llvalue) + return l_dict + + def rtype_method_get(self, hop): + v_d, v_key = hop.inputargs(self, rstr.string_repr) + hop.exception_cannot_occur() + v_result = hop.gendirectcall(ll_get, v_d, v_key) + v_result = hop.genop("cast_pointer", [v_result], + resulttype=hop.r_result.lowleveltype) + return v_result + + def rtype_method_set(self, hop): + v_d, v_key, v_value = hop.inputargs(self, rstr.string_repr, + hop.args_r[2]) + if hop.args_s[2].is_constant() and hop.args_s[2].const is None: + value = lltype.nullptr(rclass.OBJECTPTR.TO) + v_value = hop.inputconst(rclass.OBJECTPTR, value) + else: + v_value = hop.genop("cast_pointer", [v_value], + resulttype=rclass.OBJECTPTR) + hop.exception_cannot_occur() + hop.gendirectcall(ll_set, v_d, v_key, v_value) + + +def specialize_make_weakdict(hop): + hop.exception_cannot_occur() + v_d = hop.gendirectcall(ll_new_weakdict) + return v_d - @specialize.arg(1) - def new(self, valueclass): - WEAKDICT = get_WEAKDICT(valueclass) - d = lltype.malloc(WEAKDICT) - d.entries = WEAKDICT.entries.TO.allocate(DICT_INITSIZE) - d.num_pristine_entries = DICT_INITSIZE - return d - - def get_get(self, d): - return d.ll_get - - def get_set(self, d): - return d.ll_set +# ____________________________________________________________ pristine_marker = lltype.malloc(rstr.STR, 0) @@ -61,17 +100,20 @@ adtmeths=entrymeths, hints={'weakarray': 'value'}) -def ll_get(d, key): - llkey = llstr(key) +def ll_new_weakdict(): + d = lltype.malloc(WEAKDICT) + d.entries = WEAKDICT.entries.TO.allocate(DICT_INITSIZE) + d.num_pristine_entries = DICT_INITSIZE + return d + +def ll_get(d, llkey): hash = llkey.gethash() i = rdict.ll_dict_lookup(d, llkey, hash) llvalue = d.entries[i].value #print 'get', i, key, hash, llvalue - return cast_base_ptr_to_instance(d.valueclass, llvalue) + return llvalue -def ll_set(d, key, value): - llkey = llstr(key) - llvalue = cast_instance_to_base_ptr(value) +def ll_set(d, llkey, llvalue): hash = llkey.gethash() i = rdict.ll_dict_lookup(d, llkey, hash) everused = d.entries.everused(i) @@ -108,13 +150,8 @@ 'paranoia': False, } - at specialize.memo() -def get_WEAKDICT(valueclass): - adtmeths = dictmeths.copy() - adtmeths['valueclass'] = valueclass - WEAKDICT = lltype.GcStruct("weakdict", - ("num_items", lltype.Signed), - ("num_pristine_entries", lltype.Signed), - ("entries", lltype.Ptr(WEAKDICTENTRYARRAY)), - adtmeths=adtmeths) - return WEAKDICT +WEAKDICT = lltype.GcStruct("weakdict", + ("num_items", lltype.Signed), + ("num_pristine_entries", lltype.Signed), + ("entries", lltype.Ptr(WEAKDICTENTRYARRAY)), + adtmeths=dictmeths) Modified: pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py ============================================================================== --- pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py (original) +++ pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py Thu Sep 3 19:10:40 2009 @@ -48,3 +48,22 @@ # we don't implement the correct weakref behavior in lltype when # directly interpreted, but we can still test that the rest works. interpret(make_test(go_away=False, loop=12), []) + +def test_rpython_prebuilt(): + d = RWeakValueDictionary(X) + living = [X() for i in range(8)] + for i in range(8): + d.set(str(i), living[i]) + # + def f(): + x = X() + for i in range(8, 13): + d.set(str(i), x) + for i in range(0, 8): + assert d.get(str(i)) is living[i] + for i in range(8, 13): + assert d.get(str(i)) is x + assert d.get("foobar") is None + # + f() + interpret(f, []) From fijal at codespeak.net Thu Sep 3 19:12:25 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 19:12:25 +0200 (CEST) Subject: [pypy-svn] r67456 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090903171225.6831B16800D@codespeak.net> Author: fijal Date: Thu Sep 3 19:12:24 2009 New Revision: 67456 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py Log: this is enough to make test_recompilation pass. Although test_recompilation needs adaptation as not always we really overflow the number of registers Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Thu Sep 3 19:12:24 2009 @@ -15,9 +15,13 @@ from pypy.jit.backend.x86.ri386 import * from pypy.jit.metainterp.resoperation import rop + + # our calling convention - we pass first 6 args in registers # and the rest stays on the stack +RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words + MAX_FAIL_BOXES = 1000 if sys.platform == 'darwin': # darwin requires the stack to be 16 bytes aligned on calls @@ -165,20 +169,17 @@ inputargs = tree.inputargs self.logger.log_loop(tree) regalloc.walk_operations(tree) - stack_words = regalloc.max_stack_depth else: inputargs = regalloc.inputargs self.logger.log_operations mc = self.mc._mc - adr_sub = mc.tell() - mc.SUB(esp, imm32(0)) + adr_lea = mc.tell() + mc.LEA(esp, addr_add(imm32(0), ebp, 0)) regalloc._walk_operations(operations) - stack_words = max(regalloc.max_stack_depth, - tree._x86_stack_depth) + stack_words = regalloc.max_stack_depth self.mc.done() self.mc2.done() # possibly align, e.g. for Mac OS X - RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words stack_words = align_stack_words(stack_words + RET_BP) stack_depth = stack_words - RET_BP if guard_op is None: @@ -186,9 +187,9 @@ else: guard_op._x86_stack_depth = stack_words if stack_words - RET_BP != tree._x86_stack_depth: - mc = codebuf.InMemoryCodeBuilder(adr_sub, adr_sub + 128) - mc.SUB(esp, imm32((stack_words - RET_BP - - tree._x86_stack_depth) * WORD)) + mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) + mc.LEA(esp, addr_add(imm32(0), ebp, + -(stack_words - 1) * WORD)) mc.done() if we_are_translated(): self._regalloc = None # else keep it around for debugging @@ -617,7 +618,6 @@ targetmp = op.jump_target # don't break the following code sequence! mc = self.mc._mc - #mc.SUB(esp, targetmp._x86_compiled - xxx) mc.JMP(rel32(targetmp._x86_compiled)) def genop_guard_guard_true(self, op, ign_1, addr, locs, ign_2): @@ -698,7 +698,7 @@ self.generate_exception_handling(mc, eax) # don't break the following code sequence! mc = mc._mc - mc.LEA(esp, addr_add(imm(0), ebp, -3 * WORD)) + mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD)) guard_index = self.cpu.make_guard_index(op) mc.MOV(eax, imm(guard_index)) mc.POP(edi) Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py Thu Sep 3 19:12:24 2009 @@ -83,6 +83,11 @@ self.free_regs = REGS[:] def _update_bindings(self, locs, args): + newlocs = [] + for loc in locs: + if not isinstance(loc, IMM8) and not isinstance(loc, IMM32): + newlocs.append(loc) + locs = newlocs assert len(locs) == len(args) used = {} for i in range(len(locs)): @@ -211,7 +216,8 @@ i += 1 assert not self.reg_bindings jmp = operations[-1] - self.max_stack_depth = self.current_stack_depth + self.max_stack_depth = max(self.current_stack_depth, + self.max_stack_depth) def _compute_vars_longevity(self, inputargs, operations): # compute a dictionary that maps variables to index in @@ -923,6 +929,7 @@ dst_locations, tmploc) self.eventually_free_var(box) self.eventually_free_vars(op.args) + self.max_stack_depth = op.jump_target._x86_stack_depth self.PerformDiscard(op, []) def consider_debug_merge_point(self, op, ignored): Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py Thu Sep 3 19:12:24 2009 @@ -10,7 +10,7 @@ history.TreeLoop._x86_compiled = 0 history.TreeLoop._x86_bootstrap_code = 0 - +history.TreeLoop._x86_stack_depth = 0 class CPU386(AbstractLLCPU): debug = True From fijal at codespeak.net Thu Sep 3 19:28:00 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 19:28:00 +0200 (CEST) Subject: [pypy-svn] r67457 - in pypy/branch/no-recompilation/pypy/jit/backend/x86: . test Message-ID: <20090903172800.1862D16800E@codespeak.net> Author: fijal Date: Thu Sep 3 19:27:57 2009 New Revision: 67457 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py Log: Improve test and a fix Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Thu Sep 3 19:27:57 2009 @@ -183,14 +183,13 @@ stack_words = align_stack_words(stack_words + RET_BP) stack_depth = stack_words - RET_BP if guard_op is None: - tree._x86_stack_depth = stack_words - RET_BP + tree._x86_stack_depth = stack_depth else: - guard_op._x86_stack_depth = stack_words - if stack_words - RET_BP != tree._x86_stack_depth: - mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) - mc.LEA(esp, addr_add(imm32(0), ebp, - -(stack_words - 1) * WORD)) - mc.done() + guard_op._x86_stack_depth = stack_depth + mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) + mc.LEA(esp, addr_add(imm32(0), ebp, + -(stack_words - 1) * WORD)) + mc.done() if we_are_translated(): self._regalloc = None # else keep it around for debugging return newpos Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py Thu Sep 3 19:27:57 2009 @@ -86,7 +86,8 @@ def test_bridge_jumps_to_self_deeper(self): loop = self.interpret(''' - [i0, i1, i2] + [i0, i1, i2, i31, i32, i33] + i30 = int_add(i1, i2) i3 = int_add(i0, 1) i4 = int_and(i3, 1) guard_false(i4) @@ -94,7 +95,7 @@ i5 = int_lt(i3, 20) guard_true(i5) fail(1, i3) - jump(i3, i1, i2) + jump(i3, i30, 1, i30, i30, i30) ''', [0]) assert self.getint(0) == 0 assert self.getint(1) == 1 @@ -104,10 +105,14 @@ i8 = int_add(i3, 1) i6 = int_add(i8, i10) i7 = int_add(i3, i6) - jump(i3, i6, i7) + i12 = int_add(i7, i8) + i11 = int_add(i12, i6) + jump(i3, i12, i11, i10, i6, i7) ''' - bridge = self.attach_bridge(ops, loop, loop.operations[2], + guard_op = loop.operations[3] + bridge = self.attach_bridge(ops, loop, guard_op, jump_targets=[loop]) + assert guard_op._x86_stack_depth > loop._x86_stack_depth self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) self.cpu.set_future_value_int(2, 0) From arigo at codespeak.net Thu Sep 3 19:28:37 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 19:28:37 +0200 (CEST) Subject: [pypy-svn] r67458 - pypy/branch/weakdict/pypy/rlib/test Message-ID: <20090903172837.0C65D16800E@codespeak.net> Author: arigo Date: Thu Sep 3 19:28:37 2009 New Revision: 67458 Modified: pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py Log: Support for subclasses (it's right but it was not tested). Modified: pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py ============================================================================== --- pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py (original) +++ pypy/branch/weakdict/pypy/rlib/test/test_rweakref.py Thu Sep 3 19:28:37 2009 @@ -5,6 +5,9 @@ class X(object): pass +class Y(X): + pass + def make_test(go_away=True, loop=100): def f(): @@ -39,6 +42,10 @@ assert d.get("def") is x2 assert d.get("ghi") is x3 assert d.get("hello") is None + # finally, a subclass + y = Y() + d.set("hello", y) + assert d.get("hello") is y return f def test_RWeakValueDictionary(): From fijal at codespeak.net Thu Sep 3 19:36:52 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 19:36:52 +0200 (CEST) Subject: [pypy-svn] r67459 - in pypy/branch/no-recompilation/pypy/jit/backend/x86: . test Message-ID: <20090903173652.03A9216800E@codespeak.net> Author: fijal Date: Thu Sep 3 19:36:52 2009 New Revision: 67459 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Log: * Remove aligning code, as requested by pedronis * Fix one test Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Thu Sep 3 19:36:52 2009 @@ -176,19 +176,17 @@ adr_lea = mc.tell() mc.LEA(esp, addr_add(imm32(0), ebp, 0)) regalloc._walk_operations(operations) - stack_words = regalloc.max_stack_depth + stack_depth = regalloc.max_stack_depth self.mc.done() self.mc2.done() # possibly align, e.g. for Mac OS X - stack_words = align_stack_words(stack_words + RET_BP) - stack_depth = stack_words - RET_BP if guard_op is None: tree._x86_stack_depth = stack_depth else: guard_op._x86_stack_depth = stack_depth mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) mc.LEA(esp, addr_add(imm32(0), ebp, - -(stack_words - 1) * WORD)) + -(stack_depth - 1) * WORD)) mc.done() if we_are_translated(): self._regalloc = None # else keep it around for debugging Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Thu Sep 3 19:36:52 2009 @@ -270,7 +270,6 @@ assert self.getint(0) == 20 def test_two_loops_and_a_bridge(self): - py.test.skip("bridge support needed") ops = ''' [i0, i1, i2, i3] i4 = int_add(i0, 1) @@ -279,7 +278,7 @@ fail(i4, i1, i2, i3) jump(i4, i1, i2, i3) ''' - loop = self.interpret(ops, [0]) + loop = self.interpret(ops, [0, 0, 0, 0]) ops2 = ''' [i5] i1 = int_add(i5, 1) @@ -287,17 +286,18 @@ i4 = int_add(i3, 1) i2 = int_lt(i4, 30) guard_true(i2) - fail(i2) + fail(i4) jump(i4) ''' - loop2 = self.interpret(ops2, [0], jump_targets=[loop, 'self']) + loop2 = self.interpret(ops2, [0]) bridge_ops = ''' [i4] jump(i4, i4, i4, i4) ''' - xxx - bridge = self.attach_bridge(xxx) - + bridge = self.attach_bridge(bridge_ops, loop2, loop2.operations[4], + jump_targets=[loop]) + self.cpu.set_future_value_int(0, 0) + self.cpu.execute_operations(loop2) assert self.getint(0) == 31 assert self.getint(1) == 30 assert self.getint(2) == 30 From arigo at codespeak.net Thu Sep 3 19:40:02 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Sep 2009 19:40:02 +0200 (CEST) Subject: [pypy-svn] r67460 - in pypy/branch/weakdict/pypy: rlib rpython/memory/test Message-ID: <20090903174002.6CBF216800F@codespeak.net> Author: arigo Date: Thu Sep 3 19:40:01 2009 New Revision: 67460 Modified: pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py Log: Adding the test that I want to pass next. Modified: pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py ============================================================================== --- pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py (original) +++ pypy/branch/weakdict/pypy/rlib/rweakrefimpl.py Thu Sep 3 19:40:01 2009 @@ -63,7 +63,7 @@ # ____________________________________________________________ -pristine_marker = lltype.malloc(rstr.STR, 0) +pristine_marker = lltype.malloc(rstr.STR, 0, zero=True) DICT_INITSIZE = 8 WEAKDICTENTRY = lltype.Struct("weakdictentry", Modified: pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py Thu Sep 3 19:40:01 2009 @@ -222,7 +222,7 @@ assert 160 <= res <= 165 def test_weakref(self): - import weakref, gc + import weakref class A(object): pass def g(): @@ -243,7 +243,7 @@ assert res def test_weakref_to_object_with_finalizer(self): - import weakref, gc + import weakref class A(object): count = 0 a = A() @@ -262,6 +262,31 @@ res = self.interpret(f, []) assert res + def test_weakvaluedict(self): + py.test.skip("in-progress") + from pypy.rlib.rweakref import RWeakValueDictionary + class X(object): + def __init__(self, n): + self.n = n + def g(d, x111): + x222 = X(222) + d.set("abc", x111) + d.set("def", x222) + return ((d.get("abc") is x111) * 100 + + (d.get("def") is x222) * 10 + + (d.get("foobar") is not None)) + def f(): + d = RWeakValueDictionary(X) + x111 = X(111) + res = g(d, x111) + llop.gc__collect(lltype.Void) + llop.gc__collect(lltype.Void) + res = res + ((d.get("abc") is x111) * 10000 + + (d.get("def") is not None) * 1000) + return res + res = self.interpret(f, []) + assert res == 10110 + def test_id(self): class A(object): pass From fijal at codespeak.net Thu Sep 3 19:58:41 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 19:58:41 +0200 (CEST) Subject: [pypy-svn] r67461 - in pypy/branch/no-recompilation/pypy/jit/backend/x86: . test Message-ID: <20090903175841.A303D168012@codespeak.net> Author: fijal Date: Thu Sep 3 19:58:41 2009 New Revision: 67461 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Log: * Kill _compute_inpargs * Finish rewriting tests * Store _fail_op on guard_op, just to preserve order of arguments that go into faillocs Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Thu Sep 3 19:58:41 2009 @@ -662,6 +662,9 @@ exc = (guard_op.opnum == rop.GUARD_EXCEPTION or guard_op.opnum == rop.GUARD_NO_EXCEPTION) guard_op._x86_faillocs = fail_locs + # XXX horrible hack that allows us to preserve order + # of inputargs to bridge + guard_op._fail_op = guard_op.suboperations[0] self.generate_failure(self.mc2, guard_op.suboperations[0], fail_locs, exc) return addr Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py Thu Sep 3 19:58:41 2009 @@ -64,9 +64,10 @@ self.tree = tree if guard_op is not None: locs = guard_op._x86_faillocs - inpargs, longevity = self._compute_inpargs(guard_op) + inpargs = [arg for arg in guard_op._fail_op.args if + isinstance(arg, Box)] + self._compute_vars_longevity(inpargs, guard_op.suboperations) self.inputargs = inpargs - self.longevity = longevity self.position = -1 self._update_bindings(locs, inpargs) self.current_stack_depth = guard_op._x86_stack_depth @@ -250,32 +251,32 @@ assert isinstance(arg, Box) self.longevity = longevity - def _compute_inpargs(self, guard): - operations = guard.suboperations - longevity = {} - end = {} - for i in range(len(operations)-1, -1, -1): - op = operations[i] - if op.is_guard(): - for arg in op.suboperations[0].args: - if isinstance(arg, Box) and arg not in end: - end[arg] = i - for arg in op.args: - if isinstance(arg, Box) and arg not in end: - end[arg] = i - if op.result: - if op.result in end: - longevity[op.result] = (i, end[op.result]) - del end[op.result] - # otherwise this var is never ever used - for v, e in end.items(): - longevity[v] = (0, e) - inputargs = end.keys() - for arg in longevity: - assert isinstance(arg, Box) - for arg in inputargs: - assert isinstance(arg, Box) - return inputargs, longevity +# def _compute_inpargs(self, guard): +# operations = guard.suboperations +# longevity = {} +# end = {} +# for i in range(len(operations)-1, -1, -1): +# op = operations[i] +# if op.is_guard(): +# for arg in op.suboperations[0].args: +# if isinstance(arg, Box) and arg not in end: +# end[arg] = i +# for arg in op.args: +# if isinstance(arg, Box) and arg not in end: +# end[arg] = i +# if op.result: +# if op.result in end: +# longevity[op.result] = (i, end[op.result]) +# del end[op.result] +# # otherwise this var is never ever used +# for v, e in end.items(): +# longevity[v] = (0, e) +# inputargs = end.keys() +# for arg in longevity: +# assert isinstance(arg, Box) +# for arg in inputargs: +# assert isinstance(arg, Box) +# return inputargs, longevity def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): assert not isinstance(v, Const) Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Thu Sep 3 19:58:41 2009 @@ -320,18 +320,24 @@ assert not self.cpu.assembler.fail_boxes_ptr[1] def test_exception_bridge_no_exception(self): - py.test.skip("rewrite") - ops = ''' [i0] call(ConstClass(raising_fptr), i0, descr=raising_calldescr) guard_exception(ConstClass(zero_division_error)) - guard_no_exception() - fail(2) fail(1) fail(0) ''' - self.interpret(ops, [0]) + bridge_ops = ''' + [] + guard_no_exception() + fail(2) + fail(1) + ''' + loop = self.interpret(ops, [0]) + assert self.getint(0) == 1 + bridge = self.attach_bridge(bridge_ops, loop, loop.operations[1]) + self.cpu.set_future_value_int(0, 0) + self.cpu.execute_operations(loop) assert self.getint(0) == 1 def test_inputarg_unused(self): @@ -343,16 +349,25 @@ # assert did not explode def test_nested_guards(self): - py.test.skip("rewrite") ops = ''' [i0, i1] guard_true(i0) - guard_true(i0) - fail(i0, i1) - fail(3) + fail(i0, i1) fail(4) ''' - self.interpret(ops, [0, 10]) + bridge_ops = ''' + [i0, i1] + guard_true(i0) + fail(i0, i1) + fail(3) + ''' + loop = self.interpret(ops, [0, 10]) + assert self.getint(0) == 0 + assert self.getint(1) == 10 + bridge = self.attach_bridge(bridge_ops, loop, loop.operations[0]) + self.cpu.set_future_value_int(0, 0) + self.cpu.set_future_value_int(1, 10) + self.cpu.execute_operations(loop) assert self.getint(0) == 0 assert self.getint(1) == 10 From fijal at codespeak.net Thu Sep 3 20:00:44 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 20:00:44 +0200 (CEST) Subject: [pypy-svn] r67462 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090903180044.6738E168013@codespeak.net> Author: fijal Date: Thu Sep 3 20:00:44 2009 New Revision: 67462 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Log: oops Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Thu Sep 3 20:00:44 2009 @@ -186,7 +186,7 @@ guard_op._x86_stack_depth = stack_depth mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) mc.LEA(esp, addr_add(imm32(0), ebp, - -(stack_depth - 1) * WORD)) + -(stack_depth + RET_BP - 2) * WORD)) mc.done() if we_are_translated(): self._regalloc = None # else keep it around for debugging From fijal at codespeak.net Thu Sep 3 20:04:39 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 3 Sep 2009 20:04:39 +0200 (CEST) Subject: [pypy-svn] r67463 - in pypy/branch/no-recompilation/pypy/jit/backend/x86: . test Message-ID: <20090903180439.5EB5016800F@codespeak.net> Author: fijal Date: Thu Sep 3 20:04:38 2009 New Revision: 67463 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Log: A test and a fix Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py Thu Sep 3 20:04:38 2009 @@ -94,7 +94,7 @@ for i in range(len(locs)): v = args[i] loc = locs[i] - if isinstance(loc, REG): + if isinstance(loc, REG) and self.longevity[v][1] > -1: self.reg_bindings[v] = loc used[loc] = None else: Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Thu Sep 3 20:04:38 2009 @@ -371,6 +371,24 @@ assert self.getint(0) == 0 assert self.getint(1) == 10 + def test_nested_unused_arg(self): + ops = ''' + [i0, i1] + guard_true(i0) + fail(i0, i1) + fail(1) + ''' + loop = self.interpret(ops, [0, 1]) + assert self.getint(0) == 0 + bridge_ops = ''' + [i0, i1] + fail(1, 2) + ''' + self.attach_bridge(bridge_ops, loop, loop.operations[0]) + self.cpu.set_future_value_int(0, 0) + self.cpu.set_future_value_int(1, 1) + self.cpu.execute_operations(loop) + def test_spill_for_constant(self): ops = ''' [i0, i1, i2, i3] From arigo at codespeak.net Fri Sep 4 11:30:01 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 11:30:01 +0200 (CEST) Subject: [pypy-svn] r67464 - in pypy/branch/weakdict/pypy/rpython/memory: . test Message-ID: <20090904093001.94F83168013@codespeak.net> Author: arigo Date: Fri Sep 4 11:29:58 2009 New Revision: 67464 Modified: pypy/branch/weakdict/pypy/rpython/memory/gctypelayout.py pypy/branch/weakdict/pypy/rpython/memory/test/test_gctypelayout.py Log: In the encoding of GcArrays with the 'weakarray' hint, put in the weakpointer_offset the offset of the weak field within the variable part. Modified: pypy/branch/weakdict/pypy/rpython/memory/gctypelayout.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gctypelayout.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gctypelayout.py Fri Sep 4 11:29:58 2009 @@ -352,6 +352,9 @@ def weakpointer_offset(TYPE): if TYPE == WEAKREF: return llmemory.offsetof(WEAKREF, "weakptr") + if isinstance(TYPE, lltype.GcArray) and 'weakarray' in TYPE._hints: + weakfieldname = TYPE._hints['weakarray'] + return llmemory.offsetof(TYPE.OF, weakfieldname) return -1 def gc_pointers_inside(v, adr, mutable_only=False): Modified: pypy/branch/weakdict/pypy/rpython/memory/test/test_gctypelayout.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/test/test_gctypelayout.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/test/test_gctypelayout.py Fri Sep 4 11:29:58 2009 @@ -1,6 +1,6 @@ from pypy.rpython.memory.gctypelayout import TypeLayoutBuilder, GCData from pypy.rpython.memory.gctypelayout import offsets_to_gc_pointers -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, llmemory def getname(T): try: @@ -40,3 +40,22 @@ lst1 = gcdata.q_varsize_offsets_to_gcpointers_in_var_part(tid1) lst2 = gcdata.q_offsets_to_gc_pointers(tid2) assert len(lst1) == len(lst2) + +def test_weakarray(): + OBJ = lltype.GcStruct('some_object') + S = lltype.Struct('weakstruct', + ('foo', lltype.Ptr(OBJ)), + ('bar', lltype.Ptr(OBJ))) + A = lltype.GcArray(S, hints={'weakarray': 'bar'}) + layoutbuilder = TypeLayoutBuilder() + tid = layoutbuilder.get_type_id(A) + gcdata = GCData(layoutbuilder.type_info_list) + assert gcdata.q_is_varsize(tid) + assert gcdata.q_has_gcptr_in_varsize(tid) + assert not gcdata.q_is_gcarrayofgcptr(tid) + assert len(gcdata.q_offsets_to_gc_pointers(tid)) == 0 + assert len(gcdata.q_varsize_offsets_to_gcpointers_in_var_part(tid)) == 2 + weakofs = gcdata.q_weakpointer_offset(tid) + assert isinstance(weakofs, llmemory.FieldOffset) + assert weakofs.TYPE == S + assert weakofs.fldname == 'bar' From pedronis at codespeak.net Fri Sep 4 11:33:54 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 4 Sep 2009 11:33:54 +0200 (CEST) Subject: [pypy-svn] r67465 - pypy/trunk/pypy/interpreter Message-ID: <20090904093354.B3D88168013@codespeak.net> Author: pedronis Date: Fri Sep 4 11:33:53 2009 New Revision: 67465 Modified: pypy/trunk/pypy/interpreter/pycode.py Log: (micke, pedronis) let the jit see funcrun and funcrun_obj, also use fast access to the new fresh frame during further initialisation of it Modified: pypy/trunk/pypy/interpreter/pycode.py ============================================================================== --- pypy/trunk/pypy/interpreter/pycode.py (original) +++ pypy/trunk/pypy/interpreter/pycode.py Fri Sep 4 11:33:53 2009 @@ -184,28 +184,30 @@ self.fast_natural_arity = PyCode.FLATPYCALL | self.co_argcount - @jit.dont_look_inside def funcrun(self, func, args): frame = self.space.createframe(self, func.w_func_globals, func.closure) sig = self._signature # speed hack - args_matched = args.parse_into_scope(None, frame.fastlocals_w, + fresh_frame = jit.hint(frame, access_directly=True, + fresh_virtualizable=True) + args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, func.name, sig, func.defs_w) - frame.init_cells() + fresh_frame.init_cells() return frame.run() - @jit.dont_look_inside def funcrun_obj(self, func, w_obj, args): frame = self.space.createframe(self, func.w_func_globals, func.closure) sig = self._signature # speed hack - args_matched = args.parse_into_scope(w_obj, frame.fastlocals_w, + fresh_frame = jit.hint(frame, access_directly=True, + fresh_virtualizable=True) + args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, func.name, sig, func.defs_w) - frame.init_cells() + fresh_frame.init_cells() return frame.run() def getvarnames(self): From cfbolz at codespeak.net Fri Sep 4 11:41:23 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 4 Sep 2009 11:41:23 +0200 (CEST) Subject: [pypy-svn] r67466 - in pypy/branch/spine-of-frames/pypy/interpreter: . test Message-ID: <20090904094123.CC9ED168013@codespeak.net> Author: cfbolz Date: Fri Sep 4 11:41:23 2009 New Revision: 67466 Modified: pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py Log: (pedronis, cfbolz, arigo watching): write really explicit tests about the frame handling. Also refactor things so that all the obscure stuff is living in one place, in some methods on the execution context. Modified: pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py Fri Sep 4 11:41:23 2009 @@ -17,10 +17,7 @@ def __init__(self, space): self.space = space - # 'some_frame' points to any frame from this thread's frame stack - # (although in general it should point to the top one). - self.some_frame = None - self.framestackdepth = 0 + self._init_frame_chain() # tracing: space.frame_trace_action.fire() must be called to ensure # that tracing occurs whenever self.w_tracefunc or self.is_tracing # is modified. @@ -54,29 +51,122 @@ if self.framestackdepth > self.space.sys.recursionlimit: raise OperationError(self.space.w_RuntimeError, self.space.wrap("maximum recursion depth exceeded")) + self._chain(frame) + + def leave(self, frame): + if self.profilefunc: + self._trace(frame, 'leaveframe', self.space.w_None) + + self._unchain(frame) + + if self.w_tracefunc is not None and not frame.hide(): + self.space.frame_trace_action.fire() + + # ________________________________________________________________ + # the methods below are used for chaining frames in JIT-friendly way + # part of that stuff is obscure + + def _init_frame_chain(self): + # 'some_frame' points to any frame from this thread's frame stack + # (although in general it should point to the top one). + self.some_frame = None + self.framestackdepth = 0 + + @staticmethod + def _init_chaining_attributes(frame): + """ + explanation of the f_back handling: + ----------------------------------- + + in the non-JIT case, the frames simply form a doubly linked list via the + attributes f_back_some and f_forward. + + When the JIT is used, things become more complex, as functions can be + inlined into each other. In this case a frame chain can look like this: + + +---------------+ + | real_frame | + +---------------+ + | ^ + | f_back_some + | | + | | f_forward + | +--------------+ + | | virtual frame| + | +--------------+ + | ^ + | | f_forward + | +--------------+ + | | virtual frame| + | +--------------+ + | ^ + | | + v | f_forward + +---------------+ + | real_frame | + +---------------+ + | + | + v + ... + + This ensures that the virtual frames don't escape via the f_back of the + real frames. For the same reason, the executioncontext's some_frame + attribute should only point to real frames. + + All places where a frame can become accessed from applevel-code (like + sys._getframe and traceback catching) need to call force_f_back to ensure + that the intermediate virtual frames are forced to be real ones. + + """ + frame.f_back_some = None + frame.f_forward = None + frame.f_back_forced = False + + def _chain(self, frame): self.framestackdepth += 1 # frame.f_back_some = self.some_frame curtopframe = self.gettopframe() if curtopframe is not None: curtopframe.f_forward = frame - if not we_are_jitted(): + if not self._we_are_jitted(): self.some_frame = frame - def leave(self, frame): - if self.profilefunc: - self._trace(frame, 'leaveframe', self.space.w_None) - + def _unchain(self, frame): #assert frame is self.gettopframe() --- slowish f_back = frame.f_back() if f_back is not None: f_back.f_forward = None - if not we_are_jitted() or self.some_frame is frame: + if not self._we_are_jitted() or self.some_frame is frame: self.some_frame = frame.f_back_some self.framestackdepth -= 1 - - if self.w_tracefunc is not None and not frame.hide(): - self.space.frame_trace_action.fire() + + @staticmethod + def _extract_back_from_frame(frame): + back_some = frame.f_back_some + if frame.f_back_forced: + # don't check back_some.f_forward in this case + return back_some + if back_some is None: + return None + while back_some.f_forward is not frame: + back_some = back_some.f_forward + return back_some + + @staticmethod + def _force_back_of_frame(frame): + orig_frame = frame + while frame is not None and not frame.f_back_forced: + frame.f_back_some = f_back = ExecutionContext._extract_back_from_frame(frame) + frame.f_back_forced = True + frame = f_back + return orig_frame.f_back_some + + _we_are_jitted = staticmethod(we_are_jitted) # indirection for testing + + # the methods above are used for chaining frames in JIT-friendly way + # ________________________________________________________________ class Subcontext(object): Modified: pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py Fri Sep 4 11:41:23 2009 @@ -5,6 +5,7 @@ from pypy.interpreter import eval, baseobjspace, pycode from pypy.interpreter.argument import Arguments, ArgumentsFromValuestack from pypy.interpreter.error import OperationError +from pypy.interpreter.executioncontext import ExecutionContext from pypy.interpreter import pytraceback import opcode from pypy.rlib.objectmodel import we_are_translated, instantiate @@ -34,60 +35,12 @@ * 'valuestack_w', 'blockstack', control the interpretation """ - """ - explanation of the f_back handling: - ----------------------------------- - - in the non-JIT case, the frames simply form a doubly linked list via the - attributes f_back_some and f_forward. - - When the JIT is used, things become more complex, as functions can be - inlined into each other. In this case a frame chain can look like this: - - +---------------+ - | real_frame | - +---------------+ - | ^ - | f_back_some - | | - | | f_forward - | +--------------+ - | | virtual frame| - | +--------------+ - | ^ - | | f_forward - | +--------------+ - | | virtual frame| - | +--------------+ - | ^ - | | - v | f_forward - +---------------+ - | real_frame | - +---------------+ - | - | - v - ... - - This ensures that the virtual frames don't escape via the f_back of the - real frames. For the same reason, the executioncontext's some_frame - attribute should only point to real frames. - - All places where a frame can become accessed from applevel-code (like - sys._getframe and traceback catching) need to call force_f_back to ensure - that the intermediate virtual frames are forced to be real ones. - - """ __metaclass__ = extendabletype frame_finished_execution = False last_instr = -1 last_exception = None - f_back_some = None # these two should be modified together - f_forward = None # they make a sort of doubly-linked list - f_back_forced = False w_f_trace = None # For tracing instr_lb = 0 @@ -111,6 +64,7 @@ self.fastlocals_w = [None]*self.numlocals make_sure_not_resized(self.fastlocals_w) self.f_lineno = code.co_firstlineno + ExecutionContext._init_chaining_attributes(self) def get_builtin(self): if self.space.config.objspace.honor__builtins__: @@ -457,23 +411,10 @@ pass def f_back(self): - back_some = self.f_back_some - if self.f_back_forced: - # don't check back_some.f_forward in this case - return back_some - if back_some is None: - return None - while back_some.f_forward is not self: - back_some = back_some.f_forward - return back_some - - def force_f_back(self): - self.f_back_some = f_back = self.f_back() - self.f_back_forced = True - if f_back is not None: - f_back.force_f_back() - return f_back + return ExecutionContext._extract_back_from_frame(self) + def force_f_back(self): + return ExecutionContext._force_back_of_frame(self) ### line numbers ### Modified: pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py Fri Sep 4 11:41:23 2009 @@ -1,5 +1,6 @@ import py from pypy.interpreter import executioncontext +from pypy.interpreter.executioncontext import ExecutionContext from pypy.conftest import gettestobjspace class Finished(Exception): @@ -219,3 +220,216 @@ """) events = space.unwrap(w_events) assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] + +class TestFrameChaining(object): + class EC(ExecutionContext): + def __init__(self, jitted=False): + self.jitted = jitted + self._init_frame_chain() + + def _we_are_jitted(self): + return self.jitted + + class Frame(object): + def __init__(self): + ExecutionContext._init_chaining_attributes(self) + + def f_back(self): + return ExecutionContext._extract_back_from_frame(self) + + def force_f_back(self): + return ExecutionContext._force_back_of_frame(self) + + def test_frame_chain(self): + + ec = self.EC() + + assert ec.some_frame is None + assert ec.framestackdepth == 0 + + frame = self.Frame() + ec._chain(frame) + assert ec.some_frame is frame + assert ec.framestackdepth == 1 + assert frame.f_back_some is None + assert frame.f_forward is None + + frame2 = self.Frame() + ec._chain(frame2) + assert ec.some_frame is frame2 + assert ec.framestackdepth == 2 + assert frame2.f_back_some is frame + assert frame.f_forward is frame2 + assert frame2.f_forward is None + + frame3 = self.Frame() + ec._chain(frame3) + assert ec.some_frame is frame3 + assert frame3.f_back_some is frame2 + assert frame2.f_forward is frame3 + # now we should unchain + + assert frame3.f_back() is frame2 + ec._unchain(frame3) + assert ec.some_frame is frame2 + assert ec.framestackdepth == 2 + assert frame2.f_forward is None + assert frame3.f_back_some is frame2 + + assert frame2.f_back() is frame + ec._unchain(frame2) + assert ec.some_frame is frame + assert ec.framestackdepth == 1 + assert frame.f_forward is None + assert frame2.f_back_some is frame + + assert frame.f_back() is None + ec._unchain(frame) + assert ec.some_frame is None + assert ec.framestackdepth == 0 + assert frame.f_back_some is None + + # we want a simplified copy of the previous tests and do a force on frame2 ok + def test_frame_chain_forced(self): + + ec = self.EC() + + frame = self.Frame() + ec._chain(frame) + + frame2 = self.Frame() + ec._chain(frame2) + assert ec.some_frame is frame2 + assert ec.framestackdepth == 2 + assert frame2.f_back_some is frame + assert frame.f_forward is frame2 + assert frame2.f_forward is None + res = frame2.force_f_back() + assert res is frame + assert frame.f_back_forced + + frame3 = self.Frame() + ec._chain(frame3) + # now we should unchain + + assert frame3.f_back() is frame2 + ec._unchain(frame3) + assert ec.some_frame is frame2 + assert frame3.f_back_some is frame2 + + assert frame2.f_back() is frame + ec._unchain(frame2) + assert frame2.f_back_some is frame + + assert frame.f_back() is None + ec._unchain(frame) + assert ec.some_frame is None + assert frame.f_back_some is None + + assert frame2.f_back() is frame + assert frame.f_back() is None + + def test_frame_chain_jitted(self): + + ec = self.EC() + + assert ec.some_frame is None + assert ec.framestackdepth == 0 + + frame = self.Frame() + ec._chain(frame) + assert ec.some_frame is frame + assert ec.framestackdepth == 1 + assert frame.f_back_some is None + assert frame.f_forward is None + + ec.jitted = True + frame2 = self.Frame() + ec._chain(frame2) + assert ec.some_frame is frame + assert ec.framestackdepth == 2 + assert frame2.f_back_some is frame + assert frame.f_forward is frame2 + assert frame2.f_forward is None + + # recursive enter/leave seen by the jit + frame3 = self.Frame() + ec._chain(frame3) + assert ec.some_frame is frame + assert frame3.f_back_some is frame + assert frame2.f_forward is frame3 + # now we should unchain + + assert frame3.f_back() is frame2 + ec._unchain(frame3) + assert ec.some_frame is frame + assert ec.framestackdepth == 2 + assert frame2.f_forward is None + assert frame3.f_back_some is frame + + # recursive enter/leave not seen by the jit + ec.jitted = False + ec._chain(frame3) + assert ec.some_frame is frame3 + assert frame3.f_back_some is frame + assert frame2.f_forward is frame3 # this btw is the bit that may be problematic xxx + # now we should unchain + + assert frame3.f_back() is frame2 + ec._unchain(frame3) + assert ec.some_frame is frame + assert ec.framestackdepth == 2 + assert frame2.f_forward is None + assert frame3.f_back_some is frame + ec.jitted = True + + assert frame2.f_back() is frame + ec._unchain(frame2) + assert ec.some_frame is frame + assert ec.framestackdepth == 1 + assert frame.f_forward is None + assert frame2.f_back_some is frame + + ec.jitted = False + assert frame.f_back() is None + ec._unchain(frame) + assert ec.some_frame is None + assert ec.framestackdepth == 0 + assert frame.f_back_some is None + + + def test_frame_chain_jitted_forced(self): + + ec = self.EC() + + assert ec.some_frame is None + assert ec.framestackdepth == 0 + + frame = self.Frame() + ec._chain(frame) + + ec.jitted = True + frame2 = self.Frame() + ec._chain(frame2) + + # recursive enter/leave seen by the jit + frame3 = self.Frame() + ec._chain(frame3) + res = frame3.force_f_back() + assert res is frame2 + + assert frame3.f_back() is frame2 + ec._unchain(frame3) + + assert frame2.f_back() is frame + ec._unchain(frame2) + ec.jitted = False + assert frame.f_back() is None + ec._unchain(frame) + + assert frame3.f_back() is frame2 + assert frame2.f_back() is frame + assert frame.f_back() is None + # cool yes + + From pedronis at codespeak.net Fri Sep 4 11:52:10 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 4 Sep 2009 11:52:10 +0200 (CEST) Subject: [pypy-svn] r67467 - in pypy/trunk/pypy/objspace/std: . test Message-ID: <20090904095210.E30A5168016@codespeak.net> Author: pedronis Date: Fri Sep 4 11:52:10 2009 New Revision: 67467 Modified: pypy/trunk/pypy/objspace/std/test/test_typeobject.py pypy/trunk/pypy/objspace/std/typeobject.py Log: (micke, pedronis) fix getattributeshortcut optimisation resetting bug, this makes this optimisation not depend implicitly on versioning for its resetting- Modified: pypy/trunk/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/pypy/objspace/std/test/test_typeobject.py Fri Sep 4 11:52:10 2009 @@ -948,3 +948,46 @@ del list.a raises(AttributeError, "l.a") +class AppTestGetattributeShortcut: + + def setup_class(cls): + cls.space = gettestobjspace( + **{"objspace.std.getattributeshortcut": True}) + + def test_reset_logic(self): + class X(object): + pass + + class Y(X): + pass + + y = Y() + y.x = 3 + assert y.x == 3 + + def ga(self, name): + return 'GA' + + X.__getattribute__ = ga + + assert y.x == 'GA' + + class M(type): + pass + + class X(object): + __metaclass__ = M + + class Y(X): + pass + + y = Y() + y.x = 3 + assert y.x == 3 + + def ga(self, name): + return 'GA' + + X.__getattribute__ = ga + + assert y.x == 'GA' Modified: pypy/trunk/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/pypy/objspace/std/typeobject.py Fri Sep 4 11:52:10 2009 @@ -86,24 +86,22 @@ def mutated(w_self): space = w_self.space + if (not space.config.objspace.std.withtypeversion and + not space.config.objspace.std.getattributeshortcut): + return + if space.config.objspace.std.getattributeshortcut: w_self.uses_object_getattribute = False # ^^^ conservative default, fixed during real usage - if not space.config.objspace.std.withtypeversion: - return - # Invariant: version_tag is None if and only if - # 'w_self.instancetypedef.hasdict' is True, which is the case - # for a built-in type that provides its instances with their own - # __dict__. If 'hasdict' is True for a type T then it is also - # True for all subtypes of T; so we don't need to look for - # version_tags to update in the subclasses of a type T whose - # version_tag is None. - if w_self.version_tag is not None: + + if (space.config.objspace.std.withtypeversion + and w_self.version_tag is not None): w_self.version_tag = VersionTag() - subclasses_w = w_self.get_subclasses() - for w_subclass in subclasses_w: - assert isinstance(w_subclass, W_TypeObject) - w_subclass.mutated() + + subclasses_w = w_self.get_subclasses() + for w_subclass in subclasses_w: + assert isinstance(w_subclass, W_TypeObject) + w_subclass.mutated() def ready(w_self): for w_base in w_self.bases_w: From arigo at codespeak.net Fri Sep 4 11:57:42 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 11:57:42 +0200 (CEST) Subject: [pypy-svn] r67468 - in pypy/branch/weakdict/pypy/rpython/memory: . test Message-ID: <20090904095742.33BE4168016@codespeak.net> Author: arigo Date: Fri Sep 4 11:57:41 2009 New Revision: 67468 Modified: pypy/branch/weakdict/pypy/rpython/memory/gctypelayout.py pypy/branch/weakdict/pypy/rpython/memory/test/test_gctypelayout.py Log: Actually, the weak pointer field should not be listed in the regular part of offsets_to_gc_pointers. Modified: pypy/branch/weakdict/pypy/rpython/memory/gctypelayout.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gctypelayout.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gctypelayout.py Fri Sep 4 11:57:41 2009 @@ -166,7 +166,8 @@ info.ofstovar = llmemory.itemoffsetof(TYPE, 0) assert isinstance(ARRAY, lltype.Array) if ARRAY.OF != lltype.Void: - offsets = offsets_to_gc_pointers(ARRAY.OF) + ignore = ARRAY._hints.get('weakarray', None) + offsets = offsets_to_gc_pointers(ARRAY.OF, ignoring=ignore) else: offsets = () info.varofstoptrs = builder.offsets2table(offsets, ARRAY.OF) @@ -322,10 +323,12 @@ # # Helpers to discover GC pointers inside structures -def offsets_to_gc_pointers(TYPE): +def offsets_to_gc_pointers(TYPE, ignoring=None): offsets = [] if isinstance(TYPE, lltype.Struct): for name in TYPE._names: + if name == ignoring: + continue FIELD = getattr(TYPE, name) if isinstance(FIELD, lltype.Array): continue # skip inlined array Modified: pypy/branch/weakdict/pypy/rpython/memory/test/test_gctypelayout.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/test/test_gctypelayout.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/test/test_gctypelayout.py Fri Sep 4 11:57:41 2009 @@ -54,7 +54,7 @@ assert gcdata.q_has_gcptr_in_varsize(tid) assert not gcdata.q_is_gcarrayofgcptr(tid) assert len(gcdata.q_offsets_to_gc_pointers(tid)) == 0 - assert len(gcdata.q_varsize_offsets_to_gcpointers_in_var_part(tid)) == 2 + assert len(gcdata.q_varsize_offsets_to_gcpointers_in_var_part(tid)) == 1 weakofs = gcdata.q_weakpointer_offset(tid) assert isinstance(weakofs, llmemory.FieldOffset) assert weakofs.TYPE == S From arigo at codespeak.net Fri Sep 4 12:26:30 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 12:26:30 +0200 (CEST) Subject: [pypy-svn] r67469 - pypy/branch/weakdict/pypy/rpython/lltypesystem Message-ID: <20090904102630.59270168016@codespeak.net> Author: arigo Date: Fri Sep 4 12:26:27 2009 New Revision: 67469 Modified: pypy/branch/weakdict/pypy/rpython/lltypesystem/llarena.py Log: llarena does not support GcStructs with no field or empty arrays. Crash explicitly instead of very obscurely. Modified: pypy/branch/weakdict/pypy/rpython/lltypesystem/llarena.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/lltypesystem/llarena.py (original) +++ pypy/branch/weakdict/pypy/rpython/lltypesystem/llarena.py Fri Sep 4 12:26:27 2009 @@ -94,6 +94,8 @@ return addr2 def setobject(self, objaddr, offset, bytes): + assert bytes > 0, ("llarena does not support GcStructs with no field" + " or empty arrays") assert offset not in self.objectptrs self.objectptrs[offset] = objaddr.ptr self.objectsizes[offset] = bytes From arigo at codespeak.net Fri Sep 4 13:03:05 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 13:03:05 +0200 (CEST) Subject: [pypy-svn] r67470 - in pypy/branch/weakdict/pypy: jit/backend/llsupport jit/backend/llsupport/test rpython/memory/gc rpython/memory/gctransform Message-ID: <20090904110305.8D306168016@codespeak.net> Author: arigo Date: Fri Sep 4 13:03:04 2009 New Revision: 67470 Modified: pypy/branch/weakdict/pypy/jit/backend/llsupport/gc.py pypy/branch/weakdict/pypy/jit/backend/llsupport/test/test_gc.py pypy/branch/weakdict/pypy/rpython/memory/gc/base.py pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py pypy/branch/weakdict/pypy/rpython/memory/gc/hybrid.py pypy/branch/weakdict/pypy/rpython/memory/gc/markcompact.py pypy/branch/weakdict/pypy/rpython/memory/gc/marksweep.py pypy/branch/weakdict/pypy/rpython/memory/gc/semispace.py pypy/branch/weakdict/pypy/rpython/memory/gctransform/framework.py Log: Remove support for finalizers in varsized objects from our GCs. Modified: pypy/branch/weakdict/pypy/jit/backend/llsupport/gc.py ============================================================================== --- pypy/branch/weakdict/pypy/jit/backend/llsupport/gc.py (original) +++ pypy/branch/weakdict/pypy/jit/backend/llsupport/gc.py Fri Sep 4 13:03:04 2009 @@ -343,7 +343,7 @@ return llop1.do_malloc_varsize_clear( llmemory.GCREF, type_id, num_elem, self.array_basesize, itemsize, - self.array_length_ofs, True, False) + self.array_length_ofs, True) self.malloc_array = malloc_array self.GC_MALLOC_ARRAY = lltype.Ptr(lltype.FuncType( [lltype.Signed] * 3, llmemory.GCREF)) @@ -359,12 +359,12 @@ return llop1.do_malloc_varsize_clear( llmemory.GCREF, str_type_id, length, str_basesize, str_itemsize, - str_ofs_length, True, False) + str_ofs_length, True) def malloc_unicode(length): return llop1.do_malloc_varsize_clear( llmemory.GCREF, unicode_type_id, length, unicode_basesize, unicode_itemsize, - unicode_ofs_length, True, False) + unicode_ofs_length, True) self.malloc_str = malloc_str self.malloc_unicode = malloc_unicode self.GC_MALLOC_STR_UNICODE = lltype.Ptr(lltype.FuncType( Modified: pypy/branch/weakdict/pypy/jit/backend/llsupport/test/test_gc.py ============================================================================== --- pypy/branch/weakdict/pypy/jit/backend/llsupport/test/test_gc.py (original) +++ pypy/branch/weakdict/pypy/jit/backend/llsupport/test/test_gc.py Fri Sep 4 13:03:04 2009 @@ -124,10 +124,8 @@ return p def do_malloc_varsize_clear(self, RESTYPE, type_id, length, size, - itemsize, offset_to_length, can_collect, - has_finalizer): + itemsize, offset_to_length, can_collect): assert can_collect - assert not has_finalizer p = llmemory.raw_malloc(size + itemsize * length) (p + offset_to_length).signed[0] = length p = llmemory.cast_adr_to_ptr(p, RESTYPE) Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/base.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/base.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/base.py Fri Sep 4 13:03:04 2009 @@ -100,6 +100,7 @@ assert not (needs_finalizer and contains_weakptr) if self.is_varsize(typeid): assert not contains_weakptr + assert not needs_finalizer itemsize = self.varsize_item_sizes(typeid) offset_to_length = self.varsize_offset_to_length(typeid) if zero or not hasattr(self, 'malloc_varsize'): @@ -107,7 +108,7 @@ else: malloc_varsize = self.malloc_varsize ref = malloc_varsize(typeid, length, size, itemsize, - offset_to_length, True, needs_finalizer) + offset_to_length, True) else: if zero or not hasattr(self, 'malloc_fixedsize'): malloc_fixedsize = self.malloc_fixedsize_clear Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py Fri Sep 4 13:03:04 2009 @@ -160,8 +160,7 @@ return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect, - has_finalizer=False): + offset_to_length, can_collect): # Only use the nursery if there are not too many items. if not raw_malloc_usage(itemsize): too_many_items = False @@ -180,7 +179,7 @@ maxlength = maxlength_for_minimal_nursery << self.nursery_scale too_many_items = length > maxlength - if (has_finalizer or not can_collect or + if (not can_collect or too_many_items or (raw_malloc_usage(size) > self.lb_young_var_basesize and raw_malloc_usage(size) > self.largest_young_var_basesize)): @@ -190,7 +189,7 @@ # second comparison as well. return SemiSpaceGC.malloc_varsize_clear(self, typeid, length, size, itemsize, offset_to_length, - can_collect, has_finalizer) + can_collect) # with the above checks we know now that totalsize cannot be more # than about half of the nursery size; in particular, the + and * # cannot overflow Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/hybrid.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/hybrid.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/hybrid.py Fri Sep 4 13:03:04 2009 @@ -132,12 +132,11 @@ # 'large'. def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect, - has_finalizer=False): - if has_finalizer or not can_collect: + offset_to_length, can_collect): + if not can_collect: return SemiSpaceGC.malloc_varsize_clear(self, typeid, length, size, itemsize, offset_to_length, - can_collect, has_finalizer) + can_collect) size_gc_header = self.gcheaderbuilder.size_gc_header nonvarsize = size_gc_header + size Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/markcompact.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/markcompact.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/markcompact.py Fri Sep 4 13:03:04 2009 @@ -131,8 +131,7 @@ return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect, - has_finalizer=False): + offset_to_length, can_collect): size_gc_header = self.gcheaderbuilder.size_gc_header nonvarsize = size_gc_header + size try: @@ -147,8 +146,6 @@ self.init_gc_object(result, typeid) (result + size_gc_header + offset_to_length).signed[0] = length self.free = result + llarena.round_up_for_allocation(totalsize) - if has_finalizer: - self.objects_with_finalizers.append(result + size_gc_header) return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def obtain_free_space(self, totalsize): Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/marksweep.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/marksweep.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/marksweep.py Fri Sep 4 13:03:04 2009 @@ -151,7 +151,7 @@ malloc_fixedsize_clear._dont_inline_ = True def malloc_varsize(self, typeid, length, size, itemsize, offset_to_length, - can_collect, has_finalizer=False): + can_collect): if can_collect: self.maybe_collect() size_gc_header = self.gcheaderbuilder.size_gc_header @@ -170,12 +170,8 @@ (result + size_gc_header + offset_to_length).signed[0] = length hdr = llmemory.cast_adr_to_ptr(result, self.HDRPTR) hdr.typeid = typeid << 1 - if has_finalizer: - hdr.next = self.malloced_objects_with_finalizer - self.malloced_objects_with_finalizer = hdr - else: - hdr.next = self.malloced_objects - self.malloced_objects = hdr + hdr.next = self.malloced_objects + self.malloced_objects = hdr self.bytes_malloced = bytes_malloced result += size_gc_header @@ -187,8 +183,7 @@ malloc_varsize._dont_inline_ = True def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect, - has_finalizer=False): + offset_to_length, can_collect): if can_collect: self.maybe_collect() size_gc_header = self.gcheaderbuilder.size_gc_header @@ -208,12 +203,8 @@ (result + size_gc_header + offset_to_length).signed[0] = length hdr = llmemory.cast_adr_to_ptr(result, self.HDRPTR) hdr.typeid = typeid << 1 - if has_finalizer: - hdr.next = self.malloced_objects_with_finalizer - self.malloced_objects_with_finalizer = hdr - else: - hdr.next = self.malloced_objects - self.malloced_objects = hdr + hdr.next = self.malloced_objects + self.malloced_objects = hdr self.bytes_malloced = bytes_malloced result += size_gc_header Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/semispace.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/semispace.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/semispace.py Fri Sep 4 13:03:04 2009 @@ -83,8 +83,7 @@ return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect, - has_finalizer=False): + offset_to_length, can_collect): size_gc_header = self.gcheaderbuilder.size_gc_header nonvarsize = size_gc_header + size try: @@ -101,8 +100,6 @@ self.init_gc_object(result, typeid) (result + size_gc_header + offset_to_length).signed[0] = length self.free = result + llarena.round_up_for_allocation(totalsize) - if has_finalizer: - self.objects_with_finalizers.append(result + size_gc_header) return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def obtain_free_space(self, needed): Modified: pypy/branch/weakdict/pypy/rpython/memory/gctransform/framework.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gctransform/framework.py Fri Sep 4 13:03:04 2009 @@ -235,7 +235,7 @@ self.malloc_varsize_clear_ptr = getfn( GCClass.malloc_varsize_clear.im_func, [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)] - + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref) + + [annmodel.SomeBool()], s_gcref) self.collect_ptr = getfn(GCClass.collect.im_func, [s_gc], annmodel.s_None) self.can_move_ptr = getfn(GCClass.can_move.im_func, @@ -285,7 +285,7 @@ annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), - s_True, s_False], s_gcref, + s_True], s_gcref, inline = True) else: self.malloc_varsize_clear_fast_ptr = None @@ -524,30 +524,28 @@ args = [self.c_const_gc, c_type_id, c_size, c_can_collect, c_has_finalizer, rmodel.inputconst(lltype.Bool, False)] else: + assert not c_has_finalizer.value v_length = op.args[-1] c_ofstolength = rmodel.inputconst(lltype.Signed, info.ofstolength) c_varitemsize = rmodel.inputconst(lltype.Signed, info.varitemsize) if flags.get('resizable') and self.malloc_varsize_resizable_ptr: assert c_can_collect.value - assert not c_has_finalizer.value malloc_ptr = self.malloc_varsize_resizable_ptr args = [self.c_const_gc, c_type_id, v_length] elif flags.get('nonmovable') and self.malloc_varsize_nonmovable_ptr: # we don't have tests for such cases, let's fail # explicitely assert c_can_collect.value - assert not c_has_finalizer.value malloc_ptr = self.malloc_varsize_nonmovable_ptr args = [self.c_const_gc, c_type_id, v_length] else: if (self.malloc_varsize_clear_fast_ptr is not None and - c_can_collect.value and not c_has_finalizer.value): + c_can_collect.value): malloc_ptr = self.malloc_varsize_clear_fast_ptr else: malloc_ptr = self.malloc_varsize_clear_ptr args = [self.c_const_gc, c_type_id, v_length, c_size, - c_varitemsize, c_ofstolength, c_can_collect, - c_has_finalizer] + c_varitemsize, c_ofstolength, c_can_collect] keep_current_args = flags.get('keep_current_args', False) livevars = self.push_roots(hop, keep_current_args=keep_current_args) v_result = hop.genop("direct_call", [malloc_ptr] + args, @@ -623,12 +621,12 @@ # used by the JIT (see pypy.jit.backend.llsupport.gc) op = hop.spaceop [v_typeid, v_length, v_size, v_itemsize, - v_offset_to_length, v_can_collect, v_has_finalizer] = op.args + v_offset_to_length, v_can_collect] = op.args livevars = self.push_roots(hop) hop.genop("direct_call", [self.malloc_varsize_clear_ptr, self.c_const_gc, v_typeid, v_length, v_size, v_itemsize, - v_offset_to_length, v_can_collect, v_has_finalizer], + v_offset_to_length, v_can_collect], resultvar=op.result) self.pop_roots(hop, livevars) From arigo at codespeak.net Fri Sep 4 14:28:06 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 14:28:06 +0200 (CEST) Subject: [pypy-svn] r67471 - in pypy/branch/weakdict/pypy: config config/test doc/config jit/backend/llsupport jit/backend/llsupport/test jit/metainterp jit/tl objspace/std rpython rpython/memory/gc rpython/memory/gctransform rpython/memory/test translator/goal Message-ID: <20090904122806.B46B5168016@codespeak.net> Author: arigo Date: Fri Sep 4 14:28:03 2009 New Revision: 67471 Added: pypy/branch/weakdict/pypy/doc/config/translation.norweakarray.txt (contents, props changed) pypy/branch/weakdict/pypy/doc/config/translation.norweakref.txt - copied unchanged from r67470, pypy/branch/weakdict/pypy/doc/config/translation.rweakref.txt Removed: pypy/branch/weakdict/pypy/doc/config/translation.rweakref.txt Modified: pypy/branch/weakdict/pypy/config/pypyoption.py pypy/branch/weakdict/pypy/config/test/test_pypyoption.py pypy/branch/weakdict/pypy/config/translationoption.py pypy/branch/weakdict/pypy/jit/backend/llsupport/gc.py pypy/branch/weakdict/pypy/jit/backend/llsupport/test/test_gc.py pypy/branch/weakdict/pypy/jit/metainterp/codewriter.py pypy/branch/weakdict/pypy/jit/tl/targetpypyjit.py pypy/branch/weakdict/pypy/objspace/std/typeobject.py pypy/branch/weakdict/pypy/rpython/memory/gc/base.py pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py pypy/branch/weakdict/pypy/rpython/memory/gc/hybrid.py pypy/branch/weakdict/pypy/rpython/memory/gc/markcompact.py pypy/branch/weakdict/pypy/rpython/memory/gc/marksweep.py pypy/branch/weakdict/pypy/rpython/memory/gc/semispace.py pypy/branch/weakdict/pypy/rpython/memory/gctransform/framework.py pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py pypy/branch/weakdict/pypy/rpython/rweakref.py pypy/branch/weakdict/pypy/translator/goal/targetpreimportedpypy.py pypy/branch/weakdict/pypy/translator/goal/targetpypystandalone.py Log: Intermediate check-in. Hugeish. Add the "contains_weakptr" flag to all malloc_varsize() around, and fix the gc transformer. Add "norweakarray" as a translation option, forced to True by the GCs that don't support it. Rename the translation option "rweakref" into "norweakref" so that it can, if set to True, force "norweakarray" to be True too. Tons of fun, not really tested so far. Modified: pypy/branch/weakdict/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/weakdict/pypy/config/pypyoption.py (original) +++ pypy/branch/weakdict/pypy/config/pypyoption.py Fri Sep 4 14:28:03 2009 @@ -269,7 +269,7 @@ cmdline=None, default=False, # weakrefs needed, because of get_subclasses() - requires=[("translation.rweakref", True)]), + requires=[("translation.norweakref", False)]), BoolOption("withshadowtracking", "track whether an instance attribute shadows a type" @@ -277,12 +277,12 @@ default=False, requires=[("objspace.std.withmultidict", True), ("objspace.std.withtypeversion", True), - ("translation.rweakref", True)]), + ("translation.norweakref", False)]), BoolOption("withmethodcache", "try to cache method lookups", default=False, requires=[("objspace.std.withtypeversion", True), - ("translation.rweakref", True)]), + ("translation.norweakref", False)]), BoolOption("withmethodcachecounter", "try to cache methods and provide a counter in __pypy__. " "for testing purposes only.", Modified: pypy/branch/weakdict/pypy/config/test/test_pypyoption.py ============================================================================== --- pypy/branch/weakdict/pypy/config/test/test_pypyoption.py (original) +++ pypy/branch/weakdict/pypy/config/test/test_pypyoption.py Fri Sep 4 14:28:03 2009 @@ -54,7 +54,7 @@ def test_rweakref_required(): conf = get_pypy_config() - conf.translation.rweakref = False + conf.translation.norweakref = True set_pypy_opt_level(conf, '3') assert not conf.objspace.std.withtypeversion Modified: pypy/branch/weakdict/pypy/config/translationoption.py ============================================================================== --- pypy/branch/weakdict/pypy/config/translationoption.py (original) +++ pypy/branch/weakdict/pypy/config/translationoption.py Fri Sep 4 14:28:03 2009 @@ -47,17 +47,21 @@ ["boehm", "ref", "marksweep", "semispace", "statistics", "generation", "hybrid", "markcompact", "none"], "ref", requires={ - "ref": [("translation.rweakref", False), # XXX + "ref": [("translation.norweakref", True), # XXX ("translation.gctransformer", "ref")], - "none": [("translation.rweakref", False), # XXX + "none": [("translation.norweakref", True), # XXX ("translation.gctransformer", "none")], "semispace": [("translation.gctransformer", "framework")], - "marksweep": [("translation.gctransformer", "framework")], - "statistics": [("translation.gctransformer", "framework")], + "marksweep": [("translation.gctransformer", "framework"), + ("translation.norweakarray", True)], + "statistics": [("translation.gctransformer", "framework"), + ("translation.norweakarray", True)], "generation": [("translation.gctransformer", "framework")], "hybrid": [("translation.gctransformer", "framework")], - "boehm": [("translation.gctransformer", "boehm")], - "markcompact": [("translation.gctransformer", "framework")], + "boehm": [("translation.gctransformer", "boehm"), + ("translation.norweakarray", True)], + "markcompact": [("translation.gctransformer", "framework"), + ("translation.norweakarray", True)], }, cmdline="--gc"), ChoiceOption("gctransformer", "GC transformer that is used - internal", @@ -91,8 +95,11 @@ default=False, cmdline="--sandbox", requires=[("translation.thread", False)], suggests=[("translation.gc", "generation")]), - BoolOption("rweakref", "The backend supports RPython-level weakrefs", - default=True), + BoolOption("norweakref", "No support for RPython-level weakrefs", + default=False, + requires=[("translation.norweakarray", True)]), + BoolOption("norweakarray", "No support for RPython-level weak arrays", + default=False), # JIT generation: use -Ojit to enable it BoolOption("jit", "generate a JIT", Added: pypy/branch/weakdict/pypy/doc/config/translation.norweakarray.txt ============================================================================== --- (empty file) +++ pypy/branch/weakdict/pypy/doc/config/translation.norweakarray.txt Fri Sep 4 14:28:03 2009 @@ -0,0 +1,2 @@ +This indicates if the backend and GC policy support "weak arrays". +These arrays are used by pypy.rlib.rweakref.RWeakValueDictionary. Modified: pypy/branch/weakdict/pypy/jit/backend/llsupport/gc.py ============================================================================== --- pypy/branch/weakdict/pypy/jit/backend/llsupport/gc.py (original) +++ pypy/branch/weakdict/pypy/jit/backend/llsupport/gc.py Fri Sep 4 14:28:03 2009 @@ -343,7 +343,7 @@ return llop1.do_malloc_varsize_clear( llmemory.GCREF, type_id, num_elem, self.array_basesize, itemsize, - self.array_length_ofs, True) + self.array_length_ofs, True, False) self.malloc_array = malloc_array self.GC_MALLOC_ARRAY = lltype.Ptr(lltype.FuncType( [lltype.Signed] * 3, llmemory.GCREF)) @@ -359,12 +359,12 @@ return llop1.do_malloc_varsize_clear( llmemory.GCREF, str_type_id, length, str_basesize, str_itemsize, - str_ofs_length, True) + str_ofs_length, True, False) def malloc_unicode(length): return llop1.do_malloc_varsize_clear( llmemory.GCREF, unicode_type_id, length, unicode_basesize, unicode_itemsize, - unicode_ofs_length, True) + unicode_ofs_length, True, False) self.malloc_str = malloc_str self.malloc_unicode = malloc_unicode self.GC_MALLOC_STR_UNICODE = lltype.Ptr(lltype.FuncType( Modified: pypy/branch/weakdict/pypy/jit/backend/llsupport/test/test_gc.py ============================================================================== --- pypy/branch/weakdict/pypy/jit/backend/llsupport/test/test_gc.py (original) +++ pypy/branch/weakdict/pypy/jit/backend/llsupport/test/test_gc.py Fri Sep 4 14:28:03 2009 @@ -124,8 +124,10 @@ return p def do_malloc_varsize_clear(self, RESTYPE, type_id, length, size, - itemsize, offset_to_length, can_collect): + itemsize, offset_to_length, can_collect, + contains_weakptr): assert can_collect + assert not contains_weakptr p = llmemory.raw_malloc(size + itemsize * length) (p + offset_to_length).signed[0] = length p = llmemory.cast_adr_to_ptr(p, RESTYPE) Modified: pypy/branch/weakdict/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/branch/weakdict/pypy/jit/metainterp/codewriter.py (original) +++ pypy/branch/weakdict/pypy/jit/metainterp/codewriter.py Fri Sep 4 14:28:03 2009 @@ -737,6 +737,8 @@ else: # XXX only strings or simple arrays for now ARRAY = op.args[0].value + assert isinstance(ARRAY, lltype.GcArray) + assert not isinstance(ARRAY.OF, lltype.Struct) arraydescr = self.cpu.arraydescrof(ARRAY) self.emit('new_array') self.emit(self.get_position(arraydescr)) Modified: pypy/branch/weakdict/pypy/jit/tl/targetpypyjit.py ============================================================================== --- pypy/branch/weakdict/pypy/jit/tl/targetpypyjit.py (original) +++ pypy/branch/weakdict/pypy/jit/tl/targetpypyjit.py Fri Sep 4 14:28:03 2009 @@ -39,7 +39,7 @@ def handle_config(config, translateconfig): config.translation.backendopt.inline_threshold = 0 # XXX - config.translation.rweakref = False # XXX + config.translation.norweakref = True # XXX # set up the objspace optimizations based on the --opt argument from pypy.config.pypyoption import set_pypy_opt_level set_pypy_opt_level(config, translateconfig.opt) Modified: pypy/branch/weakdict/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/branch/weakdict/pypy/objspace/std/typeobject.py (original) +++ pypy/branch/weakdict/pypy/objspace/std/typeobject.py Fri Sep 4 14:28:03 2009 @@ -285,7 +285,7 @@ def add_subclass(w_self, w_subclass): space = w_self.space - if not space.config.translation.rweakref: + if space.config.translation.norweakref: return # no weakref support, don't keep track of subclasses import weakref assert isinstance(w_subclass, W_TypeObject) @@ -300,7 +300,7 @@ def remove_subclass(w_self, w_subclass): space = w_self.space - if not space.config.translation.rweakref: + if space.config.translation.norweakref: return # no weakref support, don't keep track of subclasses for i in range(len(w_self.weak_subclasses)): ref = w_self.weak_subclasses[i] @@ -310,7 +310,7 @@ def get_subclasses(w_self): space = w_self.space - if not space.config.translation.rweakref: + if space.config.translation.norweakref: msg = ("this feature requires weakrefs, " "which are not available in this build of PyPy") raise OperationError(space.w_RuntimeError, Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/base.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/base.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/base.py Fri Sep 4 14:28:03 2009 @@ -99,7 +99,6 @@ contains_weakptr = self.weakpointer_offset(typeid) >= 0 assert not (needs_finalizer and contains_weakptr) if self.is_varsize(typeid): - assert not contains_weakptr assert not needs_finalizer itemsize = self.varsize_item_sizes(typeid) offset_to_length = self.varsize_offset_to_length(typeid) @@ -108,7 +107,7 @@ else: malloc_varsize = self.malloc_varsize ref = malloc_varsize(typeid, length, size, itemsize, - offset_to_length, True) + offset_to_length, True, contains_weakptr) else: if zero or not hasattr(self, 'malloc_fixedsize'): malloc_fixedsize = self.malloc_fixedsize_clear Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py Fri Sep 4 14:28:03 2009 @@ -28,6 +28,7 @@ old objects that contain pointers to young objects are recorded in a list. """ + gcname = "generation" inline_simple_malloc = True inline_simple_malloc_varsize = True needs_write_barrier = True @@ -160,7 +161,8 @@ return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect): + offset_to_length, can_collect, + contains_weakptr): # Only use the nursery if there are not too many items. if not raw_malloc_usage(itemsize): too_many_items = False @@ -179,7 +181,7 @@ maxlength = maxlength_for_minimal_nursery << self.nursery_scale too_many_items = length > maxlength - if (not can_collect or + if (contains_weakptr or not can_collect or too_many_items or (raw_malloc_usage(size) > self.lb_young_var_basesize and raw_malloc_usage(size) > self.largest_young_var_basesize)): @@ -189,7 +191,8 @@ # second comparison as well. return SemiSpaceGC.malloc_varsize_clear(self, typeid, length, size, itemsize, offset_to_length, - can_collect) + can_collect, + contains_weakptr) # with the above checks we know now that totalsize cannot be more # than about half of the nursery size; in particular, the + and * # cannot overflow Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/hybrid.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/hybrid.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/hybrid.py Fri Sep 4 14:28:03 2009 @@ -78,6 +78,7 @@ except that objects above a certain size are handled separately: they are allocated via raw_malloc/raw_free in a mark-n-sweep fashion. """ + gcname = "hybrid" first_unused_gcflag = _gcflag_next_bit prebuilt_gc_objects_are_static_roots = True can_realloc = False @@ -132,11 +133,12 @@ # 'large'. def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect): - if not can_collect: + offset_to_length, can_collect, contains_weakptr): + if contains_weakptr or not can_collect: return SemiSpaceGC.malloc_varsize_clear(self, typeid, length, size, itemsize, offset_to_length, - can_collect) + can_collect, + contains_weakptr) size_gc_header = self.gcheaderbuilder.size_gc_header nonvarsize = size_gc_header + size Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/markcompact.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/markcompact.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/markcompact.py Fri Sep 4 14:28:03 2009 @@ -69,6 +69,7 @@ BYTES_PER_TID = rffi.sizeof(TID_TYPE) class MarkCompactGC(MovingGCBase): + gcname = "markcompact" HDR = lltype.Struct('header', ('forward_ptr', llmemory.Address)) TID_BACKUP = lltype.Array(TID_TYPE, hints={'nolength':True}) WEAKREF_OFFSETS = lltype.Array(lltype.Signed) Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/marksweep.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/marksweep.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/marksweep.py Fri Sep 4 14:28:03 2009 @@ -21,6 +21,7 @@ memoryError = MemoryError() class MarkSweepGC(GCBase): + gcname = "marksweep" HDR = lltype.ForwardReference() HDRPTR = lltype.Ptr(HDR) # need to maintain a linked list of malloced objects, since we used the @@ -151,7 +152,8 @@ malloc_fixedsize_clear._dont_inline_ = True def malloc_varsize(self, typeid, length, size, itemsize, offset_to_length, - can_collect): + can_collect, contains_weakptr): + assert not contains_weakptr if can_collect: self.maybe_collect() size_gc_header = self.gcheaderbuilder.size_gc_header @@ -183,7 +185,8 @@ malloc_varsize._dont_inline_ = True def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect): + offset_to_length, can_collect, contains_weakptr): + assert not contains_weakptr if can_collect: self.maybe_collect() size_gc_header = self.gcheaderbuilder.size_gc_header @@ -293,7 +296,6 @@ size = self.fixed_size(typeid) estimate = raw_malloc_usage(size_gc_header + size) if hdr.typeid & 1: - typeid = hdr.typeid >> 1 offset = self.weakpointer_offset(typeid) hdr.typeid = hdr.typeid & (~1) gc_info = llmemory.cast_ptr_to_adr(hdr) @@ -687,6 +689,7 @@ class PrintingMarkSweepGC(MarkSweepGC): _alloc_flavor_ = "raw" + gcname = "statistics" COLLECT_EVERY = 2000 def __init__(self, chunk_size=DEFAULT_CHUNK_SIZE, start_heap_size=4096): Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/semispace.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/semispace.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/semispace.py Fri Sep 4 14:28:03 2009 @@ -25,6 +25,7 @@ class SemiSpaceGC(MovingGCBase): _alloc_flavor_ = "raw" + gcname = "semispace" inline_simple_malloc = True inline_simple_malloc_varsize = True malloc_zero_filled = True @@ -83,7 +84,8 @@ return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect): + offset_to_length, can_collect, + contains_weakptr=False): size_gc_header = self.gcheaderbuilder.size_gc_header nonvarsize = size_gc_header + size try: @@ -100,6 +102,8 @@ self.init_gc_object(result, typeid) (result + size_gc_header + offset_to_length).signed[0] = length self.free = result + llarena.round_up_for_allocation(totalsize) + if contains_weakptr: + self.objects_with_weakrefs.append(result + size_gc_header) return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def obtain_free_space(self, needed): @@ -516,18 +520,45 @@ if not self.surviving(obj): continue # weakref itself dies obj = self.get_forwarding_address(obj) - offset = self.weakpointer_offset(self.get_type_id(obj)) - pointing_to = (obj + offset).address[0] - # XXX I think that pointing_to cannot be NULL here + tid = self.get_type_id(obj) + offset = self.weakpointer_offset(tid) + if self.is_varsize(tid): + self.invalidate_weakarray(obj, tid, offset) + new_with_weakref.append(obj) + else: + # a weakref object, with a single weak pointer + pointing_to = (obj + offset).address[0] + # XXX I think that pointing_to cannot be NULL here + if pointing_to: + if self.surviving(pointing_to): + (obj + offset).address[0] = \ + self.get_forwarding_address(pointing_to) + new_with_weakref.append(obj) + else: + (obj + offset).address[0] = NULL + self.objects_with_weakrefs.delete() + self.objects_with_weakrefs = new_with_weakref + + def invalidate_weakarray(self, obj, typeid, weakoffset): + # a weakarray: walk over all entries + item = obj + self.varsize_offset_to_variable_part(typeid) + length = (obj + self.varsize_offset_to_length(typeid)).signed[0] + offsets = self.varsize_offsets_to_gcpointers_in_var_part(typeid) + itemlength = self.varsize_item_sizes(typeid) + while length > 0: + pointing_to = (item + weakoffset).address[0] if pointing_to: if self.surviving(pointing_to): - (obj + offset).address[0] = self.get_forwarding_address( - pointing_to) - new_with_weakref.append(obj) + (item + weakoffset).address[0] = \ + self.get_forwarding_address(pointing_to) else: - (obj + offset).address[0] = NULL - self.objects_with_weakrefs.delete() - self.objects_with_weakrefs = new_with_weakref + (item + weakoffset).address[0] = NULL + j = 0 + while j < len(offsets): + (item + offsets[j]).address[0] = NULL + j += 1 + item += itemlength + length -= 1 def update_run_finalizers(self): # we are in an inner collection, caused by a finalizer Modified: pypy/branch/weakdict/pypy/rpython/memory/gctransform/framework.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gctransform/framework.py Fri Sep 4 14:28:03 2009 @@ -621,12 +621,12 @@ # used by the JIT (see pypy.jit.backend.llsupport.gc) op = hop.spaceop [v_typeid, v_length, v_size, v_itemsize, - v_offset_to_length, v_can_collect] = op.args + v_offset_to_length, v_can_collect, v_contains_weakptr] = op.args livevars = self.push_roots(hop) hop.genop("direct_call", [self.malloc_varsize_clear_ptr, self.c_const_gc, v_typeid, v_length, v_size, v_itemsize, - v_offset_to_length, v_can_collect], + v_offset_to_length, v_can_collect, v_contains_weakptr], resultvar=op.result) self.pop_roots(hop, livevars) Modified: pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py Fri Sep 4 14:28:03 2009 @@ -33,6 +33,13 @@ def teardown_class(cls): py.log._setstate(cls._saved_logstate) + def get_config(self): + from pypy.config.translationoption import \ + get_combined_translation_config + config = get_combined_translation_config() + config.translation.gc = self.GCClass.gcname + return config + def interpret(self, func, values, **kwds): interp, graph = get_interpreter(func, values, **kwds) gcwrapper.prepare_graphs_and_create_gc(interp, self.GCClass, @@ -262,6 +269,47 @@ res = self.interpret(f, []) assert res + def test_weakarray(self): + if self.get_config().translation.norweakarray: + py.test.skip("no weak arrays on this GC") + OBJ = lltype.GcStruct('OBJ', ('x', lltype.Signed)) + prebuilt_obj = lltype.malloc(OBJ, zero=True) + S = lltype.Struct('S', ('foo', lltype.Ptr(OBJ)), + ('bar', lltype.Ptr(OBJ))) + A = lltype.GcArray(S, hints={'weakarray': 'bar'}) + # + def set(d, n): + obj1 = lltype.malloc(OBJ, zero=True) + obj2 = lltype.malloc(OBJ, zero=True) + d[n].foo = obj1 + d[n].bar = obj2 + return obj1, obj2 + def g(d): + key1, value1 = set(d, 1) + key2, value2 = set(d, 2) + key3, value3 = set(d, 3) + return key1, value1, key3, value3 # key2, value2 dropped + def f(): + d = lltype.malloc(A, 4) + i = 0 + while i < 4: + d[i].foo = prebuilt_obj + d[i].bar = lltype.nullptr(OBJ) + i += 1 + key1, value1, key3, value3 = g(d) + llop.gc__collect(lltype.Void) + llop.gc__collect(lltype.Void) + return (((d[0].foo == prebuilt_obj) << 0) + + ((not d[0].bar) << 1) + + ((d[1].foo == key1) << 2) + + ((d[1].bar == value1) << 3) + + ((not d[2].foo) << 4) + # \ removed by + ((not d[2].bar) << 5) + # / gc.collect + ((d[3].foo == key3) << 6) + + ((d[3].bar == value3) << 7)) + res = self.interpret(f, []) + assert res == 255 + def test_weakvaluedict(self): py.test.skip("in-progress") from pypy.rlib.rweakref import RWeakValueDictionary Modified: pypy/branch/weakdict/pypy/rpython/rweakref.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/rweakref.py (original) +++ pypy/branch/weakdict/pypy/rpython/rweakref.py Fri Sep 4 14:28:03 2009 @@ -24,7 +24,7 @@ def __init__(self, rtyper): self.rtyper = rtyper - if not rtyper.getconfig().translation.rweakref: + if rtyper.getconfig().translation.norweakref: raise TyperError("RPython-level weakrefs are not supported by " "this backend or GC policy") Modified: pypy/branch/weakdict/pypy/translator/goal/targetpreimportedpypy.py ============================================================================== --- pypy/branch/weakdict/pypy/translator/goal/targetpreimportedpypy.py (original) +++ pypy/branch/weakdict/pypy/translator/goal/targetpreimportedpypy.py Fri Sep 4 14:28:03 2009 @@ -181,7 +181,7 @@ "to translate.py instead of " "--withmod-_stackless directly") - if not config.translation.rweakref: + if config.translation.norweakref: config.objspace.usemodules._weakref = False if self.translateconfig.goal_options.jit: Modified: pypy/branch/weakdict/pypy/translator/goal/targetpypystandalone.py ============================================================================== --- pypy/branch/weakdict/pypy/translator/goal/targetpypystandalone.py (original) +++ pypy/branch/weakdict/pypy/translator/goal/targetpypystandalone.py Fri Sep 4 14:28:03 2009 @@ -172,7 +172,7 @@ "to translate.py instead of " "--withmod-_stackless directly") - if not config.translation.rweakref: + if config.translation.norweakref: config.objspace.usemodules._weakref = False if config.translation.jit: From fijal at codespeak.net Fri Sep 4 15:23:32 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 4 Sep 2009 15:23:32 +0200 (CEST) Subject: [pypy-svn] r67472 - pypy/branch/no-recompilation/pypy/jit/backend/x86/test Message-ID: <20090904132332.7401A168016@codespeak.net> Author: fijal Date: Fri Sep 4 15:23:28 2009 New Revision: 67472 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Log: A test for last "oups" commit Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_regalloc.py Fri Sep 4 15:23:28 2009 @@ -491,6 +491,26 @@ self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0]) assert self.getint(0) == 0 + def test_bug_wrong_stack_adj(self): + ops = ''' + [i0, i1, i2, i3, i4, i5, i6, i7, i8] + guard_true(i0) + fail(0, i0, i1, i2, i3, i4, i5, i6, i7, i8) + fail(1, i0, i1, i2, i3, i4, i5, i6, i7, i8) + ''' + loop = self.interpret(ops, [0, 1, 2, 3, 4, 5, 6, 7, 8]) + assert self.getint(0) == 0 + bridge_ops = ''' + [i0, i1, i2, i3, i4, i5, i6, i7, i8] + call(ConstClass(raising_fptr), 0, descr=raising_calldescr) + fail(i0, i1, i2, i3, i4, i5, i6, i7, i8) + ''' + self.attach_bridge(bridge_ops, loop, loop.operations[0]) + for i in range(9): + self.cpu.set_future_value_int(i, i) + self.cpu.execute_operations(loop) + assert self.getints(9) == range(9) + class TestRegallocCompOps(BaseTestRegalloc): def test_cmp_op_0(self): From fijal at codespeak.net Fri Sep 4 15:30:08 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 4 Sep 2009 15:30:08 +0200 (CEST) Subject: [pypy-svn] r67473 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090904133008.1F052168016@codespeak.net> Author: fijal Date: Fri Sep 4 15:30:07 2009 New Revision: 67473 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Log: rpythonization Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Fri Sep 4 15:30:07 2009 @@ -165,6 +165,7 @@ regalloc = RegAlloc(self, tree, self.cpu.translate_support_code, guard_op) self._regalloc = regalloc + adr_lea = 0 if guard_op is None: inputargs = tree.inputargs self.logger.log_loop(tree) From antocuni at codespeak.net Fri Sep 4 15:41:43 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 4 Sep 2009 15:41:43 +0200 (CEST) Subject: [pypy-svn] r67474 - in pypy/trunk/pypy: jit/metainterp module/pypyjit Message-ID: <20090904134143.12E2C168016@codespeak.net> Author: antocuni Date: Fri Sep 4 15:41:42 2009 New Revision: 67474 Modified: pypy/trunk/pypy/jit/metainterp/policy.py pypy/trunk/pypy/module/pypyjit/policy.py Log: kill ManualJitPolicy, as it's no longer used Modified: pypy/trunk/pypy/jit/metainterp/policy.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/policy.py (original) +++ pypy/trunk/pypy/jit/metainterp/policy.py Fri Sep 4 15:41:42 2009 @@ -99,96 +99,3 @@ if func in self.funcs: return False return super(StopAtXPolicy, self).look_inside_function(func) - -# ____________________________________________________________ - -from pypy.annotation.specialize import getuniquenondirectgraph - -class ManualJitPolicy(JitPolicy): - def __init__(self, translator): - self.translator = translator - self.bookkeeper = translator.annotator.bookkeeper - self.enabled_graphs = {} - self.memo = {} - self.fill_seen_graphs() - - def look_inside_graph(self, graph): - if graph in self.enabled_graphs: - return self.enabled_graphs[graph] - res = super(ManualJitPolicy, self).look_inside_graph(graph) - self.enabled_graphs[graph] = res # cache the result - return res - - def fill_seen_graphs(self): - # subclasses should have their own - pass - - def _graph(self, func): - func = getattr(func, 'im_func', func) - desc = self.bookkeeper.getdesc(func) - return getuniquenondirectgraph(desc) - - def seefunc(self, fromfunc, *tofuncs): - targetgraphs = {} - for tofunc in tofuncs: - targetgraphs[self._graph(tofunc)] = True - graphs = graphs_on_the_path_to(self.translator, self._graph(fromfunc), - targetgraphs, self.memo) - for graph in graphs: - if graph not in self.enabled_graphs: - self.enabled_graphs[graph] = True - print '++', graph - - def seepath(self, *path): - assert len(path) >= 2 - for i in range(1, len(path)): - self.seefunc(path[i-1], path[i]) - - def seegraph(self, func, look=True): - graph = self._graph(func) - self.enabled_graphs[graph] = look - if look: - print '++', graph - else: - print '--', graph - -def enumerate_reachable_graphs(translator, startgraph, memo=None): - from pypy.translator.backendopt.support import find_calls_from - pending = [(startgraph, None)] - yield pending[0] - seen = {startgraph: True} - while pending: - yield None # hack: a separator meaning "length increases now" - nextlengthlist = [] - nextseen = {} - for node in pending: - head, tail = node - for block, callee in find_calls_from(translator, head, memo): - if callee not in seen: - newnode = callee, node - yield newnode - nextlengthlist.append(newnode) - nextseen[callee] = True - pending = nextlengthlist - seen.update(nextseen) - yield None - -def graphs_on_the_path_to(translator, startgraph, targetgraphs, memo=None): - targetgraphs = targetgraphs.copy() - result = {} - found = {} - for node in enumerate_reachable_graphs(translator, startgraph, memo): - if node is None: # hack: a separator meaning "length increases now" - for graph in found: - del targetgraphs[graph] - found.clear() - if not targetgraphs: - return result - elif node[0] in targetgraphs: - found[node[0]] = True - while node is not None: - head, tail = node - result[head] = True - node = tail - raise Exception("did not reach all targets:\nmissing %r" % ( - targetgraphs.keys(),)) Modified: pypy/trunk/pypy/module/pypyjit/policy.py ============================================================================== --- pypy/trunk/pypy/module/pypyjit/policy.py (original) +++ pypy/trunk/pypy/module/pypyjit/policy.py Fri Sep 4 15:41:42 2009 @@ -1,6 +1,6 @@ -from pypy.jit.metainterp.policy import ManualJitPolicy +from pypy.jit.metainterp.policy import JitPolicy -class PyPyJitPolicy(ManualJitPolicy): +class PyPyJitPolicy(JitPolicy): def look_inside_function(self, func): mod = func.__module__ or '?' From pedronis at codespeak.net Fri Sep 4 15:45:46 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 4 Sep 2009 15:45:46 +0200 (CEST) Subject: [pypy-svn] r67475 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090904134546.18C74168016@codespeak.net> Author: pedronis Date: Fri Sep 4 15:45:45 2009 New Revision: 67475 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Log: (pedronis, arigo) force the LEA to be fixed sized so that it can be patched safely Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Fri Sep 4 15:45:45 2009 @@ -175,7 +175,7 @@ self.logger.log_operations mc = self.mc._mc adr_lea = mc.tell() - mc.LEA(esp, addr_add(imm32(0), ebp, 0)) + mc.LEA(esp, fixedsize_ebp_ofs(0)) regalloc._walk_operations(operations) stack_depth = regalloc.max_stack_depth self.mc.done() @@ -186,8 +186,8 @@ else: guard_op._x86_stack_depth = stack_depth mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) - mc.LEA(esp, addr_add(imm32(0), ebp, - -(stack_depth + RET_BP - 2) * WORD)) + + mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) mc.done() if we_are_translated(): self._regalloc = None # else keep it around for debugging From fijal at codespeak.net Fri Sep 4 15:47:00 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 4 Sep 2009 15:47:00 +0200 (CEST) Subject: [pypy-svn] r67476 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090904134700.94EEE168016@codespeak.net> Author: fijal Date: Fri Sep 4 15:47:00 2009 New Revision: 67476 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Log: Kill dead code Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Fri Sep 4 15:47:00 2009 @@ -592,31 +592,28 @@ #tree.comeback_bootstrap_addr = self.assemble_comeback_bootstrap(pos, # locs, stacklocs) - def patch_jump(self, old_pos, new_pos, oldlocs, newlocs, olddepth, newdepth): - for i in range(len(oldlocs)): - oldloc = oldlocs[i] - newloc = newlocs[i] - if isinstance(newloc, MODRM): - assert isinstance(oldloc, MODRM) - assert newloc.position == oldloc.position - else: - assert newloc is oldloc - # newlocs should be sorted in acending order, excluding the regs - if not we_are_translated(): - locs = [loc.position for loc in newlocs if isinstance(loc, MODRM)] - assert locs == sorted(locs) - # - mc = codebuf.InMemoryCodeBuilder(old_pos, old_pos + - MachineCodeBlockWrapper.MC_SIZE) - mc.SUB(esp, imm(WORD * (newdepth - olddepth))) - mc.JMP(rel32(new_pos)) - mc.done() +# def patch_jump(self, old_pos, new_pos, oldlocs, newlocs, olddepth, newdepth): +# for i in range(len(oldlocs)): +# oldloc = oldlocs[i] +# newloc = newlocs[i] +# if isinstance(newloc, MODRM): +# assert isinstance(oldloc, MODRM) +# assert newloc.position == oldloc.position +# else: +# assert newloc is oldloc +# # newlocs should be sorted in acending order, excluding the regs +# if not we_are_translated(): +# locs = [loc.position for loc in newlocs if isinstance(loc, MODRM)] +# assert locs == sorted(locs) +# # +# mc = codebuf.InMemoryCodeBuilder(old_pos, old_pos + +# MachineCodeBlockWrapper.MC_SIZE) +# mc.SUB(esp, imm(WORD * (newdepth - olddepth))) +# mc.JMP(rel32(new_pos)) +# mc.done() def genop_discard_jump(self, op, locs): - targetmp = op.jump_target - # don't break the following code sequence! - mc = self.mc._mc - mc.JMP(rel32(targetmp._x86_compiled)) + self.mc.JMP(rel32(op.jump_target._x86_compiled)) def genop_guard_guard_true(self, op, ign_1, addr, locs, ign_2): loc = locs[0] From fijal at codespeak.net Fri Sep 4 15:58:33 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 4 Sep 2009 15:58:33 +0200 (CEST) Subject: [pypy-svn] r67477 - pypy/branch/no-recompilation/pypy/jit/backend/x86 Message-ID: <20090904135833.03D05168016@codespeak.net> Author: fijal Date: Fri Sep 4 15:58:33 2009 New Revision: 67477 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Log: Kill commented out code Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Fri Sep 4 15:58:33 2009 @@ -589,28 +589,6 @@ def make_merge_point(self, tree, locs): pos = self.mc.tell() tree._x86_compiled = pos - #tree.comeback_bootstrap_addr = self.assemble_comeback_bootstrap(pos, - # locs, stacklocs) - -# def patch_jump(self, old_pos, new_pos, oldlocs, newlocs, olddepth, newdepth): -# for i in range(len(oldlocs)): -# oldloc = oldlocs[i] -# newloc = newlocs[i] -# if isinstance(newloc, MODRM): -# assert isinstance(oldloc, MODRM) -# assert newloc.position == oldloc.position -# else: -# assert newloc is oldloc -# # newlocs should be sorted in acending order, excluding the regs -# if not we_are_translated(): -# locs = [loc.position for loc in newlocs if isinstance(loc, MODRM)] -# assert locs == sorted(locs) -# # -# mc = codebuf.InMemoryCodeBuilder(old_pos, old_pos + -# MachineCodeBlockWrapper.MC_SIZE) -# mc.SUB(esp, imm(WORD * (newdepth - olddepth))) -# mc.JMP(rel32(new_pos)) -# mc.done() def genop_discard_jump(self, op, locs): self.mc.JMP(rel32(op.jump_target._x86_compiled)) @@ -783,15 +761,6 @@ print "not implemented operation (guard): %s" % op.getopname() raise NotImplementedError - #def genop_call__1(self, op, arglocs, resloc): - # self.gen_call(op, arglocs, resloc) - # self.mc.MOVZX(eax, al) - - #def genop_call__2(self, op, arglocs, resloc): - # # XXX test it test it test it - # self.gen_call(op, arglocs, resloc) - # self.mc.MOVZX(eax, eax) - def mark_gc_roots(self): gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap: From arigo at codespeak.net Fri Sep 4 15:59:20 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 15:59:20 +0200 (CEST) Subject: [pypy-svn] r67478 - in pypy/branch/weakdict/pypy/rpython: lltypesystem memory/gc memory/test Message-ID: <20090904135920.1984D168016@codespeak.net> Author: arigo Date: Fri Sep 4 15:59:19 2009 New Revision: 67478 Modified: pypy/branch/weakdict/pypy/rpython/lltypesystem/llarena.py pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py Log: In-progress, with debug prints. Abandonning that path for now... Modified: pypy/branch/weakdict/pypy/rpython/lltypesystem/llarena.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/lltypesystem/llarena.py (original) +++ pypy/branch/weakdict/pypy/rpython/lltypesystem/llarena.py Fri Sep 4 15:59:19 2009 @@ -32,6 +32,8 @@ else: stop = start + llmemory.raw_malloc_usage(size) assert 0 <= start <= stop <= self.nbytes + print '------------------ reset %s %d %d ----------------' % ( + id(self), start, stop) for offset, ptr in self.objectptrs.items(): size = self.objectsizes[offset] if offset < start: # object is before the cleared area @@ -40,6 +42,7 @@ assert offset >= stop, "object overlaps cleared area" else: obj = ptr._obj + print offset, '\t', obj del Arena.object_arena_location[obj] del self.objectptrs[offset] del self.objectsizes[offset] @@ -49,6 +52,7 @@ else: initialbyte = "#" self.usagemap[start:stop] = array.array('c', initialbyte*(stop-start)) + print self.usagemap.tostring()[:150] def check(self): if self.freed: Modified: pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/gc/generation.py Fri Sep 4 15:59:19 2009 @@ -394,6 +394,9 @@ if self.is_in_nursery(pointer.address[0]): pointer.address[0] = self.copy(pointer.address[0]) + # The code relies on the fact that no weakref can be an old object + # weakly pointing to a young object. Indeed, weakrefs are immutable + # so they cannot point to an object that was created after it. def invalidate_young_weakrefs(self): # walk over the list of objects that contain weakrefs and are in the # nursery. if the object it references survives then update the Modified: pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py ============================================================================== --- pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py (original) +++ pypy/branch/weakdict/pypy/rpython/memory/test/test_gc.py Fri Sep 4 15:59:19 2009 @@ -273,14 +273,14 @@ if self.get_config().translation.norweakarray: py.test.skip("no weak arrays on this GC") OBJ = lltype.GcStruct('OBJ', ('x', lltype.Signed)) - prebuilt_obj = lltype.malloc(OBJ, zero=True) + prebuilt_obj = lltype.malloc(OBJ); prebuilt_obj.x = -1 S = lltype.Struct('S', ('foo', lltype.Ptr(OBJ)), ('bar', lltype.Ptr(OBJ))) A = lltype.GcArray(S, hints={'weakarray': 'bar'}) # def set(d, n): - obj1 = lltype.malloc(OBJ, zero=True) - obj2 = lltype.malloc(OBJ, zero=True) + obj1 = lltype.malloc(OBJ); obj1.x = n + obj2 = lltype.malloc(OBJ); obj2.x = n+100 d[n].foo = obj1 d[n].bar = obj2 return obj1, obj2 @@ -310,7 +310,59 @@ res = self.interpret(f, []) assert res == 255 + def test_weakarray_larger(self): + if self.get_config().translation.norweakarray: + py.test.skip("no weak arrays on this GC") + OBJ = lltype.GcStruct('OBJ', ('x', lltype.Signed)) + prebuilt_obj = lltype.malloc(OBJ); prebuilt_obj.x = -1 + S = lltype.Struct('S', ('foo', lltype.Ptr(OBJ)), + ('bar', lltype.Ptr(OBJ))) + A = lltype.GcArray(S, hints={'weakarray': 'bar'}) + # + def set(d, n): + obj1 = lltype.malloc(OBJ, zero=True) + obj2 = lltype.malloc(OBJ, zero=True) + d[n].foo = obj1 + d[n].bar = obj2 + return obj1, obj2 + def g(d, a, b, discard): + lst = [] + while a < b: + key, value = set(d, a) + if not discard: + lst.append(key) + lst.append(value) + set(d, a+1) + a += 2 + return lst + def f(): + d = lltype.malloc(A, 65) + i = 0 + while i < 65: + d[i].foo = prebuilt_obj + d[i].bar = lltype.nullptr(OBJ) + i += 1 + g(d, 0, 16, True) # discard the first list + lst1 = g(d, 16, 64, False) + llop.gc__collect(lltype.Void) + llop.gc__collect(lltype.Void) + res = d[64].foo == prebuilt_obj and not d[64].bar + i = 0 + while i < 16: + res = res and not d[i].foo and not d[i].bar + i += 1 + while i < 64: + res = res and d[i].foo == lst1[i-16] and d[i].bar == lst1[i-15] + i += 1 + res = res and not d[i].foo and not d[i].bar + i += 1 + return res + res = self.interpret(f, []) + assert res + def test_weakvaluedict(self): + if self.get_config().translation.norweakarray: + py.test.skip("no weak arrays on this GC") py.test.skip("in-progress") from pypy.rlib.rweakref import RWeakValueDictionary class X(object): From arigo at codespeak.net Fri Sep 4 16:02:06 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 16:02:06 +0200 (CEST) Subject: [pypy-svn] r67479 - pypy/branch/weakdict2 Message-ID: <20090904140206.5AA34168016@codespeak.net> Author: arigo Date: Fri Sep 4 16:02:05 2009 New Revision: 67479 Added: pypy/branch/weakdict2/ - copied from r67470, pypy/branch/weakdict/ Log: A new branch, in which I am going to try a simplified "90%" approach in which I don't mess up with the GCs at all. From arigo at codespeak.net Fri Sep 4 16:06:33 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 16:06:33 +0200 (CEST) Subject: [pypy-svn] r67480 - in pypy/branch/weakdict2/pypy/rpython/memory: . test Message-ID: <20090904140633.04502168016@codespeak.net> Author: arigo Date: Fri Sep 4 16:06:33 2009 New Revision: 67480 Modified: pypy/branch/weakdict2/pypy/rpython/memory/gctypelayout.py pypy/branch/weakdict2/pypy/rpython/memory/test/test_gc.py pypy/branch/weakdict2/pypy/rpython/memory/test/test_gctypelayout.py Log: Revert checkins that were about 'weakarray'. Modified: pypy/branch/weakdict2/pypy/rpython/memory/gctypelayout.py ============================================================================== --- pypy/branch/weakdict2/pypy/rpython/memory/gctypelayout.py (original) +++ pypy/branch/weakdict2/pypy/rpython/memory/gctypelayout.py Fri Sep 4 16:06:33 2009 @@ -166,8 +166,7 @@ info.ofstovar = llmemory.itemoffsetof(TYPE, 0) assert isinstance(ARRAY, lltype.Array) if ARRAY.OF != lltype.Void: - ignore = ARRAY._hints.get('weakarray', None) - offsets = offsets_to_gc_pointers(ARRAY.OF, ignoring=ignore) + offsets = offsets_to_gc_pointers(ARRAY.OF) else: offsets = () info.varofstoptrs = builder.offsets2table(offsets, ARRAY.OF) @@ -323,12 +322,10 @@ # # Helpers to discover GC pointers inside structures -def offsets_to_gc_pointers(TYPE, ignoring=None): +def offsets_to_gc_pointers(TYPE): offsets = [] if isinstance(TYPE, lltype.Struct): for name in TYPE._names: - if name == ignoring: - continue FIELD = getattr(TYPE, name) if isinstance(FIELD, lltype.Array): continue # skip inlined array @@ -355,9 +352,6 @@ def weakpointer_offset(TYPE): if TYPE == WEAKREF: return llmemory.offsetof(WEAKREF, "weakptr") - if isinstance(TYPE, lltype.GcArray) and 'weakarray' in TYPE._hints: - weakfieldname = TYPE._hints['weakarray'] - return llmemory.offsetof(TYPE.OF, weakfieldname) return -1 def gc_pointers_inside(v, adr, mutable_only=False): Modified: pypy/branch/weakdict2/pypy/rpython/memory/test/test_gc.py ============================================================================== --- pypy/branch/weakdict2/pypy/rpython/memory/test/test_gc.py (original) +++ pypy/branch/weakdict2/pypy/rpython/memory/test/test_gc.py Fri Sep 4 16:06:33 2009 @@ -222,7 +222,7 @@ assert 160 <= res <= 165 def test_weakref(self): - import weakref + import weakref, gc class A(object): pass def g(): @@ -243,7 +243,7 @@ assert res def test_weakref_to_object_with_finalizer(self): - import weakref + import weakref, gc class A(object): count = 0 a = A() @@ -262,31 +262,6 @@ res = self.interpret(f, []) assert res - def test_weakvaluedict(self): - py.test.skip("in-progress") - from pypy.rlib.rweakref import RWeakValueDictionary - class X(object): - def __init__(self, n): - self.n = n - def g(d, x111): - x222 = X(222) - d.set("abc", x111) - d.set("def", x222) - return ((d.get("abc") is x111) * 100 + - (d.get("def") is x222) * 10 + - (d.get("foobar") is not None)) - def f(): - d = RWeakValueDictionary(X) - x111 = X(111) - res = g(d, x111) - llop.gc__collect(lltype.Void) - llop.gc__collect(lltype.Void) - res = res + ((d.get("abc") is x111) * 10000 + - (d.get("def") is not None) * 1000) - return res - res = self.interpret(f, []) - assert res == 10110 - def test_id(self): class A(object): pass Modified: pypy/branch/weakdict2/pypy/rpython/memory/test/test_gctypelayout.py ============================================================================== --- pypy/branch/weakdict2/pypy/rpython/memory/test/test_gctypelayout.py (original) +++ pypy/branch/weakdict2/pypy/rpython/memory/test/test_gctypelayout.py Fri Sep 4 16:06:33 2009 @@ -1,6 +1,6 @@ from pypy.rpython.memory.gctypelayout import TypeLayoutBuilder, GCData from pypy.rpython.memory.gctypelayout import offsets_to_gc_pointers -from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem import lltype def getname(T): try: @@ -40,22 +40,3 @@ lst1 = gcdata.q_varsize_offsets_to_gcpointers_in_var_part(tid1) lst2 = gcdata.q_offsets_to_gc_pointers(tid2) assert len(lst1) == len(lst2) - -def test_weakarray(): - OBJ = lltype.GcStruct('some_object') - S = lltype.Struct('weakstruct', - ('foo', lltype.Ptr(OBJ)), - ('bar', lltype.Ptr(OBJ))) - A = lltype.GcArray(S, hints={'weakarray': 'bar'}) - layoutbuilder = TypeLayoutBuilder() - tid = layoutbuilder.get_type_id(A) - gcdata = GCData(layoutbuilder.type_info_list) - assert gcdata.q_is_varsize(tid) - assert gcdata.q_has_gcptr_in_varsize(tid) - assert not gcdata.q_is_gcarrayofgcptr(tid) - assert len(gcdata.q_offsets_to_gc_pointers(tid)) == 0 - assert len(gcdata.q_varsize_offsets_to_gcpointers_in_var_part(tid)) == 1 - weakofs = gcdata.q_weakpointer_offset(tid) - assert isinstance(weakofs, llmemory.FieldOffset) - assert weakofs.TYPE == S - assert weakofs.fldname == 'bar' From arigo at codespeak.net Fri Sep 4 16:08:46 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 16:08:46 +0200 (CEST) Subject: [pypy-svn] r67481 - pypy/branch/weakdict2/pypy/rpython/memory/gc Message-ID: <20090904140846.CD2D5168029@codespeak.net> Author: arigo Date: Fri Sep 4 16:08:45 2009 New Revision: 67481 Modified: pypy/branch/weakdict2/pypy/rpython/memory/gc/generation.py Log: Add a comment. Modified: pypy/branch/weakdict2/pypy/rpython/memory/gc/generation.py ============================================================================== --- pypy/branch/weakdict2/pypy/rpython/memory/gc/generation.py (original) +++ pypy/branch/weakdict2/pypy/rpython/memory/gc/generation.py Fri Sep 4 16:08:45 2009 @@ -391,6 +391,9 @@ if self.is_in_nursery(pointer.address[0]): pointer.address[0] = self.copy(pointer.address[0]) + # The code relies on the fact that no weakref can be an old object + # weakly pointing to a young object. Indeed, weakrefs are immutable + # so they cannot point to an object that was created after it. def invalidate_young_weakrefs(self): # walk over the list of objects that contain weakrefs and are in the # nursery. if the object it references survives then update the From fijal at codespeak.net Fri Sep 4 16:25:00 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 4 Sep 2009 16:25:00 +0200 (CEST) Subject: [pypy-svn] r67482 - pypy/branch/no-recompilation/pypy/jit/backend/test Message-ID: <20090904142500.DAC20168025@codespeak.net> Author: fijal Date: Fri Sep 4 16:24:57 2009 New Revision: 67482 Modified: pypy/branch/no-recompilation/pypy/jit/backend/test/test_random.py Log: I *think* this one is correctly preserving assumptions. Mess mess mess :-( Modified: pypy/branch/no-recompilation/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/test/test_random.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/test/test_random.py Fri Sep 4 16:24:57 2009 @@ -502,6 +502,7 @@ bridge_builder = self.builder.fork(self.builder.cpu, subloop, op.args[:]) self.generate_ops(bridge_builder, r, subloop, op.args[:]) + dont_compile = False if r.random() < 0.1: subset = bridge_builder.subset_of_intvars(r) if len(subset) == 0: @@ -517,17 +518,22 @@ if self.guard_op is None: guard_op.suboperations[-1] = jump_op else: + self.guard_op.suboperations[0].args.extend(subset) + self.builder.cpu.compile_operations(self.loop, guard_op) if self.guard_op.is_guard_exception(): # exception clearing self.guard_op.suboperations.insert(-1, exc_handling( self.guard_op)) self.guard_op.suboperations[-1] = jump_op + self.builder.cpu.compile_operations(self.loop, self.guard_op) + dont_compile = True self.guard_op = jump_target.guard_op self.prebuilt_ptr_consts += jump_target.prebuilt_ptr_consts self.dont_generate_more = True if r.random() < .05: return False - self.builder.cpu.compile_operations(self.loop) + if not dont_compile: + self.builder.cpu.compile_operations(self.loop, guard_op) return True def check_random_function(cpu, BuilderClass, r, num=None, max=None): From pedronis at codespeak.net Fri Sep 4 16:26:37 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 4 Sep 2009 16:26:37 +0200 (CEST) Subject: [pypy-svn] r67483 - in pypy/trunk/pypy: config doc/config objspace/std objspace/std/test Message-ID: <20090904142637.81929168025@codespeak.net> Author: pedronis Date: Fri Sep 4 16:26:36 2009 New Revision: 67483 Added: pypy/trunk/pypy/doc/config/objspace.std.newshortcut.txt (contents, props changed) Modified: pypy/trunk/pypy/config/pypyoption.py pypy/trunk/pypy/objspace/std/test/test_typeobject.py pypy/trunk/pypy/objspace/std/typeobject.py Log: (micke, pedronis) add a shortcut path to object creation, it speeds up object creation more than 20% for types without a custom __new__ Modified: pypy/trunk/pypy/config/pypyoption.py ============================================================================== --- pypy/trunk/pypy/config/pypyoption.py (original) +++ pypy/trunk/pypy/config/pypyoption.py Fri Sep 4 16:26:36 2009 @@ -328,6 +328,9 @@ BoolOption("getattributeshortcut", "track types that override __getattribute__", default=False), + BoolOption("newshortcut", + "cache and shortcut calling __new__ from builtin types", + default=False), BoolOption("logspaceoptypes", "a instrumentation option: before exit, print the types seen by " @@ -369,6 +372,7 @@ config.objspace.std.suggest(builtinshortcut=True) config.objspace.std.suggest(optimized_list_getitem=True) config.objspace.std.suggest(getattributeshortcut=True) + config.objspace.std.suggest(newshortcut=True) # extra costly optimizations only go in level 3 if level == '3': Added: pypy/trunk/pypy/doc/config/objspace.std.newshortcut.txt ============================================================================== --- (empty file) +++ pypy/trunk/pypy/doc/config/objspace.std.newshortcut.txt Fri Sep 4 16:26:36 2009 @@ -0,0 +1 @@ +Performance only: cache and shortcut calling __new__ from builtin types Modified: pypy/trunk/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/pypy/objspace/std/test/test_typeobject.py Fri Sep 4 16:26:36 2009 @@ -991,3 +991,82 @@ X.__getattribute__ = ga assert y.x == 'GA' + +class TestNewShortcut: + + def setup_class(cls): + cls.space = gettestobjspace( + **{"objspace.std.newshortcut": True}) + + def test_mechanics(self): + space = self.space + w_tup = space.appexec([], """(): + class A(object): + pass + class B(object): + __new__ = staticmethod(lambda t: 1) + class M(type): + pass + return A, B, M +""") + w_A, w_B, w_M = space.unpackiterable(w_tup) + + assert w_A.w_bltin_new is None + assert w_B.w_bltin_new is None + assert w_M.w_bltin_new is None + + _, w_object_newdescr = space.lookup_in_type_where(space.w_object, + '__new__') + w_object___new__ = space.get(w_object_newdescr, None, + w_type=space.w_object) + + w_a = space.call_function(w_A) + assert w_A.w_bltin_new is w_object___new__ + + # will shortcut + w_a = space.call_function(w_A) + + w_b = space.call_function(w_B) + assert w_B.w_bltin_new is None + + w_m = space.call_function(w_M, space.wrap('C'), space.newlist([]), + space.newdict()) + assert w_M.w_bltin_new is None + + +class AppTestNewShortcut: + + def setup_class(cls): + cls.space = gettestobjspace( + **{"objspace.std.newshortcut": True}) + + def test_reset_logic(self): + class X(object): + pass + + class Y(X): + pass + + y = Y() + + assert isinstance(y, Y) + + + X.__new__ = staticmethod(lambda t: 1) + + y = Y() + + assert y == 1 + + def test_dont_explode_on_non_types(self): + class A: + __new__ = staticmethod(lambda t: 1) + + class B(A, object): + pass + + b = B() + + assert b == 1 + + Modified: pypy/trunk/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/pypy/objspace/std/typeobject.py Fri Sep 4 16:26:36 2009 @@ -52,9 +52,14 @@ _immutable_fields_ = ["__flags__"] - uses_object_getattribute = False - # ^^^ for config.objspace.std.getattributeshortcut + # for config.objspace.std.getattributeshortcut # (False is a conservative default, fixed during real usage) + uses_object_getattribute = False + + # used to cache the type __new__ function if it comes from a builtin type + # != 'type', in that case call__Type will also assumes the result + # of the __new__ is an instance of the type + w_bltin_new = None def __init__(w_self, space, name, bases_w, dict_w, overridetypedef=None): @@ -87,13 +92,17 @@ def mutated(w_self): space = w_self.space if (not space.config.objspace.std.withtypeversion and - not space.config.objspace.std.getattributeshortcut): + not space.config.objspace.std.getattributeshortcut and + not space.config.objspace.std.newshortcut): return if space.config.objspace.std.getattributeshortcut: w_self.uses_object_getattribute = False # ^^^ conservative default, fixed during real usage + if space.config.objspace.std.newshortcut: + w_self.w_bltin_new = None + if (space.config.objspace.std.withtypeversion and w_self.version_tag is not None): w_self.version_tag = VersionTag() @@ -570,10 +579,23 @@ else: return space.type(w_obj) # invoke the __new__ of the type - w_newfunc = space.getattr(w_type, space.wrap('__new__')) - w_newobject = space.call_obj_args(w_newfunc, w_type, __args__) + w_bltin_new = w_type.w_bltin_new + call_init = True + if w_bltin_new is not None: + w_newobject = space.call_obj_args(w_bltin_new, w_type, __args__) + else: + w_newtype, w_newdescr = w_type.lookup_where('__new__') + w_newfunc = space.get(w_newdescr, w_type) + if (space.config.objspace.std.newshortcut and + isinstance(w_newtype, W_TypeObject) and + not w_newtype.is_heaptype() and + not space.is_w(w_newtype, space.w_type)): + w_type.w_bltin_new = w_newfunc + w_newobject = space.call_obj_args(w_newfunc, w_type, __args__) + call_init = space.is_true(space.isinstance(w_newobject, w_type)) + # maybe invoke the __init__ of the type - if space.is_true(space.isinstance(w_newobject, w_type)): + if call_init: w_descr = space.lookup(w_newobject, '__init__') w_result = space.get_and_call_args(w_descr, w_newobject, __args__) if not space.is_w(w_result, space.w_None): From arigo at codespeak.net Fri Sep 4 16:31:58 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 16:31:58 +0200 (CEST) Subject: [pypy-svn] r67484 - in pypy/branch/weakdict2/pypy/rlib: . test Message-ID: <20090904143158.48F02168022@codespeak.net> Author: arigo Date: Fri Sep 4 16:31:57 2009 New Revision: 67484 Modified: pypy/branch/weakdict2/pypy/rlib/rweakrefimpl.py pypy/branch/weakdict2/pypy/rlib/test/test_rweakref.py Log: Rewrite this code to use regular weakrefs. Modified: pypy/branch/weakdict2/pypy/rlib/rweakrefimpl.py ============================================================================== --- pypy/branch/weakdict2/pypy/rlib/rweakrefimpl.py (original) +++ pypy/branch/weakdict2/pypy/rlib/rweakrefimpl.py Fri Sep 4 16:31:57 2009 @@ -1,5 +1,6 @@ from pypy.objspace.flow.model import Constant -from pypy.rpython.lltypesystem import lltype, rstr, rclass, rdict +from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass, rdict +from pypy.rpython.lltypesystem.llmemory import weakref_create, weakref_deref from pypy.rpython.rclass import getinstancerepr from pypy.rpython.rmodel import Repr from pypy.rlib.rweakref import RWeakValueDictionary @@ -31,7 +32,7 @@ llvalue = r_value.convert_const(dictvalue) if llvalue: llvalue = lltype.cast_pointer(rclass.OBJECTPTR, llvalue) - ll_set(l_dict, llkey, llvalue) + ll_set_nonnull(l_dict, llkey, llvalue) return l_dict def rtype_method_get(self, hop): @@ -45,14 +46,13 @@ def rtype_method_set(self, hop): v_d, v_key, v_value = hop.inputargs(self, rstr.string_repr, hop.args_r[2]) + hop.exception_cannot_occur() if hop.args_s[2].is_constant() and hop.args_s[2].const is None: - value = lltype.nullptr(rclass.OBJECTPTR.TO) - v_value = hop.inputconst(rclass.OBJECTPTR, value) + hop.gendirectcall(ll_set_null, v_d, v_key) else: v_value = hop.genop("cast_pointer", [v_value], resulttype=rclass.OBJECTPTR) - hop.exception_cannot_occur() - hop.gendirectcall(ll_set, v_d, v_key, v_value) + hop.gendirectcall(ll_set, v_d, v_key, v_value) def specialize_make_weakdict(hop): @@ -63,34 +63,23 @@ # ____________________________________________________________ -pristine_marker = lltype.malloc(rstr.STR, 0, zero=True) -DICT_INITSIZE = 8 - WEAKDICTENTRY = lltype.Struct("weakdictentry", ("key", lltype.Ptr(rstr.STR)), - ("value", rclass.OBJECTPTR)) + ("value", llmemory.WeakRefPtr)) def ll_valid(entries, i): - key = entries[i].key - return key != pristine_marker and bool(key) + return (bool(entries[i].value) and + bool(weakref_deref(rclass.OBJECTPTR, entries[i].value))) def ll_everused(entries, i): - key = entries[i].key - return key != pristine_marker - -str_fasthashfn = rstr.string_repr.get_ll_fasthash_function() + return bool(entries[i].value) def ll_hash(entries, i): return str_fasthashfn(entries[i].key) - -def ll_malloc_entries_and_initialize(ENTRIES, n): - entries = lltype.malloc(ENTRIES, n, zero=True) - for i in range(n): - entries[i].key = pristine_marker - return entries +str_fasthashfn = rstr.string_repr.get_ll_fasthash_function() entrymeths = { - 'allocate': lltype.typeMethod(ll_malloc_entries_and_initialize), + 'allocate': lltype.typeMethod(rdict._ll_malloc_entries), 'delete': rdict._ll_free_entries, 'valid': ll_valid, 'everused': ll_everused, @@ -102,44 +91,53 @@ def ll_new_weakdict(): d = lltype.malloc(WEAKDICT) - d.entries = WEAKDICT.entries.TO.allocate(DICT_INITSIZE) - d.num_pristine_entries = DICT_INITSIZE + d.entries = WEAKDICT.entries.TO.allocate(rdict.DICT_INITSIZE) + d.num_pristine_entries = rdict.DICT_INITSIZE return d def ll_get(d, llkey): - hash = llkey.gethash() - i = rdict.ll_dict_lookup(d, llkey, hash) - llvalue = d.entries[i].value - #print 'get', i, key, hash, llvalue - return llvalue + i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) + valueref = d.entries[i].value + if valueref: + return weakref_deref(rclass.OBJECTPTR, valueref) + else: + return lltype.nullptr(rclass.OBJECTPTR.TO) def ll_set(d, llkey, llvalue): - hash = llkey.gethash() - i = rdict.ll_dict_lookup(d, llkey, hash) + if llvalue: + ll_set_nonnull(d, llkey, llvalue) + else: + ll_set_null(d, llkey) + +def ll_set_nonnull(d, llkey, llvalue): + valueref = weakref_create(llvalue) # GC effects here, before the rest + i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) everused = d.entries.everused(i) - #print 'set', i, key, hash, llvalue d.entries[i].key = llkey - d.entries[i].value = llvalue + d.entries[i].value = valueref if not everused: d.num_pristine_entries -= 1 - #print 'num_pristine_entries:', d.num_pristine_entries if d.num_pristine_entries <= len(d.entries) / 3: ll_weakdict_resize(d) - else: - pass #print 'entry reused' + +def ll_set_null(d, llkey): + i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) + if d.entries.everused(i): + d.entries[i].key = null_str + d.entries[i].value = null_valueref + +null_str = lltype.nullptr(rstr.STR) +null_valueref = llmemory.dead_wref def ll_weakdict_resize(d): # first set num_items to its correct, up-to-date value - #print 'in ll_weakdict_resize' entries = d.entries num_items = 0 for i in range(len(entries)): if entries.valid(i): num_items += 1 d.num_items = num_items - #print 'num_items:', num_items rdict.ll_dict_resize(d) - #print 'resized.' str_keyeq = lltype.staticAdtMethod(rstr.string_repr.get_ll_eq_function()) Modified: pypy/branch/weakdict2/pypy/rlib/test/test_rweakref.py ============================================================================== --- pypy/branch/weakdict2/pypy/rlib/test/test_rweakref.py (original) +++ pypy/branch/weakdict2/pypy/rlib/test/test_rweakref.py Fri Sep 4 16:31:57 2009 @@ -9,9 +9,8 @@ pass -def make_test(go_away=True, loop=100): - def f(): - d = RWeakValueDictionary(X) +def make_test(loop=100): + def g(d): assert d.get("hello") is None x1 = X(); x2 = X(); x3 = X() d.set("abc", x1) @@ -21,16 +20,18 @@ assert d.get("def") is x2 assert d.get("ghi") is x3 assert d.get("hello") is None - if go_away: - x2 = None - rgc.collect(); rgc.collect() + return x1, x3 # x2 dies + def f(): + d = RWeakValueDictionary(X) + x1, x3 = g(d) + rgc.collect(); rgc.collect() assert d.get("abc") is x1 - assert d.get("def") is x2 + assert d.get("def") is None assert d.get("ghi") is x3 assert d.get("hello") is None d.set("abc", None) assert d.get("abc") is None - assert d.get("def") is x2 + assert d.get("def") is None assert d.get("ghi") is x3 assert d.get("hello") is None # resizing should also work @@ -39,7 +40,7 @@ for i in range(loop): assert d.get(str(i)) is x1 assert d.get("abc") is None - assert d.get("def") is x2 + assert d.get("def") is None assert d.get("ghi") is x3 assert d.get("hello") is None # finally, a subclass @@ -52,9 +53,7 @@ make_test()() def test_rpython_RWeakValueDictionary(): - # we don't implement the correct weakref behavior in lltype when - # directly interpreted, but we can still test that the rest works. - interpret(make_test(go_away=False, loop=12), []) + interpret(make_test(loop=12), []) def test_rpython_prebuilt(): d = RWeakValueDictionary(X) From arigo at codespeak.net Fri Sep 4 16:59:28 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 16:59:28 +0200 (CEST) Subject: [pypy-svn] r67485 - in pypy/branch/weakdict2/pypy/rlib: . test Message-ID: <20090904145928.28996168022@codespeak.net> Author: arigo Date: Fri Sep 4 16:59:27 2009 New Revision: 67485 Modified: pypy/branch/weakdict2/pypy/rlib/rweakrefimpl.py pypy/branch/weakdict2/pypy/rlib/test/test_rweakref.py Log: Write comments and improve test coverage for ll_set_null. Modified: pypy/branch/weakdict2/pypy/rlib/rweakrefimpl.py ============================================================================== --- pypy/branch/weakdict2/pypy/rlib/rweakrefimpl.py (original) +++ pypy/branch/weakdict2/pypy/rlib/rweakrefimpl.py Fri Sep 4 16:59:27 2009 @@ -1,6 +1,7 @@ from pypy.objspace.flow.model import Constant from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass, rdict from pypy.rpython.lltypesystem.llmemory import weakref_create, weakref_deref +from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.rclass import getinstancerepr from pypy.rpython.rmodel import Repr from pypy.rlib.rweakref import RWeakValueDictionary @@ -97,6 +98,7 @@ def ll_get(d, llkey): i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) + #llop.debug_print(lltype.Void, i, 'get') valueref = d.entries[i].value if valueref: return weakref_deref(rclass.OBJECTPTR, valueref) @@ -115,19 +117,22 @@ everused = d.entries.everused(i) d.entries[i].key = llkey d.entries[i].value = valueref + #llop.debug_print(lltype.Void, i, 'stored') if not everused: d.num_pristine_entries -= 1 if d.num_pristine_entries <= len(d.entries) / 3: + #llop.debug_print(lltype.Void, 'RESIZE') ll_weakdict_resize(d) def ll_set_null(d, llkey): i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) if d.entries.everused(i): - d.entries[i].key = null_str - d.entries[i].value = null_valueref - -null_str = lltype.nullptr(rstr.STR) -null_valueref = llmemory.dead_wref + # If the entry was ever used, clean up its key and value. + # We don't store a NULL value, but a dead weakref, because + # the entry must still be marked as everused(). + d.entries[i].value = llmemory.dead_wref + d.entries[i].key = lltype.nullptr(rstr.STR) + #llop.debug_print(lltype.Void, i, 'zero') def ll_weakdict_resize(d): # first set num_items to its correct, up-to-date value Modified: pypy/branch/weakdict2/pypy/rlib/test/test_rweakref.py ============================================================================== --- pypy/branch/weakdict2/pypy/rlib/test/test_rweakref.py (original) +++ pypy/branch/weakdict2/pypy/rlib/test/test_rweakref.py Fri Sep 4 16:59:27 2009 @@ -43,10 +43,23 @@ assert d.get("def") is None assert d.get("ghi") is x3 assert d.get("hello") is None - # finally, a subclass + # a subclass y = Y() d.set("hello", y) assert d.get("hello") is y + # storing a lot of Nones + for i in range(loop, loop*2-5): + d.set('%dfoobar' % i, x1) + for i in range(loop): + d.set(str(i), None) + for i in range(loop): + assert d.get(str(i)) is None + assert d.get("abc") is None + assert d.get("def") is None + assert d.get("ghi") is x3 + assert d.get("hello") is y + for i in range(loop, loop*2-5): + assert d.get('%dfoobar' % i) is x1 return f def test_RWeakValueDictionary(): From arigo at codespeak.net Fri Sep 4 17:06:42 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 17:06:42 +0200 (CEST) Subject: [pypy-svn] r67486 - in pypy/trunk/pypy: jit/backend rlib rlib/test rpython Message-ID: <20090904150642.71D43168024@codespeak.net> Author: arigo Date: Fri Sep 4 17:06:40 2009 New Revision: 67486 Added: pypy/trunk/pypy/jit/backend/ - copied from r67485, pypy/branch/weakdict2/pypy/jit/backend/ pypy/trunk/pypy/rlib/rweakref.py - copied unchanged from r67485, pypy/branch/weakdict2/pypy/rlib/rweakref.py pypy/trunk/pypy/rlib/rweakrefimpl.py - copied unchanged from r67485, pypy/branch/weakdict2/pypy/rlib/rweakrefimpl.py pypy/trunk/pypy/rlib/test/ - copied from r67485, pypy/branch/weakdict2/pypy/rlib/test/ pypy/trunk/pypy/rpython/ - copied from r67485, pypy/branch/weakdict2/pypy/rpython/ Log: Merge the branch weakdict2: add pypy.rlib.rweakref.RWeakValueDictionary. From arigo at codespeak.net Fri Sep 4 17:06:57 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 17:06:57 +0200 (CEST) Subject: [pypy-svn] r67487 - pypy/branch/weakdict2 Message-ID: <20090904150657.BABEC16802A@codespeak.net> Author: arigo Date: Fri Sep 4 17:06:56 2009 New Revision: 67487 Removed: pypy/branch/weakdict2/ Log: Remove merged branch. From pedronis at codespeak.net Fri Sep 4 17:12:23 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 4 Sep 2009 17:12:23 +0200 (CEST) Subject: [pypy-svn] r67488 - in pypy/branch/no-recompilation/pypy/jit/backend/x86: . test Message-ID: <20090904151223.883E516802A@codespeak.net> Author: pedronis Date: Fri Sep 4 17:12:22 2009 New Revision: 67488 Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py Log: (micke, pedronis) disambiguate the usage of _x86_stack_depth minimizing confusion, one overlapping and potentially dangerous usage was test only Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py Fri Sep 4 17:12:22 2009 @@ -184,7 +184,9 @@ if guard_op is None: tree._x86_stack_depth = stack_depth else: - guard_op._x86_stack_depth = stack_depth + if not we_are_translated(): + # for the benefit of tests + guard_op._x86_bridge_stack_depth = stack_depth mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py Fri Sep 4 17:12:22 2009 @@ -70,7 +70,7 @@ self.inputargs = inpargs self.position = -1 self._update_bindings(locs, inpargs) - self.current_stack_depth = guard_op._x86_stack_depth + self.current_stack_depth = guard_op._x86_current_stack_depth cpu.gc_ll_descr.rewrite_assembler(cpu, guard_op.suboperations) self.loop_consts = {} else: @@ -147,7 +147,7 @@ self.assembler.regalloc_perform(op, arglocs, result_loc) def perform_with_guard(self, op, guard_op, locs, arglocs, result_loc): - guard_op._x86_stack_depth = self.current_stack_depth + guard_op._x86_current_stack_depth = self.current_stack_depth if not we_are_translated(): self.assembler.dump('%s <- %s(%s) [GUARDED]' % (result_loc, op, arglocs)) @@ -155,7 +155,7 @@ arglocs, result_loc) def perform_guard(self, op, locs, arglocs, result_loc): - op._x86_stack_depth = self.current_stack_depth + op._x86_current_stack_depth = self.current_stack_depth if not we_are_translated(): if result_loc is not None: self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) Modified: pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py ============================================================================== --- pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py (original) +++ pypy/branch/no-recompilation/pypy/jit/backend/x86/test/test_recompilation.py Fri Sep 4 17:12:22 2009 @@ -49,7 +49,7 @@ fail(i3, i4, i5, i6, i7, i8, i9) ''' bridge = self.attach_bridge(ops, loop, loop.operations[-2]) - new = loop.operations[2]._x86_stack_depth + new = loop.operations[2]._x86_bridge_stack_depth assert new > previous self.cpu.set_future_value_int(0, 0) op = self.cpu.execute_operations(loop) @@ -112,7 +112,7 @@ guard_op = loop.operations[3] bridge = self.attach_bridge(ops, loop, guard_op, jump_targets=[loop]) - assert guard_op._x86_stack_depth > loop._x86_stack_depth + assert guard_op._x86_bridge_stack_depth > loop._x86_stack_depth self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) self.cpu.set_future_value_int(2, 0) From arigo at codespeak.net Fri Sep 4 17:19:11 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 17:19:11 +0200 (CEST) Subject: [pypy-svn] r67489 - pypy/branch/no-recompilation-merge Message-ID: <20090904151911.BEDEA16802A@codespeak.net> Author: arigo Date: Fri Sep 4 17:19:10 2009 New Revision: 67489 Added: pypy/branch/no-recompilation-merge/ - copied from r67488, pypy/trunk/ Log: A branch of trunk, in which to merge no-recompilation. From arigo at codespeak.net Fri Sep 4 17:25:37 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 17:25:37 +0200 (CEST) Subject: [pypy-svn] r67490 - pypy/branch/no-recompilation-merge/pypy/jit/backend/x86 Message-ID: <20090904152537.37B6316802A@codespeak.net> Author: arigo Date: Fri Sep 4 17:25:35 2009 New Revision: 67490 Added: pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/regalloc.py.merge.tmp - copied, changed from r67489, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/regalloc.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/no-recompilation/pypy/jit/backend/x86/regalloc.py revisions 67416 to 67489: ------------------------------------------------------------------------ r67488 | pedronis | 2009-09-04 17:12:22 +0200 (Fri, 04 Sep 2009) | 4 lines (micke, pedronis) disambiguate the usage of _x86_stack_depth minimizing confusion, one overlapping and potentially dangerous usage was test only ------------------------------------------------------------------------ r67463 | fijal | 2009-09-03 20:04:38 +0200 (Thu, 03 Sep 2009) | 2 lines A test and a fix ------------------------------------------------------------------------ r67461 | fijal | 2009-09-03 19:58:41 +0200 (Thu, 03 Sep 2009) | 5 lines * Kill _compute_inpargs * Finish rewriting tests * Store _fail_op on guard_op, just to preserve order of arguments that go into faillocs ------------------------------------------------------------------------ r67456 | fijal | 2009-09-03 19:12:24 +0200 (Thu, 03 Sep 2009) | 3 lines this is enough to make test_recompilation pass. Although test_recompilation needs adaptation as not always we really overflow the number of registers ------------------------------------------------------------------------ r67445 | fijal | 2009-09-03 14:12:11 +0200 (Thu, 03 Sep 2009) | 3 lines Good, this is enough to pass the first test of recompilation series. ------------------------------------------------------------------------ r67426 | fijal | 2009-09-02 12:59:03 +0200 (Wed, 02 Sep 2009) | 2 lines Remove support for bridges. test_runner passes ------------------------------------------------------------------------ r67420 | fijal | 2009-09-01 21:06:34 +0200 (Tue, 01 Sep 2009) | 2 lines kill this debug print ------------------------------------------------------------------------ r67417 | fijal | 2009-09-01 19:49:14 +0200 (Tue, 01 Sep 2009) | 2 lines A branch to get away from constant recompilation of code ------------------------------------------------------------------------ Copied: pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/regalloc.py.merge.tmp (from r67489, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/regalloc.py) ============================================================================== --- pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/regalloc.py.merge.tmp Fri Sep 4 17:25:35 2009 @@ -54,46 +54,56 @@ exc = False def __init__(self, assembler, tree, translate_support_code=False, - regalloc=None, guard_op=None): + guard_op=None): # variables that have place in register self.assembler = assembler self.translate_support_code = translate_support_code - if regalloc is None: - cpu = self.assembler.cpu + cpu = self.assembler.cpu + self.reg_bindings = newcheckdict() + self.stack_bindings = newcheckdict() + self.tree = tree + if guard_op is not None: + locs = guard_op._x86_faillocs + inpargs = [arg for arg in guard_op._fail_op.args if + isinstance(arg, Box)] + self._compute_vars_longevity(inpargs, guard_op.suboperations) + self.inputargs = inpargs + self.position = -1 + self._update_bindings(locs, inpargs) + self.current_stack_depth = guard_op._x86_current_stack_depth + cpu.gc_ll_descr.rewrite_assembler(cpu, guard_op.suboperations) + self.loop_consts = {} + else: cpu.gc_ll_descr.rewrite_assembler(cpu, tree.operations) - self.tree = tree - self.reg_bindings = newcheckdict() - self.stack_bindings = newcheckdict() - # compute longevity of variables self._compute_vars_longevity(tree.inputargs, tree.operations) - self.free_regs = REGS[:] + # compute longevity of variables jump = tree.operations[-1] loop_consts = self._compute_loop_consts(tree.inputargs, jump) self.loop_consts = loop_consts self.current_stack_depth = 0 - else: - inp = guard_op.inputargs - assert inp is not None - self.reg_bindings = {} - self.stack_bindings = {} - for arg in inp: - if arg in regalloc.reg_bindings: - self.reg_bindings[arg] = regalloc.reg_bindings[arg] - if arg in regalloc.stack_bindings: - self.stack_bindings[arg] = regalloc.stack_bindings[arg] - else: - assert arg in regalloc.reg_bindings - allocated_regs = self.reg_bindings.values() - self.free_regs = [v for v in REGS if v not in allocated_regs] - self.current_stack_depth = regalloc.current_stack_depth - self.longevity = guard_op.longevity - jump_or_fail = guard_op.suboperations[-1] - self.loop_consts = {} - self.tree = regalloc.tree + self.free_regs = REGS[:] - def regalloc_for_guard(self, guard_op): - return RegAlloc(self.assembler, None, self.translate_support_code, - self, guard_op) + def _update_bindings(self, locs, args): + newlocs = [] + for loc in locs: + if not isinstance(loc, IMM8) and not isinstance(loc, IMM32): + newlocs.append(loc) + locs = newlocs + assert len(locs) == len(args) + used = {} + for i in range(len(locs)): + v = args[i] + loc = locs[i] + if isinstance(loc, REG) and self.longevity[v][1] > -1: + self.reg_bindings[v] = loc + used[loc] = None + else: + self.stack_bindings[v] = loc + self.free_regs = [] + for reg in REGS: + if reg not in used: + self.free_regs.append(reg) + self._check_invariants() def _compute_loop_consts(self, inputargs, jump): if jump.opnum != rop.JUMP or jump.jump_target is not self.tree: @@ -136,24 +146,22 @@ self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) self.assembler.regalloc_perform(op, arglocs, result_loc) - def perform_with_guard(self, op, guard_op, regalloc, arglocs, result_loc): + def perform_with_guard(self, op, guard_op, locs, arglocs, result_loc): + guard_op._x86_current_stack_depth = self.current_stack_depth if not we_are_translated(): self.assembler.dump('%s <- %s(%s) [GUARDED]' % (result_loc, op, arglocs)) - self.assembler.regalloc_perform_with_guard(op, guard_op, regalloc, + self.assembler.regalloc_perform_with_guard(op, guard_op, locs, arglocs, result_loc) - self.max_stack_depth = max(self.max_stack_depth, - regalloc.max_stack_depth) - def perform_guard(self, op, regalloc, arglocs, result_loc): + def perform_guard(self, op, locs, arglocs, result_loc): + op._x86_current_stack_depth = self.current_stack_depth if not we_are_translated(): if result_loc is not None: self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) else: self.assembler.dump('%s(%s)' % (op, arglocs)) - self.assembler.regalloc_perform_guard(op, regalloc, arglocs, result_loc) - self.max_stack_depth = max(self.max_stack_depth, - regalloc.max_stack_depth) + self.assembler.regalloc_perform_guard(op, locs, arglocs, result_loc) def PerformDiscard(self, op, arglocs): if not we_are_translated(): @@ -170,25 +178,24 @@ if operations[i + 1].args[0] is not op.result: return False if (self.longevity[op.result][1] > i + 1 or - op.result in operations[i + 1].inputargs): - print "!!!! boolean flag not optimized away !!!!" + op.result in operations[i + 1].suboperations[0].args): return False return True def walk_operations(self, tree): # first pass - walk along the operations in order to find # load/store places - operations = tree.operations self.position = -1 + operations = tree.operations self.process_inputargs(tree) self._walk_operations(operations) - def walk_guard_ops(self, inputargs, operations, exc): - self.exc = exc - old_regalloc = self.assembler._regalloc - self.assembler._regalloc = self - self._walk_operations(operations) - self.assembler._regalloc = old_regalloc + #def walk_guard_ops(self, inputargs, operations, exc): + # self.exc = exc + # old_regalloc = self.assembler._regalloc + # self.assembler._regalloc = self + # self._walk_operations(operations) + # self.assembler._regalloc = old_regalloc def _walk_operations(self, operations): i = 0 @@ -210,11 +217,8 @@ i += 1 assert not self.reg_bindings jmp = operations[-1] - #if jmp.opnum == rop.JUMP and jmp.jump_target is not self.tree: - # self.max_stack_depth = max(jmp.jump_target._x86_stack_depth, - # self.max_stack_depth) - self.max_stack_depth = max(self.max_stack_depth, - self.current_stack_depth + 1) + self.max_stack_depth = max(self.current_stack_depth, + self.max_stack_depth) def _compute_vars_longevity(self, inputargs, operations): # compute a dictionary that maps variables to index in @@ -234,8 +238,7 @@ raise AssertionError longevity[arg] = (start_live[arg], i) if op.is_guard(): - self._compute_inpargs(op) - for arg in op.inputargs: + for arg in op.suboperations[0].args: if isinstance(arg, Box): if arg not in start_live: print "Bogus arg in guard %d at %d" % (op.opnum, i) @@ -248,35 +251,32 @@ assert isinstance(arg, Box) self.longevity = longevity - def _compute_inpargs(self, guard): - if guard.inputargs is not None: - return - operations = guard.suboperations - longevity = {} - end = {} - for i in range(len(operations)-1, -1, -1): - op = operations[i] - if op.is_guard(): - self._compute_inpargs(op) - for arg in op.inputargs: - if isinstance(arg, Box) and arg not in end: - end[arg] = i - for arg in op.args: - if isinstance(arg, Box) and arg not in end: - end[arg] = i - if op.result: - if op.result in end: - longevity[op.result] = (i, end[op.result]) - del end[op.result] - # otherwise this var is never ever used - for v, e in end.items(): - longevity[v] = (0, e) - guard.longevity = longevity - guard.inputargs = end.keys() - for arg in longevity: - assert isinstance(arg, Box) - for arg in guard.inputargs: - assert isinstance(arg, Box) +# def _compute_inpargs(self, guard): +# operations = guard.suboperations +# longevity = {} +# end = {} +# for i in range(len(operations)-1, -1, -1): +# op = operations[i] +# if op.is_guard(): +# for arg in op.suboperations[0].args: +# if isinstance(arg, Box) and arg not in end: +# end[arg] = i +# for arg in op.args: +# if isinstance(arg, Box) and arg not in end: +# end[arg] = i +# if op.result: +# if op.result in end: +# longevity[op.result] = (i, end[op.result]) +# del end[op.result] +# # otherwise this var is never ever used +# for v, e in end.items(): +# longevity[v] = (0, e) +# inputargs = end.keys() +# for arg in longevity: +# assert isinstance(arg, Box) +# for arg in inputargs: +# assert isinstance(arg, Box) +# return inputargs, longevity def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): assert not isinstance(v, Const) @@ -482,6 +482,10 @@ loc = self.reg_bindings[result_v] return loc + def locs_for_fail(self, guard_op): + assert len(guard_op.suboperations) == 1 + return [self.loc(v) for v in guard_op.suboperations[0].args] + def process_inputargs(self, tree): # XXX we can sort out here by longevity if we need something # more optimal @@ -510,10 +514,10 @@ def _consider_guard(self, op, ignored): loc = self.make_sure_var_in_reg(op.args[0], []) - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [loc], None) + locs = self.locs_for_fail(op) + self.perform_guard(op, locs, [loc], None) self.eventually_free_var(op.args[0]) - self.eventually_free_vars(op.inputargs) + self.eventually_free_vars(op.suboperations[0].args) consider_guard_true = _consider_guard consider_guard_false = _consider_guard @@ -521,13 +525,13 @@ def consider_fail(self, op, ignored): # make sure all vars are on stack locs = [self.loc(arg) for arg in op.args] - self.assembler.generate_failure(op, locs, self.exc) + self.assembler.generate_failure(self.assembler.mc, op, locs, self.exc) self.eventually_free_vars(op.args) def consider_guard_no_exception(self, op, ignored): - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [], None) - self.eventually_free_vars(op.inputargs) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [], None) + self.eventually_free_vars(op.suboperations[0].args) def consider_guard_exception(self, op, ignored): loc = self.make_sure_var_in_reg(op.args[0], []) @@ -538,9 +542,9 @@ resloc = self.force_allocate_reg(op.result, op.args + [box]) else: resloc = None - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [loc, loc1], resloc) - self.eventually_free_vars(op.inputargs) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [loc, loc1], resloc) + self.eventually_free_vars(op.suboperations[0].args) self.eventually_free_vars(op.args) self.eventually_free_var(box) @@ -550,18 +554,18 @@ def consider_guard_value(self, op, ignored): x = self.make_sure_var_in_reg(op.args[0], []) y = self.loc(op.args[1]) - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [x, y], None) - self.eventually_free_vars(op.inputargs) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [x, y], None) + self.eventually_free_vars(op.suboperations[0].args) self.eventually_free_vars(op.args) def consider_guard_class(self, op, ignored): assert isinstance(op.args[0], Box) x = self.make_sure_var_in_reg(op.args[0], []) y = self.loc(op.args[1]) - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [x, y], None) - self.eventually_free_vars(op.inputargs) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [x, y], None) + self.eventually_free_vars(op.suboperations[0].args) self.eventually_free_vars(op.args) def _consider_binop_part(self, op, ignored): @@ -640,11 +644,11 @@ need_lower_byte=True) self.Perform(op, arglocs, loc) else: - regalloc = self.regalloc_for_guard(guard_op) + faillocs = self.locs_for_fail(guard_op) self.position += 1 - self.perform_with_guard(op, guard_op, regalloc, arglocs, None) + self.perform_with_guard(op, guard_op, faillocs, arglocs, None) self.eventually_free_var(op.result) - self.eventually_free_vars(guard_op.inputargs) + self.eventually_free_vars(guard_op.suboperations[0].args) consider_int_lt = _consider_compop consider_int_gt = _consider_compop @@ -864,11 +868,11 @@ if guard_op is not None: argloc = self.make_sure_var_in_reg(op.args[0], []) self.eventually_free_var(op.args[0]) - regalloc = self.regalloc_for_guard(guard_op) + faillocs = self.locs_for_fail(guard_op) self.position += 1 - self.perform_with_guard(op, guard_op, regalloc, [argloc], None) + self.perform_with_guard(op, guard_op, faillocs, [argloc], None) self.eventually_free_var(op.result) - self.eventually_free_vars(guard_op.inputargs) + self.eventually_free_vars(guard_op.suboperations[0].args) else: argloc = self.loc(op.args[0]) self.eventually_free_var(op.args[0]) @@ -925,6 +929,7 @@ dst_locations, tmploc) self.eventually_free_var(box) self.eventually_free_vars(op.args) + self.max_stack_depth = op.jump_target._x86_stack_depth self.PerformDiscard(op, []) def consider_debug_merge_point(self, op, ignored): From arigo at codespeak.net Fri Sep 4 17:25:40 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 17:25:40 +0200 (CEST) Subject: [pypy-svn] r67491 - pypy/branch/no-recompilation-merge/pypy/jit/backend/x86 Message-ID: <20090904152540.7C48116802A@codespeak.net> Author: arigo Date: Fri Sep 4 17:25:39 2009 New Revision: 67491 Added: pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/runner.py.merge.tmp - copied, changed from r67489, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/runner.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/no-recompilation/pypy/jit/backend/x86/runner.py revisions 67416 to 67489: ------------------------------------------------------------------------ r67456 | fijal | 2009-09-03 19:12:24 +0200 (Thu, 03 Sep 2009) | 3 lines this is enough to make test_recompilation pass. Although test_recompilation needs adaptation as not always we really overflow the number of registers ------------------------------------------------------------------------ r67445 | fijal | 2009-09-03 14:12:11 +0200 (Thu, 03 Sep 2009) | 3 lines Good, this is enough to pass the first test of recompilation series. ------------------------------------------------------------------------ r67426 | fijal | 2009-09-02 12:59:03 +0200 (Wed, 02 Sep 2009) | 2 lines Remove support for bridges. test_runner passes ------------------------------------------------------------------------ r67418 | fijal | 2009-09-01 20:08:26 +0200 (Tue, 01 Sep 2009) | 2 lines typo ------------------------------------------------------------------------ r67417 | fijal | 2009-09-01 19:49:14 +0200 (Tue, 01 Sep 2009) | 2 lines A branch to get away from constant recompilation of code ------------------------------------------------------------------------ Copied: pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/runner.py.merge.tmp (from r67489, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/runner.py) ============================================================================== --- pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/runner.py.merge.tmp Fri Sep 4 17:25:39 2009 @@ -10,7 +10,7 @@ history.TreeLoop._x86_compiled = 0 history.TreeLoop._x86_bootstrap_code = 0 - +history.TreeLoop._x86_stack_depth = 0 class CPU386(AbstractLLCPU): debug = True @@ -35,21 +35,12 @@ def setup_once(self): pass - def compile_operations(self, tree, bridge=None): - old_loop = tree._x86_compiled - if old_loop: - olddepth = tree._x86_stack_depth - oldlocs = tree.arglocs + def compile_operations(self, tree, guard_op=None): + if guard_op is not None: + self.assembler.assemble_from_guard(tree, guard_op) else: - oldlocs = None - olddepth = 0 - stack_depth = self.assembler.assemble(tree) - newlocs = tree.arglocs - if old_loop != 0: - self.assembler.patch_jump(old_loop, tree._x86_compiled, - oldlocs, newlocs, olddepth, - tree._x86_stack_depth) - + self.assembler.assemble_loop(tree) + def get_bootstrap_code(self, loop): addr = loop._x86_bootstrap_code if not addr: From arigo at codespeak.net Fri Sep 4 17:25:44 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 17:25:44 +0200 (CEST) Subject: [pypy-svn] r67492 - pypy/branch/no-recompilation-merge/pypy/jit/backend/x86 Message-ID: <20090904152544.AFAF116802D@codespeak.net> Author: arigo Date: Fri Sep 4 17:25:42 2009 New Revision: 67492 Added: pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/assembler.py.merge.tmp - copied, changed from r67489, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/assembler.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py revisions 67416 to 67489: ------------------------------------------------------------------------ r67488 | pedronis | 2009-09-04 17:12:22 +0200 (Fri, 04 Sep 2009) | 4 lines (micke, pedronis) disambiguate the usage of _x86_stack_depth minimizing confusion, one overlapping and potentially dangerous usage was test only ------------------------------------------------------------------------ r67477 | fijal | 2009-09-04 15:58:33 +0200 (Fri, 04 Sep 2009) | 2 lines Kill commented out code ------------------------------------------------------------------------ r67476 | fijal | 2009-09-04 15:47:00 +0200 (Fri, 04 Sep 2009) | 2 lines Kill dead code ------------------------------------------------------------------------ r67475 | pedronis | 2009-09-04 15:45:45 +0200 (Fri, 04 Sep 2009) | 3 lines (pedronis, arigo) force the LEA to be fixed sized so that it can be patched safely ------------------------------------------------------------------------ r67473 | fijal | 2009-09-04 15:30:07 +0200 (Fri, 04 Sep 2009) | 2 lines rpythonization ------------------------------------------------------------------------ r67462 | fijal | 2009-09-03 20:00:44 +0200 (Thu, 03 Sep 2009) | 2 lines oops ------------------------------------------------------------------------ r67461 | fijal | 2009-09-03 19:58:41 +0200 (Thu, 03 Sep 2009) | 5 lines * Kill _compute_inpargs * Finish rewriting tests * Store _fail_op on guard_op, just to preserve order of arguments that go into faillocs ------------------------------------------------------------------------ r67459 | fijal | 2009-09-03 19:36:52 +0200 (Thu, 03 Sep 2009) | 3 lines * Remove aligning code, as requested by pedronis * Fix one test ------------------------------------------------------------------------ r67457 | fijal | 2009-09-03 19:27:57 +0200 (Thu, 03 Sep 2009) | 2 lines Improve test and a fix ------------------------------------------------------------------------ r67456 | fijal | 2009-09-03 19:12:24 +0200 (Thu, 03 Sep 2009) | 3 lines this is enough to make test_recompilation pass. Although test_recompilation needs adaptation as not always we really overflow the number of registers ------------------------------------------------------------------------ r67454 | fijal | 2009-09-03 18:43:38 +0200 (Thu, 03 Sep 2009) | 3 lines Simplification - kill places_to_patch_framesizes and use lea instead for failures ------------------------------------------------------------------------ r67448 | fijal | 2009-09-03 14:33:17 +0200 (Thu, 03 Sep 2009) | 3 lines correctly adjust stack depth. Make sure test actually contains bridge that changes stack depth ------------------------------------------------------------------------ r67445 | fijal | 2009-09-03 14:12:11 +0200 (Thu, 03 Sep 2009) | 3 lines Good, this is enough to pass the first test of recompilation series. ------------------------------------------------------------------------ r67426 | fijal | 2009-09-02 12:59:03 +0200 (Wed, 02 Sep 2009) | 2 lines Remove support for bridges. test_runner passes ------------------------------------------------------------------------ r67417 | fijal | 2009-09-01 19:49:14 +0200 (Tue, 01 Sep 2009) | 2 lines A branch to get away from constant recompilation of code ------------------------------------------------------------------------ Copied: pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/assembler.py.merge.tmp (from r67489, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/assembler.py) ============================================================================== --- pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/assembler.py.merge.tmp Fri Sep 4 17:25:42 2009 @@ -14,9 +14,13 @@ from pypy.jit.backend.x86.ri386 import * from pypy.jit.metainterp.resoperation import rop -# our calling convention - we pass three first args as edx, ecx and eax + + +# our calling convention - we pass first 6 args in registers # and the rest stays on the stack +RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words + MAX_FAIL_BOXES = 1000 if sys.platform == 'darwin': # darwin requires the stack to be 16 bytes aligned on calls @@ -59,25 +63,6 @@ if name.upper() == name: setattr(MachineCodeBlockWrapper, name, _new_method(name)) -class MachineCodeStack(object): - def __init__(self): - self.mcstack = [] - self.counter = 0 - - def next_mc(self): - if len(self.mcstack) == self.counter: - mc = MachineCodeBlockWrapper() - self.mcstack.append(mc) - else: - mc = self.mcstack[self.counter] - self.counter += 1 - return mc - - def give_mc_back(self, mc): - mc.done() - assert self.mcstack[self.counter - 1] is mc - self.counter -= 1 - class Assembler386(object): mc = None @@ -92,7 +77,6 @@ self.malloc_array_func_addr = 0 self.malloc_str_func_addr = 0 self.malloc_unicode_func_addr = 0 - self.mcstack = MachineCodeStack() self.logger = Logger(cpu.ts) self.fail_boxes_int = lltype.malloc(lltype.GcArray(lltype.Signed), MAX_FAIL_BOXES, zero=True) @@ -129,9 +113,8 @@ # done # we generate the loop body in 'mc' # 'mc2' is for guard recovery code - self.mc2 = self.mcstack.next_mc() - self.mc = self.mcstack.next_mc() - + self.mc = MachineCodeBlockWrapper() + self.mc2 = MachineCodeBlockWrapper() def _compute_longest_fail_op(self, ops): max_so_far = 0 @@ -144,48 +127,57 @@ assert max_so_far < MAX_FAIL_BOXES return max_so_far - def assemble(self, tree): - self.places_to_patch_framesize = [] - self.jumps_to_look_at = [] + def assemble_loop(self, loop): + self.assemble(loop, loop.operations, None) + + def assemble_from_guard(self, tree, guard_op): + newaddr = self.assemble(tree, guard_op.suboperations, guard_op) + # patch the jump from original guard + addr = guard_op._x86_addr + mc = codebuf.InMemoryCodeBuilder(addr, addr + 128) + mc.write(packimm32(newaddr - addr - 4)) + mc.done() + + def assemble(self, tree, operations, guard_op): # the last operation can be 'jump', 'return' or 'guard_pause'; # a 'jump' can either close a loop, or end a bridge to some # previously-compiled code. - self._compute_longest_fail_op(tree.operations) + self._compute_longest_fail_op(operations) self.tree = tree self.make_sure_mc_exists() - inputargs = tree.inputargs - self.logger.log_loop(tree) - regalloc = RegAlloc(self, tree, self.cpu.translate_support_code) + newpos = self.mc.tell() + regalloc = RegAlloc(self, tree, self.cpu.translate_support_code, + guard_op) self._regalloc = regalloc - regalloc.walk_operations(tree) - self.sanitize_tree(tree.operations) + adr_lea = 0 + if guard_op is None: + inputargs = tree.inputargs + self.logger.log_loop(tree) + regalloc.walk_operations(tree) + else: + inputargs = regalloc.inputargs + self.logger.log_operations + mc = self.mc._mc + adr_lea = mc.tell() + mc.LEA(esp, fixedsize_ebp_ofs(0)) + regalloc._walk_operations(operations) + stack_depth = regalloc.max_stack_depth self.mc.done() self.mc2.done() - stack_words = regalloc.max_stack_depth # possibly align, e.g. for Mac OS X - RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words - stack_words = align_stack_words(stack_words+RET_BP) - tree._x86_stack_depth = stack_words-RET_BP - for place in self.places_to_patch_framesize: - mc = codebuf.InMemoryCodeBuilder(place, place + 128) - mc.ADD(esp, imm32(tree._x86_stack_depth * WORD)) + if guard_op is None: + tree._x86_stack_depth = stack_depth + else: + if not we_are_translated(): + # for the benefit of tests + guard_op._x86_bridge_stack_depth = stack_depth + mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) + + mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) mc.done() - for op, pos in self.jumps_to_look_at: - if op.jump_target._x86_stack_depth != tree._x86_stack_depth: - tl = op.jump_target - self.patch_jump(pos, tl._x86_compiled, tl.arglocs, tl.arglocs, - tree._x86_stack_depth, tl._x86_stack_depth) if we_are_translated(): self._regalloc = None # else keep it around for debugging - - def sanitize_tree(self, operations): - """ Cleans up all attributes attached by regalloc and backend - """ - for op in operations: - if op.is_guard(): - op.inputargs = None - op.longevity = None - self.sanitize_tree(op.suboperations) + return newpos def assemble_bootstrap_code(self, jumpaddr, arglocs, args, framesize): self.make_sure_mc_exists() @@ -256,14 +248,14 @@ def regalloc_perform_discard(self, op, arglocs): genop_discard_list[op.opnum](self, op, arglocs) - def regalloc_perform_with_guard(self, op, guard_op, regalloc, + def regalloc_perform_with_guard(self, op, guard_op, faillocs, arglocs, resloc): - addr = self.implement_guard_recovery(guard_op, regalloc) + addr = self.implement_guard_recovery(guard_op, faillocs) genop_guard_list[op.opnum](self, op, guard_op, addr, arglocs, resloc) - def regalloc_perform_guard(self, op, regalloc, arglocs, resloc): - addr = self.implement_guard_recovery(op, regalloc) + def regalloc_perform_guard(self, op, faillocs, arglocs, resloc): + addr = self.implement_guard_recovery(op, faillocs) genop_guard_list[op.opnum](self, op, None, addr, arglocs, resloc) @@ -582,40 +574,9 @@ def make_merge_point(self, tree, locs): pos = self.mc.tell() tree._x86_compiled = pos - #tree.comeback_bootstrap_addr = self.assemble_comeback_bootstrap(pos, - # locs, stacklocs) - - def patch_jump(self, old_pos, new_pos, oldlocs, newlocs, olddepth, newdepth): - for i in range(len(oldlocs)): - oldloc = oldlocs[i] - newloc = newlocs[i] - if isinstance(newloc, MODRM): - assert isinstance(oldloc, MODRM) - assert newloc.position == oldloc.position - else: - assert newloc is oldloc - # newlocs should be sorted in acending order, excluding the regs - if not we_are_translated(): - locs = [loc.position for loc in newlocs if isinstance(loc, MODRM)] - assert locs == sorted(locs) - # - mc = codebuf.InMemoryCodeBuilder(old_pos, old_pos + - MachineCodeBlockWrapper.MC_SIZE) - mc.SUB(esp, imm(WORD * (newdepth - olddepth))) - mc.JMP(rel32(new_pos)) - mc.done() def genop_discard_jump(self, op, locs): - targetmp = op.jump_target - # don't break the following code sequence! - mc = self.mc._mc - if op.jump_target is not self.tree: - self.jumps_to_look_at.append((op, mc.tell())) - mc.JMP(rel32(targetmp._x86_compiled)) - if op.jump_target is not self.tree: - # Reserve 6 bytes for a possible later patch by patch_jump(). - # Put them after the JMP by default, as it's not doing anything. - mc.SUB(esp, imm32(0)) + self.mc.JMP(rel32(op.jump_target._x86_compiled)) def genop_guard_guard_true(self, op, ign_1, addr, locs, ign_2): loc = locs[0] @@ -657,27 +618,21 @@ self.mc.CMP(mem(locs[0], offset), locs[1]) self.implement_guard(addr, op, self.mc.JNE) - def implement_guard_recovery(self, guard_op, regalloc): - oldmc = self.mc - self.mc = self.mc2 - self.mc2 = self.mcstack.next_mc() - addr = self.mc.tell() + def implement_guard_recovery(self, guard_op, fail_locs): + addr = self.mc2.tell() exc = (guard_op.opnum == rop.GUARD_EXCEPTION or guard_op.opnum == rop.GUARD_NO_EXCEPTION) - # XXX this is a heuristics to detect whether we're handling this - # exception or not. We should have a bit better interface to deal - # with that I fear - if (exc and (guard_op.suboperations[0].opnum == rop.GUARD_EXCEPTION or - guard_op.suboperations[0].opnum == rop.GUARD_NO_EXCEPTION)): - exc = False - regalloc.walk_guard_ops(guard_op.inputargs, guard_op.suboperations, exc) - self.mcstack.give_mc_back(self.mc2) - self.mc2 = self.mc - self.mc = oldmc + guard_op._x86_faillocs = fail_locs + # XXX horrible hack that allows us to preserve order + # of inputargs to bridge + guard_op._fail_op = guard_op.suboperations[0] + self.generate_failure(self.mc2, guard_op.suboperations[0], fail_locs, + exc) return addr - def generate_failure(self, op, locs, exc): - pos = self.mc.tell() + def generate_failure(self, mc, op, locs, exc): + assert op.opnum == rop.FAIL + pos = mc.tell() for i in range(len(locs)): loc = locs[i] if isinstance(loc, REG): @@ -685,7 +640,7 @@ base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr - self.mc.MOV(addr_add(imm(base), imm(i*WORD)), loc) + mc.MOV(addr_add(imm(base), imm(i*WORD)), loc) for i in range(len(locs)): loc = locs[i] if not isinstance(loc, REG): @@ -693,21 +648,20 @@ base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr - self.mc.MOV(eax, loc) - self.mc.MOV(addr_add(imm(base), imm(i*WORD)), eax) + mc.MOV(eax, loc) + mc.MOV(addr_add(imm(base), imm(i*WORD)), eax) if self.debug_markers: - self.mc.MOV(eax, imm(pos)) - self.mc.MOV(addr_add(imm(self.fail_box_int_addr), + mc.MOV(eax, imm(pos)) + mc.MOV(addr_add(imm(self.fail_box_int_addr), imm(len(locs) * WORD)), eax) if exc: # note that we don't have to save and restore eax, ecx and edx here addr = self.cpu.get_save_exception_int() - self.mc.CALL(rel32(addr)) + mc.CALL(rel32(addr)) # don't break the following code sequence! - mc = self.mc._mc - self.places_to_patch_framesize.append(mc.tell()) - mc.ADD(esp, imm32(0)) + mc = mc._mc + mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD)) guard_index = self.cpu.make_guard_index(op) mc.MOV(eax, imm(guard_index)) mc.POP(edi) @@ -719,6 +673,7 @@ @specialize.arg(3) def implement_guard(self, addr, guard_op, emit_jump): emit_jump(rel32(addr)) + guard_op._x86_addr = self.mc.tell() - 4 def genop_call(self, op, arglocs, resloc): sizeloc = arglocs[0] @@ -783,15 +738,6 @@ print "not implemented operation (guard): %s" % op.getopname() raise NotImplementedError - #def genop_call__1(self, op, arglocs, resloc): - # self.gen_call(op, arglocs, resloc) - # self.mc.MOVZX(eax, al) - - #def genop_call__2(self, op, arglocs, resloc): - # # XXX test it test it test it - # self.gen_call(op, arglocs, resloc) - # self.mc.MOVZX(eax, eax) - def mark_gc_roots(self): gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap: From arigo at codespeak.net Fri Sep 4 17:26:11 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 17:26:11 +0200 (CEST) Subject: [pypy-svn] r67493 - in pypy/branch/no-recompilation-merge/pypy: jit/backend/test jit/backend/x86 jit/backend/x86/test module/pypyjit/test/loops Message-ID: <20090904152611.379BC168030@codespeak.net> Author: arigo Date: Fri Sep 4 17:26:09 2009 New Revision: 67493 Added: pypy/branch/no-recompilation-merge/pypy/jit/backend/test/test_random.py - copied unchanged from r67492, pypy/branch/no-recompilation/pypy/jit/backend/test/test_random.py pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/assembler.py - copied unchanged from r67492, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/assembler.py.merge.tmp pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/regalloc.py - copied unchanged from r67492, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/regalloc.py.merge.tmp pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/runner.py - copied unchanged from r67492, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/runner.py.merge.tmp pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/test/ - copied from r67492, pypy/branch/no-recompilation/pypy/jit/backend/x86/test/ pypy/branch/no-recompilation-merge/pypy/module/pypyjit/test/loops/ - copied from r67492, pypy/branch/no-recompilation/pypy/module/pypyjit/test/loops/ Removed: pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/assembler.py.merge.tmp pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/regalloc.py.merge.tmp pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/runner.py.merge.tmp Log: Merge the branch 'no-recompilation'. From arigo at codespeak.net Fri Sep 4 17:49:02 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 17:49:02 +0200 (CEST) Subject: [pypy-svn] r67494 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090904154902.052CF168022@codespeak.net> Author: arigo Date: Fri Sep 4 17:49:02 2009 New Revision: 67494 Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py Log: Use debug_print(), not print. Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/jitprof.py (original) +++ pypy/trunk/pypy/jit/metainterp/jitprof.py Fri Sep 4 17:49:02 2009 @@ -3,6 +3,7 @@ """ import time +from pypy.rlib.debug import debug_print TRACING = 0 BACKEND = 1 @@ -69,11 +70,11 @@ t0 = self.t1 self.t1 = self.timer() if not self.current: - print "BROKEN PROFILER DATA!" + debug_print("BROKEN PROFILER DATA!") return ev1 = self.current.pop() if ev1 != event: - print "BROKEN PROFILER DATA!" + debug_print("BROKEN PROFILER DATA!") return self.times[ev1] += self.t1 - t0 From arigo at codespeak.net Fri Sep 4 18:21:12 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 18:21:12 +0200 (CEST) Subject: [pypy-svn] r67495 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090904162112.B105316800B@codespeak.net> Author: arigo Date: Fri Sep 4 18:21:11 2009 New Revision: 67495 Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py Log: This assert made sense long ago when we used ESP-based addressing. Now it's just wrong because the helper is used for much more stuff. Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py Fri Sep 4 18:21:11 2009 @@ -323,9 +323,7 @@ nargs = len(args) extra_on_stack = self.align_stack_for_call(nargs) for i in range(nargs-1, -1, -1): - arg = args[i] - assert not isinstance(arg, MODRM) - self.mc.PUSH(arg) + self.mc.PUSH(args[i]) self.mc.CALL(rel32(addr)) self.mark_gc_roots() self.mc.ADD(esp, imm(extra_on_stack * WORD)) From arigo at codespeak.net Fri Sep 4 18:32:15 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 18:32:15 +0200 (CEST) Subject: [pypy-svn] r67496 - pypy/trunk/pypy/module/pypyjit Message-ID: <20090904163215.8B3C516800D@codespeak.net> Author: arigo Date: Fri Sep 4 18:32:14 2009 New Revision: 67496 Modified: pypy/trunk/pypy/module/pypyjit/policy.py Log: Minimal fix. Modified: pypy/trunk/pypy/module/pypyjit/policy.py ============================================================================== --- pypy/trunk/pypy/module/pypyjit/policy.py (original) +++ pypy/trunk/pypy/module/pypyjit/policy.py Fri Sep 4 18:32:14 2009 @@ -2,6 +2,9 @@ class PyPyJitPolicy(JitPolicy): + def __init__(self, translator=None): + pass # xxx + def look_inside_function(self, func): mod = func.__module__ or '?' if (func.__name__.startswith('_mm_') or From arigo at codespeak.net Fri Sep 4 18:32:54 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Sep 2009 18:32:54 +0200 (CEST) Subject: [pypy-svn] r67497 - pypy/branch/no-recompilation-merge/pypy/module/pypyjit Message-ID: <20090904163254.46154168011@codespeak.net> Author: arigo Date: Fri Sep 4 18:32:54 2009 New Revision: 67497 Modified: pypy/branch/no-recompilation-merge/pypy/module/pypyjit/policy.py Log: Merge... Modified: pypy/branch/no-recompilation-merge/pypy/module/pypyjit/policy.py ============================================================================== --- pypy/branch/no-recompilation-merge/pypy/module/pypyjit/policy.py (original) +++ pypy/branch/no-recompilation-merge/pypy/module/pypyjit/policy.py Fri Sep 4 18:32:54 2009 @@ -2,6 +2,9 @@ class PyPyJitPolicy(JitPolicy): + def __init__(self, translator=None): + pass # xxx + def look_inside_function(self, func): mod = func.__module__ or '?' if (func.__name__.startswith('_mm_') or From cfbolz at codespeak.net Fri Sep 4 18:51:44 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 4 Sep 2009 18:51:44 +0200 (CEST) Subject: [pypy-svn] r67498 - in pypy/trunk/pypy/rlib: . test Message-ID: <20090904165144.2FFE7168016@codespeak.net> Author: cfbolz Date: Fri Sep 4 18:51:43 2009 New Revision: 67498 Modified: pypy/trunk/pypy/rlib/rweakref.py pypy/trunk/pypy/rlib/test/test_rweakref.py Log: Need a union of SomeWeakValueDict Modified: pypy/trunk/pypy/rlib/rweakref.py ============================================================================== --- pypy/trunk/pypy/rlib/rweakref.py (original) +++ pypy/trunk/pypy/rlib/rweakref.py Fri Sep 4 18:51:43 2009 @@ -3,6 +3,7 @@ and a limited version of WeakValueDictionary. LLType only for now! """ +from pypy.tool.pairtype import pairtype import weakref from weakref import ref @@ -54,6 +55,13 @@ s_oldvalue = self.method_get(s_key) assert s_oldvalue.contains(s_value) +class __extend__(pairtype(SomeWeakValueDict, SomeWeakValueDict)): + def union((s_wvd1, s_wvd2)): + basedef = s_wvd1.valueclassdef.commonbase(s_wvd2.valueclassdef) + if basedef is None: # no common base class! complain... + return SomeObject() + return SomeWeakValueDict(basedef) + class Entry(extregistry.ExtRegistryEntry): _about_ = RWeakValueDictionary Modified: pypy/trunk/pypy/rlib/test/test_rweakref.py ============================================================================== --- pypy/trunk/pypy/rlib/test/test_rweakref.py (original) +++ pypy/trunk/pypy/rlib/test/test_rweakref.py Fri Sep 4 18:51:43 2009 @@ -86,3 +86,24 @@ # f() interpret(f, []) + + +def test_rpython_merge_RWeakValueDictionary(): + class A(object): + def __init__(self): + self.d = RWeakValueDictionary(A) + def f(self, key): + a = A() + self.d.set(key, a) + return a + empty = A() + def f(x): + a = A() + if x: + a = empty + a2 = a.f("a") + assert a.d.get("a") is a2 + f(0) + interpret(f, [0]) + f(1) + interpret(f, [1]) From cfbolz at codespeak.net Fri Sep 4 19:04:37 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 4 Sep 2009 19:04:37 +0200 (CEST) Subject: [pypy-svn] r67499 - in pypy/trunk/pypy/rlib: . test Message-ID: <20090904170437.F33E216800E@codespeak.net> Author: cfbolz Date: Fri Sep 4 19:04:37 2009 New Revision: 67499 Modified: pypy/trunk/pypy/rlib/rweakref.py pypy/trunk/pypy/rlib/test/test_rweakref.py Log: Only allow the exact same classes Modified: pypy/trunk/pypy/rlib/rweakref.py ============================================================================== --- pypy/trunk/pypy/rlib/rweakref.py (original) +++ pypy/trunk/pypy/rlib/rweakref.py Fri Sep 4 19:04:37 2009 @@ -3,7 +3,6 @@ and a limited version of WeakValueDictionary. LLType only for now! """ -from pypy.tool.pairtype import pairtype import weakref from weakref import ref @@ -33,6 +32,7 @@ from pypy.rpython import extregistry from pypy.annotation import model as annmodel from pypy.annotation.bookkeeper import getbookkeeper +from pypy.tool.pairtype import pairtype class SomeWeakValueDict(annmodel.SomeObject): knowntype = RWeakValueDictionary @@ -57,10 +57,9 @@ class __extend__(pairtype(SomeWeakValueDict, SomeWeakValueDict)): def union((s_wvd1, s_wvd2)): - basedef = s_wvd1.valueclassdef.commonbase(s_wvd2.valueclassdef) - if basedef is None: # no common base class! complain... - return SomeObject() - return SomeWeakValueDict(basedef) + if s_wvd1.valueclassdef is not s_wvd2.valueclassdef: + return SomeObject() # not the same class! complain... + return s_wvd1 class Entry(extregistry.ExtRegistryEntry): _about_ = RWeakValueDictionary Modified: pypy/trunk/pypy/rlib/test/test_rweakref.py ============================================================================== --- pypy/trunk/pypy/rlib/test/test_rweakref.py (original) +++ pypy/trunk/pypy/rlib/test/test_rweakref.py Fri Sep 4 19:04:37 2009 @@ -1,3 +1,4 @@ +import py from pypy.rlib import rgc from pypy.rlib.rweakref import RWeakValueDictionary from pypy.rpython.test.test_llinterp import interpret @@ -107,3 +108,12 @@ interpret(f, [0]) f(1) interpret(f, [1]) + + def g(x): + if x: + d = RWeakValueDictionary(X) + else: + d = RWeakValueDictionary(Y) + d.set("x", X()) + return 41 + py.test.raises(Exception, interpret, g, [1]) From cfbolz at codespeak.net Fri Sep 4 19:06:42 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 4 Sep 2009 19:06:42 +0200 (CEST) Subject: [pypy-svn] r67500 - pypy/trunk/pypy/objspace/std Message-ID: <20090904170642.853C716800E@codespeak.net> Author: cfbolz Date: Fri Sep 4 19:06:42 2009 New Revision: 67500 Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py Log: Use the new weak value dict in the implementation of shared structures. Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/dictmultiobject.py (original) +++ pypy/trunk/pypy/objspace/std/dictmultiobject.py Fri Sep 4 19:06:42 2009 @@ -5,6 +5,7 @@ from pypy.rlib.objectmodel import r_dict, we_are_translated from pypy.rlib.jit import purefunction +from pypy.rlib.rweakref import RWeakValueDictionary def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -687,7 +688,6 @@ class SharedStructure(object): def __init__(self, keys=None, length=0, - other_structs=None, last_key=None, back_struct=None): if keys is None: @@ -695,20 +695,18 @@ self.keys = keys self.length = length self.back_struct = back_struct - if other_structs is None: - other_structs = {} + other_structs = RWeakValueDictionary(SharedStructure) self.other_structs = other_structs self.last_key = last_key if last_key is not None: assert back_struct is not None - self.propagating = False def new_structure(self, added_key): keys = self.keys.copy() keys[added_key] = len(self.keys) new_structure = SharedStructure(keys, self.length + 1, - {}, added_key, self) - self.other_structs[added_key] = new_structure + added_key, self) + self.other_structs.set(added_key, new_structure) return new_structure def lookup_position(self, key): @@ -725,7 +723,6 @@ class State(object): def __init__(self, space): self.empty_structure = SharedStructure() - self.empty_structure.propagating = True class SharedDictImplementation(DictImplementation): @@ -762,13 +759,9 @@ if i != -1: self.entries[i] = w_value return self - if not self.structure.propagating: - return self._as_rdict(as_strdict=True).setitem_str(w_key, w_value) - new_structure = self.structure.other_structs.get(key, None) + new_structure = self.structure.other_structs.get(key) if new_structure is None: new_structure = self.structure.new_structure(key) - else: - new_structure.propagating = True self.entries.append(w_value) assert self.structure.length + 1 == new_structure.length self.structure = new_structure From cfbolz at codespeak.net Fri Sep 4 19:12:12 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 4 Sep 2009 19:12:12 +0200 (CEST) Subject: [pypy-svn] r67501 - pypy/trunk/pypy/objspace/std Message-ID: <20090904171212.EBB9F168011@codespeak.net> Author: cfbolz Date: Fri Sep 4 19:12:12 2009 New Revision: 67501 Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py Log: revert r67500. makes translation fail. Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/dictmultiobject.py (original) +++ pypy/trunk/pypy/objspace/std/dictmultiobject.py Fri Sep 4 19:12:12 2009 @@ -5,7 +5,6 @@ from pypy.rlib.objectmodel import r_dict, we_are_translated from pypy.rlib.jit import purefunction -from pypy.rlib.rweakref import RWeakValueDictionary def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -688,6 +687,7 @@ class SharedStructure(object): def __init__(self, keys=None, length=0, + other_structs=None, last_key=None, back_struct=None): if keys is None: @@ -695,18 +695,20 @@ self.keys = keys self.length = length self.back_struct = back_struct - other_structs = RWeakValueDictionary(SharedStructure) + if other_structs is None: + other_structs = {} self.other_structs = other_structs self.last_key = last_key if last_key is not None: assert back_struct is not None + self.propagating = False def new_structure(self, added_key): keys = self.keys.copy() keys[added_key] = len(self.keys) new_structure = SharedStructure(keys, self.length + 1, - added_key, self) - self.other_structs.set(added_key, new_structure) + {}, added_key, self) + self.other_structs[added_key] = new_structure return new_structure def lookup_position(self, key): @@ -723,6 +725,7 @@ class State(object): def __init__(self, space): self.empty_structure = SharedStructure() + self.empty_structure.propagating = True class SharedDictImplementation(DictImplementation): @@ -759,9 +762,13 @@ if i != -1: self.entries[i] = w_value return self - new_structure = self.structure.other_structs.get(key) + if not self.structure.propagating: + return self._as_rdict(as_strdict=True).setitem_str(w_key, w_value) + new_structure = self.structure.other_structs.get(key, None) if new_structure is None: new_structure = self.structure.new_structure(key) + else: + new_structure.propagating = True self.entries.append(w_value) assert self.structure.length + 1 == new_structure.length self.structure = new_structure From antocuni at codespeak.net Sat Sep 5 00:42:47 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 5 Sep 2009 00:42:47 +0200 (CEST) Subject: [pypy-svn] r67509 - pypy/trunk/pypy/rpython/test Message-ID: <20090904224247.9DCDC168011@codespeak.net> Author: antocuni Date: Sat Sep 5 00:42:46 2009 New Revision: 67509 Modified: pypy/trunk/pypy/rpython/test/test_rclass.py Log: a failing test for ootype. This is exactly the same kind of failure that we get with the ootype jit, with the only difference that there the different variants of the method are specialized by the access_directly flag rather than by specialize:arg(1). No clue how to fix it, though :-/ Modified: pypy/trunk/pypy/rpython/test/test_rclass.py ============================================================================== --- pypy/trunk/pypy/rpython/test/test_rclass.py (original) +++ pypy/trunk/pypy/rpython/test/test_rclass.py Sat Sep 5 00:42:46 2009 @@ -266,6 +266,26 @@ res = self.interpret(f, []) assert res == 246 + def test_method_specialized_with_subclass(self): + py.test.skip('fixme!') + class A: + def meth(self, n): + return -1 + meth._annspecialcase_ = 'specialize:arg(1)' + + class B(A): + pass + + def f(): + a = A() + b = B() + a.meth(1) # the self of this variant is annotated with A + b.meth(2) # the self of this variant is annotated with B, then explodes + return 42 + + res = self.interpret(f, []) + assert res == 42 + def test_issubclass_type(self): class Abstract: pass From arigo at codespeak.net Sat Sep 5 12:23:13 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 12:23:13 +0200 (CEST) Subject: [pypy-svn] r67511 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090905102313.05506168011@codespeak.net> Author: arigo Date: Sat Sep 5 12:23:10 2009 New Revision: 67511 Added: pypy/trunk/pypy/jit/backend/x86/assembler.py.merge.tmp - copied, changed from r67510, pypy/trunk/pypy/jit/backend/x86/assembler.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/assembler.py revisions 67486 to 67510: ------------------------------------------------------------------------ r67493 | arigo | 2009-09-04 17:26:09 +0200 (Fri, 04 Sep 2009) | 2 lines Merge the branch 'no-recompilation'. ------------------------------------------------------------------------ r67492 | arigo | 2009-09-04 17:25:42 +0200 (Fri, 04 Sep 2009) | 91 lines merging of svn+ssh://codespeak.net/svn/pypy/branch/no-recompilation/pypy/jit/backend/x86/assembler.py revisions 67416 to 67489: ------------------------------------------------------------------------ r67488 | pedronis | 2009-09-04 17:12:22 +0200 (Fri, 04 Sep 2009) | 4 lines (micke, pedronis) disambiguate the usage of _x86_stack_depth minimizing confusion, one overlapping and potentially dangerous usage was test only ------------------------------------------------------------------------ r67477 | fijal | 2009-09-04 15:58:33 +0200 (Fri, 04 Sep 2009) | 2 lines Kill commented out code ------------------------------------------------------------------------ r67476 | fijal | 2009-09-04 15:47:00 +0200 (Fri, 04 Sep 2009) | 2 lines Kill dead code ------------------------------------------------------------------------ r67475 | pedronis | 2009-09-04 15:45:45 +0200 (Fri, 04 Sep 2009) | 3 lines (pedronis, arigo) force the LEA to be fixed sized so that it can be patched safely ------------------------------------------------------------------------ r67473 | fijal | 2009-09-04 15:30:07 +0200 (Fri, 04 Sep 2009) | 2 lines rpythonization ------------------------------------------------------------------------ r67462 | fijal | 2009-09-03 20:00:44 +0200 (Thu, 03 Sep 2009) | 2 lines oops ------------------------------------------------------------------------ r67461 | fijal | 2009-09-03 19:58:41 +0200 (Thu, 03 Sep 2009) | 5 lines * Kill _compute_inpargs * Finish rewriting tests * Store _fail_op on guard_op, just to preserve order of arguments that go into faillocs ------------------------------------------------------------------------ r67459 | fijal | 2009-09-03 19:36:52 +0200 (Thu, 03 Sep 2009) | 3 lines * Remove aligning code, as requested by pedronis * Fix one test ------------------------------------------------------------------------ r67457 | fijal | 2009-09-03 19:27:57 +0200 (Thu, 03 Sep 2009) | 2 lines Improve test and a fix ------------------------------------------------------------------------ r67456 | fijal | 2009-09-03 19:12:24 +0200 (Thu, 03 Sep 2009) | 3 lines this is enough to make test_recompilation pass. Although test_recompilation needs adaptation as not always we really overflow the number of registers ------------------------------------------------------------------------ r67454 | fijal | 2009-09-03 18:43:38 +0200 (Thu, 03 Sep 2009) | 3 lines Simplification - kill places_to_patch_framesizes and use lea instead for failures ------------------------------------------------------------------------ r67448 | fijal | 2009-09-03 14:33:17 +0200 (Thu, 03 Sep 2009) | 3 lines correctly adjust stack depth. Make sure test actually contains bridge that changes stack depth ------------------------------------------------------------------------ r67445 | fijal | 2009-09-03 14:12:11 +0200 (Thu, 03 Sep 2009) | 3 lines Good, this is enough to pass the first test of recompilation series. ------------------------------------------------------------------------ r67426 | fijal | 2009-09-02 12:59:03 +0200 (Wed, 02 Sep 2009) | 2 lines Remove support for bridges. test_runner passes ------------------------------------------------------------------------ r67417 | fijal | 2009-09-01 19:49:14 +0200 (Tue, 01 Sep 2009) | 2 lines A branch to get away from constant recompilation of code ------------------------------------------------------------------------ ------------------------------------------------------------------------ r67489 | arigo | 2009-09-04 17:19:10 +0200 (Fri, 04 Sep 2009) | 2 lines A branch of trunk, in which to merge no-recompilation. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/backend/x86/assembler.py.merge.tmp (from r67510, pypy/trunk/pypy/jit/backend/x86/assembler.py) ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py.merge.tmp Sat Sep 5 12:23:10 2009 @@ -14,9 +14,13 @@ from pypy.jit.backend.x86.ri386 import * from pypy.jit.metainterp.resoperation import rop -# our calling convention - we pass three first args as edx, ecx and eax + + +# our calling convention - we pass first 6 args in registers # and the rest stays on the stack +RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words + MAX_FAIL_BOXES = 1000 if sys.platform == 'darwin': # darwin requires the stack to be 16 bytes aligned on calls @@ -59,25 +63,6 @@ if name.upper() == name: setattr(MachineCodeBlockWrapper, name, _new_method(name)) -class MachineCodeStack(object): - def __init__(self): - self.mcstack = [] - self.counter = 0 - - def next_mc(self): - if len(self.mcstack) == self.counter: - mc = MachineCodeBlockWrapper() - self.mcstack.append(mc) - else: - mc = self.mcstack[self.counter] - self.counter += 1 - return mc - - def give_mc_back(self, mc): - mc.done() - assert self.mcstack[self.counter - 1] is mc - self.counter -= 1 - class Assembler386(object): mc = None @@ -92,7 +77,6 @@ self.malloc_array_func_addr = 0 self.malloc_str_func_addr = 0 self.malloc_unicode_func_addr = 0 - self.mcstack = MachineCodeStack() self.logger = Logger(cpu.ts) self.fail_boxes_int = lltype.malloc(lltype.GcArray(lltype.Signed), MAX_FAIL_BOXES, zero=True) @@ -129,9 +113,8 @@ # done # we generate the loop body in 'mc' # 'mc2' is for guard recovery code - self.mc2 = self.mcstack.next_mc() - self.mc = self.mcstack.next_mc() - + self.mc = MachineCodeBlockWrapper() + self.mc2 = MachineCodeBlockWrapper() def _compute_longest_fail_op(self, ops): max_so_far = 0 @@ -144,48 +127,57 @@ assert max_so_far < MAX_FAIL_BOXES return max_so_far - def assemble(self, tree): - self.places_to_patch_framesize = [] - self.jumps_to_look_at = [] + def assemble_loop(self, loop): + self.assemble(loop, loop.operations, None) + + def assemble_from_guard(self, tree, guard_op): + newaddr = self.assemble(tree, guard_op.suboperations, guard_op) + # patch the jump from original guard + addr = guard_op._x86_addr + mc = codebuf.InMemoryCodeBuilder(addr, addr + 128) + mc.write(packimm32(newaddr - addr - 4)) + mc.done() + + def assemble(self, tree, operations, guard_op): # the last operation can be 'jump', 'return' or 'guard_pause'; # a 'jump' can either close a loop, or end a bridge to some # previously-compiled code. - self._compute_longest_fail_op(tree.operations) + self._compute_longest_fail_op(operations) self.tree = tree self.make_sure_mc_exists() - inputargs = tree.inputargs - self.logger.log_loop(tree) - regalloc = RegAlloc(self, tree, self.cpu.translate_support_code) + newpos = self.mc.tell() + regalloc = RegAlloc(self, tree, self.cpu.translate_support_code, + guard_op) self._regalloc = regalloc - regalloc.walk_operations(tree) - self.sanitize_tree(tree.operations) + adr_lea = 0 + if guard_op is None: + inputargs = tree.inputargs + self.logger.log_loop(tree) + regalloc.walk_operations(tree) + else: + inputargs = regalloc.inputargs + self.logger.log_operations + mc = self.mc._mc + adr_lea = mc.tell() + mc.LEA(esp, fixedsize_ebp_ofs(0)) + regalloc._walk_operations(operations) + stack_depth = regalloc.max_stack_depth self.mc.done() self.mc2.done() - stack_words = regalloc.max_stack_depth # possibly align, e.g. for Mac OS X - RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words - stack_words = align_stack_words(stack_words+RET_BP) - tree._x86_stack_depth = stack_words-RET_BP - for place in self.places_to_patch_framesize: - mc = codebuf.InMemoryCodeBuilder(place, place + 128) - mc.ADD(esp, imm32(tree._x86_stack_depth * WORD)) + if guard_op is None: + tree._x86_stack_depth = stack_depth + else: + if not we_are_translated(): + # for the benefit of tests + guard_op._x86_bridge_stack_depth = stack_depth + mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) + + mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) mc.done() - for op, pos in self.jumps_to_look_at: - if op.jump_target._x86_stack_depth != tree._x86_stack_depth: - tl = op.jump_target - self.patch_jump(pos, tl._x86_compiled, tl.arglocs, tl.arglocs, - tree._x86_stack_depth, tl._x86_stack_depth) if we_are_translated(): self._regalloc = None # else keep it around for debugging - - def sanitize_tree(self, operations): - """ Cleans up all attributes attached by regalloc and backend - """ - for op in operations: - if op.is_guard(): - op.inputargs = None - op.longevity = None - self.sanitize_tree(op.suboperations) + return newpos def assemble_bootstrap_code(self, jumpaddr, arglocs, args, framesize): self.make_sure_mc_exists() @@ -256,14 +248,14 @@ def regalloc_perform_discard(self, op, arglocs): genop_discard_list[op.opnum](self, op, arglocs) - def regalloc_perform_with_guard(self, op, guard_op, regalloc, + def regalloc_perform_with_guard(self, op, guard_op, faillocs, arglocs, resloc): - addr = self.implement_guard_recovery(guard_op, regalloc) + addr = self.implement_guard_recovery(guard_op, faillocs) genop_guard_list[op.opnum](self, op, guard_op, addr, arglocs, resloc) - def regalloc_perform_guard(self, op, regalloc, arglocs, resloc): - addr = self.implement_guard_recovery(op, regalloc) + def regalloc_perform_guard(self, op, faillocs, arglocs, resloc): + addr = self.implement_guard_recovery(op, faillocs) genop_guard_list[op.opnum](self, op, None, addr, arglocs, resloc) @@ -580,40 +572,9 @@ def make_merge_point(self, tree, locs): pos = self.mc.tell() tree._x86_compiled = pos - #tree.comeback_bootstrap_addr = self.assemble_comeback_bootstrap(pos, - # locs, stacklocs) - - def patch_jump(self, old_pos, new_pos, oldlocs, newlocs, olddepth, newdepth): - for i in range(len(oldlocs)): - oldloc = oldlocs[i] - newloc = newlocs[i] - if isinstance(newloc, MODRM): - assert isinstance(oldloc, MODRM) - assert newloc.position == oldloc.position - else: - assert newloc is oldloc - # newlocs should be sorted in acending order, excluding the regs - if not we_are_translated(): - locs = [loc.position for loc in newlocs if isinstance(loc, MODRM)] - assert locs == sorted(locs) - # - mc = codebuf.InMemoryCodeBuilder(old_pos, old_pos + - MachineCodeBlockWrapper.MC_SIZE) - mc.SUB(esp, imm(WORD * (newdepth - olddepth))) - mc.JMP(rel32(new_pos)) - mc.done() def genop_discard_jump(self, op, locs): - targetmp = op.jump_target - # don't break the following code sequence! - mc = self.mc._mc - if op.jump_target is not self.tree: - self.jumps_to_look_at.append((op, mc.tell())) - mc.JMP(rel32(targetmp._x86_compiled)) - if op.jump_target is not self.tree: - # Reserve 6 bytes for a possible later patch by patch_jump(). - # Put them after the JMP by default, as it's not doing anything. - mc.SUB(esp, imm32(0)) + self.mc.JMP(rel32(op.jump_target._x86_compiled)) def genop_guard_guard_true(self, op, ign_1, addr, locs, ign_2): loc = locs[0] @@ -655,27 +616,21 @@ self.mc.CMP(mem(locs[0], offset), locs[1]) self.implement_guard(addr, op, self.mc.JNE) - def implement_guard_recovery(self, guard_op, regalloc): - oldmc = self.mc - self.mc = self.mc2 - self.mc2 = self.mcstack.next_mc() - addr = self.mc.tell() + def implement_guard_recovery(self, guard_op, fail_locs): + addr = self.mc2.tell() exc = (guard_op.opnum == rop.GUARD_EXCEPTION or guard_op.opnum == rop.GUARD_NO_EXCEPTION) - # XXX this is a heuristics to detect whether we're handling this - # exception or not. We should have a bit better interface to deal - # with that I fear - if (exc and (guard_op.suboperations[0].opnum == rop.GUARD_EXCEPTION or - guard_op.suboperations[0].opnum == rop.GUARD_NO_EXCEPTION)): - exc = False - regalloc.walk_guard_ops(guard_op.inputargs, guard_op.suboperations, exc) - self.mcstack.give_mc_back(self.mc2) - self.mc2 = self.mc - self.mc = oldmc + guard_op._x86_faillocs = fail_locs + # XXX horrible hack that allows us to preserve order + # of inputargs to bridge + guard_op._fail_op = guard_op.suboperations[0] + self.generate_failure(self.mc2, guard_op.suboperations[0], fail_locs, + exc) return addr - def generate_failure(self, op, locs, exc): - pos = self.mc.tell() + def generate_failure(self, mc, op, locs, exc): + assert op.opnum == rop.FAIL + pos = mc.tell() for i in range(len(locs)): loc = locs[i] if isinstance(loc, REG): @@ -683,7 +638,7 @@ base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr - self.mc.MOV(addr_add(imm(base), imm(i*WORD)), loc) + mc.MOV(addr_add(imm(base), imm(i*WORD)), loc) for i in range(len(locs)): loc = locs[i] if not isinstance(loc, REG): @@ -691,21 +646,20 @@ base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr - self.mc.MOV(eax, loc) - self.mc.MOV(addr_add(imm(base), imm(i*WORD)), eax) + mc.MOV(eax, loc) + mc.MOV(addr_add(imm(base), imm(i*WORD)), eax) if self.debug_markers: - self.mc.MOV(eax, imm(pos)) - self.mc.MOV(addr_add(imm(self.fail_box_int_addr), + mc.MOV(eax, imm(pos)) + mc.MOV(addr_add(imm(self.fail_box_int_addr), imm(len(locs) * WORD)), eax) if exc: # note that we don't have to save and restore eax, ecx and edx here addr = self.cpu.get_save_exception_int() - self.mc.CALL(rel32(addr)) + mc.CALL(rel32(addr)) # don't break the following code sequence! - mc = self.mc._mc - self.places_to_patch_framesize.append(mc.tell()) - mc.ADD(esp, imm32(0)) + mc = mc._mc + mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD)) guard_index = self.cpu.make_guard_index(op) mc.MOV(eax, imm(guard_index)) mc.POP(edi) @@ -717,6 +671,7 @@ @specialize.arg(3) def implement_guard(self, addr, guard_op, emit_jump): emit_jump(rel32(addr)) + guard_op._x86_addr = self.mc.tell() - 4 def genop_call(self, op, arglocs, resloc): sizeloc = arglocs[0] @@ -781,15 +736,6 @@ print "not implemented operation (guard): %s" % op.getopname() raise NotImplementedError - #def genop_call__1(self, op, arglocs, resloc): - # self.gen_call(op, arglocs, resloc) - # self.mc.MOVZX(eax, al) - - #def genop_call__2(self, op, arglocs, resloc): - # # XXX test it test it test it - # self.gen_call(op, arglocs, resloc) - # self.mc.MOVZX(eax, eax) - def mark_gc_roots(self): gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap: From arigo at codespeak.net Sat Sep 5 12:23:42 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 12:23:42 +0200 (CEST) Subject: [pypy-svn] r67512 - in pypy/trunk/pypy: jit/backend/test jit/backend/x86 jit/backend/x86/test module/pypyjit/test Message-ID: <20090905102342.8AD9116801D@codespeak.net> Author: arigo Date: Sat Sep 5 12:23:41 2009 New Revision: 67512 Added: pypy/trunk/pypy/jit/backend/test/ - copied from r67511, pypy/branch/no-recompilation-merge/pypy/jit/backend/test/ pypy/trunk/pypy/jit/backend/x86/assembler.py - copied unchanged from r67511, pypy/trunk/pypy/jit/backend/x86/assembler.py.merge.tmp pypy/trunk/pypy/jit/backend/x86/regalloc.py - copied unchanged from r67511, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/regalloc.py pypy/trunk/pypy/jit/backend/x86/runner.py - copied unchanged from r67511, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/runner.py pypy/trunk/pypy/jit/backend/x86/test/ - copied from r67511, pypy/branch/no-recompilation-merge/pypy/jit/backend/x86/test/ pypy/trunk/pypy/module/pypyjit/test/ - copied from r67511, pypy/branch/no-recompilation-merge/pypy/module/pypyjit/test/ Removed: pypy/trunk/pypy/jit/backend/x86/assembler.py.merge.tmp Log: Merge the "no-recompilation-merge" branch. From arigo at codespeak.net Sat Sep 5 12:34:31 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 12:34:31 +0200 (CEST) Subject: [pypy-svn] r67513 - pypy/trunk/pypy/module/pypyjit Message-ID: <20090905103431.9391E168016@codespeak.net> Author: arigo Date: Sat Sep 5 12:34:30 2009 New Revision: 67513 Modified: pypy/trunk/pypy/module/pypyjit/policy.py Log: Hide pypy.rlib.rweakrefimpl from the eyes of the JIT. Restores JITability of r67500 (so that the revert of r67501 can be cancelled). Modified: pypy/trunk/pypy/module/pypyjit/policy.py ============================================================================== --- pypy/trunk/pypy/module/pypyjit/policy.py (original) +++ pypy/trunk/pypy/module/pypyjit/policy.py Sat Sep 5 12:34:30 2009 @@ -56,6 +56,9 @@ # string builder interface if mod == 'pypy.rpython.lltypesystem.rbuilder': return False + # rweakvaluedict implementation + if mod == 'pypy.rlib.rweakrefimpl': + return False #if (mod == 'pypy.rpython.rlist' or # mod == 'pypy.rpython.lltypesystem.rdict' or # mod == 'pypy.rpython.lltypesystem.rlist'): From fijal at codespeak.net Sat Sep 5 13:06:43 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 5 Sep 2009 13:06:43 +0200 (CEST) Subject: [pypy-svn] r67514 - in pypy/build/benchmark: backend server specific specific/test Message-ID: <20090905110643.EAA6416801B@codespeak.net> Author: fijal Date: Sat Sep 5 13:06:43 2009 New Revision: 67514 Added: pypy/build/benchmark/backend/ pypy/build/benchmark/server/ pypy/build/benchmark/specific/runsympy.py (contents, props changed) Modified: pypy/build/benchmark/specific/test/test_benchmarks.py Log: Add a sympy benchmark Added: pypy/build/benchmark/specific/runsympy.py ============================================================================== --- (empty file) +++ pypy/build/benchmark/specific/runsympy.py Sat Sep 5 13:06:43 2009 @@ -0,0 +1,21 @@ + +from benchmark.runner import ScriptRunner +import inspect, sys + +def run_sympy(): + import sympy, time + i = sympy.Integer(10000) + t0 = time.clock() + while i > 0: + i -= 1 + tk = time.clock() + print tk - t0 + +class SympyRunner(ScriptRunner): + def __init__(self, executable=sys.executable): + ScriptRunner.__init__(self, 'sympybench', + inspect.getsource(run_sympy) + '\nrun_sympy()', + executable=executable) + + def read_output(self, output): + return float(output.strip("\n")) Modified: pypy/build/benchmark/specific/test/test_benchmarks.py ============================================================================== --- pypy/build/benchmark/specific/test/test_benchmarks.py (original) +++ pypy/build/benchmark/specific/test/test_benchmarks.py Sat Sep 5 13:06:43 2009 @@ -1,6 +1,8 @@ +import py from benchmark.specific.pystone import PystoneRunner from benchmark.specific.richards import RichardsRunner +from benchmark.specific.runsympy import SympyRunner def test_pystone(): runner = PystoneRunner() @@ -13,3 +15,13 @@ times = runner.run(1) assert len(times) == 1 assert isinstance(times[0], float) + +def test_sympy(): + try: + import sympy + except ImportError: + py.test.skip("sympy not found") + runner = SympyRunner() + times = runner.run(1) + assert len(times) == 1 + assert isinstance(times[0], float) From arigo at codespeak.net Sat Sep 5 13:17:30 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 13:17:30 +0200 (CEST) Subject: [pypy-svn] r67515 - in pypy/branch: no-recompilation no-recompilation-merge Message-ID: <20090905111730.1242F16801E@codespeak.net> Author: arigo Date: Sat Sep 5 13:17:30 2009 New Revision: 67515 Removed: pypy/branch/no-recompilation/ pypy/branch/no-recompilation-merge/ Log: Remove the merged branches. From arigo at codespeak.net Sat Sep 5 13:26:01 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 13:26:01 +0200 (CEST) Subject: [pypy-svn] r67516 - pypy/trunk/pypy/module/_testing Message-ID: <20090905112601.270A7168022@codespeak.net> Author: arigo Date: Sat Sep 5 13:25:58 2009 New Revision: 67516 Modified: pypy/trunk/pypy/module/_testing/ (props changed) Log: fixeol From fijal at codespeak.net Sat Sep 5 15:19:35 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 5 Sep 2009 15:19:35 +0200 (CEST) Subject: [pypy-svn] r67517 - pypy/build/benchmark/specific/considerations Message-ID: <20090905131935.8F6BD16801D@codespeak.net> Author: fijal Date: Sat Sep 5 15:19:34 2009 New Revision: 67517 Added: pypy/build/benchmark/specific/considerations/ Log: A directory to store potential benchmarks, not yet ready for use From fijal at codespeak.net Sat Sep 5 15:20:29 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 5 Sep 2009 15:20:29 +0200 (CEST) Subject: [pypy-svn] r67518 - pypy/build/benchmark/specific/considerations Message-ID: <20090905132029.34583168020@codespeak.net> Author: fijal Date: Sat Sep 5 15:20:28 2009 New Revision: 67518 Added: pypy/build/benchmark/specific/considerations/fannkuch.py (contents, props changed) Log: One benchmark stolen from shootout.alioth.debian.org Added: pypy/build/benchmark/specific/considerations/fannkuch.py ============================================================================== --- (empty file) +++ pypy/build/benchmark/specific/considerations/fannkuch.py Sat Sep 5 15:20:28 2009 @@ -0,0 +1,54 @@ +# The Computer Language Benchmarks Game +# http://shootout.alioth.debian.org/ +# +# contributed by Sokolov Yura +# modified by Tupteq + +def fannkuch(n): + count = range(1, n+1) + max_flips = 0 + m = n-1 + r = n + check = 0 + perm1 = range(n) + perm = range(n) + perm1_ins = perm1.insert + perm1_pop = perm1.pop + + while 1: + if check < 30: + print "".join(str(i+1) for i in perm1) + check += 1 + + while r != 1: + count[r-1] = r + r -= 1 + + if perm1[0] != 0 and perm1[m] != m: + perm = perm1[:] + flips_count = 0 + k = perm[0] + while k: + perm[:k+1] = perm[k::-1] + flips_count += 1 + k = perm[0] + + if flips_count > max_flips: + max_flips = flips_count + + while r != n: + perm1_ins(r, perm1_pop(0)) + count[r] -= 1 + if count[r] > 0: + break + r += 1 + else: + return max_flips + +def main(): + from sys import argv + n = int(argv and argv[1] or 1) + print "Pfannkuchen(%d) = %d\n" % (n, fannkuch(n)), + +if __name__=="__main__": + main() From pedronis at codespeak.net Sat Sep 5 15:27:18 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 5 Sep 2009 15:27:18 +0200 (CEST) Subject: [pypy-svn] r67519 - pypy/extradoc/planning Message-ID: <20090905132718.8576E168025@codespeak.net> Author: pedronis Date: Sat Sep 5 15:27:16 2009 New Revision: 67519 Modified: pypy/extradoc/planning/jit.txt Log: that was done on the merged no-recompilation branch Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Sat Sep 5 15:27:16 2009 @@ -18,8 +18,7 @@ - the tragedy of the skipped tests - keep test coverage in check -- make x86 not recompile everything - - think about code memory management +- think about code memory management - compare backend vs gcc quality From fijal at codespeak.net Sat Sep 5 15:27:57 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 5 Sep 2009 15:27:57 +0200 (CEST) Subject: [pypy-svn] r67520 - pypy/build/benchmark/specific/considerations Message-ID: <20090905132757.DB40C168025@codespeak.net> Author: fijal Date: Sat Sep 5 15:27:57 2009 New Revision: 67520 Modified: pypy/build/benchmark/specific/considerations/fannkuch.py Log: Remove the strange hack (speedup possibly), it actually slows down our jit. Modified: pypy/build/benchmark/specific/considerations/fannkuch.py ============================================================================== --- pypy/build/benchmark/specific/considerations/fannkuch.py (original) +++ pypy/build/benchmark/specific/considerations/fannkuch.py Sat Sep 5 15:27:57 2009 @@ -12,8 +12,6 @@ check = 0 perm1 = range(n) perm = range(n) - perm1_ins = perm1.insert - perm1_pop = perm1.pop while 1: if check < 30: @@ -37,7 +35,7 @@ max_flips = flips_count while r != n: - perm1_ins(r, perm1_pop(0)) + perm1.insert(r, perm1.pop(0)) count[r] -= 1 if count[r] > 0: break From fijal at codespeak.net Sat Sep 5 15:31:49 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 5 Sep 2009 15:31:49 +0200 (CEST) Subject: [pypy-svn] r67521 - pypy/build/benchmark/specific/considerations Message-ID: <20090905133149.C75C2168026@codespeak.net> Author: fijal Date: Sat Sep 5 15:31:48 2009 New Revision: 67521 Added: pypy/build/benchmark/specific/considerations/cryptomath.py (contents, props changed) Log: Add something stolen from tlslite. This one is terribly slow on jit. Added: pypy/build/benchmark/specific/considerations/cryptomath.py ============================================================================== --- (empty file) +++ pypy/build/benchmark/specific/considerations/cryptomath.py Sat Sep 5 15:31:48 2009 @@ -0,0 +1,341 @@ + +"""cryptomath module + +Stolen from tlslite (http://tlslite.sourceforge.net) +and adapted as a benchmark + +This module has basic math/crypto code.""" + +import os +import math +import base64 +import binascii +import sha +import array + +def createByteArraySequence(seq): + return array.array('B', seq) +def createByteArrayZeros(howMany): + return array.array('B', [0] * howMany) +def concatArrays(a1, a2): + return a1+a2 + +def bytesToString(bytes): + return bytes.tostring() +def stringToBytes(s): + bytes = createByteArrayZeros(0) + bytes.fromstring(s) + return bytes + +import math +def numBits(n): + if n==0: + return 0 + s = "%x" % n + return ((len(s)-1)*4) + \ + {'0':0, '1':1, '2':2, '3':2, + '4':3, '5':3, '6':3, '7':3, + '8':4, '9':4, 'a':4, 'b':4, + 'c':4, 'd':4, 'e':4, 'f':4, + }[s[0]] + return int(math.floor(math.log(n, 2))+1) + +BaseException = Exception +import sys +import traceback +def formatExceptionTrace(e): + newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) + return newStr + +m2cryptoLoaded = False + + +cryptlibpyLoaded = False +gmpyLoaded = False + +pycryptoLoaded = False + + +# ************************************************************************** +# PRNG Functions +# ************************************************************************** + +# Get os.urandom PRNG +os.urandom(1) +def getRandomBytes(howMany): + return stringToBytes(os.urandom(howMany)) +prngName = "os.urandom" + +# ************************************************************************** +# Converter Functions +# ************************************************************************** + +def bytesToNumber(bytes): + total = 0L + multiplier = 1L + for count in range(len(bytes)-1, -1, -1): + byte = bytes[count] + total += multiplier * byte + multiplier *= 256 + return total + +def numberToBytes(n): + howManyBytes = numBytes(n) + bytes = createByteArrayZeros(howManyBytes) + for count in range(howManyBytes-1, -1, -1): + bytes[count] = int(n % 256) + n >>= 8 + return bytes + +def bytesToBase64(bytes): + s = bytesToString(bytes) + return stringToBase64(s) + +def base64ToBytes(s): + s = base64ToString(s) + return stringToBytes(s) + +def numberToBase64(n): + bytes = numberToBytes(n) + return bytesToBase64(bytes) + +def base64ToNumber(s): + bytes = base64ToBytes(s) + return bytesToNumber(bytes) + +def stringToNumber(s): + bytes = stringToBytes(s) + return bytesToNumber(bytes) + +def numberToString(s): + bytes = numberToBytes(s) + return bytesToString(bytes) + +def base64ToString(s): + try: + return base64.decodestring(s) + except binascii.Error, e: + raise SyntaxError(e) + except binascii.Incomplete, e: + raise SyntaxError(e) + +def stringToBase64(s): + return base64.encodestring(s).replace("\n", "") + +def mpiToNumber(mpi): #mpi is an openssl-format bignum string + if (ord(mpi[4]) & 0x80) !=0: #Make sure this is a positive number + raise AssertionError() + bytes = stringToBytes(mpi[4:]) + return bytesToNumber(bytes) + +def numberToMPI(n): + bytes = numberToBytes(n) + ext = 0 + #If the high-order bit is going to be set, + #add an extra byte of zeros + if (numBits(n) & 0x7)==0: + ext = 1 + length = numBytes(n) + ext + bytes = concatArrays(createByteArrayZeros(4+ext), bytes) + bytes[0] = (length >> 24) & 0xFF + bytes[1] = (length >> 16) & 0xFF + bytes[2] = (length >> 8) & 0xFF + bytes[3] = length & 0xFF + return bytesToString(bytes) + + + +# ************************************************************************** +# Misc. Utility Functions +# ************************************************************************** + +def numBytes(n): + if n==0: + return 0 + bits = numBits(n) + return int(math.ceil(bits / 8.0)) + +def hashAndBase64(s): + return stringToBase64(sha.sha(s).digest()) + +def getBase64Nonce(numChars=22): #defaults to an 132 bit nonce + bytes = getRandomBytes(numChars) + bytesStr = "".join([chr(b) for b in bytes]) + return stringToBase64(bytesStr)[:numChars] + + +# ************************************************************************** +# Big Number Math +# ************************************************************************** + +def getRandomNumber(low, high): + if low >= high: + raise AssertionError() + howManyBits = numBits(high) + howManyBytes = numBytes(high) + lastBits = howManyBits % 8 + while 1: + bytes = getRandomBytes(howManyBytes) + if lastBits: + bytes[0] = bytes[0] % (1 << lastBits) + n = bytesToNumber(bytes) + if n >= low and n < high: + return n + +def gcd(a,b): + a, b = max(a,b), min(a,b) + while b: + a, b = b, a % b + return a + +def lcm(a, b): + #This will break when python division changes, but we can't use // cause + #of Jython + return (a * b) / gcd(a, b) + +#Returns inverse of a mod b, zero if none +#Uses Extended Euclidean Algorithm +def invMod(a, b): + c, d = a, b + uc, ud = 1, 0 + while c != 0: + #This will break when python division changes, but we can't use // + #cause of Jython + q = d / c + c, d = d-(q*c), c + uc, ud = ud - (q * uc), uc + if d == 1: + return ud % b + return 0 + + +if gmpyLoaded: + def powMod(base, power, modulus): + base = gmpy.mpz(base) + power = gmpy.mpz(power) + modulus = gmpy.mpz(modulus) + result = pow(base, power, modulus) + return long(result) + +else: + #Copied from Bryan G. Olson's post to comp.lang.python + #Does left-to-right instead of pow()'s right-to-left, + #thus about 30% faster than the python built-in with small bases + def powMod(base, power, modulus): + nBitScan = 5 + + """ Return base**power mod modulus, using multi bit scanning + with nBitScan bits at a time.""" + + #TREV - Added support for negative exponents + negativeResult = False + if (power < 0): + power *= -1 + negativeResult = True + + exp2 = 2**nBitScan + mask = exp2 - 1 + + # Break power into a list of digits of nBitScan bits. + # The list is recursive so easy to read in reverse direction. + nibbles = None + while power: + nibbles = int(power & mask), nibbles + power = power >> nBitScan + + # Make a table of powers of base up to 2**nBitScan - 1 + lowPowers = [1] + for i in xrange(1, exp2): + lowPowers.append((lowPowers[i-1] * base) % modulus) + + # To exponentiate by the first nibble, look it up in the table + nib, nibbles = nibbles + prod = lowPowers[nib] + + # For the rest, square nBitScan times, then multiply by + # base^nibble + while nibbles: + nib, nibbles = nibbles + for i in xrange(nBitScan): + prod = (prod * prod) % modulus + if nib: prod = (prod * lowPowers[nib]) % modulus + + #TREV - Added support for negative exponents + if negativeResult: + prodInv = invMod(prod, modulus) + #Check to make sure the inverse is correct + if (prod * prodInv) % modulus != 1: + raise AssertionError() + return prodInv + return prod + + +#Pre-calculate a sieve of the ~100 primes < 1000: +def makeSieve(n): + sieve = range(n) + for count in range(2, int(math.sqrt(n))): + if sieve[count] == 0: + continue + x = sieve[count] * 2 + while x < len(sieve): + sieve[x] = 0 + x += sieve[count] + sieve = [x for x in sieve[2:] if x] + return sieve + +sieve = makeSieve(1000) + +def isPrime(n, iterations=5, display=False): + #Trial division with sieve + for x in sieve: + if x >= n: return True + if n % x == 0: return False + #Passed trial division, proceed to Rabin-Miller + #Rabin-Miller implemented per Ferguson & Schneier + #Compute s, t for Rabin-Miller + if display: print "*", + s, t = n-1, 0 + while s % 2 == 0: + s, t = s/2, t+1 + #Repeat Rabin-Miller x times + a = 2 #Use 2 as a base for first iteration speedup, per HAC + for count in range(iterations): + v = powMod(a, s, n) + if v==1: + continue + i = 0 + while v != n-1: + if i == t-1: + return False + else: + v, i = powMod(v, 2, n), i+1 + a = getRandomNumber(2, n) + return True + +def getRandomPrime(bits, display=False): + if bits < 10: + raise AssertionError() + #The 1.5 ensures the 2 MSBs are set + #Thus, when used for p,q in RSA, n will have its MSB set + # + #Since 30 is lcm(2,3,5), we'll set our test numbers to + #29 % 30 and keep them there + low = (2L ** (bits-1)) * 3/2 + high = 2L ** bits - 30 + p = getRandomNumber(low, high) + p += 29 - (p % 30) + while 1: + if display: print ".", + p += 30 + if p >= high: + p = getRandomNumber(low, high) + p += 29 - (p % 30) + if isPrime(p, display=display): + return p + +def main(): + for i in range(1000): + getRandomPrime(32) + +if __name__ == '__main__': + main() From benjamin at codespeak.net Sat Sep 5 15:54:02 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Sat, 5 Sep 2009 15:54:02 +0200 (CEST) Subject: [pypy-svn] r67522 - pypy/extradoc/planning Message-ID: <20090905135402.323F616802D@codespeak.net> Author: benjamin Date: Sat Sep 5 15:54:01 2009 New Revision: 67522 Modified: pypy/extradoc/planning/jit.txt Log: remove 'speed of backend' Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Sat Sep 5 15:54:01 2009 @@ -58,9 +58,6 @@ - speed of tracing and fallbacks? - save space on all the guard operations (see resume.py) -backend: -- speed of backend? - - support threads again! Python interpreter: From pedronis at codespeak.net Sat Sep 5 15:58:35 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 5 Sep 2009 15:58:35 +0200 (CEST) Subject: [pypy-svn] r67523 - pypy/extradoc/planning Message-ID: <20090905135835.BF5F816802F@codespeak.net> Author: pedronis Date: Sat Sep 5 15:58:35 2009 New Revision: 67523 Modified: pypy/extradoc/planning/jit.txt Log: reinstate, is not completely horrible anymore but it is still a valid question Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Sat Sep 5 15:58:35 2009 @@ -58,6 +58,9 @@ - speed of tracing and fallbacks? - save space on all the guard operations (see resume.py) +backend: +- speed of backend? + - support threads again! Python interpreter: From fijal at codespeak.net Sat Sep 5 16:31:17 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 5 Sep 2009 16:31:17 +0200 (CEST) Subject: [pypy-svn] r67524 - pypy/build/benchmark/specific/considerations Message-ID: <20090905143117.01231168035@codespeak.net> Author: fijal Date: Sat Sep 5 16:31:15 2009 New Revision: 67524 Added: pypy/build/benchmark/specific/considerations/nbody.py (contents, props changed) Log: Add another benchmark. We miss float support for that one to be fast Added: pypy/build/benchmark/specific/considerations/nbody.py ============================================================================== --- (empty file) +++ pypy/build/benchmark/specific/considerations/nbody.py Sat Sep 5 16:31:15 2009 @@ -0,0 +1,113 @@ +# The Computer Language Benchmarks Game +# http://shootout.alioth.debian.org/ +# +# contributed by Kevin Carson +# modified by Tupteq, Fredrik Johansson, and Daniel Nanz + +import sys + +PI = 3.14159265358979323 +SOLAR_MASS = 4 * PI * PI +DAYS_PER_YEAR = 365.24 + +BODIES = { + 'sun': ([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], SOLAR_MASS), + + 'jupiter': ([4.84143144246472090e+00, + -1.16032004402742839e+00, + -1.03622044471123109e-01], + [1.66007664274403694e-03 * DAYS_PER_YEAR, + 7.69901118419740425e-03 * DAYS_PER_YEAR, + -6.90460016972063023e-05 * DAYS_PER_YEAR], + 9.54791938424326609e-04 * SOLAR_MASS), + + 'saturn': ([8.34336671824457987e+00, + 4.12479856412430479e+00, + -4.03523417114321381e-01], + [-2.76742510726862411e-03 * DAYS_PER_YEAR, + 4.99852801234917238e-03 * DAYS_PER_YEAR, + 2.30417297573763929e-05 * DAYS_PER_YEAR], + 2.85885980666130812e-04 * SOLAR_MASS), + + 'uranus': ([1.28943695621391310e+01, + -1.51111514016986312e+01, + -2.23307578892655734e-01], + [2.96460137564761618e-03 * DAYS_PER_YEAR, + 2.37847173959480950e-03 * DAYS_PER_YEAR, + -2.96589568540237556e-05 * DAYS_PER_YEAR], + 4.36624404335156298e-05 * SOLAR_MASS), + + 'neptune': ([1.53796971148509165e+01, + -2.59193146099879641e+01, + 1.79258772950371181e-01], + [2.68067772490389322e-03 * DAYS_PER_YEAR, + 1.62824170038242295e-03 * DAYS_PER_YEAR, + -9.51592254519715870e-05 * DAYS_PER_YEAR], + 5.15138902046611451e-05 * SOLAR_MASS) } + + +SYSTEM = BODIES.values() +PAIRS = [] + +for i in SYSTEM: + for j in SYSTEM: + if i != j: + PAIRS.append((i, j)) + +def advance(dt, n, bodies=SYSTEM, pairs=PAIRS): + + for i in xrange(n): + for (([x1, y1, z1], v1, m1), + ([x2, y2, z2], v2, m2)) in pairs: + dx = x1 - x2 + dy = y1 - y2 + dz = z1 - z2 + mag = dt * ((dx * dx + dy * dy + dz * dz) ** (-1.5)) + b1m = m1 * mag + b2m = m2 * mag + v1[0] -= dx * b2m + v1[1] -= dy * b2m + v1[2] -= dz * b2m + v2[0] += dx * b1m + v2[1] += dy * b1m + v2[2] += dz * b1m + for (r, [vx, vy, vz], m) in bodies: + r[0] += dt * vx + r[1] += dt * vy + r[2] += dt * vz + + +def report_energy(bodies=SYSTEM, pairs=PAIRS, e=0.0): + + for (((x1, y1, z1), v1, m1), + ((x2, y2, z2), v2, m2)) in pairs: + dx = x1 - x2 + dy = y1 - y2 + dz = z1 - z2 + e -= (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5) + for (r, [vx, vy, vz], m) in bodies: + e += m * (vx * vx + vy * vy + vz * vz) / 2. + print "%.9f" % e + + +def offset_momentum(ref, bodies=SYSTEM, px=0.0, py=0.0, pz=0.0): + + for (r, [vx, vy, vz], m) in bodies: + px -= vx * m + py -= vy * m + pz -= vz * m + (r, v, m) = ref + v[0] = px / m + v[1] = py / m + v[2] = pz / m + + +def main(n, ref='sun'): + + offset_momentum(BODIES[ref]) + report_energy() + advance(0.01, n) + report_energy() + + +main(int(sys.argv[1])) From arigo at codespeak.net Sat Sep 5 16:38:12 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 16:38:12 +0200 (CEST) Subject: [pypy-svn] r67525 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090905143812.5D6EE168008@codespeak.net> Author: arigo Date: Sat Sep 5 16:38:11 2009 New Revision: 67525 Modified: pypy/trunk/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/optimizeopt.py Log: Rename the get_() method into _get_hash_(). Modified: pypy/trunk/pypy/jit/metainterp/history.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py Sat Sep 5 16:38:11 2009 @@ -68,7 +68,7 @@ self.seen = {} def repr_rpython(self, box, typechars): n = self.seen.setdefault(box, len(self.seen)) - return '%s/%s%d' % (box.get_(), typechars, n) + return '%s/%s%d' % (box._get_hash_(), typechars, n) repr_rpython = ReprRPython().repr_rpython @@ -86,7 +86,7 @@ raise NotImplementedError getref._annspecialcase_ = 'specialize:arg(1)' - def get_(self): + def _get_hash_(self): raise NotImplementedError def nonnull(self): @@ -212,7 +212,7 @@ def getaddr(self, cpu): return cpu.cast_int_to_adr(self.value) - def get_(self): + def _get_hash_(self): return self.value def nonnull(self): @@ -258,7 +258,7 @@ def getaddr(self, cpu): return self.value - def get_(self): + def _get_hash_(self): return llmemory.cast_adr_to_int(self.value) def nonnull(self): @@ -297,7 +297,7 @@ return lltype.cast_opaque_ptr(PTR, self.getref_base()) getref._annspecialcase_ = 'specialize:arg(1)' - def get_(self): + def _get_hash_(self): return lltype.cast_ptr_to_int(self.value) def getaddr(self, cpu): @@ -343,9 +343,9 @@ return ootype.cast_from_object(OBJ, self.getref_base()) getref._annspecialcase_ = 'specialize:arg(1)' - def get_(self): + def _get_hash_(self): if self.value: - return ootype.ooidentityhash(self.value) # XXX: check me + return ootype.ooidentityhash(self.value) else: return 0 @@ -448,7 +448,7 @@ def getaddr(self, cpu): return cpu.cast_int_to_adr(self.value) - def get_(self): + def _get_hash_(self): return self.value def nonnull(self): @@ -492,7 +492,7 @@ def getaddr(self, cpu): return llmemory.cast_ptr_to_adr(self.value) - def get_(self): + def _get_hash_(self): return lltype.cast_ptr_to_int(self.value) def nonnull(self): @@ -534,9 +534,9 @@ return ootype.cast_from_object(OBJ, self.getref_base()) getref._annspecialcase_ = 'specialize:arg(1)' - def get_(self): + def _get_hash_(self): if self.value: - return ootype.ooidentityhash(self.value) # XXX: check me + return ootype.ooidentityhash(self.value) else: return 0 @@ -577,7 +577,7 @@ if isinstance(c.value, Symbolic): return id(c.value) try: - return c.get_() + return c._get_hash_() except lltype.DelayedPointer: return -2 # xxx risk of changing hash... Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimizeopt.py Sat Sep 5 16:38:11 2009 @@ -560,7 +560,8 @@ def optimize_GUARD_VALUE(self, op): assert isinstance(op.args[1], Const) - assert op.args[0].get_() == op.args[1].get_() + if not we_are_translated(): + assert op.args[0].value == op.args[1].value self.optimize_guard(op) def optimize_GUARD_TRUE(self, op): From arigo at codespeak.net Sat Sep 5 17:21:42 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 17:21:42 +0200 (CEST) Subject: [pypy-svn] r67526 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090905152142.B2EAC16803B@codespeak.net> Author: arigo Date: Sat Sep 5 17:21:38 2009 New Revision: 67526 Added: pypy/trunk/pypy/jit/metainterp/test/test_executor.py (contents, props changed) Modified: pypy/trunk/pypy/jit/metainterp/executor.py pypy/trunk/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/policy.py pypy/trunk/pypy/jit/metainterp/resoperation.py Log: Port r66735: the minimum for floats - boxes and a few operations. Modified: pypy/trunk/pypy/jit/metainterp/executor.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/executor.py (original) +++ pypy/trunk/pypy/jit/metainterp/executor.py Sat Sep 5 17:21:38 2009 @@ -7,7 +7,7 @@ from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib.rarithmetic import ovfcheck, r_uint, intmask from pypy.jit.metainterp.history import BoxInt, ConstInt, check_descr -from pypy.jit.metainterp.history import INT, REF +from pypy.jit.metainterp.history import INT, REF, ConstFloat from pypy.jit.metainterp.resoperation import rop @@ -218,6 +218,44 @@ cpu._overflow_flag = ovf return BoxInt(z) +# ---------- + +def do_float_neg(cpu, args, descr=None): + return ConstFloat(-args[0].getfloat()) + +def do_float_is_true(cpu, args, descr=None): + return ConstInt(bool(args[0].getfloat())) + +def do_float_add(cpu, args, descr=None): + return ConstFloat(args[0].getfloat() + args[1].getfloat()) + +def do_float_sub(cpu, args, descr=None): + return ConstFloat(args[0].getfloat() - args[1].getfloat()) + +def do_float_mul(cpu, args, descr=None): + return ConstFloat(args[0].getfloat() * args[1].getfloat()) + +def do_float_truediv(cpu, args, descr=None): + return ConstFloat(args[0].getfloat() / args[1].getfloat()) + +def do_float_lt(cpu, args, descr=None): + return ConstInt(args[0].getfloat() < args[1].getfloat()) + +def do_float_le(cpu, args, descr=None): + return ConstInt(args[0].getfloat() <= args[1].getfloat()) + +def do_float_eq(cpu, args, descr=None): + return ConstInt(args[0].getfloat() == args[1].getfloat()) + +def do_float_ne(cpu, args, descr=None): + return ConstInt(args[0].getfloat() != args[1].getfloat()) + +def do_float_gt(cpu, args, descr=None): + return ConstInt(args[0].getfloat() > args[1].getfloat()) + +def do_float_ge(cpu, args, descr=None): + return ConstInt(args[0].getfloat() >= args[1].getfloat()) + # ____________________________________________________________ def do_debug_merge_point(cpu, args, descr=None): Modified: pypy/trunk/pypy/jit/metainterp/history.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py Sat Sep 5 17:21:38 2009 @@ -16,13 +16,16 @@ # ____________________________________________________________ -INT = 'i' -REF = 'r' +INT = 'i' +REF = 'r' +FLOAT = 'f' -def getkind(TYPE): +def getkind(TYPE, supports_floats=False): if TYPE is lltype.Void: return "void" elif isinstance(TYPE, lltype.Primitive): + if TYPE is lltype.Float and supports_floats: + return 'float' if TYPE in (lltype.Float, lltype.SingleFloat): raise NotImplementedError("type %s not supported" % TYPE) # XXX fix this for oo... @@ -79,6 +82,9 @@ def getint(self): raise NotImplementedError + def getfloat(self): + raise NotImplementedError + def getref_base(self): raise NotImplementedError @@ -276,6 +282,38 @@ def repr_rpython(self): return repr_rpython(self, 'ca') +class ConstFloat(Const): + type = FLOAT + value = 0.0 + _attrs_ = ('value',) + + def __init__(self, floatval): + assert isinstance(floatval, float) + self.value = floatval + + def clonebox(self): + return BoxFloat(self.value) + + nonconstbox = clonebox + + def getfloat(self): + return self.value + + def _get_hash_(self): + return hash(self.value) + + def set_future_value(self, cpu, j): + cpu.set_future_value_float(j, self.getfloat()) + + def equals(self, other): + return self.value == other.getfloat() + + def _getrepr_(self): + return self.value + + def repr_rpython(self): + return repr_rpython(self, 'cf') + class ConstPtr(Const): type = REF value = lltype.nullptr(llmemory.GCREF.TO) @@ -468,6 +506,40 @@ changevalue_int = __init__ +class BoxFloat(Box): + type = FLOAT + _attrs_ = ('value',) + + def __init__(self, floatval=0.0): + assert isinstance(floatval, float) + self.value = floatval + + def clonebox(self): + return BoxFloat(self.value) + + def constbox(self): + return ConstFloat(self.value) + + def getfloat(self): + return self.value + + def _get_hash_(self): + return hash(self.value) + + def set_future_value(self, cpu, j): + cpu.set_future_value_float(j, self.value) + + def _getrepr_(self): + return self.value + + def repr_rpython(self): + return repr_rpython(self, 'bf') + + def changevalue_box(self, srcbox): + self.changevalue_float(srcbox.getfloat()) + + changevalue_float = __init__ + class BoxPtr(Box): type = REF _attrs_ = ('value',) Modified: pypy/trunk/pypy/jit/metainterp/policy.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/policy.py (original) +++ pypy/trunk/pypy/jit/metainterp/policy.py Sat Sep 5 17:21:38 2009 @@ -3,6 +3,7 @@ from pypy.rpython.lltypesystem import lltype class JitPolicy(object): + supports_floats = False # patched to True if supported by the backend def look_inside_function(self, func): if hasattr(func, '_look_inside_me_'): @@ -23,7 +24,9 @@ see_function = True else: see_function = self.look_inside_function(func) - return see_function and not contains_unsupported_variable_type(graph) + return (see_function and + not contains_unsupported_variable_type(graph, + self.supports_floats)) def graphs_from(self, op): if op.opname == 'direct_call': @@ -73,16 +76,16 @@ return 'residual' return 'regular' -def contains_unsupported_variable_type(graph): +def contains_unsupported_variable_type(graph, supports_floats): getkind = history.getkind try: for block in graph.iterblocks(): for v in block.inputargs: - getkind(v.concretetype) + getkind(v.concretetype, supports_floats) for op in block.operations: for v in op.args: - getkind(v.concretetype) - getkind(op.result.concretetype) + getkind(v.concretetype, supports_floats) + getkind(op.result.concretetype, supports_floats) except NotImplementedError, e: history.log.WARNING('%s, ignoring graph' % (e,)) history.log.WARNING(' %s' % (graph,)) Modified: pypy/trunk/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resoperation.py (original) +++ pypy/trunk/pypy/jit/metainterp/resoperation.py Sat Sep 5 17:21:38 2009 @@ -138,6 +138,10 @@ 'INT_RSHIFT', 'INT_LSHIFT', 'UINT_RSHIFT', + 'FLOAT_ADD', + 'FLOAT_SUB', + 'FLOAT_MUL', + 'FLOAT_TRUEDIV', # '_COMPARISON_FIRST', 'INT_LT', Added: pypy/trunk/pypy/jit/metainterp/test/test_executor.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/jit/metainterp/test/test_executor.py Sat Sep 5 17:21:38 2009 @@ -0,0 +1,26 @@ +from pypy.jit.metainterp.executor import make_execute_list, execute +from pypy.jit.metainterp.resoperation import rop +from pypy.jit.metainterp.history import BoxInt, ConstInt +from pypy.jit.metainterp.history import BoxFloat, ConstFloat +from pypy.jit.backend.model import AbstractCPU + + +class FakeCPU(AbstractCPU): + pass +make_execute_list(FakeCPU) + + +def test_int_ops(): + box = execute(FakeCPU(), rop.INT_ADD, [BoxInt(40), ConstInt(2)]) + assert box.value == 42 + +def test_float_ops(): + cpu = FakeCPU() + box = execute(cpu, rop.FLOAT_ADD, [BoxFloat(40.5), ConstFloat(2.25)]) + assert box.value == 42.75 + box = execute(cpu, rop.FLOAT_SUB, [BoxFloat(40.5), ConstFloat(2.25)]) + assert box.value == 38.25 + box = execute(cpu, rop.FLOAT_MUL, [BoxFloat(40.5), ConstFloat(2.25)]) + assert box.value == 91.125 + box = execute(cpu, rop.FLOAT_TRUEDIV, [BoxFloat(10.125), ConstFloat(2.25)]) + assert box.value == 4.5 From arigo at codespeak.net Sat Sep 5 17:42:33 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 17:42:33 +0200 (CEST) Subject: [pypy-svn] r67527 - in pypy/trunk/pypy/jit: backend backend/llgraph metainterp Message-ID: <20090905154233.8845916803B@codespeak.net> Author: arigo Date: Sat Sep 5 17:42:32 2009 New Revision: 67527 Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py pypy/trunk/pypy/jit/backend/model.py pypy/trunk/pypy/jit/metainterp/codewriter.py pypy/trunk/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/policy.py pypy/trunk/pypy/jit/metainterp/warmspot.py Log: Add the flag 'supports_floats' to the CPU classes, defaulting to False. Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/runner.py Sat Sep 5 17:42:32 2009 @@ -74,6 +74,7 @@ class BaseCPU(model.AbstractCPU): + supports_floats = True def __init__(self, rtyper, stats=None, translate_support_code=False, annmixlevel=None, gcdescr=None): Modified: pypy/trunk/pypy/jit/backend/model.py ============================================================================== --- pypy/trunk/pypy/jit/backend/model.py (original) +++ pypy/trunk/pypy/jit/backend/model.py Sat Sep 5 17:42:32 2009 @@ -1,4 +1,5 @@ class AbstractCPU(object): + supports_floats = False def set_class_sizes(self, class_sizes): self.class_sizes = class_sizes Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/codewriter.py Sat Sep 5 17:42:32 2009 @@ -251,7 +251,8 @@ graph, oosend_methdescr = graph_key self.bytecode = self.codewriter.get_jitcode(graph, oosend_methdescr=oosend_methdescr) - if not codewriter.policy.look_inside_graph(graph): + if not codewriter.policy.look_inside_graph(graph, + self.cpu.supports_floats): assert not portal, "portal has been hidden!" graph = make_calling_stub(codewriter.rtyper, graph) self.graph = graph @@ -1003,20 +1004,24 @@ self.emit('can_enter_jit') def serialize_op_direct_call(self, op): - kind = self.codewriter.policy.guess_call_kind(op) + kind = self.codewriter.policy.guess_call_kind(op, + self.codewriter.cpu.supports_floats) return getattr(self, 'handle_%s_call' % kind)(op) def serialize_op_indirect_call(self, op): - kind = self.codewriter.policy.guess_call_kind(op) + kind = self.codewriter.policy.guess_call_kind(op, + self.codewriter.cpu.supports_floats) return getattr(self, 'handle_%s_indirect_call' % kind)(op) def serialize_op_oosend(self, op): - kind = self.codewriter.policy.guess_call_kind(op) + kind = self.codewriter.policy.guess_call_kind(op, + self.codewriter.cpu.supports_floats) return getattr(self, 'handle_%s_oosend' % kind)(op) def handle_regular_call(self, op, oosend_methdescr=None): self.minimize_variables() - [targetgraph] = self.codewriter.policy.graphs_from(op) + [targetgraph] = self.codewriter.policy.graphs_from(op, + self.codewriter.cpu.supports_floats) jitbox = self.codewriter.get_jitcode(targetgraph, self.graph, oosend_methdescr=oosend_methdescr) if oosend_methdescr: @@ -1071,7 +1076,8 @@ handle_residual_indirect_call = handle_residual_call def handle_regular_indirect_call(self, op): - targets = self.codewriter.policy.graphs_from(op) + targets = self.codewriter.policy.graphs_from(op, + self.codewriter.cpu.supports_floats) assert targets is not None self.minimize_variables() indirectcallset = self.codewriter.get_indirectcallset(targets) Modified: pypy/trunk/pypy/jit/metainterp/history.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py Sat Sep 5 17:42:32 2009 @@ -20,7 +20,7 @@ REF = 'r' FLOAT = 'f' -def getkind(TYPE, supports_floats=False): +def getkind(TYPE, supports_floats=True): if TYPE is lltype.Void: return "void" elif isinstance(TYPE, lltype.Primitive): Modified: pypy/trunk/pypy/jit/metainterp/policy.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/policy.py (original) +++ pypy/trunk/pypy/jit/metainterp/policy.py Sat Sep 5 17:42:32 2009 @@ -3,7 +3,6 @@ from pypy.rpython.lltypesystem import lltype class JitPolicy(object): - supports_floats = False # patched to True if supported by the backend def look_inside_function(self, func): if hasattr(func, '_look_inside_me_'): @@ -17,7 +16,7 @@ return False return True - def look_inside_graph(self, graph): + def look_inside_graph(self, graph, supports_floats): try: func = graph.func except AttributeError: @@ -26,13 +25,13 @@ see_function = self.look_inside_function(func) return (see_function and not contains_unsupported_variable_type(graph, - self.supports_floats)) + supports_floats)) - def graphs_from(self, op): + def graphs_from(self, op, supports_floats): if op.opname == 'direct_call': funcobj = get_funcobj(op.args[0].value) graph = funcobj.graph - if self.look_inside_graph(graph): + if self.look_inside_graph(graph, supports_floats): return [graph] # common case: look inside this graph else: assert op.opname in ('indirect_call', 'oosend') @@ -43,13 +42,13 @@ graphs = v_obj._lookup_graphs(op.args[0].value) if graphs is not None: for graph in graphs: - if self.look_inside_graph(graph): + if self.look_inside_graph(graph, supports_floats): return graphs # common case: look inside at # least one of the graphs # residual call case: we don't need to look into any graph return None - def guess_call_kind(self, op): + def guess_call_kind(self, op, supports_floats): if op.opname == 'direct_call': funcobj = get_funcobj(op.args[0].value) if isinstance(lltype.typeOf(funcobj), lltype.Ptr): @@ -72,7 +71,7 @@ return 'builtin' # TODO: return 'recursive' if the oosend ends with calling the # portal - if self.graphs_from(op) is None: + if self.graphs_from(op, supports_floats) is None: return 'residual' return 'regular' Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Sat Sep 5 17:42:32 2009 @@ -127,18 +127,20 @@ class WarmRunnerDesc: - def __init__(self, translator, policy=None, backendopt=True, **kwds): + def __init__(self, translator, policy=None, backendopt=True, CPUClass=None, + **kwds): pyjitpl._warmrunnerdesc = self # this is a global for debugging only! if policy is None: policy = JitPolicy() self.set_translator(translator) self.find_portal() - graphs = find_all_graphs(self.portal_graph, policy, self.translator) + graphs = find_all_graphs(self.portal_graph, policy, self.translator, + CPUClass) self.check_access_directly_sanity(graphs) if backendopt: self.prejit_optimizations(policy, graphs) - self.build_meta_interp(**kwds) + self.build_meta_interp(CPUClass, **kwds) self.make_args_specification() self.rewrite_jit_merge_point() self.make_driverhook_graph() @@ -206,7 +208,7 @@ remove_asserts=True, really_remove_asserts=True) - def build_meta_interp(self, CPUClass=None, translate_support_code=False, + def build_meta_interp(self, CPUClass, translate_support_code=False, view="auto", optimizer=None, profile=None, **kwds): assert CPUClass is not None opt = history.Options(**kwds) @@ -510,8 +512,9 @@ op.args[:3] = [closures[funcname]] -def find_all_graphs(portal, policy, translator): +def find_all_graphs(portal, policy, translator, CPUClass): from pypy.translator.simplify import get_graph + supports_floats = CPUClass.supports_floats all_graphs = [portal] seen = set([portal]) todo = [portal] @@ -520,13 +523,13 @@ for _, op in top_graph.iterblockops(): if op.opname not in ("direct_call", "indirect_call", "oosend"): continue - kind = policy.guess_call_kind(op) + kind = policy.guess_call_kind(op, supports_floats) if kind != "regular": continue - for graph in policy.graphs_from(op): + for graph in policy.graphs_from(op, supports_floats): if graph in seen: continue - if policy.look_inside_graph(graph): + if policy.look_inside_graph(graph, supports_floats): todo.append(graph) all_graphs.append(graph) seen.add(graph) From arigo at codespeak.net Sat Sep 5 18:34:01 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 18:34:01 +0200 (CEST) Subject: [pypy-svn] r67528 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090905163401.CA0A7168007@codespeak.net> Author: arigo Date: Sat Sep 5 18:34:00 2009 New Revision: 67528 Modified: pypy/trunk/pypy/jit/metainterp/test/test_policy.py Log: Fix the test (sorry!). Modified: pypy/trunk/pypy/jit/metainterp/test/test_policy.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_policy.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_policy.py Sat Sep 5 18:34:00 2009 @@ -19,11 +19,29 @@ jitpolicy = policy.JitPolicy() translator = rtyper.annotator.translator - res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator) + res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator, + True) funcs = [graph.func for graph in res] assert funcs == [i, f] +def test_find_all_graphs_without_floats(): + def g(x): + return int(x * 12.5) + def f(x): + return g(x) + 1 + rtyper = support.annotate(f, [7]) + jitpolicy = policy.JitPolicy() + translator = rtyper.annotator.translator + res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator, + supports_floats=True) + funcs = [graph.func for graph in res] + assert funcs == [f, g] + res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator, + supports_floats=False) + funcs = [graph.func for graph in res] + assert funcs == [f] + def test_find_all_graphs_str_join(): def i(x, y): return "hello".join([str(x), str(y), "bye"]) @@ -32,7 +50,8 @@ jitpolicy = policy.JitPolicy() translator = rtyper.annotator.translator - res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator) + res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator, + True) funcs = [graph.func for graph in res] assert funcs[:1] == [i] From fijal at codespeak.net Sat Sep 5 18:55:24 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 5 Sep 2009 18:55:24 +0200 (CEST) Subject: [pypy-svn] r67529 - pypy/trunk/pypy/jit/backend/x86/test Message-ID: <20090905165524.65EEA16800A@codespeak.net> Author: fijal Date: Sat Sep 5 18:55:24 2009 New Revision: 67529 Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py Log: Try to make those tests really test what they were supposed to. Fails though Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py Sat Sep 5 18:55:24 2009 @@ -14,6 +14,7 @@ from pypy.rpython.annlowlevel import llhelper from pypy.rpython.lltypesystem import rclass, rstr from pypy.jit.backend.x86.ri386 import * +from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList class DummyTree(object): operations = [ResOperation(rop.FAIL, [], None)] @@ -74,9 +75,10 @@ gcrootmap = MockGcRootMap() def initialize(self): - pass - def rewrite_assembler(self, cpu, operations): - pass + self.gcrefs = GcRefList() + self.gcrefs.initialize() + + rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func class RegAllocForTests(RegAlloc): @@ -612,6 +614,10 @@ class TestRegallocGc(BaseTestRegalloc): + + def setup_class(cls): + py.test.skip("fails") + cpu = CPU(None, None) cpu.gc_ll_descr = MockGcDescr(False) @@ -649,6 +655,26 @@ ''' self.interpret(ops, []) assert not self.getptr(0, lltype.Ptr(self.S)) + + def test_rewrite_constptr_bridge(self): + ops = ''' + [i0] + guard_true(i0) + fail(1, ConstPtr(struct_ref)) + fail(0) + ''' + loop = self.interpret(ops, [0]) + assert self.getint(0) == 1 + assert self.getptr(1, lltype.Ptr(self.S)) + bridge_ops = ''' + [i0] + p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) + fail(p1) + ''' + self.attach_bridge(bridge_ops, loop, loop.operations[0]) + self.cpu.set_future_value_int(0, 0) + self.cpu.execute_operations(loop) + not self.getptr(0, lltype.Ptr(self.S)) def test_bug_0(self): ops = ''' From fijal at codespeak.net Sat Sep 5 18:59:14 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 5 Sep 2009 18:59:14 +0200 (CEST) Subject: [pypy-svn] r67530 - pypy/trunk/pypy/jit/backend/x86/test Message-ID: <20090905165914.9E33E16800A@codespeak.net> Author: fijal Date: Sat Sep 5 18:59:14 2009 New Revision: 67530 Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py Log: fail with Const is forbidden Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py Sat Sep 5 18:59:14 2009 @@ -660,12 +660,11 @@ ops = ''' [i0] guard_true(i0) - fail(1, ConstPtr(struct_ref)) + fail(1) fail(0) ''' loop = self.interpret(ops, [0]) assert self.getint(0) == 1 - assert self.getptr(1, lltype.Ptr(self.S)) bridge_ops = ''' [i0] p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) From arigo at codespeak.net Sat Sep 5 19:00:15 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 19:00:15 +0200 (CEST) Subject: [pypy-svn] r67531 - in pypy/trunk/pypy/jit: backend/llgraph backend/test metainterp metainterp/test Message-ID: <20090905170015.3537316800A@codespeak.net> Author: arigo Date: Sat Sep 5 19:00:14 2009 New Revision: 67531 Added: pypy/trunk/pypy/jit/metainterp/test/test_float.py (contents, props changed) Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py pypy/trunk/pypy/jit/backend/llgraph/runner.py pypy/trunk/pypy/jit/backend/test/runner_test.py pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/test_basic.py pypy/trunk/pypy/jit/metainterp/warmspot.py Log: Trying to fix all places that used to check INT versus REF so that now they also know about FLOAT. This was mostly done with greps. Added a small test_float to prove that I got at least the basic cases right. All tests seem to pass again, including test_zrpy_basic. Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py Sat Sep 5 19:00:14 2009 @@ -8,7 +8,8 @@ from pypy.objspace.flow.model import Variable, Constant from pypy.annotation import model as annmodel from pypy.jit.metainterp.history import (ConstInt, ConstPtr, ConstAddr, - BoxInt, BoxPtr, BoxObj, REF) + BoxInt, BoxPtr, BoxObj, BoxFloat, + REF, INT, FLOAT) from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr from pypy.rpython.ootypesystem import ootype from pypy.rpython.module.support import LLSupport, OOSupport @@ -82,6 +83,10 @@ 'uint_ge' : (('int', 'int'), 'bool'), 'uint_xor' : (('int', 'int'), 'int'), 'uint_rshift' : (('int', 'int'), 'int'), + 'float_add' : (('float', 'float'), 'float'), + 'float_sub' : (('float', 'float'), 'float'), + 'float_mul' : (('float', 'float'), 'float'), + 'float_truediv' : (('float', 'float'), 'float'), 'same_as' : (('int',), 'int'), # could also be ptr=>ptr 'new_with_vtable' : (('ref',), 'ref'), 'new' : ((), 'ref'), @@ -248,6 +253,8 @@ return str(bool(x)) #elif tp == 'fieldname': # return str(symbolic.TokenToField[x...][1]) + elif tp == 'float': + return str(x) else: raise NotImplementedError("tp = %s" % tp) @@ -258,14 +265,10 @@ return _to_opaque(CompiledLoop()) def compile_start_int_var(loop): - loop = _from_opaque(loop) - assert not loop.operations - v = Variable() - v.concretetype = lltype.Signed - loop.inputargs.append(v) - r = len(_variables) - _variables.append(v) - return r + return compile_start_ref_var(loop, lltype.Signed) + +def compile_start_float_var(loop): + return compile_start_ref_var(loop, lltype.Float) def compile_start_ref_var(loop, TYPE): loop = _from_opaque(loop) @@ -294,11 +297,10 @@ op.args.append(_variables[intvar]) def compile_add_int_const(loop, value): - loop = _from_opaque(loop) - const = Constant(value) - const.concretetype = lltype.Signed - op = loop.operations[-1] - op.args.append(const) + compile_add_ref_const(loop, value, lltype.Signed) + +def compile_add_float_const(loop, value): + compile_add_ref_const(loop, value, lltype.Float) def compile_add_ref_const(loop, value, TYPE): loop = _from_opaque(loop) @@ -308,14 +310,10 @@ op.args.append(const) def compile_add_int_result(loop): - loop = _from_opaque(loop) - v = Variable() - v.concretetype = lltype.Signed - op = loop.operations[-1] - op.result = v - r = len(_variables) - _variables.append(v) - return r + return compile_add_ref_result(loop, lltype.Signed) + +def compile_add_float_result(loop): + return compile_add_ref_result(loop, lltype.Float) def compile_add_ref_result(loop, TYPE): loop = _from_opaque(loop) @@ -410,6 +408,8 @@ x = self.as_ptr(result) elif RESTYPE is ootype.Object: x = self.as_object(result) + elif RESTYPE is lltype.Float: + x = self.as_float(result) else: raise Exception("op.result.concretetype is %r" % (RESTYPE,)) @@ -472,6 +472,9 @@ def as_object(self, x): return ootype.cast_to_object(x) + def as_float(self, x): + return cast_to_float(x) + def log_progress(self): count = sum(_stats.exec_counters.values()) count_jumps = _stats.exec_jumps @@ -500,6 +503,8 @@ for x in args: if type(x) is int: boxedargs.append(BoxInt(x)) + elif type(x) is float: + boxedargs.append(BoxFloat(x)) elif isinstance(ootype.typeOf(x), ootype.OOType): boxedargs.append(BoxObj(ootype.cast_to_object(x))) else: @@ -616,24 +621,36 @@ def op_getarrayitem_gc(self, arraydescr, array, index): if arraydescr.typeinfo == REF: return do_getarrayitem_gc_ptr(array, index) - else: + elif arraydescr.typeinfo == INT: return do_getarrayitem_gc_int(array, index, self.memocast) + elif arraydescr.typeinfo == FLOAT: + return do_getarrayitem_gc_float(array, index) + else: + raise NotImplementedError op_getarrayitem_gc_pure = op_getarrayitem_gc def op_getfield_gc(self, fielddescr, struct): if fielddescr.typeinfo == REF: return do_getfield_gc_ptr(struct, fielddescr.ofs) - else: + elif fielddescr.typeinfo == INT: return do_getfield_gc_int(struct, fielddescr.ofs, self.memocast) + elif fielddescr.typeinfo == FLOAT: + return do_getfield_gc_float(struct, fielddescr.ofs) + else: + raise NotImplementedError op_getfield_gc_pure = op_getfield_gc def op_getfield_raw(self, fielddescr, struct): if fielddescr.typeinfo == REF: return do_getfield_raw_ptr(struct, fielddescr.ofs, self.memocast) - else: + elif fielddescr.typeinfo == INT: return do_getfield_raw_int(struct, fielddescr.ofs, self.memocast) + elif fielddescr.typeinfo == FLOAT: + return do_getfield_raw_float(struct, fielddescr.ofs, self.memocast) + else: + raise NotImplementedError def op_new(self, size): return do_new(size.ofs) @@ -649,23 +666,36 @@ def op_setarrayitem_gc(self, arraydescr, array, index, newvalue): if arraydescr.typeinfo == REF: do_setarrayitem_gc_ptr(array, index, newvalue) - else: + elif arraydescr.typeinfo == INT: do_setarrayitem_gc_int(array, index, newvalue, self.memocast) + elif arraydescr.typeinfo == FLOAT: + do_setarrayitem_gc_float(array, index, newvalue) + else: + raise NotImplementedError def op_setfield_gc(self, fielddescr, struct, newvalue): if fielddescr.typeinfo == REF: do_setfield_gc_ptr(struct, fielddescr.ofs, newvalue) - else: + elif fielddescr.typeinfo == INT: do_setfield_gc_int(struct, fielddescr.ofs, newvalue, self.memocast) + elif fielddescr.typeinfo == FLOAT: + do_setfield_gc_float(struct, fielddescr.ofs, newvalue) + else: + raise NotImplementedError def op_setfield_raw(self, fielddescr, struct, newvalue): if fielddescr.typeinfo == REF: do_setfield_raw_ptr(struct, fielddescr.ofs, newvalue, self.memocast) - else: + elif fielddescr.typeinfo == INT: do_setfield_raw_int(struct, fielddescr.ofs, newvalue, self.memocast) + elif fielddescr.typeinfo == FLOAT: + do_setfield_raw_float(struct, fielddescr.ofs, newvalue, + self.memocast) + else: + raise NotImplementedError def op_call(self, calldescr, func, *args): _call_args[:] = args @@ -673,9 +703,12 @@ err_result = None elif calldescr.typeinfo == REF: err_result = lltype.nullptr(llmemory.GCREF.TO) - else: - assert calldescr.typeinfo == 'i' + elif calldescr.typeinfo == INT: err_result = 0 + elif calldescr.typeinfo == FLOAT: + err_result = 0.0 + else: + raise NotImplementedError return _do_call_common(func, self.memocast, err_result) op_call_pure = op_call @@ -830,6 +863,15 @@ def cast_from_ptr(TYPE, x): return lltype.cast_opaque_ptr(TYPE, x) +def cast_to_float(x): # not really a cast, just a type check + assert isinstance(x, float) + return x + +def cast_from_float(TYPE, x): # not really a cast, just a type check + assert TYPE is lltype.Float + assert isinstance(x, float) + return x + def new_frame(memocast, is_oo): if is_oo: @@ -853,9 +895,10 @@ del _future_values[:] def set_future_value_int(index, value): - del _future_values[index:] - assert len(_future_values) == index - _future_values.append(value) + set_future_value_ref(index, value) + +def set_future_value_float(index, value): + set_future_value_ref(index, value) def set_future_value_ref(index, value): del _future_values[index:] @@ -886,6 +929,10 @@ frame = _from_opaque(frame) return frame.fail_args[num] +def frame_float_getvalue(frame, num): + frame = _from_opaque(frame) + return frame.fail_args[num] + def frame_ptr_getvalue(frame, num): frame = _from_opaque(frame) result = frame.fail_args[num] @@ -1009,33 +1056,41 @@ array = array._obj.container return cast_to_int(array.getitem(index), memocast) +def do_getarrayitem_gc_float(array, index): + array = array._obj.container + return cast_to_float(array.getitem(index)) + def do_getarrayitem_gc_ptr(array, index): array = array._obj.container return cast_to_ptr(array.getitem(index)) -def do_getfield_gc_int(struct, fieldnum, memocast): +def _getfield_gc(struct, fieldnum): STRUCT, fieldname = symbolic.TokenToField[fieldnum] ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct) - x = getattr(ptr, fieldname) - return cast_to_int(x, memocast) + return getattr(ptr, fieldname) + +def do_getfield_gc_int(struct, fieldnum, memocast): + return cast_to_int(_getfield_gc(struct, fieldnum), memocast) + +def do_getfield_gc_float(struct, fieldnum): + return cast_to_float(_getfield_gc(struct, fieldnum)) def do_getfield_gc_ptr(struct, fieldnum): - STRUCT, fieldname = symbolic.TokenToField[fieldnum] - ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct) - x = getattr(ptr, fieldname) - return cast_to_ptr(x) + return cast_to_ptr(_getfield_gc(struct, fieldnum)) -def do_getfield_raw_int(struct, fieldnum, memocast): +def _getfield_raw(struct, fieldnum, memocast): STRUCT, fieldname = symbolic.TokenToField[fieldnum] ptr = cast_from_int(lltype.Ptr(STRUCT), struct, memocast) - x = getattr(ptr, fieldname) - return cast_to_int(x, memocast) + return getattr(ptr, fieldname) + +def do_getfield_raw_int(struct, fieldnum, memocast): + return cast_to_int(_getfield_raw(struct, fieldnum, memocast), memocast) + +def do_getfield_raw_float(struct, fieldnum, memocast): + return cast_to_float(_getfield_raw(struct, fieldnum, memocast)) def do_getfield_raw_ptr(struct, fieldnum, memocast): - STRUCT, fieldname = symbolic.TokenToField[fieldnum] - ptr = cast_from_int(lltype.Ptr(STRUCT), struct, memocast) - x = getattr(ptr, fieldname) - return cast_to_ptr(x) + return cast_to_ptr(_getfield_raw(struct, fieldnum, memocast)) def do_new(size): TYPE = symbolic.Size2Type[size] @@ -1053,6 +1108,12 @@ newvalue = cast_from_int(ITEMTYPE, newvalue, memocast) array.setitem(index, newvalue) +def do_setarrayitem_gc_float(array, index, newvalue): + array = array._obj.container + ITEMTYPE = lltype.typeOf(array).OF + newvalue = cast_from_float(ITEMTYPE, newvalue) + array.setitem(index, newvalue) + def do_setarrayitem_gc_ptr(array, index, newvalue): array = array._obj.container ITEMTYPE = lltype.typeOf(array).OF @@ -1066,6 +1127,13 @@ newvalue = cast_from_int(FIELDTYPE, newvalue, memocast) setattr(ptr, fieldname, newvalue) +def do_setfield_gc_float(struct, fieldnum, newvalue): + STRUCT, fieldname = symbolic.TokenToField[fieldnum] + ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct) + FIELDTYPE = getattr(STRUCT, fieldname) + newvalue = cast_from_float(FIELDTYPE, newvalue) + setattr(ptr, fieldname, newvalue) + def do_setfield_gc_ptr(struct, fieldnum, newvalue): STRUCT, fieldname = symbolic.TokenToField[fieldnum] ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct) @@ -1080,6 +1148,13 @@ newvalue = cast_from_int(FIELDTYPE, newvalue, memocast) setattr(ptr, fieldname, newvalue) +def do_setfield_raw_float(struct, fieldnum, newvalue, memocast): + STRUCT, fieldname = symbolic.TokenToField[fieldnum] + ptr = cast_from_int(lltype.Ptr(STRUCT), struct, memocast) + FIELDTYPE = getattr(STRUCT, fieldname) + newvalue = cast_from_float(FIELDTYPE, newvalue) + setattr(ptr, fieldname, newvalue) + def do_setfield_raw_ptr(struct, fieldnum, newvalue, memocast): STRUCT, fieldname = symbolic.TokenToField[fieldnum] ptr = cast_from_int(lltype.Ptr(STRUCT), struct, memocast) @@ -1109,6 +1184,9 @@ def do_call_pushint(x): _call_args.append(x) +def do_call_pushfloat(x): + _call_args.append(x) + def do_call_pushptr(x): _call_args.append(x) @@ -1139,6 +1217,10 @@ x = _do_call_common(f, memocast, 0) return cast_to_int(x, memocast) +def do_call_float(f, memocast): + x = _do_call_common(f, memocast, 0) + return cast_to_float(x) + def do_call_ptr(f, memocast): x = _do_call_common(f, memocast, lltype.nullptr(llmemory.GCREF.TO)) return cast_to_ptr(x) @@ -1155,6 +1237,8 @@ x = ootype.cast_from_object(TYPE, x) elif isinstance(TYPE, lltype.Ptr) and TYPE.TO._gckind == 'gc': x = cast_from_ptr(TYPE, x) + elif TYPE is lltype.Float: + x = cast_from_float(TYPE, x) else: x = cast_from_int(TYPE, x, memocast) args.append(x) @@ -1244,13 +1328,16 @@ setannotation(compile_start, s_CompiledLoop) setannotation(compile_start_int_var, annmodel.SomeInteger()) setannotation(compile_start_ref_var, annmodel.SomeInteger()) +setannotation(compile_start_float_var, annmodel.SomeInteger()) setannotation(compile_add, annmodel.s_None) setannotation(compile_add_descr, annmodel.s_None) setannotation(compile_add_var, annmodel.s_None) setannotation(compile_add_int_const, annmodel.s_None) setannotation(compile_add_ref_const, annmodel.s_None) +setannotation(compile_add_float_const, annmodel.s_None) setannotation(compile_add_int_result, annmodel.SomeInteger()) setannotation(compile_add_ref_result, annmodel.SomeInteger()) +setannotation(compile_add_float_result, annmodel.SomeInteger()) setannotation(compile_add_jump_target, annmodel.s_None) setannotation(compile_add_fail, annmodel.s_None) setannotation(compile_suboperations, s_CompiledLoop) @@ -1260,9 +1347,11 @@ setannotation(frame_clear, annmodel.s_None) setannotation(set_future_value_int, annmodel.s_None) setannotation(set_future_value_ref, annmodel.s_None) +setannotation(set_future_value_float, annmodel.s_None) setannotation(frame_execute, annmodel.SomeInteger()) setannotation(frame_int_getvalue, annmodel.SomeInteger()) setannotation(frame_ptr_getvalue, annmodel.SomePtr(llmemory.GCREF)) +setannotation(frame_float_getvalue, annmodel.SomeFloat()) setannotation(get_exception, annmodel.SomeAddress()) setannotation(get_exc_value, annmodel.SomePtr(llmemory.GCREF)) @@ -1284,18 +1373,24 @@ setannotation(do_unicodegetitem, annmodel.SomeInteger()) setannotation(do_getarrayitem_gc_int, annmodel.SomeInteger()) setannotation(do_getarrayitem_gc_ptr, annmodel.SomePtr(llmemory.GCREF)) +setannotation(do_getarrayitem_gc_float, annmodel.SomeFloat()) setannotation(do_getfield_gc_int, annmodel.SomeInteger()) setannotation(do_getfield_gc_ptr, annmodel.SomePtr(llmemory.GCREF)) +setannotation(do_getfield_gc_float, annmodel.SomeFloat()) setannotation(do_getfield_raw_int, annmodel.SomeInteger()) setannotation(do_getfield_raw_ptr, annmodel.SomePtr(llmemory.GCREF)) +setannotation(do_getfield_raw_float, annmodel.SomeFloat()) setannotation(do_new, annmodel.SomePtr(llmemory.GCREF)) setannotation(do_new_array, annmodel.SomePtr(llmemory.GCREF)) setannotation(do_setarrayitem_gc_int, annmodel.s_None) setannotation(do_setarrayitem_gc_ptr, annmodel.s_None) +setannotation(do_setarrayitem_gc_float, annmodel.s_None) setannotation(do_setfield_gc_int, annmodel.s_None) setannotation(do_setfield_gc_ptr, annmodel.s_None) +setannotation(do_setfield_gc_float, annmodel.s_None) setannotation(do_setfield_raw_int, annmodel.s_None) setannotation(do_setfield_raw_ptr, annmodel.s_None) +setannotation(do_setfield_raw_float, annmodel.s_None) setannotation(do_newstr, annmodel.SomePtr(llmemory.GCREF)) setannotation(do_strsetitem, annmodel.s_None) setannotation(do_newunicode, annmodel.SomePtr(llmemory.GCREF)) @@ -1304,4 +1399,5 @@ setannotation(do_call_pushptr, annmodel.s_None) setannotation(do_call_int, annmodel.SomeInteger()) setannotation(do_call_ptr, annmodel.SomePtr(llmemory.GCREF)) +setannotation(do_call_float, annmodel.SomeFloat()) setannotation(do_call_void, annmodel.s_None) Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/runner.py Sat Sep 5 19:00:14 2009 @@ -8,7 +8,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rpython.llinterp import LLInterpreter from pypy.jit.metainterp import history -from pypy.jit.metainterp.history import REF +from pypy.jit.metainterp.history import REF, INT, FLOAT from pypy.jit.metainterp.warmspot import unwrap from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.backend import model @@ -119,6 +119,8 @@ elif isinstance(box, self.ts.BoxRef): TYPE = self.ts.BASETYPE var2index[box] = llimpl.compile_start_ref_var(c, TYPE) + elif isinstance(box, history.BoxFloat): + var2index[box] = llimpl.compile_start_float_var(c) else: raise Exception("box is: %r" % (box,)) self._compile_branch(c, loop.operations, var2index) @@ -145,6 +147,8 @@ llimpl.compile_add_ref_const(c, x.value, self.ts.BASETYPE) elif isinstance(x, history.ConstAddr): llimpl.compile_add_int_const(c, x.getint()) + elif isinstance(x, history.ConstFloat): + llimpl.compile_add_float_const(c, x.value) else: raise Exception("%s args contain: %r" % (op.getopname(), x)) @@ -157,6 +161,8 @@ var2index[x] = llimpl.compile_add_int_result(c) elif isinstance(x, self.ts.BoxRef): var2index[x] = llimpl.compile_add_ref_result(c, self.ts.BASETYPE) + elif isinstance(x, history.BoxFloat): + var2index[x] = llimpl.compile_add_float_result(c) else: raise Exception("%s.result contain: %r" % (op.getopname(), x)) @@ -187,12 +193,18 @@ def set_future_value_ref(self, index, objvalue): llimpl.set_future_value_ref(index, objvalue) + def set_future_value_float(self, index, floatvalue): + llimpl.set_future_value_float(index, floatvalue) + def get_latest_value_int(self, index): return llimpl.frame_int_getvalue(self.latest_frame, index) def get_latest_value_ref(self, index): return llimpl.frame_ptr_getvalue(self.latest_frame, index) + def get_latest_value_float(self, index): + return llimpl.frame_float_getvalue(self.latest_frame, index) + # ---------- def get_exception(self): @@ -303,9 +315,14 @@ index = args[1].getint() if arraydescr.typeinfo == REF: return history.BoxPtr(llimpl.do_getarrayitem_gc_ptr(array, index)) - else: + elif arraydescr.typeinfo == INT: return history.BoxInt(llimpl.do_getarrayitem_gc_int(array, index, self.memo_cast)) + elif arraydescr.typeinfo == FLOAT: + return history.BoxFloat(llimpl.do_getarrayitem_gc_float(array, + index)) + else: + raise NotImplementedError def do_getfield_gc(self, args, fielddescr): assert isinstance(fielddescr, Descr) @@ -313,10 +330,16 @@ if fielddescr.typeinfo == REF: return history.BoxPtr(llimpl.do_getfield_gc_ptr(struct, fielddescr.ofs)) - else: + elif fielddescr.typeinfo == INT: return history.BoxInt(llimpl.do_getfield_gc_int(struct, fielddescr.ofs, self.memo_cast)) + elif fielddescr.typeinfo == FLOAT: + return history.BoxFloat(llimpl.do_getfield_gc_float(struct, + fielddescr.ofs)) + else: + raise NotImplementedError + def do_getfield_raw(self, args, fielddescr): assert isinstance(fielddescr, Descr) struct = self.cast_int_to_adr(args[0].getint()) @@ -324,10 +347,16 @@ return history.BoxPtr(llimpl.do_getfield_raw_ptr(struct, fielddescr.ofs, self.memo_cast)) - else: + elif fielddescr.typeinfo == INT: return history.BoxInt(llimpl.do_getfield_raw_int(struct, fielddescr.ofs, self.memo_cast)) + elif fielddescr.typeinfo == FLOAT: + return history.BoxFloat(llimpl.do_getfield_raw_float(struct, + fielddescr.ofs, + self.memo_cast)) + else: + raise NotImplementedError def do_new(self, args, size): assert isinstance(size, Descr) @@ -354,10 +383,15 @@ if arraydescr.typeinfo == REF: newvalue = args[2].getref_base() llimpl.do_setarrayitem_gc_ptr(array, index, newvalue) - else: + elif arraydescr.typeinfo == INT: newvalue = args[2].getint() llimpl.do_setarrayitem_gc_int(array, index, newvalue, self.memo_cast) + elif arraydescr.typeinfo == FLOAT: + newvalue = args[2].getfloat() + llimpl.do_setarrayitem_gc_float(array, index, newvalue) + else: + raise NotImplementedError def do_setfield_gc(self, args, fielddescr): assert isinstance(fielddescr, Descr) @@ -365,10 +399,15 @@ if fielddescr.typeinfo == REF: newvalue = args[1].getref_base() llimpl.do_setfield_gc_ptr(struct, fielddescr.ofs, newvalue) - else: + elif fielddescr.typeinfo == INT: newvalue = args[1].getint() llimpl.do_setfield_gc_int(struct, fielddescr.ofs, newvalue, self.memo_cast) + elif fielddescr.typeinfo == FLOAT: + newvalue = args[1].getfloat() + llimpl.do_setfield_gc_float(struct, fielddescr.ofs, newvalue) + else: + raise NotImplementedError def do_setfield_raw(self, args, fielddescr): assert isinstance(fielddescr, Descr) @@ -377,10 +416,16 @@ newvalue = args[1].getref_base() llimpl.do_setfield_raw_ptr(struct, fielddescr.ofs, newvalue, self.memo_cast) - else: + elif fielddescr.typeinfo == INT: newvalue = args[1].getint() llimpl.do_setfield_raw_int(struct, fielddescr.ofs, newvalue, self.memo_cast) + elif fielddescr.typeinfo == FLOAT: + newvalue = args[1].getfloat() + llimpl.do_setfield_raw_float(struct, fielddescr.ofs, newvalue, + self.memo_cast) + else: + raise NotImplementedError def do_same_as(self, args, descr=None): return args[0].clonebox() @@ -420,10 +465,14 @@ llimpl.do_call_pushint(arg.getint()) if calldescr.typeinfo == REF: return history.BoxPtr(llimpl.do_call_ptr(func, self.memo_cast)) - elif calldescr.typeinfo == 'i': + elif calldescr.typeinfo == INT: return history.BoxInt(llimpl.do_call_int(func, self.memo_cast)) - else: # calldescr.typeinfo == 'v' # void + elif calldescr.typeinfo == FLOAT: + return history.BoxFloat(llimpl.do_call_float(func, self.memo_cast)) + elif calldescr.typeinfo == 'v': # void llimpl.do_call_void(func, self.memo_cast) + else: + raise NotImplementedError def do_cast_ptr_to_int(self, args, descr=None): assert descr is None @@ -571,6 +620,8 @@ def boxresult(RESULT, result): if isinstance(RESULT, ootype.OOType): return history.BoxObj(ootype.cast_to_object(result)) + elif RESULT is lltype.Float: + return history.BoxFloat(result) else: return history.BoxInt(lltype.cast_primitive(ootype.Signed, result)) boxresult._annspecialcase_ = 'specialize:arg(0)' Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/runner_test.py (original) +++ pypy/trunk/pypy/jit/backend/test/runner_test.py Sat Sep 5 19:00:14 2009 @@ -1,8 +1,8 @@ import py, sys, random from pypy.jit.metainterp.history import (BoxInt, Box, BoxPtr, TreeLoop, - ConstInt, ConstPtr, BoxObj, - ConstObj) + ConstInt, ConstPtr, BoxObj, Const, + ConstObj, BoxFloat, ConstFloat) from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.typesystem import deref from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi, rclass @@ -26,6 +26,11 @@ elif isinstance(box, (BoxPtr, BoxObj)): self.cpu.set_future_value_ref(j, box.getref_base()) j += 1 + elif isinstance(box, BoxFloat): + self.cpu.set_future_value_float(j, box.getfloat()) + j += 1 + else: + assert isinstance(box, Const) res = self.cpu.execute_operations(loop) if res is loop.operations[-1]: self.guard_failed = False @@ -35,6 +40,8 @@ return BoxInt(self.cpu.get_latest_value_int(0)) elif result_type == 'ref': return BoxPtr(self.cpu.get_latest_value_ref(0)) + elif result_type == 'float': + return BoxFloat(self.cpu.get_latest_value_float(0)) elif result_type == 'void': return None else: @@ -48,6 +55,8 @@ result = BoxInt() elif result_type == 'ref': result = BoxPtr() + elif result_type == 'float': + result = BoxFloat() else: raise ValueError(result_type) if result is None: @@ -210,6 +219,23 @@ 'int') assert res.value == y + def _requires_floats(self): + if not self.cpu.supports_floats: + py.test.skip("requires float support from the backend") + + def test_float_binary_operations(self): + self._requires_floats() + for opnum, testcases in [ + (rop.FLOAT_ADD, [(10.5, -2.25, 8.25)]), + (rop.FLOAT_SUB, [(10.5, -2.25, 12.75)]), + (rop.FLOAT_MUL, [(-6.5, -3.5, 22.75)]), + (rop.FLOAT_TRUEDIV, [(118.75, 12.5, 9.5)]), + ]: + for x, y, z in testcases: + res = self.execute_operation(opnum, [BoxFloat(x), BoxFloat(y)], + 'float') + assert res.value == z + def test_ovf_operations(self, reversed=False): minint = -sys.maxint-1 boom = 'boom' Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Sat Sep 5 19:00:14 2009 @@ -7,7 +7,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.history import TreeLoop, log, Box, History from pypy.jit.metainterp.history import AbstractDescr, BoxInt, BoxPtr, BoxObj,\ - Const + BoxFloat, Const from pypy.jit.metainterp import history from pypy.jit.metainterp.specnode import NotSpecNode from pypy.jit.metainterp.typesystem import llhelper, oohelper @@ -163,6 +163,17 @@ result = resultbox.getref_base() raise metainterp_sd.DoneWithThisFrameRef(cpu, result) +class DoneWithThisFrameDescrFloat(AbstractDescr): + def handle_fail_op(self, metainterp_sd, fail_op): + assert metainterp_sd.result_type == 'float' + resultbox = fail_op.args[0] + if isinstance(resultbox, BoxFloat): + result = metainterp_sd.cpu.get_latest_value_float(0) + else: + assert isinstance(resultbox, history.Const) + result = resultbox.getfloat() + raise metainterp_sd.DoneWithThisFrameFloat(result) + class ExitFrameWithExceptionDescrRef(AbstractDescr): def handle_fail_op(self, metainterp_sd, fail_op): assert len(fail_op.args) == 1 @@ -178,6 +189,7 @@ done_with_this_frame_descr_void = DoneWithThisFrameDescrVoid() done_with_this_frame_descr_int = DoneWithThisFrameDescrInt() done_with_this_frame_descr_ref = DoneWithThisFrameDescrRef() +done_with_this_frame_descr_float = DoneWithThisFrameDescrFloat() exit_frame_with_exception_descr_ref = ExitFrameWithExceptionDescrRef() class TerminatingLoop(TreeLoop): @@ -204,6 +216,12 @@ _loop.finishdescr = done_with_this_frame_descr_ref oohelper.loops_done_with_this_frame_ref = [_loop] +_loop = TerminatingLoop('done_with_this_frame_float') +_loop.specnodes = [prebuiltNotSpecNode] +_loop.inputargs = [BoxFloat()] +_loop.finishdescr = done_with_this_frame_descr_float +loops_done_with_this_frame_float = [_loop] + _loop = TerminatingLoop('done_with_this_frame_void') _loop.specnodes = [] _loop.inputargs = [] Modified: pypy/trunk/pypy/jit/metainterp/history.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py Sat Sep 5 19:00:14 2009 @@ -163,6 +163,8 @@ return ConstInt(intval) elif kind == "ref": return cpu.ts.new_ConstRef(x) + elif kind == "float": + return ConstFloat(x) else: raise NotImplementedError(kind) @@ -428,6 +430,8 @@ # XXX add ootype support? ptrval = lltype.cast_opaque_ptr(llmemory.GCREF, x) return BoxPtr(ptrval) + elif kind == "float": + return BoxFloat(x) else: raise NotImplementedError(kind) Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Sat Sep 5 19:00:14 2009 @@ -227,6 +227,7 @@ 'int_and', 'int_or', 'int_xor', 'int_rshift', 'int_lshift', 'uint_rshift', 'uint_lt', 'uint_le', 'uint_gt', 'uint_ge', + 'float_add', 'float_sub', 'float_mul', 'float_truediv', ]: exec py.code.Source(''' @arguments("box", "box") @@ -1148,6 +1149,8 @@ raise sd.DoneWithThisFrameInt(resultbox.getint()) elif sd.result_type == 'ref': raise sd.DoneWithThisFrameRef(self.cpu, resultbox.getref_base()) + elif sd.result_type == 'float': + raise sd.DoneWithThisFrameFloat(resultbox.getfloat()) else: assert False @@ -1456,6 +1459,9 @@ elif sd.result_type == 'ref': exits = [exitbox] loops = sd.cpu.ts.loops_done_with_this_frame_ref + elif sd.result_type == 'float': + exits = [exitbox] + loops = compile.loops_done_with_this_frame_float else: assert False self.history.record(rop.JUMP, exits, None) Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Sat Sep 5 19:00:14 2009 @@ -89,6 +89,7 @@ metainterp.staticdata.state = FakeWarmRunnerDesc() metainterp.staticdata.DoneWithThisFrameInt = DoneWithThisFrame metainterp.staticdata.DoneWithThisFrameRef = DoneWithThisFrameRef + metainterp.staticdata.DoneWithThisFrameFloat = DoneWithThisFrame self.metainterp = metainterp try: metainterp.compile_and_run_once(*args) Added: pypy/trunk/pypy/jit/metainterp/test/test_float.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/jit/metainterp/test/test_float.py Sat Sep 5 19:00:14 2009 @@ -0,0 +1,17 @@ +from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin + + +class FloatTests: + + def test_simple(self): + def f(a, b, c, d, e): + return (((a + b) - c) * d) / e + res = self.interp_operations(f, [41.5, 2.25, 17.5, 3.0, 2.5]) + assert res == 31.5 + + +class TestOOtype(FloatTests, OOJitMixin): + pass + +class TestLLtype(FloatTests, LLJitMixin): + pass Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Sat Sep 5 19:00:14 2009 @@ -135,7 +135,7 @@ self.set_translator(translator) self.find_portal() graphs = find_all_graphs(self.portal_graph, policy, self.translator, - CPUClass) + CPUClass.supports_floats) self.check_access_directly_sanity(graphs) if backendopt: self.prejit_optimizations(policy, graphs) @@ -395,6 +395,13 @@ def __str__(self): return 'DoneWithThisFrameRef(%s)' % (self.result,) + class DoneWithThisFrameFloat(JitException): + def __init__(self, cpu, result): + assert lltype.typeOf(result) is lltype.Float + self.result = result + def __str__(self): + return 'DoneWithThisFrameFloat(%s)' % (self.result,) + class ExitFrameWithExceptionRef(JitException): def __init__(self, cpu, value): assert lltype.typeOf(value) == cpu.ts.BASETYPE @@ -418,11 +425,13 @@ self.DoneWithThisFrameVoid = DoneWithThisFrameVoid self.DoneWithThisFrameInt = DoneWithThisFrameInt self.DoneWithThisFrameRef = DoneWithThisFrameRef + self.DoneWithThisFrameFloat = DoneWithThisFrameFloat self.ExitFrameWithExceptionRef = ExitFrameWithExceptionRef self.ContinueRunningNormally = ContinueRunningNormally self.metainterp_sd.DoneWithThisFrameVoid = DoneWithThisFrameVoid self.metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrameInt self.metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef + self.metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrameFloat self.metainterp_sd.ExitFrameWithExceptionRef = ExitFrameWithExceptionRef self.metainterp_sd.ContinueRunningNormally = ContinueRunningNormally rtyper = self.translator.rtyper @@ -449,6 +458,9 @@ except DoneWithThisFrameRef, e: assert result_kind == 'ref' return ts.cast_from_ref(RESULT, e.result) + except DoneWithThisFrameFloat, e: + assert result_kind == 'float' + return e.result except ExitFrameWithExceptionRef, e: value = ts.cast_to_baseclass(e.value) if not we_are_translated(): @@ -512,9 +524,8 @@ op.args[:3] = [closures[funcname]] -def find_all_graphs(portal, policy, translator, CPUClass): +def find_all_graphs(portal, policy, translator, supports_floats): from pypy.translator.simplify import get_graph - supports_floats = CPUClass.supports_floats all_graphs = [portal] seen = set([portal]) todo = [portal] @@ -555,6 +566,8 @@ return box.getref(TYPE) if isinstance(TYPE, ootype.OOType): return box.getref(TYPE) + if TYPE == lltype.Float: + return box.getfloat() else: return lltype.cast_primitive(TYPE, box.getint()) unwrap._annspecialcase_ = 'specialize:arg(0)' @@ -577,6 +590,11 @@ return history.ConstObj(value) else: return history.BoxObj(value) + elif isinstance(value, float): + if in_const_box: + return history.ConstFloat(value) + else: + return history.BoxFloat(value) else: value = intmask(value) if in_const_box: @@ -686,6 +704,9 @@ elif typecode == 'int': intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) + elif typecode == 'float': + assert isinstance(value, float) + cpu.set_future_value_float(j, value) else: assert False set_future_value._annspecialcase_ = 'specialize:ll_and_arg(2)' From fijal at codespeak.net Sat Sep 5 19:23:01 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 5 Sep 2009 19:23:01 +0200 (CEST) Subject: [pypy-svn] r67532 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090905172301.58C4516800B@codespeak.net> Author: fijal Date: Sat Sep 5 19:22:58 2009 New Revision: 67532 Modified: pypy/trunk/pypy/jit/backend/x86/regalloc.py Log: Fix the hybrid build Modified: pypy/trunk/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/regalloc.py Sat Sep 5 19:22:58 2009 @@ -64,6 +64,7 @@ self.tree = tree if guard_op is not None: locs = guard_op._x86_faillocs + cpu.gc_ll_descr.rewrite_assembler(cpu, guard_op.suboperations) inpargs = [arg for arg in guard_op._fail_op.args if isinstance(arg, Box)] self._compute_vars_longevity(inpargs, guard_op.suboperations) @@ -71,7 +72,6 @@ self.position = -1 self._update_bindings(locs, inpargs) self.current_stack_depth = guard_op._x86_current_stack_depth - cpu.gc_ll_descr.rewrite_assembler(cpu, guard_op.suboperations) self.loop_consts = {} else: cpu.gc_ll_descr.rewrite_assembler(cpu, tree.operations) From arigo at codespeak.net Sat Sep 5 19:27:18 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 19:27:18 +0200 (CEST) Subject: [pypy-svn] r67533 - pypy/trunk/pypy/jit/tl Message-ID: <20090905172718.C4F2316800B@codespeak.net> Author: arigo Date: Sat Sep 5 19:27:18 2009 New Revision: 67533 Modified: pypy/trunk/pypy/jit/tl/pypyjit_child.py Log: Disable supports_floats here, until the frontend is ready to handle all float operations used in PyPy. Modified: pypy/trunk/pypy/jit/tl/pypyjit_child.py ============================================================================== --- pypy/trunk/pypy/jit/tl/pypyjit_child.py (original) +++ pypy/trunk/pypy/jit/tl/pypyjit_child.py Sat Sep 5 19:27:18 2009 @@ -38,6 +38,7 @@ print 'warmspot.jittify_and_run() started...' from pypy.jit.backend.llgraph.runner import LLtypeCPU + LLtypeCPU.supports_floats = False # for now policy = PyPyJitPolicy(interp.typer.annotator.translator) option.view = True warmspot.jittify_and_run(interp, graph, [], policy=policy, From fijal at codespeak.net Sat Sep 5 20:00:05 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 5 Sep 2009 20:00:05 +0200 (CEST) Subject: [pypy-svn] r67534 - pypy/build/benchmark/specific/considerations Message-ID: <20090905180005.BB1CB16800B@codespeak.net> Author: fijal Date: Sat Sep 5 20:00:05 2009 New Revision: 67534 Added: pypy/build/benchmark/specific/considerations/meteor_contest.py (contents, props changed) pypy/build/benchmark/specific/considerations/symfac.py (contents, props changed) Log: Some more benchmarks, those have problems. Added: pypy/build/benchmark/specific/considerations/meteor_contest.py ============================================================================== --- (empty file) +++ pypy/build/benchmark/specific/considerations/meteor_contest.py Sat Sep 5 20:00:05 2009 @@ -0,0 +1,142 @@ +# The Computer Language Benchmarks Game +# http://shootout.alioth.debian.org/ +# +# contributed by Daniel Nanz, 2008-08-21 + +import sys +from bisect import bisect + +w, h = 5, 10 +dir_no = 6 +S, E = w * h, 2 +SE = S + (E / 2) +SW = SE - E +W, NW, NE = -E, -SE, -SW + + +def rotate(ido, rd={E: NE, NE: NW, NW: W, W: SW, SW: SE, SE: E}): + return [rd[o] for o in ido] + +def flip(ido, fd={E: E, NE: SE, NW: SW, W: W, SW: NW, SE: NE}): + return [fd[o] for o in ido] + + +def permute(ido, r_ido, rotate=rotate, flip=flip): + + ps = [ido] + for r in xrange(dir_no - 1): + ps.append(rotate(ps[-1])) + if ido == r_ido: # C2-symmetry + ps = ps[0:dir_no/2] + for pp in ps[:]: + ps.append(flip(pp)) + return ps + + +def convert(ido): + '''incremental direction offsets -> "coordinate offsets" ''' + out = [0] + for o in ido: + out.append(out[-1] + o) + return list(set(out)) + + +def get_footprints(board, cti, pieces): + + fps = [[[] for p in xrange(len(pieces))] for ci in xrange(len(board))] + for c in board: + for pi, p in enumerate(pieces): + for pp in p: + fp = frozenset(cti[c + o] for o in pp if (c + o) in cti) + if len(fp) == 5: + fps[min(fp)][pi].append(fp) + return fps + + +def get_senh(board, cti): + '''-> south-east neighborhood''' + se_nh = [] + nh = [E, SW, SE] + for c in board: + se_nh.append(frozenset(cti[c + o] for o in nh if (c + o) in cti)) + return se_nh + + +def get_puzzle(w=w, h=h): + + board = [E*x + S*y + (y%2) for y in xrange(h) for x in xrange(w)] + cti = dict((board[i], i) for i in xrange(len(board))) + + idos = [[E, E, E, SE], # incremental direction offsets + [SE, SW, W, SW], + [W, W, SW, SE], + [E, E, SW, SE], + [NW, W, NW, SE, SW], + [E, E, NE, W], + [NW, NE, NE, W], + [NE, SE, E, NE], + [SE, SE, E, SE], + [E, NW, NW, NW]] + + perms = (permute(p, idos[3]) for p in idos) # restrict piece 4 + pieces = [[convert(pp) for pp in p] for p in perms] + return (board, cti, pieces) + + +def print_board(board, w=w, h=h): + + for y in xrange(h): + for x in xrange(w): + print board[x + y * w], + print '' + if y % 2 == 0: + print '', + print + + +board, cti, pieces = get_puzzle() +fps = get_footprints(board, cti, pieces) +se_nh = get_senh(board, cti) + + +def solve(n, i_min, free, curr_board, pieces_left, solutions, + fps=fps, se_nh=se_nh, bisect=bisect): + + fp_i_cands = fps[i_min] + for p in pieces_left: + fp_cands = fp_i_cands[p] + for fp in fp_cands: + if fp <= free: + n_curr_board = curr_board[:] + for ci in fp: + n_curr_board[ci] = p + if len(pieces_left) > 1: + n_free = free - fp + n_i_min = min(n_free) + if len(n_free & se_nh[n_i_min]) > 0: + n_pieces_left = pieces_left[:] + n_pieces_left.remove(p) + solve(n, n_i_min, n_free, n_curr_board, + n_pieces_left, solutions) + else: + s = ''.join(map(str, n_curr_board)) + solutions.insert(bisect(solutions, s), s) + rs = s[::-1] + solutions.insert(bisect(solutions, rs), rs) + if len(solutions) >= n: + return + if len(solutions) >= n: + return + return + +def main(n): + + free = frozenset(xrange(len(board))) + curr_board = [-1] * len(board) + pieces_left = range(len(pieces)) + solutions = [] + solve(n, 0, free, curr_board, pieces_left, solutions) + print len(solutions), 'solutions found\n' + for i in (0, -1): print_board(solutions[i]) + +main(int(sys.argv[1])) Added: pypy/build/benchmark/specific/considerations/symfac.py ============================================================================== --- (empty file) +++ pypy/build/benchmark/specific/considerations/symfac.py Sat Sep 5 20:00:05 2009 @@ -0,0 +1,8 @@ +from sympy import factor, Symbol + +def f(): + x = Symbol('x') + y = Symbol('y') + factor(x**20 - y**20) + +f() From arigo at codespeak.net Sat Sep 5 20:34:01 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 20:34:01 +0200 (CEST) Subject: [pypy-svn] r67535 - pypy/trunk/pypy/rlib Message-ID: <20090905183401.2EE5516800B@codespeak.net> Author: arigo Date: Sat Sep 5 20:33:59 2009 New Revision: 67535 Modified: pypy/trunk/pypy/rlib/rarithmetic.py Log: Add an assert: intmask() is not supposed to be called on floats. Modified: pypy/trunk/pypy/rlib/rarithmetic.py ============================================================================== --- pypy/trunk/pypy/rlib/rarithmetic.py (original) +++ pypy/trunk/pypy/rlib/rarithmetic.py Sat Sep 5 20:33:59 2009 @@ -67,6 +67,7 @@ return int(n) # possibly bool->int if isinstance(n, objectmodel.Symbolic): return n # assume Symbolics don't overflow + assert not isinstance(n, float) n = long(n) n &= LONG_MASK if n >= LONG_TEST: From arigo at codespeak.net Sat Sep 5 22:57:56 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 22:57:56 +0200 (CEST) Subject: [pypy-svn] r67536 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090905205756.5BE9F16800B@codespeak.net> Author: arigo Date: Sat Sep 5 22:57:54 2009 New Revision: 67536 Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py pypy/trunk/pypy/jit/metainterp/support.py pypy/trunk/pypy/jit/metainterp/test/test_del.py Log: (pedronis, arigo) Fix for mallocing objects that have a __del__. It was fairly broken before :-( sorry fijal... Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/codewriter.py Sat Sep 5 22:57:54 2009 @@ -718,7 +718,8 @@ pass else: if hasattr(rtti._obj, 'destructor_funcptr'): - self.handle_builtin_call(op) + c_vtable = Constant(vtable, lltype.typeOf(vtable)) + self._do_builtin_call(op, 'alloc_with_del', [c_vtable]) return # store the vtable as an address -- that's fine, because the # GC doesn't need to follow them @@ -1107,6 +1108,9 @@ def handle_builtin_call(self, op): oopspec_name, args = support.decode_builtin_call(op) + return self._do_builtin_call(op, oopspec_name, args) + + def _do_builtin_call(self, op, oopspec_name, args): argtypes = [v.concretetype for v in args] resulttype = op.result.concretetype c_func, TP = support.builtin_func_for_spec(self.codewriter.rtyper, Modified: pypy/trunk/pypy/jit/metainterp/support.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/support.py (original) +++ pypy/trunk/pypy/jit/metainterp/support.py Sat Sep 5 22:57:54 2009 @@ -186,9 +186,11 @@ # ---------- malloc with del ---------- - def _ll_0_alloc_with_del(RESULT): - return lltype.malloc(RESULT) - _ll_0_alloc_with_del.need_result_type = True + def _ll_1_alloc_with_del(RESULT, vtable): + p = lltype.malloc(RESULT) + lltype.cast_pointer(rclass.OBJECTPTR, p).typeptr = vtable + return p + _ll_1_alloc_with_del.need_result_type = True class OOtypeHelpers: @@ -341,10 +343,6 @@ else: raise Exception("oohash() of type %r" % (T,)) -def get_malloc_oopspec(op): - assert op.args[1].value == {'flavor': 'gc'} - return 'alloc_with_del', [] - RENAMED_ADT_NAME = { 'list': { @@ -375,8 +373,6 @@ return get_oostring_oopspec(op) elif op.opname == 'oohash': return get_oohash_oopspec(op) - elif op.opname == 'malloc': # for malloc with a __del__ - return get_malloc_oopspec(op) else: raise ValueError(op.opname) Modified: pypy/trunk/pypy/jit/metainterp/test/test_del.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_del.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_del.py Sat Sep 5 22:57:54 2009 @@ -27,6 +27,33 @@ 'guard_true': 1, 'jump': 1}) + def test_class_of_allocated(self): + myjitdriver = JitDriver(greens = [], reds = ['n', 'x']) + class Foo: + def __del__(self): + pass + def f(self): + return self.meth() + class X(Foo): + def meth(self): + return 456 + class Y(Foo): + def meth(self): + return 123 + def f(n): + x = None + while n > 0: + myjitdriver.can_enter_jit(x=x, n=n) + myjitdriver.jit_merge_point(x=x, n=n) + x = X() + y = Y() + assert x.f() == 456 + assert y.f() == 123 + n -= 1 + return 42 + res = self.meta_interp(f, [20]) + assert res == 42 + class TestLLtype(DelTests, LLJitMixin): def test_signal_action(self): @@ -52,6 +79,6 @@ self.check_loops(getfield_raw=1, call=0, call_pure=0) class TestOOtype(DelTests, OOJitMixin): - def test_del_keep_obj(self): + def setup_class(cls): py.test.skip("XXX dels are not implemented in the" " static CLI or JVM backend") From arigo at codespeak.net Sat Sep 5 23:53:43 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Sep 2009 23:53:43 +0200 (CEST) Subject: [pypy-svn] r67537 - pypy/trunk/pypy/rlib Message-ID: <20090905215343.5297B16800B@codespeak.net> Author: arigo Date: Sat Sep 5 23:53:41 2009 New Revision: 67537 Modified: pypy/trunk/pypy/rlib/rweakrefimpl.py Log: Add @jit markers to prevent the JIT from seeing that code. Modified: pypy/trunk/pypy/rlib/rweakrefimpl.py ============================================================================== --- pypy/trunk/pypy/rlib/rweakrefimpl.py (original) +++ pypy/trunk/pypy/rlib/rweakrefimpl.py Sat Sep 5 23:53:41 2009 @@ -5,6 +5,7 @@ from pypy.rpython.rclass import getinstancerepr from pypy.rpython.rmodel import Repr from pypy.rlib.rweakref import RWeakValueDictionary +from pypy.rlib import jit class WeakValueDictRepr(Repr): @@ -90,12 +91,15 @@ adtmeths=entrymeths, hints={'weakarray': 'value'}) + at jit.dont_look_inside def ll_new_weakdict(): d = lltype.malloc(WEAKDICT) d.entries = WEAKDICT.entries.TO.allocate(rdict.DICT_INITSIZE) + d.num_items = 0 d.num_pristine_entries = rdict.DICT_INITSIZE return d + at jit.dont_look_inside def ll_get(d, llkey): i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) #llop.debug_print(lltype.Void, i, 'get') @@ -105,12 +109,14 @@ else: return lltype.nullptr(rclass.OBJECTPTR.TO) + at jit.dont_look_inside def ll_set(d, llkey, llvalue): if llvalue: ll_set_nonnull(d, llkey, llvalue) else: ll_set_null(d, llkey) + at jit.dont_look_inside def ll_set_nonnull(d, llkey, llvalue): valueref = weakref_create(llvalue) # GC effects here, before the rest i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) @@ -124,6 +130,7 @@ #llop.debug_print(lltype.Void, 'RESIZE') ll_weakdict_resize(d) + at jit.dont_look_inside def ll_set_null(d, llkey): i = rdict.ll_dict_lookup(d, llkey, llkey.gethash()) if d.entries.everused(i): From arigo at codespeak.net Sun Sep 6 00:05:47 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 6 Sep 2009 00:05:47 +0200 (CEST) Subject: [pypy-svn] r67538 - in pypy/trunk/pypy/jit: backend/llgraph backend/test metainterp metainterp/test Message-ID: <20090905220547.81B9616800B@codespeak.net> Author: arigo Date: Sun Sep 6 00:05:46 2009 New Revision: 67538 Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py pypy/trunk/pypy/jit/backend/test/runner_test.py pypy/trunk/pypy/jit/metainterp/executor.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/resoperation.py pypy/trunk/pypy/jit/metainterp/test/test_executor.py pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py Log: (pedronis, arigo) Refactor tests about floats. Add the float comparisons and casts. Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py Sun Sep 6 00:05:46 2009 @@ -87,6 +87,14 @@ 'float_sub' : (('float', 'float'), 'float'), 'float_mul' : (('float', 'float'), 'float'), 'float_truediv' : (('float', 'float'), 'float'), + 'float_lt' : (('float', 'float'), 'int'), + 'float_le' : (('float', 'float'), 'int'), + 'float_eq' : (('float', 'float'), 'int'), + 'float_ne' : (('float', 'float'), 'int'), + 'float_gt' : (('float', 'float'), 'int'), + 'float_ge' : (('float', 'float'), 'int'), + 'cast_float_to_int':(('float',), 'int'), + 'cast_int_to_float':(('int',), 'float'), 'same_as' : (('int',), 'int'), # could also be ptr=>ptr 'new_with_vtable' : (('ref',), 'ref'), 'new' : ((), 'ref'), Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/runner_test.py (original) +++ pypy/trunk/pypy/jit/backend/test/runner_test.py Sun Sep 6 00:05:46 2009 @@ -219,22 +219,18 @@ 'int') assert res.value == y - def _requires_floats(self): - if not self.cpu.supports_floats: - py.test.skip("requires float support from the backend") - - def test_float_binary_operations(self): - self._requires_floats() - for opnum, testcases in [ - (rop.FLOAT_ADD, [(10.5, -2.25, 8.25)]), - (rop.FLOAT_SUB, [(10.5, -2.25, 12.75)]), - (rop.FLOAT_MUL, [(-6.5, -3.5, 22.75)]), - (rop.FLOAT_TRUEDIV, [(118.75, 12.5, 9.5)]), - ]: - for x, y, z in testcases: - res = self.execute_operation(opnum, [BoxFloat(x), BoxFloat(y)], - 'float') - assert res.value == z + def test_float_operations(self): + from pypy.jit.metainterp.test.test_executor import get_float_tests + for opnum, boxargs, rettype, retvalue in get_float_tests(self.cpu): + if len(boxargs) == 2: + args_variants = [(boxargs[0], boxargs[1]), + (boxargs[0], boxargs[1].constbox()), + (boxargs[0].constbox(), boxargs[1])] + else: + args_variants = [boxargs] + for argboxes in args_variants: + res = self.execute_operation(opnum, argboxes, rettype) + assert res.value == retvalue def test_ovf_operations(self, reversed=False): minint = -sys.maxint-1 Modified: pypy/trunk/pypy/jit/metainterp/executor.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/executor.py (original) +++ pypy/trunk/pypy/jit/metainterp/executor.py Sun Sep 6 00:05:46 2009 @@ -256,6 +256,12 @@ def do_float_ge(cpu, args, descr=None): return ConstInt(args[0].getfloat() >= args[1].getfloat()) +def do_cast_float_to_int(cpu, args, descr=None): + return ConstInt(int(args[0].getfloat())) + +def do_cast_int_to_float(cpu, args, descr=None): + return ConstFloat(float(args[0].getint())) + # ____________________________________________________________ def do_debug_merge_point(cpu, args, descr=None): Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Sun Sep 6 00:05:46 2009 @@ -228,6 +228,8 @@ 'int_rshift', 'int_lshift', 'uint_rshift', 'uint_lt', 'uint_le', 'uint_gt', 'uint_ge', 'float_add', 'float_sub', 'float_mul', 'float_truediv', + 'float_lt', 'float_le', 'float_eq', + 'float_ne', 'float_gt', 'float_ge', ]: exec py.code.Source(''' @arguments("box", "box") @@ -244,7 +246,8 @@ ''' % (_opimpl, _opimpl.upper())).compile() for _opimpl in ['int_is_true', 'int_neg', 'int_invert', 'bool_not', - 'cast_ptr_to_int', + 'cast_ptr_to_int', 'cast_float_to_int', + 'cast_int_to_float', ]: exec py.code.Source(''' @arguments("box") @@ -471,9 +474,8 @@ def opimpl_ptr_iszero(self, box): self.execute(rop.OOISNULL, [box]) - @arguments("box") - def opimpl_oononnull(self, box): - self.execute(rop.OONONNULL, [box]) + opimpl_oononnull = opimpl_ptr_nonzero + opimpl_ooisnull = opimpl_ptr_iszero @arguments("box", "box") def opimpl_ptr_eq(self, box1, box2): @@ -484,6 +486,7 @@ self.execute(rop.OOISNOT, [box1, box2]) opimpl_oois = opimpl_ptr_eq + opimpl_ooisnot = opimpl_ptr_ne @arguments("box", "descr") def opimpl_getfield_gc(self, box, fielddesc): Modified: pypy/trunk/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resoperation.py (original) +++ pypy/trunk/pypy/jit/metainterp/resoperation.py Sun Sep 6 00:05:46 2009 @@ -142,6 +142,8 @@ 'FLOAT_SUB', 'FLOAT_MUL', 'FLOAT_TRUEDIV', + 'CAST_FLOAT_TO_INT', + 'CAST_INT_TO_FLOAT', # '_COMPARISON_FIRST', 'INT_LT', @@ -155,6 +157,12 @@ 'UINT_GT', 'UINT_GE', '_COMPARISON_LAST', + 'FLOAT_LT', # maybe these ones should be comparisons too + 'FLOAT_LE', + 'FLOAT_EQ', + 'FLOAT_NE', + 'FLOAT_GT', + 'FLOAT_GE', # 'INT_IS_TRUE', 'INT_NEG', Modified: pypy/trunk/pypy/jit/metainterp/test/test_executor.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_executor.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_executor.py Sun Sep 6 00:05:46 2009 @@ -1,3 +1,4 @@ +import py from pypy.jit.metainterp.executor import make_execute_list, execute from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.history import BoxInt, ConstInt @@ -6,7 +7,7 @@ class FakeCPU(AbstractCPU): - pass + supports_floats = True make_execute_list(FakeCPU) @@ -14,13 +15,52 @@ box = execute(FakeCPU(), rop.INT_ADD, [BoxInt(40), ConstInt(2)]) assert box.value == 42 +def _float_binary_operations(): + for opnum, testcases in [ + (rop.FLOAT_ADD, [(10.5, -2.25, 8.25)]), + (rop.FLOAT_SUB, [(10.5, -2.25, 12.75)]), + (rop.FLOAT_MUL, [(-6.5, -3.5, 22.75)]), + (rop.FLOAT_TRUEDIV, [(118.75, 12.5, 9.5)]), + ]: + for x, y, z in testcases: + yield (opnum, [x, y], 'float', z) + +def _float_comparison_operations(): + for y in [-522.25, 10.125, 22.6]: + yield (rop.FLOAT_LT, [10.125, y], 'int', 10.125 < y) + yield (rop.FLOAT_LE, [10.125, y], 'int', 10.125 <= y) + yield (rop.FLOAT_EQ, [10.125, y], 'int', 10.125 == y) + yield (rop.FLOAT_NE, [10.125, y], 'int', 10.125 != y) + yield (rop.FLOAT_GT, [10.125, y], 'int', 10.125 > y) + yield (rop.FLOAT_GE, [10.125, y], 'int', 10.125 >= y) + +def _float_unary_operations(): + yield (rop.CAST_FLOAT_TO_INT, [-5.9], 'int', -5) + yield (rop.CAST_FLOAT_TO_INT, [5.9], 'int', 5) + yield (rop.CAST_INT_TO_FLOAT, [123], 'float', 123.0) + +def get_float_tests(cpu): + if not cpu.supports_floats: + py.test.skip("requires float support from the backend") + for opnum, args, rettype, retvalue in ( + list(_float_binary_operations()) + + list(_float_comparison_operations()) + + list(_float_unary_operations())): + boxargs = [] + for x in args: + if isinstance(x, float): + boxargs.append(BoxFloat(x)) + else: + boxargs.append(BoxInt(x)) + yield opnum, boxargs, rettype, retvalue + def test_float_ops(): cpu = FakeCPU() - box = execute(cpu, rop.FLOAT_ADD, [BoxFloat(40.5), ConstFloat(2.25)]) - assert box.value == 42.75 - box = execute(cpu, rop.FLOAT_SUB, [BoxFloat(40.5), ConstFloat(2.25)]) - assert box.value == 38.25 - box = execute(cpu, rop.FLOAT_MUL, [BoxFloat(40.5), ConstFloat(2.25)]) - assert box.value == 91.125 - box = execute(cpu, rop.FLOAT_TRUEDIV, [BoxFloat(10.125), ConstFloat(2.25)]) - assert box.value == 4.5 + for opnum, boxargs, rettype, retvalue in get_float_tests(cpu): + box = execute(cpu, opnum, boxargs) + if rettype == 'float': + assert box.getfloat() == retvalue + elif rettype == 'int': + assert box.getint() == retvalue + else: + assert retvalue is None Modified: pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py Sun Sep 6 00:05:46 2009 @@ -1,7 +1,7 @@ # some unit tests for the bytecode decoding -from pypy.jit.metainterp import pyjitpl, codewriter +from pypy.jit.metainterp import pyjitpl, codewriter, resoperation def make_frame(code): bytecode = codewriter.JitCode("hello") @@ -24,3 +24,11 @@ frame = make_frame("\x01") assert frame.load_bool() + +def test_simple_opimpl_exist(): + rop = resoperation.rop + for opnum, opname in resoperation.opname.items(): + if opnum in (rop.SAME_AS, rop.CALL_PURE, rop.OOSEND_PURE): + continue + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + assert hasattr(pyjitpl.MIFrame, 'opimpl_' + opname.lower()), opname From arigo at codespeak.net Sun Sep 6 00:17:58 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 6 Sep 2009 00:17:58 +0200 (CEST) Subject: [pypy-svn] r67539 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090905221758.2BF5F16800B@codespeak.net> Author: arigo Date: Sun Sep 6 00:17:57 2009 New Revision: 67539 Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py pypy/trunk/pypy/jit/metainterp/test/test_float.py Log: (pedronis, arigo) cast_bool_to_float. Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/codewriter.py Sun Sep 6 00:17:57 2009 @@ -613,6 +613,9 @@ def serialize_op_uint_xor(self, op): self._defl(op, 'int_xor') def serialize_op_uint_lshift(self, op): self._defl(op, 'int_lshift') + def serialize_op_cast_bool_to_float(self, op): + self.default_serialize_op(op, 'cast_int_to_float') + serialize_op_unichar_eq = serialize_op_char_eq serialize_op_unichar_ne = serialize_op_char_ne Modified: pypy/trunk/pypy/jit/metainterp/test/test_float.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_float.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_float.py Sun Sep 6 00:17:57 2009 @@ -9,6 +9,14 @@ res = self.interp_operations(f, [41.5, 2.25, 17.5, 3.0, 2.5]) assert res == 31.5 + def test_cast_bool_to_float(self): + def f(a): + return float(a == 12.0) + res = self.interp_operations(f, [41.5]) + assert res == 0.0 + res = self.interp_operations(f, [12.0]) + assert res == 1.0 + class TestOOtype(FloatTests, OOJitMixin): pass From arigo at codespeak.net Sun Sep 6 00:29:06 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 6 Sep 2009 00:29:06 +0200 (CEST) Subject: [pypy-svn] r67540 - in pypy/trunk/pypy/jit: backend/llgraph metainterp metainterp/test Message-ID: <20090905222906.753E316800B@codespeak.net> Author: arigo Date: Sun Sep 6 00:29:04 2009 New Revision: 67540 Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py pypy/trunk/pypy/jit/metainterp/executor.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/resoperation.py pypy/trunk/pypy/jit/metainterp/test/test_executor.py Log: (pedronis, arigo) Finish FLOAT_NEG and add FLOAT_ABS. Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py Sun Sep 6 00:29:04 2009 @@ -93,6 +93,8 @@ 'float_ne' : (('float', 'float'), 'int'), 'float_gt' : (('float', 'float'), 'int'), 'float_ge' : (('float', 'float'), 'int'), + 'float_neg' : (('float',), 'float'), + 'float_abs' : (('float',), 'float'), 'cast_float_to_int':(('float',), 'int'), 'cast_int_to_float':(('int',), 'float'), 'same_as' : (('int',), 'int'), # could also be ptr=>ptr Modified: pypy/trunk/pypy/jit/metainterp/executor.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/executor.py (original) +++ pypy/trunk/pypy/jit/metainterp/executor.py Sun Sep 6 00:29:04 2009 @@ -223,6 +223,9 @@ def do_float_neg(cpu, args, descr=None): return ConstFloat(-args[0].getfloat()) +def do_float_abs(cpu, args, descr=None): + return ConstFloat(abs(args[0].getfloat())) + def do_float_is_true(cpu, args, descr=None): return ConstInt(bool(args[0].getfloat())) Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Sun Sep 6 00:29:04 2009 @@ -247,7 +247,7 @@ for _opimpl in ['int_is_true', 'int_neg', 'int_invert', 'bool_not', 'cast_ptr_to_int', 'cast_float_to_int', - 'cast_int_to_float', + 'cast_int_to_float', 'float_neg', 'float_abs', ]: exec py.code.Source(''' @arguments("box") Modified: pypy/trunk/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resoperation.py (original) +++ pypy/trunk/pypy/jit/metainterp/resoperation.py Sun Sep 6 00:29:04 2009 @@ -142,6 +142,8 @@ 'FLOAT_SUB', 'FLOAT_MUL', 'FLOAT_TRUEDIV', + 'FLOAT_NEG', + 'FLOAT_ABS', 'CAST_FLOAT_TO_INT', 'CAST_INT_TO_FLOAT', # Modified: pypy/trunk/pypy/jit/metainterp/test/test_executor.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_executor.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_executor.py Sun Sep 6 00:29:04 2009 @@ -35,6 +35,10 @@ yield (rop.FLOAT_GE, [10.125, y], 'int', 10.125 >= y) def _float_unary_operations(): + yield (rop.FLOAT_NEG, [-5.9], 'float', 5.9) + yield (rop.FLOAT_NEG, [15.9], 'float', -15.9) + yield (rop.FLOAT_ABS, [-5.9], 'float', 5.9) + yield (rop.FLOAT_ABS, [15.9], 'float', 15.9) yield (rop.CAST_FLOAT_TO_INT, [-5.9], 'int', -5) yield (rop.CAST_FLOAT_TO_INT, [5.9], 'int', 5) yield (rop.CAST_INT_TO_FLOAT, [123], 'float', 123.0) From arigo at codespeak.net Sun Sep 6 00:31:47 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 6 Sep 2009 00:31:47 +0200 (CEST) Subject: [pypy-svn] r67541 - in pypy/trunk/pypy/jit: backend/llgraph metainterp metainterp/test Message-ID: <20090905223147.D882A16800B@codespeak.net> Author: arigo Date: Sun Sep 6 00:31:47 2009 New Revision: 67541 Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/resoperation.py pypy/trunk/pypy/jit/metainterp/test/test_executor.py Log: (pedronis, arigo) FLOAT_IS_TRUE. Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py Sun Sep 6 00:31:47 2009 @@ -87,14 +87,15 @@ 'float_sub' : (('float', 'float'), 'float'), 'float_mul' : (('float', 'float'), 'float'), 'float_truediv' : (('float', 'float'), 'float'), - 'float_lt' : (('float', 'float'), 'int'), - 'float_le' : (('float', 'float'), 'int'), - 'float_eq' : (('float', 'float'), 'int'), - 'float_ne' : (('float', 'float'), 'int'), - 'float_gt' : (('float', 'float'), 'int'), - 'float_ge' : (('float', 'float'), 'int'), + 'float_lt' : (('float', 'float'), 'bool'), + 'float_le' : (('float', 'float'), 'bool'), + 'float_eq' : (('float', 'float'), 'bool'), + 'float_ne' : (('float', 'float'), 'bool'), + 'float_gt' : (('float', 'float'), 'bool'), + 'float_ge' : (('float', 'float'), 'bool'), 'float_neg' : (('float',), 'float'), 'float_abs' : (('float',), 'float'), + 'float_is_true' : (('float',), 'bool'), 'cast_float_to_int':(('float',), 'int'), 'cast_int_to_float':(('int',), 'float'), 'same_as' : (('int',), 'int'), # could also be ptr=>ptr Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Sun Sep 6 00:31:47 2009 @@ -248,6 +248,7 @@ for _opimpl in ['int_is_true', 'int_neg', 'int_invert', 'bool_not', 'cast_ptr_to_int', 'cast_float_to_int', 'cast_int_to_float', 'float_neg', 'float_abs', + 'float_is_true', ]: exec py.code.Source(''' @arguments("box") Modified: pypy/trunk/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resoperation.py (original) +++ pypy/trunk/pypy/jit/metainterp/resoperation.py Sun Sep 6 00:31:47 2009 @@ -144,6 +144,7 @@ 'FLOAT_TRUEDIV', 'FLOAT_NEG', 'FLOAT_ABS', + 'FLOAT_IS_TRUE', 'CAST_FLOAT_TO_INT', 'CAST_INT_TO_FLOAT', # Modified: pypy/trunk/pypy/jit/metainterp/test/test_executor.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_executor.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_executor.py Sun Sep 6 00:31:47 2009 @@ -39,6 +39,8 @@ yield (rop.FLOAT_NEG, [15.9], 'float', -15.9) yield (rop.FLOAT_ABS, [-5.9], 'float', 5.9) yield (rop.FLOAT_ABS, [15.9], 'float', 15.9) + yield (rop.FLOAT_IS_TRUE, [-5.9], 'int', 1) + yield (rop.FLOAT_IS_TRUE, [0.0], 'int', 0) yield (rop.CAST_FLOAT_TO_INT, [-5.9], 'int', -5) yield (rop.CAST_FLOAT_TO_INT, [5.9], 'int', 5) yield (rop.CAST_INT_TO_FLOAT, [123], 'float', 123.0) From pedronis at codespeak.net Sun Sep 6 16:47:26 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 6 Sep 2009 16:47:26 +0200 (CEST) Subject: [pypy-svn] r67543 - pypy/extradoc/planning Message-ID: <20090906144726.2AF08168005@codespeak.net> Author: pedronis Date: Sun Sep 6 16:47:24 2009 New Revision: 67543 Modified: pypy/extradoc/planning/jit.txt Log: another task Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Sun Sep 6 16:47:24 2009 @@ -24,6 +24,8 @@ - asmgcc: support callbacks (threads?) +- jit should inline the fast path of mallocs + - update things in metainterp/doc Python interpreter: From benjamin at codespeak.net Sun Sep 6 22:28:19 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Sun, 6 Sep 2009 22:28:19 +0200 (CEST) Subject: [pypy-svn] r67547 - pypy/trunk/pypy/module/__builtin__ Message-ID: <20090906202819.84921168014@codespeak.net> Author: benjamin Date: Sun Sep 6 22:28:16 2009 New Revision: 67547 Modified: pypy/trunk/pypy/module/__builtin__/__init__.py pypy/trunk/pypy/module/__builtin__/app_functional.py pypy/trunk/pypy/module/__builtin__/functional.py Log: reimplement min, max, reduce, sum, filter, map, zip, enumerate, and reversed on the interp level for speed Modified: pypy/trunk/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/__init__.py (original) +++ pypy/trunk/pypy/module/__builtin__/__init__.py Sun Sep 6 22:28:16 2009 @@ -27,23 +27,11 @@ 'raw_input' : 'app_io.raw_input', 'input' : 'app_io.input', - 'sum' : 'app_functional.sum', 'apply' : 'app_functional.apply', - 'map' : 'app_functional.map', - 'filter' : 'app_functional.filter', - 'zip' : 'app_functional.zip', - 'reduce' : 'app_functional.reduce', #'range' : 'app_functional.range', # redirected to functional.py, applevel version # is still needed and should stay where it is. - 'min' : 'app_functional.min', - 'max' : 'app_functional.max', - 'enumerate' : 'app_functional.enumerate', 'sorted' : 'app_functional.sorted', - 'reversed' : 'app_functional.reversed', - '_install_pickle_support_for_reversed_iterator': - 'app_functional._install_pickle_support_for_reversed_iterator', - 'globals' : 'app_inspect.globals', 'locals' : 'app_inspect.locals', 'vars' : 'app_inspect.vars', @@ -106,8 +94,17 @@ 'range' : 'functional.range_int', 'xrange' : 'functional.W_XRange', + 'enumerate' : 'functional.W_Enumerate', 'all' : 'functional.all', 'any' : 'functional.any', + 'min' : 'functional.min', + 'max' : 'functional.max', + 'sum' : 'functional.sum', + 'map' : 'functional.map', + 'zip' : 'functional.zip', + 'reduce' : 'functional.reduce', + 'reversed' : 'functional.reversed', + 'filter' : 'functional.filter', 'super' : 'descriptor.W_Super', 'staticmethod' : 'descriptor.StaticMethod', 'classmethod' : 'descriptor.ClassMethod', Modified: pypy/trunk/pypy/module/__builtin__/app_functional.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/app_functional.py (original) +++ pypy/trunk/pypy/module/__builtin__/app_functional.py Sun Sep 6 22:28:16 2009 @@ -3,151 +3,12 @@ functional programming. """ - -def sum(sequence, total=0): - """sum(sequence, start=0) -> value - -Returns the sum of a sequence of numbers (NOT strings) plus the value -of parameter 'start'. When the sequence is empty, returns start.""" - # must forbid "summing" strings, per specs of built-in 'sum' - if isinstance(total, str): raise TypeError - for item in sequence: - total = total + item - return total - # ____________________________________________________________ def apply(function, args=(), kwds={}): """call a function (or other callable object) and return its result""" return function(*args, **kwds) -def map(function, *collections): - """does 3 separate things, hence this enormous docstring. - 1. if function is None, return a list of tuples, each with one - item from each collection. If the collections have different - lengths, shorter ones are padded with None. - - 2. if function is not None, and there is only one collection, - apply function to every item in the collection and return a - list of the results. - - 3. if function is not None, and there are several collections, - repeatedly call the function with one argument from each - collection. If the collections have different lengths, - shorter ones are padded with None - """ - - if len(collections) == 0: - raise TypeError, "map() requires at least one sequence" - - if len(collections) == 1: - #it's the most common case, so make it faster - if function is None: - return list(collections[0]) - return [function(x) for x in collections[0]] - - iterators = [ iter(collection) for collection in collections ] - res = [] - while 1: - cont = False #is any collection not empty? - args = [] - for iterator in iterators: - try: - elem = iterator.next() - cont = True - except StopIteration: - elem = None - args.append(elem) - if cont: - if function is None: - res.append(tuple(args)) - else: - res.append(function(*args)) - else: - return res - -def filterstring(function, collection, str_type): - if function is None and type(collection) is str_type: - return collection - res = [] - for i in xrange(len(collection)): - c = collection[i] - if function is None or function(c): - if not isinstance(c, str_type): - raise TypeError("can't filter %s to %s: __getitem__ returned different type", str_type.__name__, str_type.__name__) - res.append(c) - return str_type().join(res) - -def filtertuple(function, collection): - if function is None: - function = bool - res = [] - for i in xrange(len(collection)): - c = collection[i] - if function(c): - res.append(c) - return tuple(res) - -def filter(function, collection): - """construct a list of those elements of collection for which function - is True. If function is None, then return the items in the sequence - which are True.""" - if isinstance(collection, str): - return filterstring(function, collection, str) - elif isinstance(collection, unicode): - return filterstring(function, collection, unicode) - elif isinstance(collection, tuple): - return filtertuple(function, collection) - - if function is None: - return [item for item in collection if item] - else: - return [item for item in collection if function(item)] - -def zip(*collections): - """return a list of tuples, where the nth tuple contains every - nth item of each collection. If the collections have different - lengths, zip returns a list as long as the shortest collection, - ignoring the trailing items in the other collections.""" - - if len(collections) == 0: - import sys - if sys.version_info < (2,4): - raise TypeError("zip() requires at least one sequence") - return [] - res = [] - iterators = [ iter(collection) for collection in collections ] - while 1: - try: - elems = [] - for iterator in iterators: - elems.append(iterator.next()) - res.append(tuple(elems)) - except StopIteration: - return res - -def reduce(function, seq, *initialt): - """ Apply function of two arguments cumulatively to the items of - sequence, from left to right, so as to reduce the sequence to a - single value. Optionally begin with an initial value.""" - - seqiter = iter(seq) - if initialt: - initial, = initialt - else: - try: - initial = seqiter.next() - except StopIteration: - raise TypeError, "reduce() of empty sequence with no initial value" - while 1: - try: - arg = seqiter.next() - except StopIteration: - break - initial = function(initial, arg) - - return initial - # ____________________________________________________________ """ @@ -206,135 +67,10 @@ # ____________________________________________________________ - -def _identity(arg): - return arg - - -def min(*arr, **kwargs): - """return the smallest number in a list, - or its smallest argument if more than one is given.""" - from operator import gt - - return min_max(gt, "min", *arr, **kwargs) - -def min_max(comp, funcname, *arr, **kwargs): - key = kwargs.pop("key", _identity) - if len(kwargs): - raise TypeError, '%s() got an unexpected keyword argument' % funcname - - if not arr: - raise TypeError, '%s() takes at least one argument' % funcname - - if len(arr) == 1: - arr = arr[0] - - iterator = iter(arr) - try: - min_max_val = iterator.next() - except StopIteration: - raise ValueError, '%s() arg is an empty sequence' % funcname - - keyed_min_max_val = key(min_max_val) - - for i in iterator: - keyed = key(i) - if comp(keyed_min_max_val, keyed): - min_max_val = i - keyed_min_max_val = keyed - return min_max_val - -def max(*arr, **kwargs): - """return the largest number in a list, - or its largest argument if more than one is given.""" - from operator import lt - - return min_max(lt, "max", *arr, **kwargs) - -class enumerate(object): - """enumerate(iterable) -> iterator for (index, value) of iterable. - -Return an enumerate object. iterable must be an other object that supports -iteration. The enumerate object yields pairs containing a count (from -zero) and a value yielded by the iterable argument. enumerate is useful -for obtaining an indexed list: (0, seq[0]), (1, seq[1]), (2, seq[2]), ...""" - - def __init__(self, collection): - self._iter = iter(collection) - self._index = 0 - - def next(self): - try: - next = self._iter.next - except AttributeError: - # CPython raises a TypeError when next() is not defined - raise TypeError('%s object has no next() method' % - (type(self._iter).__name__,)) - result = self._index, next() - self._index += 1 - return result - - def __iter__(self): - return self - - -# ____________________________________________________________ - def sorted(lst, cmp=None, key=None, reverse=None): "sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list" sorted_lst = list(lst) sorted_lst.sort(cmp, key, reverse) return sorted_lst -def reversed(sequence): - "reversed(sequence) -> reverse iterator over values of the sequence" - if hasattr(sequence, '__reversed__'): - return sequence.__reversed__() - if not hasattr(sequence, '__getitem__'): - raise TypeError("argument to reversed() must be a sequence") - return reversed_iterator(sequence) - - -class reversed_iterator(object): - - def __init__(self, seq): - self.seq = seq - self.remaining = len(seq) - - def __iter__(self): - return self - - def next(self): - if self.remaining > len(self.seq): - self.remaining = 0 - i = self.remaining - if i > 0: - i -= 1 - item = self.seq[i] - self.remaining = i - return item - raise StopIteration - -# XXX __length_hint__() -## def __len__(self): -## if self.remaining > len(self.seq): -## self.remaining = 0 -## return self.remaining - - def __reduce__(self): - tup = (self.seq, self.remaining) - return (make_reversed_iterator, tup) - -def make_reversed_iterator(seq, remaining): - ri = reversed_iterator.__new__(reversed_iterator) - ri.seq = seq - #or "ri = reversed_iterator(seq)" but that executes len(seq) - ri.remaining = remaining - return ri - -def _install_pickle_support_for_reversed_iterator(): - import _pickle_support - make_reversed_iterator.__module__ = '_pickle_support' - _pickle_support.make_reversed_iterator = make_reversed_iterator - Modified: pypy/trunk/pypy/module/__builtin__/functional.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/functional.py (original) +++ pypy/trunk/pypy/module/__builtin__/functional.py Sun Sep 6 22:28:16 2009 @@ -8,7 +8,9 @@ from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.argument import Arguments from pypy.rlib.rarithmetic import r_uint, intmask +from pypy.rlib.objectmodel import specialize from pypy.module.__builtin__.app_functional import range as app_range from inspect import getsource, getfile @@ -100,7 +102,244 @@ return W_ListMultiObject(space, impl) + at specialize.arg(2) +def min_max(space, arguments, implementation_of): + if implementation_of == "max": + compare = space.gt + else: + compare = space.lt + args, kwargs = arguments.unpack() + if len(args) > 1: + w_sequence = space.newtuple(args) + elif len(args): + w_sequence = args[0] + else: + msg = "%s() expects at least one argument" % (implementation_of,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + try: + w_key = kwargs["key"] + except KeyError: + w_key = None + else: + del kwargs["key"] + if kwargs: + msg = "%s() got unexpected keyword argument" % (implementation_of,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_iter = space.iter(w_sequence) + w_max_item = None + w_max_val = None + while True: + try: + w_item = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if w_key is not None: + w_compare_with = space.call_function(w_key, w_item) + else: + w_compare_with = w_item + if w_max_item is None or \ + space.is_true(compare(w_compare_with, w_max_val)): + w_max_item = w_item + w_max_val = w_compare_with + if w_max_item is None: + msg = "arg is an empty sequence" + raise OperationError(space.w_ValueError, space.wrap(msg)) + return w_max_item +def max(space, __args__): + """Return the largest item in a sequence. + + If more than one argument is passed, return the maximum of them. + """ + return min_max(space, __args__, "max") +max.unwrap_spec = [ObjSpace, Arguments] + +def min(space, __args__): + """Return the smallest item in a sequence. + + If more than one argument is passed, return the minimum of them. + """ + return min_max(space, __args__, "min") +min.unwrap_spec = [ObjSpace, Arguments] + +def map(space, w_func, collections_w): + """does 3 separate things, hence this enormous docstring. + 1. if function is None, return a list of tuples, each with one + item from each collection. If the collections have different + lengths, shorter ones are padded with None. + + 2. if function is not None, and there is only one collection, + apply function to every item in the collection and return a + list of the results. + + 3. if function is not None, and there are several collections, + repeatedly call the function with one argument from each + collection. If the collections have different lengths, + shorter ones are padded with None + """ + if not collections_w: + msg = "map() requires at least two arguments" + raise OperationError(space.w_TypeError, space.wrap(msg)) + num_collections = len(collections_w) + none_func = space.is_w(w_func, space.w_None) + if none_func and num_collections == 1: + return space.call_function(space.w_list, collections_w[0]) + result_w = [] + iterators_w = [space.iter(w_seq) for w_seq in collections_w] + num_iterators = len(iterators_w) + while True: + cont = False + args_w = [space.w_None] * num_iterators + for i in range(len(iterators_w)): + try: + args_w[i] = space.next(iterators_w[i]) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + else: + cont = True + w_args = space.newtuple(args_w) + if cont: + if none_func: + result_w.append(w_args) + else: + w_res = space.call(w_func, w_args) + result_w.append(w_res) + else: + return space.newlist(result_w) +map.unwrap_spec = [ObjSpace, W_Root, "args_w"] + +def sum(space, w_sequence, w_start=None): + if space.is_w(w_start, space.w_None): + w_start = space.wrap(0) + elif space.is_true(space.isinstance(w_start, space.w_basestring)): + msg = "sum() can't sum strings" + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_iter = space.iter(w_sequence) + w_last = w_start + while True: + try: + w_next = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + w_last = space.add(w_last, w_next) + return w_last +sum.unwrap_spec = [ObjSpace, W_Root, W_Root] + +def zip(space, sequences_w): + """Return a list of tuples, where the nth tuple contains every nth item of + each collection. + + If the collections have different lengths, zip returns a list as long as the + shortest collection, ignoring the trailing items in the other collections. + """ + if not sequences_w: + return space.newlist([]) + result_w = [] + iterators_w = [space.iter(w_seq) for w_seq in sequences_w] + while True: + try: + items_w = [space.next(w_it) for w_it in iterators_w] + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + return space.newlist(result_w) + result_w.append(space.newtuple(items_w)) +zip.unwrap_spec = [ObjSpace, "args_w"] + +def reduce(space, w_func, w_sequence, rest_w): + """ Apply function of two arguments cumulatively to the items of sequence, + from left to right, so as to reduce the sequence to a single value. + Optionally begin with an initial value. + """ + w_iter = space.iter(w_sequence) + if rest_w: + if len(rest_w) > 1: + msg = "reduce() takes only 3 possible arguments" + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_initial, = rest_w + else: + try: + w_initial = space.next(w_iter) + except OperationError, e: + if e.match(space, space.w_StopIteration): + msg = "reduce() of empty sequence with no initial value" + raise OperationError(space.w_TypeError, space.wrap(msg)) + raise + w_result = w_initial + while True: + try: + w_next = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + w_result = space.call_function(w_func, w_result, w_next) + return w_result +reduce.unwrap_spec = [ObjSpace, W_Root, W_Root, "args_w"] + +def filter(space, w_func, w_seq): + """construct a list of those elements of collection for which function + is True. If function is None, then return the items in the sequence + which are True. + """ + if space.is_true(space.isinstance(w_seq, space.w_str)): + return _filter_string(space, w_func, w_seq, space.w_str) + if space.is_true(space.isinstance(w_seq, space.w_unicode)): + return _filter_string(space, w_func, w_seq, space.w_unicode) + if space.is_true(space.isinstance(w_seq, space.w_tuple)): + return _filter_tuple(space, w_func, w_seq) + w_iter = space.iter(w_seq) + result_w = [] + none_func = space.is_w(w_func, space.w_None) + while True: + try: + w_next = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if none_func: + w_keep = w_next + else: + w_keep = space.call_function(w_func, w_next) + if space.is_true(w_keep): + result_w.append(w_next) + return space.newlist(result_w) + +def _filter_tuple(space, w_func, w_tuple): + none_func = space.is_w(w_func, space.w_None) + length = space.int_w(space.len(w_tuple)) + result_w = [] + for i in range(length): + w_item = space.getitem(w_tuple, space.wrap(i)) + if none_func: + w_keep = w_item + else: + w_keep = space.call_function(w_func, w_item) + if space.is_true(w_keep): + result_w.append(w_item) + return space.newtuple(result_w) + +def _filter_string(space, w_func, w_string, w_str_type): + none_func = space.is_w(w_func, space.w_None) + if none_func and space.is_w(space.type(w_string), w_str_type): + return w_string + length = space.int_w(space.len(w_string)) + result_w = [] + for i in range(length): + w_item = space.getitem(w_string, space.wrap(i)) + if none_func or space.is_true(space.call_function(w_func, w_item)): + if not space.is_true(space.isinstance(w_item, w_str_type)): + msg = "__getitem__ returned a non-string type" + raise OperationError(space.w_TypeError, space.wrap(msg)) + result_w.append(w_item) + w_empty = space.call_function(w_str_type) + return space.call_method(w_empty, "join", space.newlist(result_w)) def all(space, w_S): """all(iterable) -> bool @@ -138,6 +377,77 @@ any.unwrap_spec = [ObjSpace, W_Root] +class W_Enumerate(Wrappable): + + def __init__(self, w_iter, w_start): + self.w_iter = w_iter + self.w_index = w_start + + def descr___new__(space, w_subtype, w_iterable): + self = space.allocate_instance(W_Enumerate, w_subtype) + self.__init__(space.iter(w_iterable), space.wrap(0)) + return space.wrap(self) + + def descr___iter__(self, space): + return space.wrap(self) + descr___iter__.unwrap_spec = ["self", ObjSpace] + + def descr_next(self, space): + w_item = space.next(self.w_iter) + w_index = self.w_index + self.w_index = space.add(w_index, space.wrap(1)) + return space.newtuple([w_index, w_item]) + descr_next.unwrap_spec = ["self", ObjSpace] + + +W_Enumerate.typedef = TypeDef("enumerate", + __new__=interp2app(W_Enumerate.descr___new__.im_func), + __iter__=interp2app(W_Enumerate.descr___iter__), + next=interp2app(W_Enumerate.descr_next), +) + + +def reversed(space, w_sequence): + """Return a iterator that yields items of sequence in reverse.""" + w_reversed_descr = space.lookup(w_sequence, "__reversed__") + if w_reversed_descr is None: + return space.wrap(W_ReversedIterator(space, w_sequence)) + return space.get_and_call_function(w_reversed_descr, w_sequence) +reversed.unwrap_spec = [ObjSpace, W_Root] + +class W_ReversedIterator(Wrappable): + + def __init__(self, space, w_sequence): + self.remaining = space.int_w(space.len(w_sequence)) - 1 + self.w_sequence = w_sequence + + def descr___iter__(self, space): + return space.wrap(self) + descr___iter__.unwrap_spec = ["self", ObjSpace] + + def descr_next(self, space): + if self.remaining >= 0: + w_index = space.wrap(self.remaining) + try: + w_item = space.getitem(self.w_sequence, w_index) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + else: + self.remaining -= 1 + return w_item + + # Done + self.remaining = -1 + raise OperationError(space.w_StopIteration, space.w_None) + descr_next.unwrap_spec = ["self", ObjSpace] + +W_ReversedIterator.typedef = TypeDef("reversed", + __iter__=interp2app(W_ReversedIterator.descr___iter__), + next=interp2app(W_ReversedIterator.descr_next), +) + + class W_XRange(Wrappable): def __init__(self, space, start, len, step): self.space = space From benjamin at codespeak.net Mon Sep 7 03:48:00 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Mon, 7 Sep 2009 03:48:00 +0200 (CEST) Subject: [pypy-svn] r67549 - pypy/trunk/pypy/module/__builtin__ Message-ID: <20090907014800.A6CBD168016@codespeak.net> Author: benjamin Date: Mon Sep 7 03:47:58 2009 New Revision: 67549 Modified: pypy/trunk/pypy/module/__builtin__/functional.py Log: use NoneNotWrapped for nicer implementation Modified: pypy/trunk/pypy/module/__builtin__/functional.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/functional.py (original) +++ pypy/trunk/pypy/module/__builtin__/functional.py Mon Sep 7 03:47:58 2009 @@ -251,18 +251,13 @@ result_w.append(space.newtuple(items_w)) zip.unwrap_spec = [ObjSpace, "args_w"] -def reduce(space, w_func, w_sequence, rest_w): +def reduce(space, w_func, w_sequence, w_initial=NoneNotWrapped): """ Apply function of two arguments cumulatively to the items of sequence, from left to right, so as to reduce the sequence to a single value. Optionally begin with an initial value. """ w_iter = space.iter(w_sequence) - if rest_w: - if len(rest_w) > 1: - msg = "reduce() takes only 3 possible arguments" - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_initial, = rest_w - else: + if w_initial is None: try: w_initial = space.next(w_iter) except OperationError, e: @@ -280,7 +275,7 @@ break w_result = space.call_function(w_func, w_result, w_next) return w_result -reduce.unwrap_spec = [ObjSpace, W_Root, W_Root, "args_w"] +reduce.unwrap_spec = [ObjSpace, W_Root, W_Root, W_Root] def filter(space, w_func, w_seq): """construct a list of those elements of collection for which function From antocuni at codespeak.net Mon Sep 7 11:57:44 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 7 Sep 2009 11:57:44 +0200 (CEST) Subject: [pypy-svn] r67550 - in pypy/trunk/pypy/rpython: . test Message-ID: <20090907095744.88BA5168015@codespeak.net> Author: antocuni Date: Mon Sep 7 11:57:43 2009 New Revision: 67550 Modified: pypy/trunk/pypy/rpython/rpbc.py pypy/trunk/pypy/rpython/rtyper.py pypy/trunk/pypy/rpython/test/test_rclass.py Log: (antocuni, arigato and pedronis around) fix test_rclass.test_method_specialized_with_subclass. See the comments in the code and the IRC discussion between 10:44 and 12:51: http://wyvern.cs.uni-duesseldorf.de/irc-logs/pypy/%23pypy.log.20090905 Modified: pypy/trunk/pypy/rpython/rpbc.py ============================================================================== --- pypy/trunk/pypy/rpython/rpbc.py (original) +++ pypy/trunk/pypy/rpython/rpbc.py Mon Sep 7 11:57:43 2009 @@ -834,7 +834,15 @@ "classes with no common base: %r" % (mdescs,)) self.methodname = methodname - self.classdef = classdef.locate_attribute(methodname) + # for ootype, the right thing to do is to always keep the most precise + # type of the instance, while for lltype we want to cast it to the + # type where the method is actually defined. See also + # test_rclass.test_method_specialized_with_subclass and + # rtyper.attach_methods_to_subclasses + if self.rtyper.type_system.name == 'ootypesystem': + self.classdef = classdef + else: + self.classdef = classdef.locate_attribute(methodname) # the low-level representation is just the bound 'self' argument. self.s_im_self = annmodel.SomeInstance(self.classdef, flags=flags) self.r_im_self = rclass.getinstancerepr(rtyper, self.classdef) Modified: pypy/trunk/pypy/rpython/rtyper.py ============================================================================== --- pypy/trunk/pypy/rpython/rtyper.py (original) +++ pypy/trunk/pypy/rpython/rtyper.py Mon Sep 7 11:57:43 2009 @@ -198,7 +198,9 @@ if self.exceptiondata is not None: self.exceptiondata.make_helpers(self) self.specialize_more_blocks() # for the helpers just made - + if self.type_system.name == 'ootypesystem': + self.attach_methods_to_subclasses() + # from pypy.annotation import listdef ldef = listdef.ListDef(None, annmodel.SomeString()) @@ -268,6 +270,40 @@ if annmixlevel is not None: annmixlevel.finish() + def attach_methods_to_subclasses(self): + # in ootype, it might happen that a method is defined in the + # superclass but the annotator discovers that it's always called + # through instances of a subclass (e.g. because of specialization, see + # test_rclass.test_method_specialized_with_subclass). In that cases, + # we copy the method also in the ootype.Instance of the subclass, so + # that the type of v_self coincides with the type returned by + # _lookup(). + assert self.type_system.name == 'ootypesystem' + def allclasses(TYPE, seen): + '''Yield TYPE and all its subclasses''' + if TYPE in seen: + return + seen.add(TYPE) + yield TYPE + for SUB in TYPE._subclasses: + for T in allclasses(SUB, seen): + yield T + + for TYPE in allclasses(ootype.ROOT, set()): + for methname, meth in TYPE._methods.iteritems(): + try: + graph = meth.graph + except AttributeError: + continue + SELF = graph.getargs()[0].concretetype + if TYPE != SELF and ootype.isSubclass(SELF, TYPE): + # the annotator found that this method has a more precise + # type. Attach it to the proper subclass, so that the type + # of 'self' coincides with the type returned by _lookup(), + # else we might have type errors + if methname not in SELF._methods: + ootype.addMethods(SELF, {methname: meth}) + def dump_typererrors(self, num=None, minimize=True, to_log=False): c = 0 bc = 0 Modified: pypy/trunk/pypy/rpython/test/test_rclass.py ============================================================================== --- pypy/trunk/pypy/rpython/test/test_rclass.py (original) +++ pypy/trunk/pypy/rpython/test/test_rclass.py Mon Sep 7 11:57:43 2009 @@ -267,7 +267,6 @@ assert res == 246 def test_method_specialized_with_subclass(self): - py.test.skip('fixme!') class A: def meth(self, n): return -1 @@ -280,7 +279,7 @@ a = A() b = B() a.meth(1) # the self of this variant is annotated with A - b.meth(2) # the self of this variant is annotated with B, then explodes + b.meth(2) # the self of this variant is annotated with B return 42 res = self.interpret(f, []) From cfbolz at codespeak.net Mon Sep 7 12:06:23 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 7 Sep 2009 12:06:23 +0200 (CEST) Subject: [pypy-svn] r67551 - pypy/branch/spine-of-frames/pypy/interpreter/test Message-ID: <20090907100623.6267F168015@codespeak.net> Author: cfbolz Date: Mon Sep 7 12:06:22 2009 New Revision: 67551 Modified: pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py Log: Explicitly check that stuff does not escape. Unfortunately, all but the most simplest cases fail :-(. Modified: pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py Mon Sep 7 12:06:22 2009 @@ -221,17 +221,39 @@ events = space.unwrap(w_events) assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call'] + + class TestFrameChaining(object): class EC(ExecutionContext): + _some_frame = None def __init__(self, jitted=False): self.jitted = jitted + self.virtualizable = None + self.framestackdepth = 0 self._init_frame_chain() def _we_are_jitted(self): return self.jitted + + def _get_some_frame(self): + if self._some_frame: + self._some_frame.look_at() + return self._some_frame + def _set_some_frame(self, frame): + if frame.virtual_with_base_frame: + frame.escaped = True + self._some_frame = frame + some_frame = property(_get_some_frame, _set_some_frame) + class Frame(object): - def __init__(self): + _f_back_some = None + _f_forward = None + + def __init__(self, ec, virtual_with_base_frame=None): + self.ec = ec + self.virtual_with_base_frame = virtual_with_base_frame + self.escaped = not virtual_with_base_frame ExecutionContext._init_chaining_attributes(self) def f_back(self): @@ -240,6 +262,48 @@ def force_f_back(self): return ExecutionContext._force_back_of_frame(self) + def force(self): + if not self.escaped: + self.virtual_with_base_frame = None + self.escaped = True + if self._f_back_some: + self._f_back_some.force() + if self._f_forward: + self._f_back_some.force() + + def look_at(self): + if (not self.ec.jitted or + self.ec.virtualizable is not self.virtual_with_base_frame): + self.force() + + def store_ref_to(self, other): + if (other.virtual_with_base_frame is not self and + other.virtual_with_base_frame is not self.virtual_with_base_frame): + other.force() + + def _get_f_back_some(self): + self.look_at() + return self._f_back_some + def _set_f_back_some(self, frame): + self.look_at() + if frame: + frame.look_at() + self.store_ref_to(frame) + self._f_back_some = frame + f_back_some = property(_get_f_back_some, _set_f_back_some) + + def _get_f_forward(self): + self.look_at() + return self._f_forward + def _set_f_forward(self, frame): + self.look_at() + if frame: + frame.look_at() + self.store_ref_to(frame) + self._f_forward = frame + f_forward = property(_get_f_forward, _set_f_forward) + + def test_frame_chain(self): ec = self.EC() @@ -247,14 +311,14 @@ assert ec.some_frame is None assert ec.framestackdepth == 0 - frame = self.Frame() + frame = self.Frame(ec) ec._chain(frame) assert ec.some_frame is frame assert ec.framestackdepth == 1 assert frame.f_back_some is None assert frame.f_forward is None - frame2 = self.Frame() + frame2 = self.Frame(ec) ec._chain(frame2) assert ec.some_frame is frame2 assert ec.framestackdepth == 2 @@ -262,7 +326,7 @@ assert frame.f_forward is frame2 assert frame2.f_forward is None - frame3 = self.Frame() + frame3 = self.Frame(ec) ec._chain(frame3) assert ec.some_frame is frame3 assert frame3.f_back_some is frame2 @@ -289,15 +353,14 @@ assert ec.framestackdepth == 0 assert frame.f_back_some is None - # we want a simplified copy of the previous tests and do a force on frame2 ok def test_frame_chain_forced(self): ec = self.EC() - frame = self.Frame() + frame = self.Frame(ec) ec._chain(frame) - frame2 = self.Frame() + frame2 = self.Frame(ec) ec._chain(frame2) assert ec.some_frame is frame2 assert ec.framestackdepth == 2 @@ -308,7 +371,7 @@ assert res is frame assert frame.f_back_forced - frame3 = self.Frame() + frame3 = self.Frame(ec) ec._chain(frame3) # now we should unchain @@ -329,6 +392,7 @@ assert frame2.f_back() is frame assert frame.f_back() is None + def test_frame_chain_jitted(self): ec = self.EC() @@ -336,7 +400,7 @@ assert ec.some_frame is None assert ec.framestackdepth == 0 - frame = self.Frame() + frame = self.Frame(ec) ec._chain(frame) assert ec.some_frame is frame assert ec.framestackdepth == 1 @@ -344,7 +408,8 @@ assert frame.f_forward is None ec.jitted = True - frame2 = self.Frame() + ec.virtualizable = frame + frame2 = self.Frame(ec, frame) ec._chain(frame2) assert ec.some_frame is frame assert ec.framestackdepth == 2 @@ -353,7 +418,7 @@ assert frame2.f_forward is None # recursive enter/leave seen by the jit - frame3 = self.Frame() + frame3 = self.Frame(ec, frame) ec._chain(frame3) assert ec.some_frame is frame assert frame3.f_back_some is frame @@ -366,14 +431,18 @@ assert ec.framestackdepth == 2 assert frame2.f_forward is None assert frame3.f_back_some is frame + assert not frame3.escaped + assert not frame2.escaped # recursive enter/leave not seen by the jit ec.jitted = False + ec.virtualizable = None ec._chain(frame3) assert ec.some_frame is frame3 assert frame3.f_back_some is frame - assert frame2.f_forward is frame3 # this btw is the bit that may be problematic xxx - # now we should unchain + assert frame2.f_forward is frame3 + assert frame3.escaped + #assert not frame2.escaped # XXX this is failing! assert frame3.f_back() is frame2 ec._unchain(frame3) @@ -382,6 +451,7 @@ assert frame2.f_forward is None assert frame3.f_back_some is frame ec.jitted = True + ec.virtualizable = frame assert frame2.f_back() is frame ec._unchain(frame2) @@ -405,15 +475,15 @@ assert ec.some_frame is None assert ec.framestackdepth == 0 - frame = self.Frame() + frame = self.Frame(ec) ec._chain(frame) ec.jitted = True - frame2 = self.Frame() + frame2 = self.Frame(ec) ec._chain(frame2) # recursive enter/leave seen by the jit - frame3 = self.Frame() + frame3 = self.Frame(ec) ec._chain(frame3) res = frame3.force_f_back() assert res is frame2 @@ -430,6 +500,136 @@ assert frame3.f_back() is frame2 assert frame2.f_back() is frame assert frame.f_back() is None - # cool yes - + def enter_two_jitted_levels(self): + ec = self.EC() + + assert ec.some_frame is None + assert ec.framestackdepth == 0 + + frame = self.Frame(ec) + ec._chain(frame) + + ec.jitted = True + ec.virtualizable = frame + frame2 = self.Frame(ec, frame) + ec._chain(frame2) + assert not frame2.escaped + return ec, frame, frame2 + + def leave_two_jitted_levels(self, ec, frame, frame2): + assert frame2.f_back() is frame + ec._unchain(frame2) + ec.jitted = False + assert frame.f_back() is None + ec._unchain(frame) + + + def test_check_escaping_all_inlined(self): + ec, frame, frame2 = self.enter_two_jitted_levels() + + # recursive enter/leave seen by the jit + frame3 = self.Frame(ec, frame) + ec._chain(frame3) + assert not frame2.escaped + assert not frame3.escaped + + assert frame3.f_back() is frame2 + ec._unchain(frame3) + assert not frame2.escaped + self.leave_two_jitted_levels(ec, frame, frame2) + + + def test_check_escaping_not_all_inlined_enter_leave_not_seen(self): + py.test.skip("escapes") + ec, frame, frame2 = self.enter_two_jitted_levels() + + ec.jitted = False + # recursive enter/leave not seen by the jit + frame3 = self.Frame(ec) + ec._chain(frame3) + + assert not frame2.escaped + assert frame3.escaped + + assert frame3.f_back() is frame2 + ec._unchain(frame3) + ec.jitted = True + assert not frame2.escaped + + self.leave_two_jitted_levels(ec, frame, frame2) + + def test_check_escaping_not_all_inlined_enter_leave_seen(self): + ec, frame, frame2 = self.enter_two_jitted_levels() + + # recursive enter/leave seen by the jit + frame3 = self.Frame(ec, frame) + ec._chain(frame3) + ec.jitted = False + frame3.look_at() + assert not frame2.escaped + assert frame3.escaped + + ec.jitted = True + assert frame3.f_back() is frame2 + ec._unchain(frame3) + assert not frame2.escaped + + self.leave_two_jitted_levels(ec, frame, frame2) + + + def test_check_escaping_multi_non_jitted_levels(self): + py.test.skip("escapes") + ec, frame, frame2 = self.enter_two_jitted_levels() + + # recursive enter/leave seen by the jit + frame3 = self.Frame(ec, frame) + ec._chain(frame3) + ec.jitted = False + + frame3.look_at() + assert not frame2.escaped + assert frame3.escaped + + frame4 = self.Frame(ec) + ec._chain(frame4) + assert ec.framestackdepth == 4 + + ec._unchain(frame4) + assert frame3.escaped + assert not frame2.escaped + + ec.jitted = True + assert frame3.f_back() is frame2 + ec._unchain(frame3) + assert not frame2.escaped + + self.leave_two_jitted_levels(ec, frame, frame2) + + def test_check_escaping_jitted_with_two_differen_virtualizables(self): + py.test.skip("escapes") + ec, frame, frame2 = self.enter_two_jitted_levels() + + frame3 = self.Frame(ec, frame) + ec._chain(frame3) + # frame3 is not inlined, but contains a loop itself, for which code has + # been generated + ec.virtualizable = frame3 + + frame3.look_at() + assert not frame2.escaped + assert frame3.escaped + + frame4 = self.Frame(ec) + ec._chain(frame4) + assert ec.framestackdepth == 4 + + ec._unchain(frame4) + assert frame3.escaped + assert not frame2.escaped + + ec.virtualizable = frame + + ec._unchain(frame3) + assert not frame2.escaped + From cfbolz at codespeak.net Mon Sep 7 14:17:44 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 7 Sep 2009 14:17:44 +0200 (CEST) Subject: [pypy-svn] r67552 - in pypy/trunk/pypy/rlib: . test Message-ID: <20090907121744.DCA9A168015@codespeak.net> Author: cfbolz Date: Mon Sep 7 14:17:43 2009 New Revision: 67552 Modified: pypy/trunk/pypy/rlib/rweakref.py pypy/trunk/pypy/rlib/test/test_rweakref.py Log: stupid stupid. really need to make a new annotations, otherwise the constness of one can survive. Modified: pypy/trunk/pypy/rlib/rweakref.py ============================================================================== --- pypy/trunk/pypy/rlib/rweakref.py (original) +++ pypy/trunk/pypy/rlib/rweakref.py Mon Sep 7 14:17:43 2009 @@ -59,7 +59,7 @@ def union((s_wvd1, s_wvd2)): if s_wvd1.valueclassdef is not s_wvd2.valueclassdef: return SomeObject() # not the same class! complain... - return s_wvd1 + return SomeWeakValueDict(s_wvd1.valueclassdef) class Entry(extregistry.ExtRegistryEntry): _about_ = RWeakValueDictionary Modified: pypy/trunk/pypy/rlib/test/test_rweakref.py ============================================================================== --- pypy/trunk/pypy/rlib/test/test_rweakref.py (original) +++ pypy/trunk/pypy/rlib/test/test_rweakref.py Mon Sep 7 14:17:43 2009 @@ -88,8 +88,23 @@ f() interpret(f, []) - def test_rpython_merge_RWeakValueDictionary(): + empty = RWeakValueDictionary(X) + def f(n): + x = X() + if n: + d = empty + else: + d = RWeakValueDictionary(X) + d.set("a", x) + return d.get("a") is x + assert f(0) + assert interpret(f, [0]) + assert not f(1) + assert not interpret(f, [1]) + + +def test_rpython_merge_RWeakValueDictionary2(): class A(object): def __init__(self): self.d = RWeakValueDictionary(A) From antocuni at codespeak.net Mon Sep 7 14:24:58 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 7 Sep 2009 14:24:58 +0200 (CEST) Subject: [pypy-svn] r67553 - in pypy/trunk/pypy/jit: backend/llgraph metainterp/test Message-ID: <20090907122458.5722C168015@codespeak.net> Author: antocuni Date: Mon Sep 7 14:24:55 2009 New Revision: 67553 Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py pypy/trunk/pypy/jit/metainterp/test/test_basic.py Log: a test that was failing for ootype and the corresponding fix (a cast was missing) Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py Mon Sep 7 14:24:55 2009 @@ -775,6 +775,8 @@ obj = ootype.cast_from_object(TYPE, obj) if isinstance(ootype.typeOf(newvalue), ootype.OOType): newvalue = ootype.cast_from_object(T, newvalue) + elif isinstance(T, lltype.Primitive): + newvalue = lltype.cast_primitive(T, newvalue) setattr(obj, fieldname, newvalue) def op_getarrayitem_gc(self, typedescr, obj, index): Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Mon Sep 7 14:24:55 2009 @@ -403,6 +403,24 @@ assert res == 210 self.check_history_(getfield_gc=0) + def test_setfield_bool(self): + class A: + def __init__(self): + self.flag = True + myjitdriver = JitDriver(greens = [], reds = ['n', 'obj']) + def f(n): + obj = A() + res = False + while n > 0: + myjitdriver.can_enter_jit(n=n, obj=obj) + myjitdriver.jit_merge_point(n=n, obj=obj) + obj.flag = False + n -= 1 + return res + res = self.meta_interp(f, [7]) + assert type(res) == bool + assert not res + def test_switch_dict(self): def f(x): if x == 1: return 61 From pedronis at codespeak.net Mon Sep 7 14:49:51 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 7 Sep 2009 14:49:51 +0200 (CEST) Subject: [pypy-svn] r67554 - in pypy/trunk/pypy: jit/backend/x86/test rpython/lltypesystem rpython/lltypesystem/test Message-ID: <20090907124951.415FC16801E@codespeak.net> Author: pedronis Date: Mon Sep 7 14:49:50 2009 New Revision: 67554 Added: pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py (contents, props changed) - copied, changed from r67551, pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Log: (micke, pedronis) move the gc (integration) tests to their own file, fixes in ll2ctypes to make them pass given the exercised code in llsupport/gc.py Copied: pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py (from r67551, pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py) ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py Mon Sep 7 14:49:50 2009 @@ -14,40 +14,10 @@ from pypy.rpython.annlowlevel import llhelper from pypy.rpython.lltypesystem import rclass, rstr from pypy.jit.backend.x86.ri386 import * -from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList +from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList, GcPtrFieldDescr -class DummyTree(object): - operations = [ResOperation(rop.FAIL, [], None)] - inputargs = [] - -class MockAssembler(object): - gcrefs = None - - def __init__(self, cpu=None): - self.loads = [] - self.stores = [] - self.performs = [] - self.lea = [] - self.cpu = cpu or CPU(None, None) - self.cpu.gc_ll_descr = MockGcDescr(False) - - def dump(self, *args): - pass - - def regalloc_load(self, from_loc, to_loc): - self.loads.append((from_loc, to_loc)) - - def regalloc_store(self, from_loc, to_loc): - self.stores.append((from_loc, to_loc)) - - def regalloc_perform(self, op, arglocs, resloc): - self.performs.append((op, arglocs, resloc)) - - def regalloc_perform_discard(self, op, arglocs): - self.performs.append((op, arglocs)) - - def load_effective_addr(self, *args): - self.lea.append(args) +from pypy.jit.backend.x86.test.test_regalloc import DummyTree, MockAssembler +from pypy.jit.backend.x86.test.test_regalloc import fill_regs, BaseTestRegalloc class MockGcRootMap(object): def get_basic_shape(self): @@ -77,86 +47,17 @@ def initialize(self): self.gcrefs = GcRefList() self.gcrefs.initialize() - + self.single_gcref_descr = GcPtrFieldDescr(0) + rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func - -class RegAllocForTests(RegAlloc): - position = 0 - def _compute_next_usage(self, v, _): - return -1 - -class TestRegallocDirect(object): - def fill_regs(self, regalloc, cls=BoxInt): - allboxes = [] - for reg in REGS: - box = cls() - allboxes.append(box) - regalloc.reg_bindings[box] = reg - regalloc.free_regs = [] - return allboxes - - def test_make_sure_var_in_reg(self): - regalloc = RegAlloc(MockAssembler(), DummyTree()) - boxes = self.fill_regs(regalloc) - box = boxes[-1] - oldloc = regalloc.loc(box) - newloc = regalloc.make_sure_var_in_reg(box, []) - assert oldloc is newloc - regalloc._check_invariants() - - def test_make_sure_var_in_reg_need_lower_byte(self): - regalloc = RegAlloc(MockAssembler(), DummyTree()) - box = BoxInt() - regalloc.reg_bindings[box] = edi - regalloc.free_regs.remove(edi) - loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True) - assert loc is not edi and loc is not esi - assert len(regalloc.assembler.loads) == 1 - regalloc._check_invariants() - - def test_make_sure_var_in_reg_need_lower_byte_no_free_reg(self): - regalloc = RegAllocForTests(MockAssembler(), DummyTree()) - box = BoxInt() - regalloc.reg_bindings = {BoxInt(): eax, BoxInt(): ebx, BoxInt(): ecx, - BoxInt(): edx, box:edi} - regalloc.free_regs = [esi] - regalloc._check_invariants() - loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True) - assert loc is not edi and loc is not esi - assert len(regalloc.assembler.loads) == 1 - regalloc._check_invariants() - - def test_make_sure_var_in_reg_mem(self): - regalloc = RegAlloc(MockAssembler(), DummyTree()) - box = BoxInt() - regalloc.stack_loc(box) - loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True) - assert loc is not edi and loc is not esi - assert len(regalloc.assembler.loads) == 1 - regalloc._check_invariants() - - def test_registers_around_call(self): - cpu = CPU(None, None) - regalloc = RegAlloc(MockAssembler(cpu), DummyTree()) - boxes = self.fill_regs(regalloc) - TP = lltype.FuncType([], lltype.Void) - calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) - regalloc._check_invariants() - for box in boxes: - regalloc.longevity[box] = (0, 1) - box = boxes[0] - regalloc.position = 0 - regalloc.consider_call(ResOperation(rop.CALL, [box], None, calldescr), - None) - assert len(regalloc.assembler.stores) == 3 - regalloc._check_invariants() +class TestRegallocDirectGcIntegration(object): def test_mark_gc_roots(self): cpu = CPU(None, None) - regalloc = RegAlloc(MockAssembler(cpu), DummyTree()) + regalloc = RegAlloc(MockAssembler(cpu, MockGcDescr(False)), DummyTree()) cpu = regalloc.assembler.cpu - boxes = self.fill_regs(regalloc, cls=BoxPtr) + boxes = fill_regs(regalloc, cls=BoxPtr) TP = lltype.FuncType([], lltype.Signed) calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) regalloc._check_invariants() @@ -173,450 +74,7 @@ expected = ['ebx', 'esi', 'edi', -16, -20, -24] assert dict.fromkeys(mark[1:]) == dict.fromkeys(expected) - def test_registers_around_newstr(self): - cpu = CPU(None, None) - regalloc = RegAllocForTests(MockAssembler(cpu), DummyTree()) - boxes = self.fill_regs(regalloc) - regalloc._check_invariants() - for box in boxes: - regalloc.longevity[box] = (0, 1) - regalloc.position = 0 - resbox = BoxInt() - regalloc.longevity[resbox] = (1, 1) - regalloc.consider_newstr(ResOperation(rop.NEWSTR, [box], resbox, - None), None) - regalloc._check_invariants() - - def test_move_away_does_not_spill(self): - regalloc = RegAlloc(MockAssembler(), DummyTree()) - regalloc.position = 0 - resbox = BoxInt() - box = BoxInt() - regalloc.reg_bindings = {box: eax} - regalloc.free_regs = [ebx, ecx, edx, esi, edi] - regalloc._check_invariants() - regalloc.longevity = {resbox: (0, 1), box: (0, 1)} - regalloc.consider_int_add(ResOperation(rop.INT_ADD, [box, ConstInt(1)], - resbox), None) - regalloc._check_invariants() - assert len(regalloc.assembler.stores) == 0 - -class BaseTestRegalloc(object): - cpu = CPU(None, None) - - def raising_func(i): - if i: - raise LLException(zero_division_error, - zero_division_value) - FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) - raising_fptr = llhelper(FPTR, raising_func) - zero_division_tp, zero_division_value = cpu.get_zero_division_error() - zd_addr = cpu.cast_int_to_adr(zero_division_tp) - zero_division_error = llmemory.cast_adr_to_ptr(zd_addr, - lltype.Ptr(rclass.OBJECT_VTABLE)) - raising_calldescr = cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT) - - namespace = locals().copy() - type_system = 'lltype' - - def parse(self, s, boxkinds=None, jump_targets=None): - return parse(s, self.cpu, self.namespace, - type_system=self.type_system, - jump_targets=jump_targets, - boxkinds=boxkinds) - - def interpret(self, ops, args, jump_targets=None, run=True): - loop = self.parse(ops, jump_targets=jump_targets) - self.cpu.compile_operations(loop) - for i, arg in enumerate(args): - if isinstance(arg, int): - self.cpu.set_future_value_int(i, arg) - else: - assert isinstance(lltype.typeOf(arg), lltype.Ptr) - llgcref = lltype.cast_opaque_ptr(llmemory.GCREF, arg) - self.cpu.set_future_value_ref(i, llgcref) - if run: - self.cpu.execute_operations(loop) - return loop - - def getint(self, index): - return self.cpu.get_latest_value_int(index) - - def getints(self, end): - return [self.cpu.get_latest_value_int(index) for - index in range(0, end)] - - def getptr(self, index, T): - gcref = self.cpu.get_latest_value_ref(index) - return lltype.cast_opaque_ptr(T, gcref) - - def attach_bridge(self, ops, loop, guard_op, **kwds): - assert guard_op.is_guard() - bridge = self.parse(ops, **kwds) - guard_op.suboperations = bridge.operations - self.cpu.compile_operations(loop, guard_op) - return bridge - - -class TestRegallocSimple(BaseTestRegalloc): - def test_simple_loop(self): - ops = ''' - [i0] - i1 = int_add(i0, 1) - i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) - jump(i1) - ''' - self.interpret(ops, [0]) - assert self.getint(0) == 20 - - def test_two_loops_and_a_bridge(self): - ops = ''' - [i0, i1, i2, i3] - i4 = int_add(i0, 1) - i5 = int_lt(i4, 20) - guard_true(i5) - fail(i4, i1, i2, i3) - jump(i4, i1, i2, i3) - ''' - loop = self.interpret(ops, [0, 0, 0, 0]) - ops2 = ''' - [i5] - i1 = int_add(i5, 1) - i3 = int_add(i1, 1) - i4 = int_add(i3, 1) - i2 = int_lt(i4, 30) - guard_true(i2) - fail(i4) - jump(i4) - ''' - loop2 = self.interpret(ops2, [0]) - bridge_ops = ''' - [i4] - jump(i4, i4, i4, i4) - ''' - bridge = self.attach_bridge(bridge_ops, loop2, loop2.operations[4], - jump_targets=[loop]) - self.cpu.set_future_value_int(0, 0) - self.cpu.execute_operations(loop2) - assert self.getint(0) == 31 - assert self.getint(1) == 30 - assert self.getint(2) == 30 - assert self.getint(3) == 30 - - def test_pointer_arg(self): - ops = ''' - [i0, p0] - i1 = int_add(i0, 1) - i2 = int_lt(i1, 10) - guard_true(i2) - fail(p0) - jump(i1, p0) - ''' - S = lltype.GcStruct('S') - ptr = lltype.malloc(S) - self.interpret(ops, [0, ptr]) - assert self.getptr(0, lltype.Ptr(S)) == ptr - assert not self.cpu.assembler.fail_boxes_ptr[0] - assert not self.cpu.assembler.fail_boxes_ptr[1] - - def test_exception_bridge_no_exception(self): - ops = ''' - [i0] - call(ConstClass(raising_fptr), i0, descr=raising_calldescr) - guard_exception(ConstClass(zero_division_error)) - fail(1) - fail(0) - ''' - bridge_ops = ''' - [] - guard_no_exception() - fail(2) - fail(1) - ''' - loop = self.interpret(ops, [0]) - assert self.getint(0) == 1 - bridge = self.attach_bridge(bridge_ops, loop, loop.operations[1]) - self.cpu.set_future_value_int(0, 0) - self.cpu.execute_operations(loop) - assert self.getint(0) == 1 - - def test_inputarg_unused(self): - ops = ''' - [i0] - fail(1) - ''' - self.interpret(ops, [0]) - # assert did not explode - - def test_nested_guards(self): - ops = ''' - [i0, i1] - guard_true(i0) - fail(i0, i1) - fail(4) - ''' - bridge_ops = ''' - [i0, i1] - guard_true(i0) - fail(i0, i1) - fail(3) - ''' - loop = self.interpret(ops, [0, 10]) - assert self.getint(0) == 0 - assert self.getint(1) == 10 - bridge = self.attach_bridge(bridge_ops, loop, loop.operations[0]) - self.cpu.set_future_value_int(0, 0) - self.cpu.set_future_value_int(1, 10) - self.cpu.execute_operations(loop) - assert self.getint(0) == 0 - assert self.getint(1) == 10 - - def test_nested_unused_arg(self): - ops = ''' - [i0, i1] - guard_true(i0) - fail(i0, i1) - fail(1) - ''' - loop = self.interpret(ops, [0, 1]) - assert self.getint(0) == 0 - bridge_ops = ''' - [i0, i1] - fail(1, 2) - ''' - self.attach_bridge(bridge_ops, loop, loop.operations[0]) - self.cpu.set_future_value_int(0, 0) - self.cpu.set_future_value_int(1, 1) - self.cpu.execute_operations(loop) - - def test_spill_for_constant(self): - ops = ''' - [i0, i1, i2, i3] - i4 = int_add(3, i1) - i5 = int_lt(i4, 30) - guard_true(i5) - fail(i0, i4, i2, i3) - jump(1, i4, 3, 4) - ''' - self.interpret(ops, [0, 0, 0, 0]) - assert self.getints(4) == [1, 30, 3, 4] - - def test_spill_for_constant_lshift(self): - ops = ''' - [i0, i2, i1, i3] - i4 = int_lshift(1, i1) - i5 = int_add(1, i1) - i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4, i5, i2, i3) - jump(i4, 3, i5, 4) - ''' - self.interpret(ops, [0, 0, 0, 0]) - assert self.getints(4) == [1<<29, 30, 3, 4] - ops = ''' - [i0, i1, i2, i3] - i4 = int_lshift(1, i1) - i5 = int_add(1, i1) - i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4, i5, i2, i3) - jump(i4, i5, 3, 4) - ''' - self.interpret(ops, [0, 0, 0, 0]) - assert self.getints(4) == [1<<29, 30, 3, 4] - ops = ''' - [i0, i3, i1, i2] - i4 = int_lshift(1, i1) - i5 = int_add(1, i1) - i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4, i5, i2, i3) - jump(i4, 4, i5, 3) - ''' - self.interpret(ops, [0, 0, 0, 0]) - assert self.getints(4) == [1<<29, 30, 3, 4] - - def test_result_selected_reg_via_neg(self): - ops = ''' - [i0, i1, i2, i3] - i6 = int_neg(i2) - i7 = int_add(1, i1) - i4 = int_lt(i7, 10) - guard_true(i4) - fail(i0, i6, i7) - jump(1, i7, i2, i6) - ''' - self.interpret(ops, [0, 0, 3, 0]) - assert self.getints(3) == [1, -3, 10] - - def test_compare_memory_result_survives(self): - ops = ''' - [i0, i1, i2, i3] - i4 = int_lt(i0, i1) - i5 = int_add(i3, 1) - i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4) - jump(i0, i1, i4, i5) - ''' - self.interpret(ops, [0, 10, 0, 0]) - assert self.getint(0) == 1 - - def test_jump_different_args(self): - ops = ''' - [i0, i15, i16, i18, i1, i2, i3] - i4 = int_add(i3, 1) - i5 = int_lt(i4, 20) - guard_true(i5) - fail(i2, i1) - jump(i0, i18, i15, i16, i2, i1, i4) - ''' - self.interpret(ops, [0, 1, 2, 3]) - - def test_op_result_unused(self): - ops = ''' - [i0, i1] - i2 = int_add(i0, i1) - fail(0) - ''' - self.interpret(ops, [0, 0]) - - def test_guard_value_two_boxes(self): - ops = ''' - [i0, i1, i2, i3, i4, i5, i6, i7] - guard_value(i6, i1) - fail(i0, i2, i3, i4, i5, i6) - fail(i0, i2, i3, i4, i5, i6) - ''' - self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0]) - assert self.getint(0) == 0 - - def test_bug_wrong_stack_adj(self): - ops = ''' - [i0, i1, i2, i3, i4, i5, i6, i7, i8] - guard_true(i0) - fail(0, i0, i1, i2, i3, i4, i5, i6, i7, i8) - fail(1, i0, i1, i2, i3, i4, i5, i6, i7, i8) - ''' - loop = self.interpret(ops, [0, 1, 2, 3, 4, 5, 6, 7, 8]) - assert self.getint(0) == 0 - bridge_ops = ''' - [i0, i1, i2, i3, i4, i5, i6, i7, i8] - call(ConstClass(raising_fptr), 0, descr=raising_calldescr) - fail(i0, i1, i2, i3, i4, i5, i6, i7, i8) - ''' - self.attach_bridge(bridge_ops, loop, loop.operations[0]) - for i in range(9): - self.cpu.set_future_value_int(i, i) - self.cpu.execute_operations(loop) - assert self.getints(9) == range(9) - -class TestRegallocCompOps(BaseTestRegalloc): - - def test_cmp_op_0(self): - ops = ''' - [i0, i3] - i2 = int_lt(i0, 100) - guard_true(i3) - fail(1, i2) - fail(0, i2) - ''' - self.interpret(ops, [0, 1]) - assert self.getint(0) == 0 - -class TestRegallocMoreRegisters(BaseTestRegalloc): - - cpu = BaseTestRegalloc.cpu - - S = lltype.GcStruct('S', ('field', lltype.Char)) - fielddescr = cpu.fielddescrof(S, 'field') - - A = lltype.GcArray(lltype.Char) - arraydescr = cpu.arraydescrof(A) - - namespace = locals().copy() - - def test_int_is_true(self): - ops = ''' - [i0, i1, i2, i3, i4, i5, i6, i7] - i10 = int_is_true(i0) - i11 = int_is_true(i1) - i12 = int_is_true(i2) - i13 = int_is_true(i3) - i14 = int_is_true(i4) - i15 = int_is_true(i5) - i16 = int_is_true(i6) - i17 = int_is_true(i7) - fail(i10, i11, i12, i13, i14, i15, i16, i17) - ''' - self.interpret(ops, [0, 42, 12, 0, 13, 0, 0, 3333]) - assert self.getints(8) == [0, 1, 1, 0, 1, 0, 0, 1] - - def test_comparison_ops(self): - ops = ''' - [i0, i1, i2, i3, i4, i5, i6] - i10 = int_lt(i0, i1) - i11 = int_le(i2, i3) - i12 = int_ge(i4, i5) - i13 = int_eq(i5, i6) - i14 = int_gt(i6, i2) - i15 = int_ne(i2, i6) - fail(i10, i11, i12, i13, i14, i15) - ''' - self.interpret(ops, [0, 1, 2, 3, 4, 5, 6]) - assert self.getints(6) == [1, 1, 0, 0, 1, 1] - - def test_nullity(self): - ops = ''' - [i0, i1, i2, i3, i4, i5, i6] - i10 = oononnull(i0) - i11 = ooisnull(i1) - i12 = oononnull(i2) - i13 = oononnull(i3) - i14 = ooisnull(i6) - i15 = ooisnull(i5) - fail(i10, i11, i12, i13, i14, i15) - ''' - self.interpret(ops, [0, 1, 2, 3, 4, 5, 6]) - assert self.getints(6) == [0, 0, 1, 1, 0, 0] - - def test_strsetitem(self): - ops = ''' - [p0, i] - strsetitem(p0, 1, i) - fail() - ''' - llstr = rstr.mallocstr(10) - self.interpret(ops, [llstr, ord('a')]) - assert llstr.chars[1] == 'a' - - def test_setfield_char(self): - ops = ''' - [p0, i] - setfield_gc(p0, i, descr=fielddescr) - fail() - ''' - s = lltype.malloc(self.S) - self.interpret(ops, [s, ord('a')]) - assert s.field == 'a' - - def test_setarrayitem_gc(self): - ops = ''' - [p0, i] - setarrayitem_gc(p0, 1, i, descr=arraydescr) - fail() - ''' - s = lltype.malloc(self.A, 3) - self.interpret(ops, [s, ord('a')]) - assert s[1] == 'a' - - -class TestRegallocGc(BaseTestRegalloc): - - def setup_class(cls): - py.test.skip("fails") +class TestRegallocGcIntegration(BaseTestRegalloc): cpu = CPU(None, None) cpu.gc_ll_descr = MockGcDescr(False) Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py Mon Sep 7 14:49:50 2009 @@ -14,22 +14,34 @@ from pypy.rpython.annlowlevel import llhelper from pypy.rpython.lltypesystem import rclass, rstr from pypy.jit.backend.x86.ri386 import * -from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList + class DummyTree(object): operations = [ResOperation(rop.FAIL, [], None)] inputargs = [] +class MockGcDescr(GcCache): + def get_funcptr_for_new(self): + return 123 + get_funcptr_for_newarray = get_funcptr_for_new + get_funcptr_for_newstr = get_funcptr_for_new + get_funcptr_for_newunicode = get_funcptr_for_new + + def rewrite_assembler(self, cpu, operations): + pass + class MockAssembler(object): gcrefs = None - def __init__(self, cpu=None): + def __init__(self, cpu=None, gc_ll_descr=None): self.loads = [] self.stores = [] self.performs = [] self.lea = [] self.cpu = cpu or CPU(None, None) - self.cpu.gc_ll_descr = MockGcDescr(False) + if gc_ll_descr is None: + gc_ll_descr = MockGcDescr(False) + self.cpu.gc_ll_descr = gc_ll_descr def dump(self, *args): pass @@ -49,56 +61,25 @@ def load_effective_addr(self, *args): self.lea.append(args) -class MockGcRootMap(object): - def get_basic_shape(self): - return ['shape'] - def add_ebp_offset(self, shape, offset): - shape.append(offset) - def add_ebx(self, shape): - shape.append('ebx') - def add_esi(self, shape): - shape.append('esi') - def add_edi(self, shape): - shape.append('edi') - def compress_callshape(self, shape): - assert shape[0] == 'shape' - return ['compressed'] + shape[1:] - -class MockGcDescr(GcCache): - def get_funcptr_for_new(self): - return 123 - get_funcptr_for_newarray = get_funcptr_for_new - get_funcptr_for_newstr = get_funcptr_for_new - get_funcptr_for_newunicode = get_funcptr_for_new +def fill_regs(regalloc, cls=BoxInt): + allboxes = [] + for reg in REGS: + box = cls() + allboxes.append(box) + regalloc.reg_bindings[box] = reg + regalloc.free_regs = [] + return allboxes - moving_gc = True - gcrootmap = MockGcRootMap() - - def initialize(self): - self.gcrefs = GcRefList() - self.gcrefs.initialize() - - rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func - - class RegAllocForTests(RegAlloc): position = 0 def _compute_next_usage(self, v, _): return -1 class TestRegallocDirect(object): - def fill_regs(self, regalloc, cls=BoxInt): - allboxes = [] - for reg in REGS: - box = cls() - allboxes.append(box) - regalloc.reg_bindings[box] = reg - regalloc.free_regs = [] - return allboxes - + def test_make_sure_var_in_reg(self): regalloc = RegAlloc(MockAssembler(), DummyTree()) - boxes = self.fill_regs(regalloc) + boxes = fill_regs(regalloc) box = boxes[-1] oldloc = regalloc.loc(box) newloc = regalloc.make_sure_var_in_reg(box, []) @@ -139,7 +120,7 @@ def test_registers_around_call(self): cpu = CPU(None, None) regalloc = RegAlloc(MockAssembler(cpu), DummyTree()) - boxes = self.fill_regs(regalloc) + boxes = fill_regs(regalloc) TP = lltype.FuncType([], lltype.Void) calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) regalloc._check_invariants() @@ -152,31 +133,10 @@ assert len(regalloc.assembler.stores) == 3 regalloc._check_invariants() - def test_mark_gc_roots(self): - cpu = CPU(None, None) - regalloc = RegAlloc(MockAssembler(cpu), DummyTree()) - cpu = regalloc.assembler.cpu - boxes = self.fill_regs(regalloc, cls=BoxPtr) - TP = lltype.FuncType([], lltype.Signed) - calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) - regalloc._check_invariants() - for box in boxes: - regalloc.longevity[box] = (0, 1) - box = boxes[0] - regalloc.position = 0 - regalloc.consider_call(ResOperation(rop.CALL, [box], BoxInt(), - calldescr), None) - assert len(regalloc.assembler.stores) == 3 - # - mark = regalloc.get_mark_gc_roots(cpu.gc_ll_descr.gcrootmap) - assert mark[0] == 'compressed' - expected = ['ebx', 'esi', 'edi', -16, -20, -24] - assert dict.fromkeys(mark[1:]) == dict.fromkeys(expected) - def test_registers_around_newstr(self): cpu = CPU(None, None) regalloc = RegAllocForTests(MockAssembler(cpu), DummyTree()) - boxes = self.fill_regs(regalloc) + boxes = fill_regs(regalloc) regalloc._check_invariants() for box in boxes: regalloc.longevity[box] = (0, 1) @@ -611,111 +571,3 @@ s = lltype.malloc(self.A, 3) self.interpret(ops, [s, ord('a')]) assert s[1] == 'a' - - -class TestRegallocGc(BaseTestRegalloc): - - def setup_class(cls): - py.test.skip("fails") - - cpu = CPU(None, None) - cpu.gc_ll_descr = MockGcDescr(False) - - S = lltype.GcForwardReference() - S.become(lltype.GcStruct('S', ('field', lltype.Ptr(S)), - ('int', lltype.Signed))) - - fielddescr = cpu.fielddescrof(S, 'field') - - struct_ptr = lltype.malloc(S) - struct_ref = lltype.cast_opaque_ptr(llmemory.GCREF, struct_ptr) - child_ptr = lltype.nullptr(S) - struct_ptr.field = child_ptr - - - descr0 = cpu.fielddescrof(S, 'int') - ptr0 = struct_ref - - namespace = locals().copy() - - def test_basic(self): - ops = ''' - [p0] - p1 = getfield_gc(p0, descr=fielddescr) - fail(p1) - ''' - self.interpret(ops, [self.struct_ptr]) - assert not self.getptr(0, lltype.Ptr(self.S)) - - def test_rewrite_constptr(self): - ops = ''' - [] - p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) - fail(p1) - ''' - self.interpret(ops, []) - assert not self.getptr(0, lltype.Ptr(self.S)) - - def test_rewrite_constptr_bridge(self): - ops = ''' - [i0] - guard_true(i0) - fail(1) - fail(0) - ''' - loop = self.interpret(ops, [0]) - assert self.getint(0) == 1 - bridge_ops = ''' - [i0] - p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) - fail(p1) - ''' - self.attach_bridge(bridge_ops, loop, loop.operations[0]) - self.cpu.set_future_value_int(0, 0) - self.cpu.execute_operations(loop) - not self.getptr(0, lltype.Ptr(self.S)) - - def test_bug_0(self): - ops = ''' - [i0, i1, i2, i3, i4, i5, i6, i7, i8] - guard_value(i2, 1) - fail(i2, i3, i4, i5, i6, i7, i0, i1, i8) - guard_class(i4, 138998336) - fail(i4, i5, i6, i7, i0, i1, i8) - i11 = getfield_gc(i4, descr=descr0) - i12 = ooisnull(i11) - guard_false(i12) - fail(i4, i5, i6, i7, i0, i1, i11, i8) - i13 = getfield_gc(i11, descr=descr0) - i14 = ooisnull(i13) - guard_true(i14) - fail(i4, i5, i6, i7, i0, i1, i11, i8) - i15 = getfield_gc(i4, descr=descr0) - i17 = int_lt(i15, 0) - guard_false(i17) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) - i18 = getfield_gc(i11, descr=descr0) - i19 = int_ge(i15, i18) - guard_false(i19) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) - i20 = int_lt(i15, 0) - guard_false(i20) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) - i21 = getfield_gc(i11, descr=descr0) - i22 = getfield_gc(i11, descr=descr0) - i23 = int_mul(i15, i22) - i24 = int_add(i21, i23) - i25 = getfield_gc(i4, descr=descr0) - i27 = int_add(i25, 1) - setfield_gc(i4, i27, descr=descr0) - i29 = getfield_raw(144839744, descr=descr0) - i31 = int_and(i29, -2141192192) - i32 = int_is_true(i31) - guard_false(i32) - fail(i4, i6, i7, i0, i1, i24) - i33 = getfield_gc(i0, descr=descr0) - guard_value(i33, ConstPtr(ptr0)) - fail(i4, i6, i7, i0, i1, i33, i24) - jump(i0, i1, 1, 17, i4, ConstPtr(ptr0), i6, i7, i24) - ''' - self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0, 0], run=False) Modified: pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py Mon Sep 7 14:49:50 2009 @@ -370,15 +370,18 @@ self._storage = None def __eq__(self, other): - if not isinstance(other, lltype._parentable): - return False - if self._storage is None or other._storage is None: - raise RuntimeError("pointer comparison with a freed structure") - if other._storage is True: - return False # the other container is not ctypes-based + if isinstance(other, _llgcopaque): + addressof_other = other.intval + else: + if not isinstance(other, lltype._parentable): + return False + if self._storage is None or other._storage is None: + raise RuntimeError("pointer comparison with a freed structure") + if other._storage is True: + return False # the other container is not ctypes-based + addressof_other = ctypes.addressof(other._storage) # both containers are ctypes-based, compare by address - return (ctypes.addressof(self._storage) == - ctypes.addressof(other._storage)) + return (ctypes.addressof(self._storage) == addressof_other) def __ne__(self, other): return not (self == other) @@ -624,6 +627,7 @@ if isinstance(container, lltype._subarray): topmost, index = _find_parent(container) container = topmost + T = lltype.Ptr(lltype.typeOf(container)) if container._storage is None: raise RuntimeError("attempting to pass a freed structure to C") @@ -1099,7 +1103,13 @@ def __eq__(self, other): if isinstance(other, _llgcopaque): return self.intval == other.intval - if other.container._storage in (None, True): + storage = object() + if hasattr(other, 'container'): + storage = other.container._storage + else: + storage = other._storage + + if storage in (None, True): return False return force_cast(lltype.Signed, other._as_ptr()) == self.intval Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Mon Sep 7 14:49:50 2009 @@ -1091,8 +1091,38 @@ assert ref1 == ref2 assert ref2 == ref1 assert not (ref1 != ref2) - assert not (ref2 != ref1) - + assert not (ref2 != ref1) + + def test_convert_subarray(self): + A = lltype.GcArray(lltype.Signed) + a = lltype.malloc(A, 20) + inside = lltype.direct_ptradd(lltype.direct_arrayitems(a), 3) + + lltype2ctypes(inside) + + start = rffi.cast(lltype.Signed, lltype.direct_arrayitems(a)) + inside_int = rffi.cast(lltype.Signed, inside) + + assert inside_int == start+rffi.sizeof(lltype.Signed)*3 + + def test_gcref_comparisons_through_addresses(self): + NODE = lltype.GcStruct('NODE') + n0 = lltype.malloc(NODE) + adr0 = llmemory.cast_ptr_to_adr(n0) + + n1 = lltype.malloc(NODE) + i1 = rffi.cast(lltype.Signed, n1) + ref1 = rffi.cast(llmemory.GCREF, i1) + adr1 = llmemory.cast_ptr_to_adr(ref1) + + assert adr1 != adr0 + assert adr0 != adr1 + + adr1_2 = llmemory.cast_ptr_to_adr(n1) + + #import pdb; pdb.set_trace() + assert adr1_2 == adr1 + assert adr1 == adr1_2 class TestPlatform(object): def test_lib_on_libpaths(self): From cfbolz at codespeak.net Mon Sep 7 14:55:31 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 7 Sep 2009 14:55:31 +0200 (CEST) Subject: [pypy-svn] r67555 - pypy/branch/agressive-inlining Message-ID: <20090907125531.26FB6168020@codespeak.net> Author: cfbolz Date: Mon Sep 7 14:55:30 2009 New Revision: 67555 Added: pypy/branch/agressive-inlining/ - copied from r67554, pypy/trunk/ Log: (pedronis, cfbolz): make a branch where we try to inline more aggressively From antocuni at codespeak.net Mon Sep 7 15:09:25 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 7 Sep 2009 15:09:25 +0200 (CEST) Subject: [pypy-svn] r67556 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090907130925.C834F16801D@codespeak.net> Author: antocuni Date: Mon Sep 7 15:09:25 2009 New Revision: 67556 Modified: pypy/trunk/pypy/jit/metainterp/test/test_virtual.py Log: enable ootype tests. They all pass Modified: pypy/trunk/pypy/jit/metainterp/test/test_virtual.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_virtual.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_virtual.py Mon Sep 7 15:09:25 2009 @@ -4,6 +4,7 @@ from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin from pypy.rpython.lltypesystem import lltype, rclass from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp import heaptracker class VirtualTests: @@ -272,9 +273,9 @@ return f res = self.meta_interp(f, [21], repeat=7) - # hack - assert (getattr(res, "inst_value", -100) == f(21).value or - getattr(res, "value", -100) == f(21).value) + + fieldname = self._field_prefix + 'value' + assert getattr(res, fieldname, -100) == f(21).value self.check_tree_loop_count(2) # the loop and the entry path # we get: @@ -285,9 +286,6 @@ self.check_enter_count(4) -##class TestOOtype(VirtualTests, OOJitMixin): -## _new = staticmethod(ootype.new) - # ____________________________________________________________ # Run 1: all the tests instantiate a real RPython class @@ -296,6 +294,17 @@ class TestLLtype_Instance(VirtualTests, LLJitMixin): _new_op = 'new_with_vtable' + _field_prefix = 'inst_' + + @staticmethod + def _new(): + return MyClass() + + +class TestOOtype_Instance(VirtualTests, OOJitMixin): + _new_op = 'new_with_vtable' + _field_prefix = 'o' + @staticmethod def _new(): return MyClass() @@ -308,11 +317,25 @@ class TestLLtype_NotObject(VirtualTests, LLJitMixin): _new_op = 'new' - + _field_prefix = '' + @staticmethod def _new(): return lltype.malloc(NODE) + +OONODE = ootype.Instance('NODE', ootype.ROOT, {}) +OONODE._add_fields({'value': ootype.Signed, + 'extra': ootype.Signed}) + +class TestOOtype_NotObject(VirtualTests, OOJitMixin): + _new_op = 'new_with_vtable' + _field_prefix = '' + + @staticmethod + def _new(): + return ootype.new(OONODE) + # ____________________________________________________________ # Run 3: all the tests use lltype.malloc to make a NODE2 # (same as Run 2 but it is part of the OBJECT hierarchy) @@ -326,6 +349,8 @@ class TestLLtype_Object(VirtualTests, LLJitMixin): _new_op = 'new_with_vtable' + _field_prefix = '' + @staticmethod def _new(): p = lltype.malloc(NODE2) From benjamin at codespeak.net Mon Sep 7 15:23:21 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Mon, 7 Sep 2009 15:23:21 +0200 (CEST) Subject: [pypy-svn] r67557 - in pypy/trunk/pypy: interpreter/test module/__builtin__ Message-ID: <20090907132321.BACE2168016@codespeak.net> Author: benjamin Date: Mon Sep 7 15:23:19 2009 New Revision: 67557 Modified: pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py pypy/trunk/pypy/module/__builtin__/functional.py Log: fix picking of reversed Modified: pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py ============================================================================== --- pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py (original) +++ pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py Mon Sep 7 15:23:19 2009 @@ -369,7 +369,19 @@ result = pickle.loads(pckl) raises(TypeError, len, diter) assert list(diter) == list(result) - + + def test_pickle_reversed(self): + import pickle + r = reversed(tuple(range(10))) + r.next() + r.next() + pickled = pickle.dumps(r) + result = pickle.loads(pickled) + result.next() + r.next() + assert type(r) is type(result) + assert list(r) == list(result) + def test_pickle_enum(self): import pickle e = enumerate(range(10)) Modified: pypy/trunk/pypy/module/__builtin__/functional.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/functional.py (original) +++ pypy/trunk/pypy/module/__builtin__/functional.py Mon Sep 7 15:23:19 2009 @@ -437,11 +437,27 @@ raise OperationError(space.w_StopIteration, space.w_None) descr_next.unwrap_spec = ["self", ObjSpace] + def descr___reduce__(self, space): + info_w = [self.w_sequence, space.wrap(self.remaining)] + w_info = space.newtuple(info_w) + return space.newtuple([space.wrap(_make_reversed), w_info]) + descr___reduce__.unwrap_spec = ["self", ObjSpace] + W_ReversedIterator.typedef = TypeDef("reversed", __iter__=interp2app(W_ReversedIterator.descr___iter__), next=interp2app(W_ReversedIterator.descr_next), + __reduce__=interp2app(W_ReversedIterator.descr___reduce__), ) +def _make_reversed(space, w_seq, w_remaining): + w_type = space.gettypeobject(W_ReversedIterator.typedef) + iterator = space.allocate_instance(W_ReversedIterator, w_type) + iterator.w_sequence = w_seq + iterator.remaining = space.int_w(w_remaining) + return space.wrap(iterator) +_make_reversed.unwrap_spec = [ObjSpace, W_Root, W_Root] +_make_reversed = interp2app(_make_reversed) + class W_XRange(Wrappable): def __init__(self, space, start, len, step): From benjamin at codespeak.net Mon Sep 7 15:49:48 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Mon, 7 Sep 2009 15:49:48 +0200 (CEST) Subject: [pypy-svn] r67558 - pypy/trunk/pypy/module/__builtin__ Message-ID: <20090907134948.59223168016@codespeak.net> Author: benjamin Date: Mon Sep 7 15:49:47 2009 New Revision: 67558 Modified: pypy/trunk/pypy/module/__builtin__/functional.py Log: fix pickling of enumerate Modified: pypy/trunk/pypy/module/__builtin__/functional.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/functional.py (original) +++ pypy/trunk/pypy/module/__builtin__/functional.py Mon Sep 7 15:49:47 2009 @@ -394,11 +394,21 @@ return space.newtuple([w_index, w_item]) descr_next.unwrap_spec = ["self", ObjSpace] + def descr___reduce__(self, space): + w_info = space.newtuple([self.w_iter, self.w_index]) + return space.newtuple([space.wrap(_make_enumerate), w_info]) + descr___reduce__.unwrap_spec = ["self", ObjSpace] + +def _make_enumerate(space, w_iter, w_index): + return space.wrap(W_Enumerate(w_iter, w_index)) +_make_enumerate.unwrap_spec = [ObjSpace, W_Root, W_Root] +_make_enumerate = interp2app(_make_enumerate) W_Enumerate.typedef = TypeDef("enumerate", __new__=interp2app(W_Enumerate.descr___new__.im_func), __iter__=interp2app(W_Enumerate.descr___iter__), next=interp2app(W_Enumerate.descr_next), + __reduce__=interp2app(W_Enumerate.descr___reduce__), ) From cfbolz at codespeak.net Mon Sep 7 16:53:06 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 7 Sep 2009 16:53:06 +0200 (CEST) Subject: [pypy-svn] r67559 - in pypy/branch/agressive-inlining/pypy: jit/metainterp jit/metainterp/test rlib Message-ID: <20090907145306.345E616801B@codespeak.net> Author: cfbolz Date: Mon Sep 7 16:53:03 2009 New Revision: 67559 Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_basic.py pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py pypy/branch/agressive-inlining/pypy/rlib/jit.py Log: (cfbolz, pedronis; micke, fijal and arigo around): abort tracing if the trace gets longer than a certain threshold. Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py Mon Sep 7 16:53:03 2009 @@ -1196,6 +1196,7 @@ self.cpu.ts.get_exc_value_box(evalue)) def create_empty_history(self): + warmrunnerstate = self.staticdata.state self.history = history.History(self.cpu) if self.staticdata.stats is not None: self.staticdata.stats.history = self.history @@ -1245,6 +1246,18 @@ op.pc = self.framestack[-1].pc op.name = self.framestack[-1].jitcode.name + def switch_to_blackhole_if_trace_too_long(self): + if not self.is_blackholing(): + warmrunnerstate = self.staticdata.state + if len(self.history.operations) > warmrunnerstate.trace_limit: + self.history = history.BlackHole(self.cpu) + if not we_are_translated(): + history.log.event('ABORTING TRACING' + self.history.extratext) + elif DEBUG: + debug_print('~~~ ABORTING TRACING', self.history.extratext) + self.staticdata.profiler.end_tracing() + self.staticdata.profiler.start_blackhole() + def _interpret(self): # Execute the frames forward until we raise a DoneWithThisFrame, # a ContinueRunningNormally, or a GenerateMergePoint exception. @@ -1256,6 +1269,7 @@ try: while True: self.framestack[-1].run_one_step() + self.switch_to_blackhole_if_trace_too_long() finally: if self.is_blackholing(): self.staticdata.profiler.end_blackhole() Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_basic.py Mon Sep 7 16:53:03 2009 @@ -1,4 +1,5 @@ import py +import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats from pypy.jit.backend.llgraph import runner @@ -70,6 +71,8 @@ class FakeWarmRunnerDesc: def attach_unoptimized_bridge_from_interp(self, greenkey, newloop): pass + + trace_limit = sys.maxint if policy is None: policy = JitPolicy() Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Mon Sep 7 16:53:03 2009 @@ -4,7 +4,7 @@ from pypy.jit.metainterp import simple_optimize from pypy.jit.metainterp.policy import StopAtXPolicy from pypy.rpython.annlowlevel import hlstr -from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit +from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit, get_stats class RecursiveTests: @@ -213,6 +213,56 @@ res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) assert res == 0 + def test_inline_trace_limit(self): + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "l" not in hlstr(code) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], + get_printable_location=p, can_inline=c) + def recursive(n): + if n > 0: + return recursive(n - 1) + 1 + return 0 + def f(code, n): + myjitdriver.set_param("threshold", 10) + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(n=n, code=code, pc=pc) + op = code[pc] + if op == "-": + n -= 1 + elif op == "r": + n = recursive(n) + elif op == "i": + if n % 5 == 1: + return n + elif op == "l": + if n > 0: + myjitdriver.can_enter_jit(n=n, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return n + def main(n): + if n < 0: + code = "--" + else: + code = "r-l" + return f(code, n) + print main(100) + TRACE_LIMIT = 66 + res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT) + assert res == 0 + for loop in get_stats().loops: + assert len(loop.operations) <= TRACE_LIMIT + 5 # because we only check once per metainterp bytecode + self.check_enter_count(27) # maybe + class TestLLtype(RecursiveTests, LLJitMixin): pass Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py Mon Sep 7 16:53:03 2009 @@ -52,13 +52,14 @@ clear_tcache() return jittify_and_run(interp, graph, args, backendopt=backendopt, **kwds) -def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False, +def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False, trace_limit=sys.maxint, **kwds): translator = interp.typer.annotator.translator translator.config.translation.gc = "boehm" warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds) warmrunnerdesc.state.set_param_threshold(3) # for tests warmrunnerdesc.state.set_param_trace_eagerness(2) # for tests + warmrunnerdesc.state.set_param_trace_limit(trace_limit) warmrunnerdesc.state.create_tables_now() # for tests if hash_bits: warmrunnerdesc.state.set_param_hash_bits(hash_bits) @@ -728,6 +729,9 @@ def set_param_trace_eagerness(self, value): self.trace_eagerness = value + def set_param_trace_limit(self, value): + self.trace_limit = value + def set_param_hash_bits(self, value): if value < 1: value = 1 @@ -772,7 +776,13 @@ self.create_tables_now() return metainterp = MetaInterp(metainterp_sd) - loop = metainterp.compile_and_run_once(*args) + try: + loop = metainterp.compile_and_run_once(*args) + except warmrunnerdesc.ContinueRunningNormally: + # the trace got too long, reset the counter + self.mccounters[argshash] = 0 + raise + else: # machine code was already compiled for these greenargs # (or we have a hash collision) Modified: pypy/branch/agressive-inlining/pypy/rlib/jit.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/rlib/jit.py (original) +++ pypy/branch/agressive-inlining/pypy/rlib/jit.py Mon Sep 7 16:53:03 2009 @@ -1,3 +1,4 @@ +import sys from pypy.rpython.extregistry import ExtRegistryEntry from pypy.rlib.objectmodel import CDefinedIntSymbolic from pypy.rlib.unroll import unrolling_iterable @@ -82,6 +83,7 @@ PARAMETERS = {'threshold': 1000, 'trace_eagerness': 200, 'hash_bits': 14, + 'trace_limit': sys.maxint, } unroll_parameters = unrolling_iterable(PARAMETERS.keys()) From cfbolz at codespeak.net Mon Sep 7 17:09:10 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 7 Sep 2009 17:09:10 +0200 (CEST) Subject: [pypy-svn] r67560 - pypy/trunk/pypy/objspace/std Message-ID: <20090907150910.2B67E16801B@codespeak.net> Author: cfbolz Date: Mon Sep 7 17:09:09 2009 New Revision: 67560 Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py Log: Now this actually works. Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/dictmultiobject.py (original) +++ pypy/trunk/pypy/objspace/std/dictmultiobject.py Mon Sep 7 17:09:09 2009 @@ -5,6 +5,7 @@ from pypy.rlib.objectmodel import r_dict, we_are_translated from pypy.rlib.jit import purefunction +from pypy.rlib.rweakref import RWeakValueDictionary def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -687,7 +688,6 @@ class SharedStructure(object): def __init__(self, keys=None, length=0, - other_structs=None, last_key=None, back_struct=None): if keys is None: @@ -695,20 +695,18 @@ self.keys = keys self.length = length self.back_struct = back_struct - if other_structs is None: - other_structs = {} + other_structs = RWeakValueDictionary(SharedStructure) self.other_structs = other_structs self.last_key = last_key if last_key is not None: assert back_struct is not None - self.propagating = False def new_structure(self, added_key): keys = self.keys.copy() keys[added_key] = len(self.keys) new_structure = SharedStructure(keys, self.length + 1, - {}, added_key, self) - self.other_structs[added_key] = new_structure + added_key, self) + self.other_structs.set(added_key, new_structure) return new_structure def lookup_position(self, key): @@ -725,7 +723,6 @@ class State(object): def __init__(self, space): self.empty_structure = SharedStructure() - self.empty_structure.propagating = True class SharedDictImplementation(DictImplementation): @@ -762,13 +759,9 @@ if i != -1: self.entries[i] = w_value return self - if not self.structure.propagating: - return self._as_rdict(as_strdict=True).setitem_str(w_key, w_value) - new_structure = self.structure.other_structs.get(key, None) + new_structure = self.structure.other_structs.get(key) if new_structure is None: new_structure = self.structure.new_structure(key) - else: - new_structure.propagating = True self.entries.append(w_value) assert self.structure.length + 1 == new_structure.length self.structure = new_structure From fijal at codespeak.net Mon Sep 7 17:46:42 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 7 Sep 2009 17:46:42 +0200 (CEST) Subject: [pypy-svn] r67561 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090907154642.1297816801B@codespeak.net> Author: fijal Date: Mon Sep 7 17:46:41 2009 New Revision: 67561 Modified: pypy/trunk/pypy/jit/backend/x86/regalloc.py Log: Revert algorithm for finding which variable to spill to a pseudo-random one. Performance difference was minimal, last time I measured. Modified: pypy/trunk/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/regalloc.py Mon Sep 7 17:46:41 2009 @@ -18,6 +18,9 @@ REGS = [eax, ecx, edx, ebx, esi, edi] WORD = 4 +class NoVariableToSpill(Exception): + pass + class TempBox(Box): def __init__(self): pass @@ -424,24 +427,30 @@ reg = self.reg_bindings[next] if next in forbidden_vars: continue - if selected_reg is not None and reg is selected_reg: - return next + if selected_reg is not None: + if reg is selected_reg: + return next + else: + continue if need_lower_byte and (reg is esi or reg is edi): continue - candidates.append(next) - assert candidates - if len(candidates) == 1: - return candidates[0] - max = 0 - chosen = None - for one in candidates: - next_usage = self._compute_next_usage(one, self.position) - if next_usage == -1: - return one - elif next_usage > max: - next_usage = max - chosen = one - return chosen + return next + raise NoVariableToSpill + # below is the slightly better (even optimal, under certain + # assumptions) algorithm, which is slow. Just go with the + # first hit + #if len(candidates) == 1: + # return candidates[0] + #max = 0 + #chosen = None + #for one in candidates: + # next_usage = self._compute_next_usage(one, self.position) + # if next_usage == -1: + # return one + # elif next_usage > max: + # next_usage = max + # chosen = one + #return chosen def move_variable_away(self, v, prev_loc): reg = None @@ -508,6 +517,7 @@ locs[i] = loc # otherwise we have it saved on stack, so no worry self.free_regs.insert(0, tmpreg) + assert tmpreg not in locs tree.arglocs = locs self.assembler.make_merge_point(tree, locs) self.eventually_free_vars(inputargs) From antocuni at codespeak.net Mon Sep 7 17:49:32 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 7 Sep 2009 17:49:32 +0200 (CEST) Subject: [pypy-svn] r67562 - in pypy/trunk/pypy: jit/metainterp jit/metainterp/test rpython/ootypesystem rpython/ootypesystem/test Message-ID: <20090907154932.CCEF516801B@codespeak.net> Author: antocuni Date: Mon Sep 7 17:49:32 2009 New Revision: 67562 Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py pypy/trunk/pypy/jit/metainterp/test/test_virtual.py pypy/trunk/pypy/rpython/ootypesystem/ootype.py pypy/trunk/pypy/rpython/ootypesystem/test/test_ootype.py Log: add support for default values for ootype: while ootype.new takes care of initializing the fields, the jit operation new_with_vtable doesn't. Thus, we make the codewriter to generate a setfield_gc for each field which needs an explicit default value Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/codewriter.py Mon Sep 7 17:49:32 2009 @@ -756,6 +756,21 @@ self.const_position(cls)) self.codewriter.register_known_ooclass(cls, TYPE) self.register_var(op.result) + # initialize fields with a non-default value: while in ootype it's + # new() that takes care of it, for the jit we explicitly insert the + # corresponding setfields(). This way, the backends don't need to care + # about default fields and moreover the resulting code is more similar + # to the lltype version, so the optimizer doesn't need to take special + # care for them. + if isinstance(TYPE, ootype.Instance): + fields = TYPE._get_fields_with_different_default() + var_inst = self.var_position(op.result) + for name, (T, value) in fields: + descr = self.cpu.fielddescrof(TYPE, name) + self.emit('setfield_gc') + self.emit(var_inst) + self.emit(self.get_position(descr)) + self.emit(self.var_position(Constant(value))) def serialize_op_oonewarray(self, op): ARRAY = op.args[0].value Modified: pypy/trunk/pypy/jit/metainterp/test/test_virtual.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_virtual.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_virtual.py Mon Sep 7 17:49:32 2009 @@ -300,6 +300,30 @@ def _new(): return MyClass() + def test_class_with_default_fields(self): + class MyClass: + value = 2 + + myjitdriver = JitDriver(greens = [], reds = ['n', 'res']) + def f(n): + res = 0 + node = MyClass() + node.value = n # so that the annotator doesn't think that value is constant + while n > 0: + myjitdriver.can_enter_jit(n=n, res=res) + myjitdriver.jit_merge_point(n=n, res=res) + node = MyClass() + res += node.value + n -= 1 + return res + assert f(10) == 20 + res = self.meta_interp(f, [10]) + assert res == 20 + self.check_loop_count(1) + self.check_loops(new=0, new_with_vtable=0, + getfield_gc=0, setfield_gc=0) + + class TestOOtype_Instance(VirtualTests, OOJitMixin): _new_op = 'new_with_vtable' @@ -309,6 +333,8 @@ def _new(): return MyClass() + test_class_with_default_fields = TestLLtype_Instance.test_class_with_default_fields.im_func + # ____________________________________________________________ # Run 2: all the tests use lltype.malloc to make a NODE Modified: pypy/trunk/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/ootype.py Mon Sep 7 17:49:32 2009 @@ -258,6 +258,14 @@ graphs.update(SUBTYPE._lookup_graphs(meth_name)) return graphs + def _get_fields_with_different_default(self): + fields = [] + example = self._example() + for field in self._allfields().iteritems(): + name, (T, value) = field + if T._defl() != value: + fields.append(field) + return fields class SpecializableType(OOType): Modified: pypy/trunk/pypy/rpython/ootypesystem/test/test_ootype.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/test/test_ootype.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/test/test_ootype.py Mon Sep 7 17:49:32 2009 @@ -654,3 +654,11 @@ SM = StaticMethod([], Void) sm = SM._defl() assert not bool(sm) + +def test_get_fields_with_different_default(): + A = Instance("A", ROOT, {"a": (Signed, 3), + "b": (Signed, 0), + "c": (ROOT, ROOT._defl()) + }) + fields = A._get_fields_with_different_default() + assert fields == [("a", (Signed, 3))] From fijal at codespeak.net Mon Sep 7 17:54:19 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 7 Sep 2009 17:54:19 +0200 (CEST) Subject: [pypy-svn] r67563 - pypy/branch/less-resumedata Message-ID: <20090907155419.D674116801B@codespeak.net> Author: fijal Date: Mon Sep 7 17:54:19 2009 New Revision: 67563 Added: pypy/branch/less-resumedata/ - copied from r67562, pypy/trunk/ Log: A branch to experiment with less resume data creation From fijal at codespeak.net Mon Sep 7 19:14:00 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 7 Sep 2009 19:14:00 +0200 (CEST) Subject: [pypy-svn] r67564 - pypy/branch/less-resumedata/pypy/translator/c Message-ID: <20090907171400.9546F168016@codespeak.net> Author: fijal Date: Mon Sep 7 19:13:59 2009 New Revision: 67564 Modified: pypy/branch/less-resumedata/pypy/translator/c/genc.py Log: -pg and -fomit-frame-pointer are incompatible, force it to -fno-omit-frame-pointer in case of make profile Modified: pypy/branch/less-resumedata/pypy/translator/c/genc.py ============================================================================== --- pypy/branch/less-resumedata/pypy/translator/c/genc.py (original) +++ pypy/branch/less-resumedata/pypy/translator/c/genc.py Mon Sep 7 19:13:59 2009 @@ -472,7 +472,7 @@ ('linuxmemchk', '', '$(MAKE) CFLAGS="-g -O1 -DRPY_ASSERT -DLINUXMEMCHK" $(TARGET)'), ('llsafer', '', '$(MAKE) CFLAGS="-O2 -DRPY_LL_ASSERT" $(TARGET)'), ('lldebug', '', '$(MAKE) CFLAGS="-g -DRPY_ASSERT -DRPY_LL_ASSERT" $(TARGET)'), - ('profile', '', '$(MAKE) CFLAGS="-g -O1 -pg $(CFLAGS)" LDFLAGS="-pg $(LDFLAGS)" $(TARGET)'), + ('profile', '', '$(MAKE) CFLAGS="-g -O1 -pg $(CFLAGS) -fno-omit-frame-pointer" LDFLAGS="-pg $(LDFLAGS)" $(TARGET)'), ] if self.has_profopt(): rules.append( From pedronis at codespeak.net Tue Sep 8 10:32:41 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 8 Sep 2009 10:32:41 +0200 (CEST) Subject: [pypy-svn] r67566 - in pypy/trunk/pypy/module: __builtin__ _pickle_support Message-ID: <20090908083241.462ED16801F@codespeak.net> Author: pedronis Date: Tue Sep 8 10:32:39 2009 New Revision: 67566 Modified: pypy/trunk/pypy/module/__builtin__/functional.py pypy/trunk/pypy/module/_pickle_support/__init__.py pypy/trunk/pypy/module/_pickle_support/maker.py Log: fix translation broken by 67557-67558 inter2app objects cannot be wrapped at runtime! Modified: pypy/trunk/pypy/module/__builtin__/functional.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/functional.py (original) +++ pypy/trunk/pypy/module/__builtin__/functional.py Tue Sep 8 10:32:39 2009 @@ -395,14 +395,17 @@ descr_next.unwrap_spec = ["self", ObjSpace] def descr___reduce__(self, space): + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + w_new_inst = mod.get('enumerate_new') w_info = space.newtuple([self.w_iter, self.w_index]) - return space.newtuple([space.wrap(_make_enumerate), w_info]) + return space.newtuple([w_new_inst, w_info]) descr___reduce__.unwrap_spec = ["self", ObjSpace] +# exported through _pickle_support def _make_enumerate(space, w_iter, w_index): return space.wrap(W_Enumerate(w_iter, w_index)) -_make_enumerate.unwrap_spec = [ObjSpace, W_Root, W_Root] -_make_enumerate = interp2app(_make_enumerate) W_Enumerate.typedef = TypeDef("enumerate", __new__=interp2app(W_Enumerate.descr___new__.im_func), @@ -448,9 +451,13 @@ descr_next.unwrap_spec = ["self", ObjSpace] def descr___reduce__(self, space): + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + w_new_inst = mod.get('reversed_new') info_w = [self.w_sequence, space.wrap(self.remaining)] w_info = space.newtuple(info_w) - return space.newtuple([space.wrap(_make_reversed), w_info]) + return space.newtuple([w_new_inst, w_info]) descr___reduce__.unwrap_spec = ["self", ObjSpace] W_ReversedIterator.typedef = TypeDef("reversed", @@ -459,14 +466,14 @@ __reduce__=interp2app(W_ReversedIterator.descr___reduce__), ) +# exported through _pickle_support def _make_reversed(space, w_seq, w_remaining): w_type = space.gettypeobject(W_ReversedIterator.typedef) iterator = space.allocate_instance(W_ReversedIterator, w_type) iterator.w_sequence = w_seq iterator.remaining = space.int_w(w_remaining) return space.wrap(iterator) -_make_reversed.unwrap_spec = [ObjSpace, W_Root, W_Root] -_make_reversed = interp2app(_make_reversed) + class W_XRange(Wrappable): Modified: pypy/trunk/pypy/module/_pickle_support/__init__.py ============================================================================== --- pypy/trunk/pypy/module/_pickle_support/__init__.py (original) +++ pypy/trunk/pypy/module/_pickle_support/__init__.py Tue Sep 8 10:32:39 2009 @@ -22,4 +22,6 @@ 'xrangeiter_new': 'maker.xrangeiter_new', 'builtin_code': 'maker.builtin_code', 'builtin_function' : 'maker.builtin_function', + 'enumerate_new': 'maker.enumerate_new', + 'reversed_new': 'maker.reversed_new' } Modified: pypy/trunk/pypy/module/_pickle_support/maker.py ============================================================================== --- pypy/trunk/pypy/module/_pickle_support/maker.py (original) +++ pypy/trunk/pypy/module/_pickle_support/maker.py Tue Sep 8 10:32:39 2009 @@ -100,6 +100,17 @@ builtin_function.unwrap_spec = [ObjSpace, str] +def enumerate_new(space, w_iter, w_index): + from pypy.module.__builtin__.functional import _make_enumerate + return _make_enumerate(space, w_iter, w_index) +enumerate_new.unwrap_spec = [ObjSpace, W_Root, W_Root] + +def reversed_new(space, w_seq, w_remaining): + from pypy.module.__builtin__.functional import _make_reversed + return _make_reversed(space, w_seq, w_remaining) +reversed_new.unwrap_spec = [ObjSpace, W_Root, W_Root] + + # ___________________________________________________________________ # Helper functions for internal use From pedronis at codespeak.net Tue Sep 8 10:39:57 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 8 Sep 2009 10:39:57 +0200 (CEST) Subject: [pypy-svn] r67567 - pypy/trunk/pypy/jit/backend/x86/test Message-ID: <20090908083957.0F7D916801E@codespeak.net> Author: pedronis Date: Tue Sep 8 10:39:56 2009 New Revision: 67567 Modified: pypy/trunk/pypy/jit/backend/x86/test/test_virtual.py Log: test fix Modified: pypy/trunk/pypy/jit/backend/x86/test/test_virtual.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_virtual.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_virtual.py Tue Sep 8 10:39:56 2009 @@ -8,6 +8,7 @@ # for the individual tests see # ====> ../../../metainterp/test/test_virtual.py _new_op = 'new_with_vtable' + _field_prefix = 'inst_' @staticmethod def _new(): From cfbolz at codespeak.net Tue Sep 8 11:00:21 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 8 Sep 2009 11:00:21 +0200 (CEST) Subject: [pypy-svn] r67568 - in pypy/branch/agressive-inlining/pypy/jit/metainterp: . test Message-ID: <20090908090021.31526168016@codespeak.net> Author: cfbolz Date: Tue Sep 8 11:00:20 2009 New Revision: 67568 Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/history.py pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_basic.py pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py Log: (pedronis, cfbolz; arigo around): reset counters for bridges as well. bit annoying to test. Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/history.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/history.py Tue Sep 8 11:00:20 2009 @@ -788,6 +788,7 @@ compiled_count = 0 enter_count = 0 + aborted_count = 0 def __init__(self): self.loops = [] Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py Tue Sep 8 11:00:20 2009 @@ -1252,6 +1252,7 @@ if len(self.history.operations) > warmrunnerstate.trace_limit: self.history = history.BlackHole(self.cpu) if not we_are_translated(): + self.staticdata.stats.aborted_count += 1 history.log.event('ABORTING TRACING' + self.history.extratext) elif DEBUG: debug_print('~~~ ABORTING TRACING', self.history.extratext) @@ -1306,7 +1307,7 @@ return self.designate_target_loop(gmp) def handle_guard_failure(self, exec_result, key): - self.initialize_state_from_guard_failure(exec_result) + resumedescr = self.initialize_state_from_guard_failure(exec_result) assert isinstance(key, compile.ResumeGuardDescr) top_history = key.find_toplevel_history() source_loop = top_history.source_link @@ -1316,12 +1317,18 @@ self.resumekey = key self.seen_can_enter_jit = False guard_op = key.get_guard_op() + started_as_blackhole = self.is_blackholing() try: self.prepare_resume_from_failure(guard_op.opnum) self.interpret() assert False, "should always raise" except GenerateMergePoint, gmp: return self.designate_target_loop(gmp) + except self.staticdata.ContinueRunningNormally: + if not started_as_blackhole: + warmrunnerstate = self.staticdata.state + warmrunnerstate.reset_counter_from_failure(resumedescr) + raise def forget_consts(self, boxes, startindex=0): for i in range(startindex, len(boxes)): @@ -1556,6 +1563,7 @@ # the BlackHole is invalid because it doesn't start with # guard_failure.key.guard_op.suboperations, but that's fine self.rebuild_state_after_failure(resumedescr, guard_failure.args) + return resumedescr def initialize_virtualizable(self, original_boxes): vinfo = self.staticdata.virtualizable_info Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_basic.py Tue Sep 8 11:00:20 2009 @@ -50,6 +50,8 @@ assert get_stats().enter_count <= count def check_jumps(self, maxcount): assert get_stats().exec_jumps <= maxcount + def check_aborted_count(self, maxcount): + assert get_stats().aborted_count == maxcount def meta_interp(self, *args, **kwds): kwds['CPUClass'] = self.CPUClass Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Tue Sep 8 11:00:20 2009 @@ -213,55 +213,58 @@ res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) assert res == 0 + def check_max_trace_length(self, length): + for loop in get_stats().loops: + assert len(loop.operations) <= length + 5 # because we only check once per metainterp bytecode + for op in loop.operations: + if op.is_guard(): + assert len(op.suboperations) <= length + 5 + def test_inline_trace_limit(self): - from pypy.rpython.annlowlevel import hlstr - def p(code, pc): - code = hlstr(code) - return "%s %d %s" % (code, pc, code[pc]) - def c(code, pc): - return "l" not in hlstr(code) - myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], - get_printable_location=p, can_inline=c) + myjitdriver = JitDriver(greens=[], reds=['n']) def recursive(n): if n > 0: return recursive(n - 1) + 1 return 0 - def f(code, n): + def loop(n): myjitdriver.set_param("threshold", 10) pc = 0 - while pc < len(code): - - myjitdriver.jit_merge_point(n=n, code=code, pc=pc) - op = code[pc] - if op == "-": - n -= 1 - elif op == "r": - n = recursive(n) - elif op == "i": - if n % 5 == 1: - return n - elif op == "l": - if n > 0: - myjitdriver.can_enter_jit(n=n, code=code, pc=0) - pc = 0 - continue - else: - assert 0 - pc += 1 + while n: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + n = recursive(n) + n -= 1 return n - def main(n): - if n < 0: - code = "--" - else: - code = "r-l" - return f(code, n) - print main(100) TRACE_LIMIT = 66 - res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT) + res = self.meta_interp(loop, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT) assert res == 0 - for loop in get_stats().loops: - assert len(loop.operations) <= TRACE_LIMIT + 5 # because we only check once per metainterp bytecode - self.check_enter_count(27) # maybe + self.check_max_trace_length(TRACE_LIMIT) + self.check_enter_count(15) # maybe + self.check_aborted_count(7) + + def test_trace_limit_bridge(self): + def recursive(n): + if n > 0: + return recursive(n - 1) + 1 + return 0 + myjitdriver = JitDriver(greens=[], reds=['n']) + def loop(n): + myjitdriver.set_param("threshold", 4) + myjitdriver.set_param("trace_eagerness", 2) + while n: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + if n % 5 == 0: + n -= 1 + if n < 50: + n = recursive(n) + n -= 1 + TRACE_LIMIT = 20 + res = self.meta_interp(loop, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT) + self.check_max_trace_length(TRACE_LIMIT) + self.check_aborted_count(8) + self.check_enter_count_at_most(30) + class TestLLtype(RecursiveTests, LLJitMixin): Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py Tue Sep 8 11:00:20 2009 @@ -871,6 +871,9 @@ key.counter += 1 return key.counter >= self.trace_eagerness + def reset_counter_from_failure(self, key): + key.counter = 0 + def attach_unoptimized_bridge_from_interp(self, greenkey, bridge): greenargs = self.unwrap_greenkey(greenkey) newcell = MachineCodeEntryPoint(bridge, *greenargs) From cfbolz at codespeak.net Tue Sep 8 11:43:42 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 8 Sep 2009 11:43:42 +0200 (CEST) Subject: [pypy-svn] r67569 - pypy/branch/agressive-inlining/pypy/jit/metainterp Message-ID: <20090908094342.0267116801B@codespeak.net> Author: cfbolz Date: Tue Sep 8 11:43:40 2009 New Revision: 67569 Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py Log: (pedronis, cfbolz): fix translation Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py Tue Sep 8 11:43:40 2009 @@ -1307,6 +1307,7 @@ return self.designate_target_loop(gmp) def handle_guard_failure(self, exec_result, key): + from pypy.jit.metainterp.warmspot import ContinueRunningNormallyBase resumedescr = self.initialize_state_from_guard_failure(exec_result) assert isinstance(key, compile.ResumeGuardDescr) top_history = key.find_toplevel_history() @@ -1324,7 +1325,7 @@ assert False, "should always raise" except GenerateMergePoint, gmp: return self.designate_target_loop(gmp) - except self.staticdata.ContinueRunningNormally: + except ContinueRunningNormallyBase: if not started_as_blackhole: warmrunnerstate = self.staticdata.state warmrunnerstate.reset_counter_from_failure(resumedescr) Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py Tue Sep 8 11:43:40 2009 @@ -121,6 +121,9 @@ class JitException(Exception): _go_through_llinterp_uncaught_ = True # ugh +class ContinueRunningNormallyBase(JitException): + pass + class CannotInlineCanEnterJit(JitException): pass @@ -410,7 +413,7 @@ def __str__(self): return 'ExitFrameWithExceptionRef(%s)' % (self.value,) - class ContinueRunningNormally(JitException): + class ContinueRunningNormally(ContinueRunningNormallyBase): def __init__(self, argboxes): # accepts boxes as argument, but unpacks them immediately # before we raise the exception -- the boxes' values will From fijal at codespeak.net Tue Sep 8 12:27:20 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 8 Sep 2009 12:27:20 +0200 (CEST) Subject: [pypy-svn] r67571 - pypy/branch/less-resumedata/pypy/jit/backend/x86 Message-ID: <20090908102720.EC45E16801E@codespeak.net> Author: fijal Date: Tue Sep 8 12:27:17 2009 New Revision: 67571 Modified: pypy/branch/less-resumedata/pypy/jit/backend/x86/assembler.py Log: Ehem. This piece of code has no tests, so it does not work. I suppose I should write a test that checks if logging works correctly... Fix. Modified: pypy/branch/less-resumedata/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/less-resumedata/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/less-resumedata/pypy/jit/backend/x86/assembler.py Tue Sep 8 12:27:17 2009 @@ -156,7 +156,7 @@ regalloc.walk_operations(tree) else: inputargs = regalloc.inputargs - self.logger.log_operations + self.logger.log_operations(inputargs, guard_op.suboperations, {}) mc = self.mc._mc adr_lea = mc.tell() mc.LEA(esp, fixedsize_ebp_ofs(0)) From fijal at codespeak.net Tue Sep 8 12:51:02 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 8 Sep 2009 12:51:02 +0200 (CEST) Subject: [pypy-svn] r67572 - pypy/branch/less-resumedata/pypy/jit/backend/x86/test Message-ID: <20090908105102.3DCB716801E@codespeak.net> Author: fijal Date: Tue Sep 8 12:51:01 2009 New Revision: 67572 Modified: pypy/branch/less-resumedata/pypy/jit/backend/x86/test/test_virtual.py Log: port 67567 from trunk Modified: pypy/branch/less-resumedata/pypy/jit/backend/x86/test/test_virtual.py ============================================================================== --- pypy/branch/less-resumedata/pypy/jit/backend/x86/test/test_virtual.py (original) +++ pypy/branch/less-resumedata/pypy/jit/backend/x86/test/test_virtual.py Tue Sep 8 12:51:01 2009 @@ -8,6 +8,7 @@ # for the individual tests see # ====> ../../../metainterp/test/test_virtual.py _new_op = 'new_with_vtable' + _field_prefix = 'inst_' @staticmethod def _new(): From fijal at codespeak.net Tue Sep 8 13:48:40 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 8 Sep 2009 13:48:40 +0200 (CEST) Subject: [pypy-svn] r67573 - in pypy/branch/less-resumedata/pypy/module: __builtin__ _pickle_support Message-ID: <20090908114840.901FD16801B@codespeak.net> Author: fijal Date: Tue Sep 8 13:48:39 2009 New Revision: 67573 Modified: pypy/branch/less-resumedata/pypy/module/__builtin__/functional.py pypy/branch/less-resumedata/pypy/module/_pickle_support/__init__.py pypy/branch/less-resumedata/pypy/module/_pickle_support/maker.py Log: Port 67566 from trunk Modified: pypy/branch/less-resumedata/pypy/module/__builtin__/functional.py ============================================================================== --- pypy/branch/less-resumedata/pypy/module/__builtin__/functional.py (original) +++ pypy/branch/less-resumedata/pypy/module/__builtin__/functional.py Tue Sep 8 13:48:39 2009 @@ -395,14 +395,17 @@ descr_next.unwrap_spec = ["self", ObjSpace] def descr___reduce__(self, space): + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + w_new_inst = mod.get('enumerate_new') w_info = space.newtuple([self.w_iter, self.w_index]) - return space.newtuple([space.wrap(_make_enumerate), w_info]) + return space.newtuple([w_new_inst, w_info]) descr___reduce__.unwrap_spec = ["self", ObjSpace] +# exported through _pickle_support def _make_enumerate(space, w_iter, w_index): return space.wrap(W_Enumerate(w_iter, w_index)) -_make_enumerate.unwrap_spec = [ObjSpace, W_Root, W_Root] -_make_enumerate = interp2app(_make_enumerate) W_Enumerate.typedef = TypeDef("enumerate", __new__=interp2app(W_Enumerate.descr___new__.im_func), @@ -448,9 +451,13 @@ descr_next.unwrap_spec = ["self", ObjSpace] def descr___reduce__(self, space): + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + w_new_inst = mod.get('reversed_new') info_w = [self.w_sequence, space.wrap(self.remaining)] w_info = space.newtuple(info_w) - return space.newtuple([space.wrap(_make_reversed), w_info]) + return space.newtuple([w_new_inst, w_info]) descr___reduce__.unwrap_spec = ["self", ObjSpace] W_ReversedIterator.typedef = TypeDef("reversed", @@ -459,14 +466,14 @@ __reduce__=interp2app(W_ReversedIterator.descr___reduce__), ) +# exported through _pickle_support def _make_reversed(space, w_seq, w_remaining): w_type = space.gettypeobject(W_ReversedIterator.typedef) iterator = space.allocate_instance(W_ReversedIterator, w_type) iterator.w_sequence = w_seq iterator.remaining = space.int_w(w_remaining) return space.wrap(iterator) -_make_reversed.unwrap_spec = [ObjSpace, W_Root, W_Root] -_make_reversed = interp2app(_make_reversed) + class W_XRange(Wrappable): Modified: pypy/branch/less-resumedata/pypy/module/_pickle_support/__init__.py ============================================================================== --- pypy/branch/less-resumedata/pypy/module/_pickle_support/__init__.py (original) +++ pypy/branch/less-resumedata/pypy/module/_pickle_support/__init__.py Tue Sep 8 13:48:39 2009 @@ -22,4 +22,6 @@ 'xrangeiter_new': 'maker.xrangeiter_new', 'builtin_code': 'maker.builtin_code', 'builtin_function' : 'maker.builtin_function', + 'enumerate_new': 'maker.enumerate_new', + 'reversed_new': 'maker.reversed_new' } Modified: pypy/branch/less-resumedata/pypy/module/_pickle_support/maker.py ============================================================================== --- pypy/branch/less-resumedata/pypy/module/_pickle_support/maker.py (original) +++ pypy/branch/less-resumedata/pypy/module/_pickle_support/maker.py Tue Sep 8 13:48:39 2009 @@ -100,6 +100,17 @@ builtin_function.unwrap_spec = [ObjSpace, str] +def enumerate_new(space, w_iter, w_index): + from pypy.module.__builtin__.functional import _make_enumerate + return _make_enumerate(space, w_iter, w_index) +enumerate_new.unwrap_spec = [ObjSpace, W_Root, W_Root] + +def reversed_new(space, w_seq, w_remaining): + from pypy.module.__builtin__.functional import _make_reversed + return _make_reversed(space, w_seq, w_remaining) +reversed_new.unwrap_spec = [ObjSpace, W_Root, W_Root] + + # ___________________________________________________________________ # Helper functions for internal use From fijal at codespeak.net Tue Sep 8 14:04:24 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 8 Sep 2009 14:04:24 +0200 (CEST) Subject: [pypy-svn] r67574 - pypy/branch/less-resumedata/pypy/jit/metainterp/test Message-ID: <20090908120424.BBA6816801B@codespeak.net> Author: fijal Date: Tue Sep 8 14:04:24 2009 New Revision: 67574 Modified: pypy/branch/less-resumedata/pypy/jit/metainterp/test/oparser.py pypy/branch/less-resumedata/pypy/jit/metainterp/test/test_oparser.py Log: A hack that allows arbitrary strings in debug_merge_points Modified: pypy/branch/less-resumedata/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/less-resumedata/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/less-resumedata/pypy/jit/metainterp/test/oparser.py Tue Sep 8 14:04:24 2009 @@ -145,7 +145,10 @@ argspec = line[num + 1:endnum] if not argspec.strip(): return opnum, [], None - allargs = argspec.split(",") + if opname == 'debug_merge_point': + allargs = [argspec] + else: + allargs = argspec.split(",") args = [] descr = None poss_descr = allargs[-1].strip() @@ -195,8 +198,6 @@ ops = [] newlines = [] for line in lines: - if '#' in line: - line = line[:line.index('#')] # remove comment if not line.strip(): continue # a comment or empty line newlines.append(line) Modified: pypy/branch/less-resumedata/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/branch/less-resumedata/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/branch/less-resumedata/pypy/jit/metainterp/test/test_oparser.py Tue Sep 8 14:04:24 2009 @@ -9,7 +9,6 @@ x = """ [i0, i1] i2 = int_add(i0, i1) - # a comment i3 = int_sub(i2, 3) fail() """ @@ -146,10 +145,12 @@ [] debug_merge_point("info") debug_merge_point('info') + debug_merge_point(' info') ''' loop = parse(x) assert loop.operations[0].args[0]._get_str() == 'info' assert loop.operations[1].args[0]._get_str() == 'info' + assert loop.operations[2].args[0]._get_str() == " info" def test_descr_with_obj_print(): x = ''' From antocuni at codespeak.net Tue Sep 8 14:07:27 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 8 Sep 2009 14:07:27 +0200 (CEST) Subject: [pypy-svn] r67575 - pypy/trunk/pypy/config Message-ID: <20090908120727.078B616801B@codespeak.net> Author: antocuni Date: Tue Sep 8 14:07:27 2009 New Revision: 67575 Modified: pypy/trunk/pypy/config/pypyoption.py Log: don't enable sharingdict on ootype Modified: pypy/trunk/pypy/config/pypyoption.py ============================================================================== --- pypy/trunk/pypy/config/pypyoption.py (original) +++ pypy/trunk/pypy/config/pypyoption.py Tue Sep 8 14:07:27 2009 @@ -400,7 +400,8 @@ # extra optimizations with the JIT if level == 'jit': - config.objspace.std.suggest(withsharingdict=True) + if type_system != 'ootype': + config.objspace.std.suggest(withsharingdict=True) config.objspace.std.suggest(withcelldict=True) From fijal at codespeak.net Tue Sep 8 14:10:53 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 8 Sep 2009 14:10:53 +0200 (CEST) Subject: [pypy-svn] r67576 - pypy/branch/less-resumedata/pypy/jit/metainterp/test Message-ID: <20090908121053.70EC316801E@codespeak.net> Author: fijal Date: Tue Sep 8 14:10:52 2009 New Revision: 67576 Modified: pypy/branch/less-resumedata/pypy/jit/metainterp/test/oparser.py Log: Allow empty args Modified: pypy/branch/less-resumedata/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/less-resumedata/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/less-resumedata/pypy/jit/metainterp/test/oparser.py Tue Sep 8 14:10:52 2009 @@ -97,6 +97,8 @@ return vars def getvar(self, arg): + if not arg: + return ConstInt(0) try: return ConstInt(int(arg)) except ValueError: @@ -163,6 +165,8 @@ try: args.append(self.getvar(arg)) except KeyError: + import pdb + pdb.set_trace() raise ParseError("Unknown var: %s" % arg) if hasattr(descr, '_oparser_uses_descr'): descr._oparser_uses_descr(self, args) From cfbolz at codespeak.net Tue Sep 8 14:30:15 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 8 Sep 2009 14:30:15 +0200 (CEST) Subject: [pypy-svn] r67577 - in pypy/branch/agressive-inlining/pypy/jit/metainterp: . test Message-ID: <20090908123015.440E716801E@codespeak.net> Author: cfbolz Date: Tue Sep 8 14:30:12 2009 New Revision: 67577 Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/history.py pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py Log: (pedronis, cfbolz): make it possible to turn inlining off and on at runtime. Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/history.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/history.py Tue Sep 8 14:30:12 2009 @@ -854,10 +854,9 @@ class Options: logger_noopt = None - def __init__(self, specialize=True, listops=False, inline=False): + def __init__(self, specialize=True, listops=False): self.specialize = specialize self.listops = listops - self.inline = inline def _freeze_(self): return True Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py Tue Sep 8 14:30:12 2009 @@ -645,7 +645,8 @@ @arguments("descr", "varargs") def opimpl_recursive_call(self, calldescr, varargs): - if self.metainterp.staticdata.options.inline: + warmrunnerstate = self.metainterp.staticdata.state + if warmrunnerstate.inlining: num_green_args = self.metainterp.staticdata.num_green_args portal_code = self.metainterp.staticdata.portal_code greenkey = varargs[1:num_green_args + 1] Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Tue Sep 8 14:30:12 2009 @@ -265,6 +265,32 @@ self.check_aborted_count(8) self.check_enter_count_at_most(30) + def test_set_param_inlining(self): + myjitdriver = JitDriver(greens=[], reds=['n', 'recurse']) + def loop(n, recurse=False): + while n: + myjitdriver.jit_merge_point(n=n, recurse=recurse) + n -= 1 + if not recurse: + loop(10, True) + myjitdriver.can_enter_jit(n=n, recurse=recurse) + return n + TRACE_LIMIT = 66 + + def main(inline): + myjitdriver.set_param("threshold", 10) + if inline: + myjitdriver.set_param('inlining', True) + else: + myjitdriver.set_param('inlining', False) + return loop(100) + + res = self.meta_interp(main, [0], optimizer=simple_optimize, trace_limit=TRACE_LIMIT) + self.check_loops(call=1) + + res = self.meta_interp(main, [1], optimizer=simple_optimize, trace_limit=TRACE_LIMIT) + self.check_loops(call=0) + class TestLLtype(RecursiveTests, LLJitMixin): Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py Tue Sep 8 14:30:12 2009 @@ -53,13 +53,14 @@ return jittify_and_run(interp, graph, args, backendopt=backendopt, **kwds) def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False, trace_limit=sys.maxint, - **kwds): + inline=False, **kwds): translator = interp.typer.annotator.translator translator.config.translation.gc = "boehm" warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds) warmrunnerdesc.state.set_param_threshold(3) # for tests warmrunnerdesc.state.set_param_trace_eagerness(2) # for tests warmrunnerdesc.state.set_param_trace_limit(trace_limit) + warmrunnerdesc.state.set_param_inlining(inline) warmrunnerdesc.state.create_tables_now() # for tests if hash_bits: warmrunnerdesc.state.set_param_hash_bits(hash_bits) @@ -735,6 +736,9 @@ def set_param_trace_limit(self, value): self.trace_limit = value + def set_param_inlining(self, value): + self.inlining = value + def set_param_hash_bits(self, value): if value < 1: value = 1 From fijal at codespeak.net Tue Sep 8 14:36:47 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 8 Sep 2009 14:36:47 +0200 (CEST) Subject: [pypy-svn] r67578 - in pypy/trunk/pypy/jit: backend/x86 metainterp/test Message-ID: <20090908123647.9E81616801E@codespeak.net> Author: fijal Date: Tue Sep 8 14:36:46 2009 New Revision: 67578 Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py pypy/trunk/pypy/jit/metainterp/test/oparser.py pypy/trunk/pypy/jit/metainterp/test/test_oparser.py Log: Port 67576, 67574 and 67571 from less-resumedata Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py Tue Sep 8 14:36:46 2009 @@ -156,7 +156,7 @@ regalloc.walk_operations(tree) else: inputargs = regalloc.inputargs - self.logger.log_operations + self.logger.log_operations(inputargs, guard_op.suboperations, {}) mc = self.mc._mc adr_lea = mc.tell() mc.LEA(esp, fixedsize_ebp_ofs(0)) Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/oparser.py Tue Sep 8 14:36:46 2009 @@ -97,6 +97,8 @@ return vars def getvar(self, arg): + if not arg: + return ConstInt(0) try: return ConstInt(int(arg)) except ValueError: @@ -145,7 +147,10 @@ argspec = line[num + 1:endnum] if not argspec.strip(): return opnum, [], None - allargs = argspec.split(",") + if opname == 'debug_merge_point': + allargs = [argspec] + else: + allargs = argspec.split(",") args = [] descr = None poss_descr = allargs[-1].strip() @@ -160,6 +165,8 @@ try: args.append(self.getvar(arg)) except KeyError: + import pdb + pdb.set_trace() raise ParseError("Unknown var: %s" % arg) if hasattr(descr, '_oparser_uses_descr'): descr._oparser_uses_descr(self, args) @@ -195,8 +202,6 @@ ops = [] newlines = [] for line in lines: - if '#' in line: - line = line[:line.index('#')] # remove comment if not line.strip(): continue # a comment or empty line newlines.append(line) Modified: pypy/trunk/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_oparser.py Tue Sep 8 14:36:46 2009 @@ -9,7 +9,6 @@ x = """ [i0, i1] i2 = int_add(i0, i1) - # a comment i3 = int_sub(i2, 3) fail() """ @@ -146,10 +145,12 @@ [] debug_merge_point("info") debug_merge_point('info') + debug_merge_point(' info') ''' loop = parse(x) assert loop.operations[0].args[0]._get_str() == 'info' assert loop.operations[1].args[0]._get_str() == 'info' + assert loop.operations[2].args[0]._get_str() == " info" def test_descr_with_obj_print(): x = ''' From antocuni at codespeak.net Tue Sep 8 14:40:25 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 8 Sep 2009 14:40:25 +0200 (CEST) Subject: [pypy-svn] r67579 - pypy/trunk/pypy/rpython/ootypesystem Message-ID: <20090908124025.B3E8616801B@codespeak.net> Author: antocuni Date: Tue Sep 8 14:40:25 2009 New Revision: 67579 Modified: pypy/trunk/pypy/rpython/ootypesystem/rpbc.py Log: since we have ooisnull nowadays, generate it instead of oononnull+bool_not Modified: pypy/trunk/pypy/rpython/ootypesystem/rpbc.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/rpbc.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/rpbc.py Tue Sep 8 14:40:25 2009 @@ -21,9 +21,7 @@ if robj1 == none_frozen_pbc_repr: return hop.inputconst(ootype.Bool, True) v1 = hop.inputarg(robj1, pos) - v2 = hop.genop('oononnull', [v1], resulttype=ootype.Bool) - v3 = hop.genop('bool_not', [v2], resulttype=ootype.Bool) - return v3 + return hop.genop('ooisnull', [v1], resulttype=ootype.Bool) class FunctionsPBCRepr(AbstractFunctionsPBCRepr): From cfbolz at codespeak.net Tue Sep 8 14:41:56 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 8 Sep 2009 14:41:56 +0200 (CEST) Subject: [pypy-svn] r67580 - pypy/branch/agressive-inlining/pypy/rlib Message-ID: <20090908124156.89D6916801B@codespeak.net> Author: cfbolz Date: Tue Sep 8 14:41:56 2009 New Revision: 67580 Modified: pypy/branch/agressive-inlining/pypy/rlib/jit.py Log: (pedronis, cfbolz): this belongs to the last commit. also set a non-sys.maxint limit on trace length. Modified: pypy/branch/agressive-inlining/pypy/rlib/jit.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/rlib/jit.py (original) +++ pypy/branch/agressive-inlining/pypy/rlib/jit.py Tue Sep 8 14:41:56 2009 @@ -83,7 +83,8 @@ PARAMETERS = {'threshold': 1000, 'trace_eagerness': 200, 'hash_bits': 14, - 'trace_limit': sys.maxint, + 'trace_limit': 10000, + 'inlining': False, } unroll_parameters = unrolling_iterable(PARAMETERS.keys()) From cfbolz at codespeak.net Tue Sep 8 14:42:47 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 8 Sep 2009 14:42:47 +0200 (CEST) Subject: [pypy-svn] r67581 - in pypy/branch/agressive-inlining/pypy: interpreter/test jit/backend/x86 jit/backend/x86/test jit/metainterp jit/metainterp/test module/__builtin__ module/_pickle_support objspace/std rpython/ootypesystem rpython/ootypesystem/test translator translator/goal Message-ID: <20090908124247.D0C0616801B@codespeak.net> Author: cfbolz Date: Tue Sep 8 14:42:47 2009 New Revision: 67581 Modified: pypy/branch/agressive-inlining/pypy/interpreter/test/test_zzpickle_and_slow.py pypy/branch/agressive-inlining/pypy/jit/backend/x86/regalloc.py pypy/branch/agressive-inlining/pypy/jit/backend/x86/test/test_virtual.py pypy/branch/agressive-inlining/pypy/jit/metainterp/codewriter.py pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_virtual.py pypy/branch/agressive-inlining/pypy/module/__builtin__/functional.py pypy/branch/agressive-inlining/pypy/module/_pickle_support/__init__.py pypy/branch/agressive-inlining/pypy/module/_pickle_support/maker.py pypy/branch/agressive-inlining/pypy/objspace/std/dictmultiobject.py pypy/branch/agressive-inlining/pypy/rpython/ootypesystem/ootype.py pypy/branch/agressive-inlining/pypy/rpython/ootypesystem/test/test_ootype.py pypy/branch/agressive-inlining/pypy/translator/driver.py pypy/branch/agressive-inlining/pypy/translator/goal/richards.py Log: merge changes from trunk since r67554 Modified: pypy/branch/agressive-inlining/pypy/interpreter/test/test_zzpickle_and_slow.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/interpreter/test/test_zzpickle_and_slow.py (original) +++ pypy/branch/agressive-inlining/pypy/interpreter/test/test_zzpickle_and_slow.py Tue Sep 8 14:42:47 2009 @@ -369,7 +369,19 @@ result = pickle.loads(pckl) raises(TypeError, len, diter) assert list(diter) == list(result) - + + def test_pickle_reversed(self): + import pickle + r = reversed(tuple(range(10))) + r.next() + r.next() + pickled = pickle.dumps(r) + result = pickle.loads(pickled) + result.next() + r.next() + assert type(r) is type(result) + assert list(r) == list(result) + def test_pickle_enum(self): import pickle e = enumerate(range(10)) Modified: pypy/branch/agressive-inlining/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/backend/x86/regalloc.py Tue Sep 8 14:42:47 2009 @@ -18,6 +18,9 @@ REGS = [eax, ecx, edx, ebx, esi, edi] WORD = 4 +class NoVariableToSpill(Exception): + pass + class TempBox(Box): def __init__(self): pass @@ -424,24 +427,30 @@ reg = self.reg_bindings[next] if next in forbidden_vars: continue - if selected_reg is not None and reg is selected_reg: - return next + if selected_reg is not None: + if reg is selected_reg: + return next + else: + continue if need_lower_byte and (reg is esi or reg is edi): continue - candidates.append(next) - assert candidates - if len(candidates) == 1: - return candidates[0] - max = 0 - chosen = None - for one in candidates: - next_usage = self._compute_next_usage(one, self.position) - if next_usage == -1: - return one - elif next_usage > max: - next_usage = max - chosen = one - return chosen + return next + raise NoVariableToSpill + # below is the slightly better (even optimal, under certain + # assumptions) algorithm, which is slow. Just go with the + # first hit + #if len(candidates) == 1: + # return candidates[0] + #max = 0 + #chosen = None + #for one in candidates: + # next_usage = self._compute_next_usage(one, self.position) + # if next_usage == -1: + # return one + # elif next_usage > max: + # next_usage = max + # chosen = one + #return chosen def move_variable_away(self, v, prev_loc): reg = None @@ -508,6 +517,7 @@ locs[i] = loc # otherwise we have it saved on stack, so no worry self.free_regs.insert(0, tmpreg) + assert tmpreg not in locs tree.arglocs = locs self.assembler.make_merge_point(tree, locs) self.eventually_free_vars(inputargs) Modified: pypy/branch/agressive-inlining/pypy/jit/backend/x86/test/test_virtual.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/backend/x86/test/test_virtual.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/backend/x86/test/test_virtual.py Tue Sep 8 14:42:47 2009 @@ -8,6 +8,7 @@ # for the individual tests see # ====> ../../../metainterp/test/test_virtual.py _new_op = 'new_with_vtable' + _field_prefix = 'inst_' @staticmethod def _new(): Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/codewriter.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/codewriter.py Tue Sep 8 14:42:47 2009 @@ -756,6 +756,21 @@ self.const_position(cls)) self.codewriter.register_known_ooclass(cls, TYPE) self.register_var(op.result) + # initialize fields with a non-default value: while in ootype it's + # new() that takes care of it, for the jit we explicitly insert the + # corresponding setfields(). This way, the backends don't need to care + # about default fields and moreover the resulting code is more similar + # to the lltype version, so the optimizer doesn't need to take special + # care for them. + if isinstance(TYPE, ootype.Instance): + fields = TYPE._get_fields_with_different_default() + var_inst = self.var_position(op.result) + for name, (T, value) in fields: + descr = self.cpu.fielddescrof(TYPE, name) + self.emit('setfield_gc') + self.emit(var_inst) + self.emit(self.get_position(descr)) + self.emit(self.var_position(Constant(value))) def serialize_op_oonewarray(self, op): ARRAY = op.args[0].value Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_virtual.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_virtual.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_virtual.py Tue Sep 8 14:42:47 2009 @@ -4,6 +4,7 @@ from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin from pypy.rpython.lltypesystem import lltype, rclass from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp import heaptracker class VirtualTests: @@ -272,9 +273,9 @@ return f res = self.meta_interp(f, [21], repeat=7) - # hack - assert (getattr(res, "inst_value", -100) == f(21).value or - getattr(res, "value", -100) == f(21).value) + + fieldname = self._field_prefix + 'value' + assert getattr(res, fieldname, -100) == f(21).value self.check_tree_loop_count(2) # the loop and the entry path # we get: @@ -285,9 +286,6 @@ self.check_enter_count(4) -##class TestOOtype(VirtualTests, OOJitMixin): -## _new = staticmethod(ootype.new) - # ____________________________________________________________ # Run 1: all the tests instantiate a real RPython class @@ -296,10 +294,47 @@ class TestLLtype_Instance(VirtualTests, LLJitMixin): _new_op = 'new_with_vtable' + _field_prefix = 'inst_' + + @staticmethod + def _new(): + return MyClass() + + def test_class_with_default_fields(self): + class MyClass: + value = 2 + + myjitdriver = JitDriver(greens = [], reds = ['n', 'res']) + def f(n): + res = 0 + node = MyClass() + node.value = n # so that the annotator doesn't think that value is constant + while n > 0: + myjitdriver.can_enter_jit(n=n, res=res) + myjitdriver.jit_merge_point(n=n, res=res) + node = MyClass() + res += node.value + n -= 1 + return res + assert f(10) == 20 + res = self.meta_interp(f, [10]) + assert res == 20 + self.check_loop_count(1) + self.check_loops(new=0, new_with_vtable=0, + getfield_gc=0, setfield_gc=0) + + + +class TestOOtype_Instance(VirtualTests, OOJitMixin): + _new_op = 'new_with_vtable' + _field_prefix = 'o' + @staticmethod def _new(): return MyClass() + test_class_with_default_fields = TestLLtype_Instance.test_class_with_default_fields.im_func + # ____________________________________________________________ # Run 2: all the tests use lltype.malloc to make a NODE @@ -308,11 +343,25 @@ class TestLLtype_NotObject(VirtualTests, LLJitMixin): _new_op = 'new' - + _field_prefix = '' + @staticmethod def _new(): return lltype.malloc(NODE) + +OONODE = ootype.Instance('NODE', ootype.ROOT, {}) +OONODE._add_fields({'value': ootype.Signed, + 'extra': ootype.Signed}) + +class TestOOtype_NotObject(VirtualTests, OOJitMixin): + _new_op = 'new_with_vtable' + _field_prefix = '' + + @staticmethod + def _new(): + return ootype.new(OONODE) + # ____________________________________________________________ # Run 3: all the tests use lltype.malloc to make a NODE2 # (same as Run 2 but it is part of the OBJECT hierarchy) @@ -326,6 +375,8 @@ class TestLLtype_Object(VirtualTests, LLJitMixin): _new_op = 'new_with_vtable' + _field_prefix = '' + @staticmethod def _new(): p = lltype.malloc(NODE2) Modified: pypy/branch/agressive-inlining/pypy/module/__builtin__/functional.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/module/__builtin__/functional.py (original) +++ pypy/branch/agressive-inlining/pypy/module/__builtin__/functional.py Tue Sep 8 14:42:47 2009 @@ -394,11 +394,24 @@ return space.newtuple([w_index, w_item]) descr_next.unwrap_spec = ["self", ObjSpace] + def descr___reduce__(self, space): + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + w_new_inst = mod.get('enumerate_new') + w_info = space.newtuple([self.w_iter, self.w_index]) + return space.newtuple([w_new_inst, w_info]) + descr___reduce__.unwrap_spec = ["self", ObjSpace] + +# exported through _pickle_support +def _make_enumerate(space, w_iter, w_index): + return space.wrap(W_Enumerate(w_iter, w_index)) W_Enumerate.typedef = TypeDef("enumerate", __new__=interp2app(W_Enumerate.descr___new__.im_func), __iter__=interp2app(W_Enumerate.descr___iter__), next=interp2app(W_Enumerate.descr_next), + __reduce__=interp2app(W_Enumerate.descr___reduce__), ) @@ -437,11 +450,31 @@ raise OperationError(space.w_StopIteration, space.w_None) descr_next.unwrap_spec = ["self", ObjSpace] + def descr___reduce__(self, space): + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + w_new_inst = mod.get('reversed_new') + info_w = [self.w_sequence, space.wrap(self.remaining)] + w_info = space.newtuple(info_w) + return space.newtuple([w_new_inst, w_info]) + descr___reduce__.unwrap_spec = ["self", ObjSpace] + W_ReversedIterator.typedef = TypeDef("reversed", __iter__=interp2app(W_ReversedIterator.descr___iter__), next=interp2app(W_ReversedIterator.descr_next), + __reduce__=interp2app(W_ReversedIterator.descr___reduce__), ) +# exported through _pickle_support +def _make_reversed(space, w_seq, w_remaining): + w_type = space.gettypeobject(W_ReversedIterator.typedef) + iterator = space.allocate_instance(W_ReversedIterator, w_type) + iterator.w_sequence = w_seq + iterator.remaining = space.int_w(w_remaining) + return space.wrap(iterator) + + class W_XRange(Wrappable): def __init__(self, space, start, len, step): Modified: pypy/branch/agressive-inlining/pypy/module/_pickle_support/__init__.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/module/_pickle_support/__init__.py (original) +++ pypy/branch/agressive-inlining/pypy/module/_pickle_support/__init__.py Tue Sep 8 14:42:47 2009 @@ -22,4 +22,6 @@ 'xrangeiter_new': 'maker.xrangeiter_new', 'builtin_code': 'maker.builtin_code', 'builtin_function' : 'maker.builtin_function', + 'enumerate_new': 'maker.enumerate_new', + 'reversed_new': 'maker.reversed_new' } Modified: pypy/branch/agressive-inlining/pypy/module/_pickle_support/maker.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/module/_pickle_support/maker.py (original) +++ pypy/branch/agressive-inlining/pypy/module/_pickle_support/maker.py Tue Sep 8 14:42:47 2009 @@ -100,6 +100,17 @@ builtin_function.unwrap_spec = [ObjSpace, str] +def enumerate_new(space, w_iter, w_index): + from pypy.module.__builtin__.functional import _make_enumerate + return _make_enumerate(space, w_iter, w_index) +enumerate_new.unwrap_spec = [ObjSpace, W_Root, W_Root] + +def reversed_new(space, w_seq, w_remaining): + from pypy.module.__builtin__.functional import _make_reversed + return _make_reversed(space, w_seq, w_remaining) +reversed_new.unwrap_spec = [ObjSpace, W_Root, W_Root] + + # ___________________________________________________________________ # Helper functions for internal use Modified: pypy/branch/agressive-inlining/pypy/objspace/std/dictmultiobject.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/objspace/std/dictmultiobject.py (original) +++ pypy/branch/agressive-inlining/pypy/objspace/std/dictmultiobject.py Tue Sep 8 14:42:47 2009 @@ -5,6 +5,7 @@ from pypy.rlib.objectmodel import r_dict, we_are_translated from pypy.rlib.jit import purefunction +from pypy.rlib.rweakref import RWeakValueDictionary def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -687,7 +688,6 @@ class SharedStructure(object): def __init__(self, keys=None, length=0, - other_structs=None, last_key=None, back_struct=None): if keys is None: @@ -695,20 +695,18 @@ self.keys = keys self.length = length self.back_struct = back_struct - if other_structs is None: - other_structs = {} + other_structs = RWeakValueDictionary(SharedStructure) self.other_structs = other_structs self.last_key = last_key if last_key is not None: assert back_struct is not None - self.propagating = False def new_structure(self, added_key): keys = self.keys.copy() keys[added_key] = len(self.keys) new_structure = SharedStructure(keys, self.length + 1, - {}, added_key, self) - self.other_structs[added_key] = new_structure + added_key, self) + self.other_structs.set(added_key, new_structure) return new_structure def lookup_position(self, key): @@ -725,7 +723,6 @@ class State(object): def __init__(self, space): self.empty_structure = SharedStructure() - self.empty_structure.propagating = True class SharedDictImplementation(DictImplementation): @@ -762,13 +759,9 @@ if i != -1: self.entries[i] = w_value return self - if not self.structure.propagating: - return self._as_rdict(as_strdict=True).setitem_str(w_key, w_value) - new_structure = self.structure.other_structs.get(key, None) + new_structure = self.structure.other_structs.get(key) if new_structure is None: new_structure = self.structure.new_structure(key) - else: - new_structure.propagating = True self.entries.append(w_value) assert self.structure.length + 1 == new_structure.length self.structure = new_structure Modified: pypy/branch/agressive-inlining/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/branch/agressive-inlining/pypy/rpython/ootypesystem/ootype.py Tue Sep 8 14:42:47 2009 @@ -258,6 +258,14 @@ graphs.update(SUBTYPE._lookup_graphs(meth_name)) return graphs + def _get_fields_with_different_default(self): + fields = [] + example = self._example() + for field in self._allfields().iteritems(): + name, (T, value) = field + if T._defl() != value: + fields.append(field) + return fields class SpecializableType(OOType): Modified: pypy/branch/agressive-inlining/pypy/rpython/ootypesystem/test/test_ootype.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/rpython/ootypesystem/test/test_ootype.py (original) +++ pypy/branch/agressive-inlining/pypy/rpython/ootypesystem/test/test_ootype.py Tue Sep 8 14:42:47 2009 @@ -654,3 +654,11 @@ SM = StaticMethod([], Void) sm = SM._defl() assert not bool(sm) + +def test_get_fields_with_different_default(): + A = Instance("A", ROOT, {"a": (Signed, 3), + "b": (Signed, 0), + "c": (ROOT, ROOT._defl()) + }) + fields = A._get_fields_with_different_default() + assert fields == [("a", (Signed, 3))] Modified: pypy/branch/agressive-inlining/pypy/translator/driver.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/translator/driver.py (original) +++ pypy/branch/agressive-inlining/pypy/translator/driver.py Tue Sep 8 14:42:47 2009 @@ -362,7 +362,7 @@ from pypy.jit.metainterp.warmspot import apply_jit apply_jit(self.translator, policy=self.jitpolicy, debug_level=self.config.translation.jit_debug, - backend_name=self.config.translation.jit_backend) + backend_name=self.config.translation.jit_backend, inline=True) # self.log.info("the JIT compiler was generated") # Modified: pypy/branch/agressive-inlining/pypy/translator/goal/richards.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/translator/goal/richards.py (original) +++ pypy/branch/agressive-inlining/pypy/translator/goal/richards.py Tue Sep 8 14:42:47 2009 @@ -6,6 +6,8 @@ # Java version: Copyright (C) 1995 Sun Microsystems, Inc. # Translation from C++, Mario Wolczko # Outer loop added by Alex Jacoby +import pypyjit +pypyjit.set_param(trace_limit=2000) # Task IDs I_IDLE = 1 From fijal at codespeak.net Tue Sep 8 15:47:54 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 8 Sep 2009 15:47:54 +0200 (CEST) Subject: [pypy-svn] r67582 - pypy/trunk/pypy/interpreter Message-ID: <20090908134754.4B50716801B@codespeak.net> Author: fijal Date: Tue Sep 8 15:47:52 2009 New Revision: 67582 Modified: pypy/trunk/pypy/interpreter/function.py Log: Promote code on different kinds of calls too Modified: pypy/trunk/pypy/interpreter/function.py ============================================================================== --- pypy/trunk/pypy/interpreter/function.py (original) +++ pypy/trunk/pypy/interpreter/function.py Tue Sep 8 15:47:52 2009 @@ -39,11 +39,11 @@ def call_args(self, args): # delegate activation to code - return self.code.funcrun(self, args) + return self.getcode().funcrun(self, args) def call_obj_args(self, w_obj, args): # delegate activation to code - return self.code.funcrun_obj(self, w_obj, args) + return self.getcode().funcrun_obj(self, w_obj, args) def getcode(self): return hint(self.code, promote=True) From fijal at codespeak.net Tue Sep 8 16:06:22 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 8 Sep 2009 16:06:22 +0200 (CEST) Subject: [pypy-svn] r67583 - pypy/trunk/pypy/objspace/std Message-ID: <20090908140622.4625316801B@codespeak.net> Author: fijal Date: Tue Sep 8 16:06:21 2009 New Revision: 67583 Modified: pypy/trunk/pypy/objspace/std/typeobject.py Log: Those fields are immutable Modified: pypy/trunk/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/pypy/objspace/std/typeobject.py Tue Sep 8 16:06:21 2009 @@ -50,7 +50,10 @@ lazyloaders = {} # can be overridden by specific instances version_tag = None - _immutable_fields_ = ["__flags__"] + _immutable_fields_ = ["__flags__", + 'needsdel', + 'weakrefable', + 'hasdict'] # for config.objspace.std.getattributeshortcut # (False is a conservative default, fixed during real usage) From pedronis at codespeak.net Tue Sep 8 16:08:38 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 8 Sep 2009 16:08:38 +0200 (CEST) Subject: [pypy-svn] r67584 - pypy/branch/agressive-inlining/pypy/jit/metainterp Message-ID: <20090908140838.3E5B716801D@codespeak.net> Author: pedronis Date: Tue Sep 8 16:08:37 2009 New Revision: 67584 Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py Log: fix :( Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/warmspot.py Tue Sep 8 16:08:37 2009 @@ -26,7 +26,9 @@ # ____________________________________________________________ # Bootstrapping -def apply_jit(translator, backend_name="auto", debug_level="steps", **kwds): +def apply_jit(translator, backend_name="auto", debug_level="steps", + inline=False, + **kwds): if 'CPUClass' not in kwds: from pypy.jit.backend.detect_cpu import getcpuclass kwds['CPUClass'] = getcpuclass(backend_name) @@ -38,9 +40,9 @@ warmrunnerdesc = WarmRunnerDesc(translator, translate_support_code=True, listops=True, - #inline=True, profile=profile, **kwds) + warmrunnerdesc.state.set_param_inlining(inline) warmrunnerdesc.finish() translator.warmrunnerdesc = warmrunnerdesc # for later debugging From fijal at codespeak.net Tue Sep 8 17:31:50 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 8 Sep 2009 17:31:50 +0200 (CEST) Subject: [pypy-svn] r67585 - pypy/trunk/pypy/interpreter/test Message-ID: <20090908153150.293AE168020@codespeak.net> Author: fijal Date: Tue Sep 8 17:31:49 2009 New Revision: 67585 Modified: pypy/trunk/pypy/interpreter/test/test_compiler.py Log: (fijal, gutworth) * Kill 2.3 compatibility * Make sure that we correctly check for error on different python versions Modified: pypy/trunk/pypy/interpreter/test/test_compiler.py ============================================================================== --- pypy/trunk/pypy/interpreter/test/test_compiler.py (original) +++ pypy/trunk/pypy/interpreter/test/test_compiler.py Tue Sep 8 17:31:49 2009 @@ -641,21 +641,17 @@ def setup_method(self, method): self.compiler = CPythonCompiler(self.space) - _unicode_error_kind = "w_SyntaxError" - - if sys.version_info < (2, 4): - def skip_on_2_3(self): - py.test.skip("syntax not supported by the CPython 2.3 compiler") - test_unicodeliterals = skip_on_2_3 - test_none_assignment = skip_on_2_3 - test_import = skip_on_2_3 - elif sys.version_info < (2, 5): + if sys.version_info < (2, 5): def skip_on_2_4(self): py.test.skip("syntax not supported by the CPython 2.4 compiler") _unicode_error_kind = "w_UnicodeError" test_continue_in_nested_finally = skip_on_2_4 test_try_except_finally = skip_on_2_4 test_yield_in_finally = skip_on_2_4 + elif sys.version_info < (2, 6): + _unicode_error_kind = "w_UnicodeDecodeError" + else: + _unicode_error_kind = "w_SyntaxError" class TestPythonAstCompiler_25_grammar(BaseTestCompiler): def setup_method(self, method): From pedronis at codespeak.net Wed Sep 9 15:34:08 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 9 Sep 2009 15:34:08 +0200 (CEST) Subject: [pypy-svn] r67586 - pypy/branch/agressive-inlining/pypy/jit/metainterp/test Message-ID: <20090909133408.8348416801E@codespeak.net> Author: pedronis Date: Wed Sep 9 15:34:05 2009 New Revision: 67586 Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Log: (micke, pedronis) this test fails because exception handling isn't recursion aware Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Wed Sep 9 15:34:05 2009 @@ -213,6 +213,51 @@ res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) assert res == 0 + @py.test.mark.xfail + def test_exception_in_inlined_function(self): + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "l" not in hlstr(code) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], + get_printable_location=p, can_inline=c) + + class Exc(Exception): + pass + + def f(code, n): + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(n=n, code=code, pc=pc) + op = code[pc] + if op == "-": + n -= 1 + elif op == "c": + try: + n = f("---i---", n) + except Exc: + pass + elif op == "i": + if n % 5 == 1: + raise Exc + elif op == "l": + if n > 0: + myjitdriver.can_enter_jit(n=n, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return n + def main(n): + return f("c-l", n) + print main(100) + res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + assert res == 0 + def check_max_trace_length(self, length): for loop in get_stats().loops: assert len(loop.operations) <= length + 5 # because we only check once per metainterp bytecode From afa at codespeak.net Wed Sep 9 16:09:29 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Wed, 9 Sep 2009 16:09:29 +0200 (CEST) Subject: [pypy-svn] r67587 - pypy/branch/windowserror Message-ID: <20090909140929.97BE116801E@codespeak.net> Author: afa Date: Wed Sep 9 16:09:29 2009 New Revision: 67587 Added: pypy/branch/windowserror/ - copied from r67586, pypy/trunk/ Log: A branch to support WindowsError in RPython: today, raising a WindowsError in RPython actually sets an OSError which errno attribute is set to the value of GetLastError(). This is a problem at least in os.path.abspath, which expects WindowsError, and for py.path.local.check(), which relies on the exception errno. For example, today we have: >>>> os.path.abspath("x"*300) # should not fail OSError: [Errno 183] Unknown error >>>> os.stat("aaaa/bbbb") # expected: WindowsError(winerror=3, errno=2) OSError: [Errno 3] No such process From fijal at codespeak.net Wed Sep 9 16:48:13 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 9 Sep 2009 16:48:13 +0200 (CEST) Subject: [pypy-svn] r67588 - pypy/branch/less-resumedata Message-ID: <20090909144813.D9AA616801E@codespeak.net> Author: fijal Date: Wed Sep 9 16:48:11 2009 New Revision: 67588 Removed: pypy/branch/less-resumedata/ Log: Remove branch thay I have no idea how to proceed with From afa at codespeak.net Wed Sep 9 17:23:51 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Wed, 9 Sep 2009 17:23:51 +0200 (CEST) Subject: [pypy-svn] r67589 - pypy/branch/windowserror/pypy/module/posix/test Message-ID: <20090909152351.ACB0316801E@codespeak.net> Author: afa Date: Wed Sep 9 17:23:47 2009 New Revision: 67589 Modified: pypy/branch/windowserror/pypy/module/posix/test/test_posix2.py Log: WIP: a failing test Modified: pypy/branch/windowserror/pypy/module/posix/test/test_posix2.py ============================================================================== --- pypy/branch/windowserror/pypy/module/posix/test/test_posix2.py (original) +++ pypy/branch/windowserror/pypy/module/posix/test/test_posix2.py Wed Sep 9 17:23:47 2009 @@ -129,6 +129,19 @@ assert st.st_mtime == 42.1 assert st.st_ctime == 43 + def test_stat_exception(self): + import sys, errno + try: + self.posix.stat("nonexistentdir/nonexistentfile") + except OSError, e: + assert e.errno == errno.ENOENT + # On Windows, when the parent directory does not exist, + # the winerror is 3 (cannot find the path specified) + # instead of 2 (cannot find the file specified) + if sys.platform == 'win32': + assert isinstance(e, WindowsError) + assert e.winerror == 3 + def test_pickle(self): import pickle, os st = self.posix.stat(os.curdir) From pedronis at codespeak.net Wed Sep 9 17:34:45 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 9 Sep 2009 17:34:45 +0200 (CEST) Subject: [pypy-svn] r67590 - pypy/branch/agressive-inlining/pypy/jit/metainterp/test Message-ID: <20090909153445.9688B16801E@codespeak.net> Author: pedronis Date: Wed Sep 9 17:34:45 2009 New Revision: 67590 Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Log: (micke, pedronis) a test that fails if the blackholing call shortcut is turned off Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Wed Sep 9 17:34:45 2009 @@ -258,6 +258,48 @@ res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) assert res == 0 + def test_recurse_during_blackholing(self): + # this passes, if the blackholing short is turned off + # it fails, it is very delicate in terms of parameters, + # bridge/loop creation order + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "l" not in hlstr(code) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], + get_printable_location=p, can_inline=c) + + def f(code, n): + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(n=n, code=code, pc=pc) + op = code[pc] + if op == "-": + n -= 1 + elif op == "c": + if n < 70 and n % 3 == 1: + print "F" + n = f("--", n) + elif op == "l": + if n > 0: + myjitdriver.can_enter_jit(n=n, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return n + def main(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 5) + return f("c-l", n) + expected = main(100) + res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + assert res == expected + def check_max_trace_length(self, length): for loop in get_stats().loops: assert len(loop.operations) <= length + 5 # because we only check once per metainterp bytecode From pedronis at codespeak.net Wed Sep 9 17:43:00 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 9 Sep 2009 17:43:00 +0200 (CEST) Subject: [pypy-svn] r67591 - pypy/branch/agressive-inlining/pypy/jit/metainterp/test Message-ID: <20090909154300.8377716801E@codespeak.net> Author: pedronis Date: Wed Sep 9 17:43:00 2009 New Revision: 67591 Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Log: fix the comment Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Wed Sep 9 17:43:00 2009 @@ -259,7 +259,7 @@ assert res == 0 def test_recurse_during_blackholing(self): - # this passes, if the blackholing short is turned off + # this passes, if the blackholing shortcut for calls is turned off # it fails, it is very delicate in terms of parameters, # bridge/loop creation order from pypy.rpython.annlowlevel import hlstr From afa at codespeak.net Wed Sep 9 17:50:12 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Wed, 9 Sep 2009 17:50:12 +0200 (CEST) Subject: [pypy-svn] r67592 - pypy/branch/windowserror/pypy/interpreter Message-ID: <20090909155012.022E516801E@codespeak.net> Author: afa Date: Wed Sep 9 17:50:12 2009 New Revision: 67592 Modified: pypy/branch/windowserror/pypy/interpreter/error.py Log: wrap_oserror now recognizes WindowsError and raises OperationError accordingly. Previous test passes Modified: pypy/branch/windowserror/pypy/interpreter/error.py ============================================================================== --- pypy/branch/windowserror/pypy/interpreter/error.py (original) +++ pypy/branch/windowserror/pypy/interpreter/error.py Wed Sep 9 17:50:12 2009 @@ -262,8 +262,33 @@ # 31: ANSI color code "red" ansi_print(text, esc="31", file=file, newline=newline) +try: + WindowsError +except NameError: + _WINDOWS = False +else: + _WINDOWS = True + + def wrap_windowserror(space, e): + from pypy.rlib import rwin32 + + winerror = e.winerror + try: + msg = rwin32.FormatError(winerror) + except ValueError: + msg = 'Windows Error %d' % winerror + exc = space.w_WindowsError + w_error = space.call_function(exc, + space.wrap(winerror), + space.wrap(msg)) + return OperationError(exc, w_error) + def wrap_oserror(space, e, exception_name='w_OSError'): assert isinstance(e, OSError) + + if _WINDOWS and isinstance(e, WindowsError): + return wrap_windowserror(space, e) + errno = e.errno try: msg = os.strerror(errno) From afa at codespeak.net Wed Sep 9 17:57:43 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Wed, 9 Sep 2009 17:57:43 +0200 (CEST) Subject: [pypy-svn] r67593 - pypy/branch/windowserror/pypy/translator/c/test Message-ID: <20090909155743.B69D616801E@codespeak.net> Author: afa Date: Wed Sep 9 17:57:43 2009 New Revision: 67593 Modified: pypy/branch/windowserror/pypy/translator/c/test/test_extfunc.py Log: Next test to pass: translation fails. Modified: pypy/branch/windowserror/pypy/translator/c/test/test_extfunc.py ============================================================================== --- pypy/branch/windowserror/pypy/translator/c/test/test_extfunc.py (original) +++ pypy/branch/windowserror/pypy/translator/c/test/test_extfunc.py Wed Sep 9 17:57:43 2009 @@ -173,6 +173,19 @@ if has_blocks: assert res[4] == os.stat(filename).st_blocks +def test_os_stat_raises_winerror(): + if sys.platform != 'win32': + py.test.skip("no WindowsError on this platform") + def call_stat(): + try: + os.stat("nonexistentdir/nonexistentfile") + except WindowsError, e: + return e.winerror, e.errno + f = compile(call_stat, []) + res = f() + expected = call_stat() + assert res == expected + def test_os_fstat(): if os.environ.get('PYPY_CC', '').startswith('tcc'): py.test.skip("segfault with tcc :-(") From antocuni at codespeak.net Wed Sep 9 18:04:01 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 9 Sep 2009 18:04:01 +0200 (CEST) Subject: [pypy-svn] r67594 - pypy/trunk/pypy/translator/jvm Message-ID: <20090909160401.20ABF16801E@codespeak.net> Author: antocuni Date: Wed Sep 9 18:04:01 2009 New Revision: 67594 Modified: pypy/trunk/pypy/translator/jvm/cmpopcodes.py Log: implement ooisnull for the jvm backend Modified: pypy/trunk/pypy/translator/jvm/cmpopcodes.py ============================================================================== --- pypy/trunk/pypy/translator/jvm/cmpopcodes.py (original) +++ pypy/trunk/pypy/translator/jvm/cmpopcodes.py Wed Sep 9 18:04:01 2009 @@ -1,6 +1,6 @@ from pypy.translator.jvm.typesystem import \ IFLT, IFLE, IFEQ, IFNE, IFGT, IFGE, \ - IFNONNULL, IF_ACMPEQ, GOTO, ICONST, \ + IFNONNULL, IFNULL, IF_ACMPEQ, GOTO, ICONST, \ DCONST_0, DCMPG, LCONST_0, LCMP, \ IF_ICMPLT, IF_ICMPLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPGT, IF_ICMPGE, \ PYPYUINTCMP, PYPYULONGCMP @@ -52,6 +52,7 @@ # Double operand entries: 'oononnull': [IFNONNULL], + 'ooisnull': [IFNULL], 'oois': [IF_ACMPEQ], 'unichar_eq': [IF_ICMPEQ], From afa at codespeak.net Wed Sep 9 18:08:41 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Wed, 9 Sep 2009 18:08:41 +0200 (CEST) Subject: [pypy-svn] r67595 - in pypy/branch/windowserror/pypy: annotation rpython translator/c/test Message-ID: <20090909160841.8552716801E@codespeak.net> Author: afa Date: Wed Sep 9 18:08:40 2009 New Revision: 67595 Modified: pypy/branch/windowserror/pypy/annotation/builtin.py pypy/branch/windowserror/pypy/annotation/classdef.py pypy/branch/windowserror/pypy/rpython/rbuiltin.py pypy/branch/windowserror/pypy/translator/c/test/test_extfunc.py Log: Provide specific annotation for WindowsError.__init__. The previous test passes. Modified: pypy/branch/windowserror/pypy/annotation/builtin.py ============================================================================== --- pypy/branch/windowserror/pypy/annotation/builtin.py (original) +++ pypy/branch/windowserror/pypy/annotation/builtin.py Wed Sep 9 18:08:40 2009 @@ -270,6 +270,9 @@ def OSError_init(s_self, *args): pass +def WindowsError_init(s_self, *args): + pass + def termios_error_init(s_self, *args): pass @@ -386,6 +389,15 @@ BUILTIN_ANALYZERS[getattr(OSError.__init__, 'im_func', OSError.__init__)] = ( OSError_init) +try: + WindowsError +except NameError: + pass +else: + BUILTIN_ANALYZERS[getattr(WindowsError.__init__, 'im_func', + WindowsError.__init__)] = ( + WindowsError_init) + BUILTIN_ANALYZERS[sys.getdefaultencoding] = conf try: import unicodedata Modified: pypy/branch/windowserror/pypy/annotation/classdef.py ============================================================================== --- pypy/branch/windowserror/pypy/annotation/classdef.py (original) +++ pypy/branch/windowserror/pypy/annotation/classdef.py Wed Sep 9 18:08:40 2009 @@ -442,6 +442,13 @@ } try: + WindowsError +except NameError: + pass +else: + FORCE_ATTRIBUTES_INTO_CLASSES[WindowsError] = {'winerror': SomeInteger()} + +try: import termios except ImportError: pass Modified: pypy/branch/windowserror/pypy/rpython/rbuiltin.py ============================================================================== --- pypy/branch/windowserror/pypy/rpython/rbuiltin.py (original) +++ pypy/branch/windowserror/pypy/rpython/rbuiltin.py Wed Sep 9 18:08:40 2009 @@ -268,6 +268,16 @@ v_errno = hop.inputarg(lltype.Signed, arg=1) r_self.setfield(v_self, 'errno', v_errno, hop.llops) +def rtype_WindowsError__init__(hop): + if hop.nb_args == 2: + raise TyperError("WindowsError() should not be called with " + "a single argument") + if hop.nb_args >= 3: + v_self = hop.args_v[0] + r_self = hop.args_r[0] + v_error = hop.inputarg(lltype.Signed, arg=1) + r_self.setfield(v_self, 'winerror', v_error, hop.llops) + def rtype_we_are_translated(hop): hop.exception_cannot_occur() return hop.inputconst(lltype.Bool, True) @@ -318,6 +328,15 @@ BUILTIN_TYPER[getattr(OSError.__init__, 'im_func', OSError.__init__)] = ( rtype_OSError__init__) +try: + WindowsError +except NameError: + pass +else: + BUILTIN_TYPER[ + getattr(WindowsError.__init__, 'im_func', WindowsError.__init__)] = ( + rtype_WindowsError__init__) + BUILTIN_TYPER[object.__init__] = rtype_object__init__ # annotation of low-level types Modified: pypy/branch/windowserror/pypy/translator/c/test/test_extfunc.py ============================================================================== --- pypy/branch/windowserror/pypy/translator/c/test/test_extfunc.py (original) +++ pypy/branch/windowserror/pypy/translator/c/test/test_extfunc.py Wed Sep 9 18:08:40 2009 @@ -180,7 +180,7 @@ try: os.stat("nonexistentdir/nonexistentfile") except WindowsError, e: - return e.winerror, e.errno + return e.winerror f = compile(call_stat, []) res = f() expected = call_stat() From cfbolz at codespeak.net Wed Sep 9 18:14:24 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 9 Sep 2009 18:14:24 +0200 (CEST) Subject: [pypy-svn] r67596 - in pypy/branch/agressive-inlining/pypy/jit/metainterp: . test Message-ID: <20090909161424.C1984168021@codespeak.net> Author: cfbolz Date: Wed Sep 9 18:14:24 2009 New Revision: 67596 Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Log: Make the handling of in_recursion a lot more symmetric, by putting it into newframe and popframe methods on the MetaInterp. This fixes the exception test. Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/pyjitpl.py Wed Sep 9 18:14:24 2009 @@ -651,7 +651,6 @@ portal_code = self.metainterp.staticdata.portal_code greenkey = varargs[1:num_green_args + 1] if self.metainterp.staticdata.state.can_inline_callable(greenkey): - self.metainterp.in_recursion += 1 return self.perform_call(portal_code, varargs[1:]) return self.execute_with_exc(rop.CALL, varargs, descr=calldescr) @@ -1129,14 +1128,20 @@ def newframe(self, jitcode): if not we_are_translated(): self._debug_history.append(['enter', jitcode, None]) + if jitcode is self.staticdata.portal_code: + self.in_recursion += 1 f = MIFrame(self, jitcode) self.framestack.append(f) return f - def finishframe(self, resultbox): + def popframe(self): frame = self.framestack.pop() if frame.jitcode is self.staticdata.portal_code: self.in_recursion -= 1 + return frame + + def finishframe(self, resultbox): + frame = self.popframe() if not we_are_translated(): self._debug_history.append(['leave', frame.jitcode, None]) if self.framestack: @@ -1179,11 +1184,29 @@ return True if not we_are_translated(): self._debug_history.append(['leave_exc', frame.jitcode, None]) - self.framestack.pop() + self.popframe() if not self.is_blackholing(): self.compile_exit_frame_with_exception(excvaluebox) raise self.staticdata.ExitFrameWithExceptionRef(self.cpu, excvaluebox.getref_base()) + def check_recursion_invariant(self): + in_recursion = -1 + for frame in self.framestack: + jitcode = frame.jitcode + if jitcode is self.staticdata.portal_code: + in_recursion += 1 + if in_recursion != self.in_recursion: + print "in_recursion problem!!!" + print in_recursion, self.in_recursion + for frame in self.framestack: + jitcode = frame.jitcode + if jitcode is self.staticdata.portal_code: + print "P", + else: + print " ", + print jitcode.name + raise Exception + def raise_overflow_error(self): etype, evalue = self.cpu.get_overflow_error() return self.finishframe_exception( @@ -1272,6 +1295,8 @@ while True: self.framestack[-1].run_one_step() self.switch_to_blackhole_if_trace_too_long() + if not we_are_translated(): + self.check_recursion_invariant() finally: if self.is_blackholing(): self.staticdata.profiler.end_blackhole() @@ -1522,7 +1547,7 @@ *args[1:]) def initialize_state_from_start(self, *args): - self.in_recursion = 0 + self.in_recursion = -1 # always one portal around self.staticdata._setup_once() self.staticdata.profiler.start_tracing() self.create_empty_history() @@ -1539,7 +1564,7 @@ def initialize_state_from_guard_failure(self, guard_failure): # guard failure: rebuild a complete MIFrame stack - self.in_recursion = 0 + self.in_recursion = -1 # always one portal around resumedescr = guard_failure.descr assert isinstance(resumedescr, compile.ResumeGuardDescr) warmrunnerstate = self.staticdata.state @@ -1666,10 +1691,7 @@ jitcode, pc, exception_target = resumereader.consume_frame_info() env = resumereader.consume_boxes() f = self.newframe(jitcode) - if jitcode is self.staticdata.portal_code: - self.in_recursion += 1 f.setup_resume_at_op(pc, exception_target, env) - self.in_recursion -= 1 # always one portal around def check_synchronized_virtualizable(self): if not we_are_translated(): Modified: pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/agressive-inlining/pypy/jit/metainterp/test/test_recursive.py Wed Sep 9 18:14:24 2009 @@ -213,7 +213,6 @@ res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) assert res == 0 - @py.test.mark.xfail def test_exception_in_inlined_function(self): from pypy.rpython.annlowlevel import hlstr def p(code, pc): @@ -254,9 +253,8 @@ return n def main(n): return f("c-l", n) - print main(100) res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) - assert res == 0 + assert res == main(100) def test_recurse_during_blackholing(self): # this passes, if the blackholing shortcut for calls is turned off From pedronis at codespeak.net Wed Sep 9 19:52:46 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 9 Sep 2009 19:52:46 +0200 (CEST) Subject: [pypy-svn] r67597 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090909175246.C9D14168024@codespeak.net> Author: pedronis Date: Wed Sep 9 19:52:44 2009 New Revision: 67597 Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py pypy/trunk/pypy/jit/metainterp/test/test_oparser.py Log: restore comment support for the benefit of test code, comments are not allowed on debug_merge_point lines Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/oparser.py Wed Sep 9 19:52:44 2009 @@ -165,8 +165,6 @@ try: args.append(self.getvar(arg)) except KeyError: - import pdb - pdb.set_trace() raise ParseError("Unknown var: %s" % arg) if hasattr(descr, '_oparser_uses_descr'): descr._oparser_uses_descr(self, args) @@ -202,6 +200,15 @@ ops = [] newlines = [] for line in lines: + # for simplicity comments are not allowed on + # debug_merge_point lines + if '#' in line and 'debug_merge_point(' not in line: + if line.lstrip()[0] == '#': # comment only + continue + comm = line.rfind('#') + rpar = line.find(')') # assume there's a op(...) + if comm > rpar: + line = line[:comm].rstrip() if not line.strip(): continue # a comment or empty line newlines.append(line) Modified: pypy/trunk/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_oparser.py Wed Sep 9 19:52:44 2009 @@ -8,9 +8,10 @@ def test_basic_parse(): x = """ [i0, i1] + # a comment i2 = int_add(i0, i1) - i3 = int_sub(i2, 3) - fail() + i3 = int_sub(i2, 3) # another comment + fail() # (tricky) """ loop = parse(x) assert len(loop.operations) == 3 @@ -146,11 +147,14 @@ debug_merge_point("info") debug_merge_point('info') debug_merge_point(' info') + debug_merge_point('(stuff) #1') ''' loop = parse(x) assert loop.operations[0].args[0]._get_str() == 'info' assert loop.operations[1].args[0]._get_str() == 'info' assert loop.operations[2].args[0]._get_str() == " info" + assert loop.operations[3].args[0]._get_str() == "(stuff) #1" + def test_descr_with_obj_print(): x = ''' From afa at codespeak.net Wed Sep 9 22:18:16 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Wed, 9 Sep 2009 22:18:16 +0200 (CEST) Subject: [pypy-svn] r67598 - in pypy/trunk/pypy/translator: c c/gcc c/gcc/test c/src platform Message-ID: <20090909201816.7A223168024@codespeak.net> Author: afa Date: Wed Sep 9 22:18:15 2009 New Revision: 67598 Modified: pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py pypy/trunk/pypy/translator/c/gcc/trackgcroot.py pypy/trunk/pypy/translator/c/genc.py pypy/trunk/pypy/translator/c/src/thread_nt.h pypy/trunk/pypy/translator/platform/__init__.py pypy/trunk/pypy/translator/platform/posix.py pypy/trunk/pypy/translator/platform/windows.py Log: Merge asmgcc-mingw32: Support tracgcroot on Windows, when the mingw32 gcc compiler is used. Modified: pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py Wed Sep 9 22:18:15 2009 @@ -7,7 +7,9 @@ from pypy import conftest if sys.platform == 'win32': - py.test.skip("No asmgcc on Windows") + if not ('mingw' in os.popen('gcc --version').read() and + 'GNU' in os.popen('make --version').read()): + py.test.skip("mingw32 and MSYS are required for asmgcc on Windows") class AbstractTestAsmGCRoot: # the asmgcroot gc transformer doesn't generate gc_reload_possibly_moved @@ -30,6 +32,8 @@ config = get_pypy_config(translating=True) config.translation.gc = self.gcpolicy config.translation.gcrootfinder = "asmgcc" + if sys.platform == 'win32': + config.translation.cc = 'mingw32' t = TranslationContext(config=config) self.t = t a = t.buildannotator() @@ -48,7 +52,7 @@ def run(): lines = [] print >> sys.stderr, 'RUN: starting', exe_name - g = os.popen("'%s'" % (exe_name,), 'r') + g = os.popen('"%s"' % (exe_name,), 'r') for line in g: print >> sys.stderr, 'RUN:', line.rstrip() lines.append(line) Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Wed Sep 9 22:18:15 2009 @@ -23,15 +23,16 @@ r_functionstart_darwin = re.compile(r"_(\w+):\s*$") # inside functions -r_label = re.compile(r"([.]?\w+)[:]\s*$") +LABEL = r'([.]?[\w$@]+)' +r_label = re.compile(LABEL+"[:]\s*$") r_globl = re.compile(r"\t[.]globl\t(\w+)\s*$") r_insn = re.compile(r"\t([a-z]\w*)\s") -r_jump = re.compile(r"\tj\w+\s+([.]?[\w$]+)\s*$") +r_jump = re.compile(r"\tj\w+\s+"+LABEL+"\s*$") OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' r_unaryinsn = re.compile(r"\t[a-z]\w*\s+("+OPERAND+")\s*$") r_unaryinsn_star= re.compile(r"\t[a-z]\w*\s+([*]"+OPERAND+")\s*$") -r_jmp_switch = re.compile(r"\tjmp\t[*]([.]?\w+)[(]") -r_jmptable_item = re.compile(r"\t.long\t([.]?\w+)\s*$") +r_jmp_switch = re.compile(r"\tjmp\t[*]"+LABEL+"[(]") +r_jmptable_item = re.compile(r"\t.long\t"+LABEL+"\s*$") r_jmptable_end = re.compile(r"\t.text|\t.section\s+.text") r_binaryinsn = re.compile(r"\t[a-z]\w*\s+("+OPERAND+"),\s*("+OPERAND+")\s*$") LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|\d*[(]%esp[)]" @@ -75,23 +76,22 @@ shapelines = [] shapeofs = 0 def _globalname(name): - if self.format == 'darwin': + if self.format in ('darwin', 'mingw32'): return '_' + name return name def _globl(name): print >> output, "\t.globl %s" % _globalname(name) def _label(name): print >> output, "%s:" % _globalname(name) - def _variant(elf, darwin): - if self.format == 'darwin': - txt = darwin - else: - txt = elf + def _variant(**kwargs): + txt = kwargs[self.format] print >> output, "\t%s" % txt - + print >> output, "\t.text" _globl('pypy_asm_stackwalk') - _variant('.type pypy_asm_stackwalk, @function', '') + _variant(elf='.type pypy_asm_stackwalk, @function', + darwin='', + mingw32='') _label('pypy_asm_stackwalk') print >> output, """\ /* See description in asmgcroot.py */ @@ -114,7 +114,9 @@ popl %eax ret """ - _variant('.size pypy_asm_stackwalk, .-pypy_asm_stackwalk', '') + _variant(elf='.size pypy_asm_stackwalk, .-pypy_asm_stackwalk', + darwin='', + mingw32='') print >> output, '\t.data' print >> output, '\t.align\t4' _globl('__gcmapstart') @@ -135,7 +137,9 @@ print >> output, '\t.long\t%d' % (n,) _globl('__gcmapend') _label('__gcmapend') - _variant('.section\t.rodata', '.const') + _variant(elf='.section\t.rodata', + darwin='.const', + mingw32='') _globl('__gccallshapes') _label('__gccallshapes') output.writelines(shapelines) @@ -188,8 +192,10 @@ if functionlines: yield in_function, functionlines + _find_functions_mingw32 = _find_functions_darwin + def process(self, iterlines, newfile, entrypoint='main', filename='?'): - if self.format == 'darwin': + if self.format in ('darwin', 'mingw32'): entrypoint = '_' + entrypoint for in_function, lines in self.find_functions(iterlines): if in_function: @@ -232,6 +238,9 @@ elif format == 'darwin': match = r_functionstart_darwin.match(lines[0]) funcname = '_'+match.group(1) + elif format == 'mingw32': + match = r_functionstart_darwin.match(lines[0]) + funcname = '_'+match.group(1) else: assert False, "unknown format: %s" % format @@ -738,8 +747,15 @@ if lineoffset >= 0: assert lineoffset in (1,2) return [InsnStackAdjust(-4)] - return [InsnCall(self.currentlineno), - InsnSetLocal('%eax')] # the result is there + insns = [InsnCall(self.currentlineno), + InsnSetLocal('%eax')] # the result is there + if sys.platform == 'win32': + # handle __stdcall calling convention: + # Stack cleanup is performed by the called function, + # Function name is decorated with "@N" where N is the stack size + if match and '@' in target: + insns.append(InsnStackAdjust(int(target.split('@')[1]))) + return insns class UnrecognizedOperation(Exception): @@ -1108,6 +1124,8 @@ break if sys.platform == 'darwin': format = 'darwin' + elif sys.platform == 'win32': + format = 'mingw32' else: format = 'elf' tracker = GcRootTracker(verbose=verbose, shuffle=shuffle, format=format) Modified: pypy/trunk/pypy/translator/c/genc.py ============================================================================== --- pypy/trunk/pypy/translator/c/genc.py (original) +++ pypy/trunk/pypy/translator/c/genc.py Wed Sep 9 22:18:15 2009 @@ -492,8 +492,14 @@ mk.definition('GCMAPFILES', gcmapfiles) mk.definition('OBJECTS', '$(ASMLBLFILES) gcmaptable.s') mk.rule('%.s', '%.c', '$(CC) $(CFLAGS) -frandom-seed=$< -o $@ -S $< $(INCLUDEDIRS)') - mk.rule('%.lbl.s %.gcmap', '%.s', '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -t $< > $*.gcmap') - mk.rule('gcmaptable.s', '$(GCMAPFILES)', '$(PYPYDIR)/translator/c/gcc/trackgcroot.py $(GCMAPFILES) > $@') + if sys.platform == 'win32': + python = sys.executable.replace('\\', '/') + ' ' + else: + python = "" + mk.rule('%.lbl.s %.gcmap', '%.s', + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -t $< > $*.gcmap') + mk.rule('gcmaptable.s', '$(GCMAPFILES)', + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py $(GCMAPFILES) > $@') mk.write() #self.translator.platform, Modified: pypy/trunk/pypy/translator/c/src/thread_nt.h ============================================================================== --- pypy/trunk/pypy/translator/c/src/thread_nt.h (original) +++ pypy/trunk/pypy/translator/c/src/thread_nt.h Wed Sep 9 22:18:15 2009 @@ -61,7 +61,7 @@ return GetCurrentThreadId(); } -static int +static void bootstrap(void *call) { callobj *obj = (callobj*)call; @@ -71,7 +71,6 @@ obj->id = RPyThreadGetIdent(); ReleaseSemaphore(obj->done, 1, NULL); func(); - return 0; } long RPyThreadStart(void (*func)(void)) @@ -130,69 +129,14 @@ /************************************************************/ -typedef PVOID WINAPI interlocked_cmp_xchg_t(PVOID *dest, PVOID exc, PVOID comperand) ; - -/* Sorry mate, but we haven't got InterlockedCompareExchange in Win95! */ -static PVOID WINAPI interlocked_cmp_xchg(PVOID *dest, PVOID exc, PVOID comperand) -{ - static LONG spinlock = 0 ; - PVOID result ; - DWORD dwSleep = 0; - - /* Acqire spinlock (yielding control to other threads if cant aquire for the moment) */ - while(InterlockedExchange(&spinlock, 1)) - { - // Using Sleep(0) can cause a priority inversion. - // Sleep(0) only yields the processor if there's - // another thread of the same priority that's - // ready to run. If a high-priority thread is - // trying to acquire the lock, which is held by - // a low-priority thread, then the low-priority - // thread may never get scheduled and hence never - // free the lock. NT attempts to avoid priority - // inversions by temporarily boosting the priority - // of low-priority runnable threads, but the problem - // can still occur if there's a medium-priority - // thread that's always runnable. If Sleep(1) is used, - // then the thread unconditionally yields the CPU. We - // only do this for the second and subsequent even - // iterations, since a millisecond is a long time to wait - // if the thread can be scheduled in again sooner - // (~100,000 instructions). - // Avoid priority inversion: 0, 1, 0, 1,... - Sleep(dwSleep); - dwSleep = !dwSleep; - } - result = *dest ; - if (result == comperand) - *dest = exc ; - /* Release spinlock */ - spinlock = 0 ; - return result ; -} ; - -static interlocked_cmp_xchg_t *ixchg ; BOOL InitializeNonRecursiveMutex(PNRMUTEX mutex) { - if (!ixchg) - { - /* Sorely, Win95 has no InterlockedCompareExchange API (Win98 has), so we have to use emulation */ - HANDLE kernel = GetModuleHandle("kernel32.dll") ; - if (!kernel || (ixchg = (interlocked_cmp_xchg_t *)GetProcAddress(kernel, "InterlockedCompareExchange")) == NULL) - ixchg = interlocked_cmp_xchg ; - } - mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */ mutex->thread_id = 0 ; mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ; return mutex->hevent != NULL ; /* TRUE if the mutex is created */ } -#ifdef InterlockedCompareExchange -#undef InterlockedCompareExchange -#endif -#define InterlockedCompareExchange(dest,exchange,comperand) (ixchg((dest), (exchange), (comperand))) - VOID DeleteNonRecursiveMutex(PNRMUTEX mutex) { /* No in-use check */ @@ -208,7 +152,7 @@ /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */ if (!wait) { - if (InterlockedCompareExchange((PVOID *)&mutex->owned, (PVOID)0, (PVOID)-1) != (PVOID)-1) + if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1) return WAIT_TIMEOUT ; ret = WAIT_OBJECT_0 ; } Modified: pypy/trunk/pypy/translator/platform/__init__.py ============================================================================== --- pypy/trunk/pypy/translator/platform/__init__.py (original) +++ pypy/trunk/pypy/translator/platform/__init__.py Wed Sep 9 22:18:15 2009 @@ -110,9 +110,9 @@ errorfile = outname.new(ext='errors') errorfile.write(stderr) stderrlines = stderr.splitlines() - for line in stderrlines[:20]: + for line in stderrlines[:50]: log.ERROR(line) - if len(stderrlines) > 20: + if len(stderrlines) > 50: log.ERROR('...') raise CompilationError(stdout, stderr) Modified: pypy/trunk/pypy/translator/platform/posix.py ============================================================================== --- pypy/trunk/pypy/translator/platform/posix.py (original) +++ pypy/trunk/pypy/translator/platform/posix.py Wed Sep 9 22:18:15 2009 @@ -121,6 +121,7 @@ def write(self, f): def write_list(prefix, lst): for i, fn in enumerate(lst): + fn = fn.replace('\\', '\\\\') print >> f, prefix, fn, if i < len(lst)-1: print >> f, '\\' @@ -129,7 +130,7 @@ prefix = ' ' * len(prefix) name, value = self.name, self.value if isinstance(value, str): - f.write('%s = %s\n' % (name, value)) + f.write('%s = %s\n' % (name, value.replace('\\', '\\\\'))) else: write_list('%s =' % (name,), value) if value: @@ -171,7 +172,8 @@ if fpath.dirpath() == self.makefile_dir: return fpath.basename elif fpath.dirpath().dirpath() == self.makefile_dir.dirpath(): - return '../' + fpath.relto(self.makefile_dir.dirpath()) + path = '../' + fpath.relto(self.makefile_dir.dirpath()) + return path.replace('\\', '/') else: return str(fpath) Modified: pypy/trunk/pypy/translator/platform/windows.py ============================================================================== --- pypy/trunk/pypy/translator/platform/windows.py (original) +++ pypy/trunk/pypy/translator/platform/windows.py Wed Sep 9 22:18:15 2009 @@ -281,4 +281,7 @@ def library_dirs_for_libffi(self): return [] - + def _handle_error(self, returncode, stderr, stdout, outname): + # Mingw tools write compilation errors to stdout + super(MingwPlatform, self)._handle_error( + returncode, stderr + stdout, '', outname) From afa at codespeak.net Wed Sep 9 22:19:34 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Wed, 9 Sep 2009 22:19:34 +0200 (CEST) Subject: [pypy-svn] r67599 - pypy/branch/asmgcc-mingw32 Message-ID: <20090909201934.0CF4F168024@codespeak.net> Author: afa Date: Wed Sep 9 22:19:34 2009 New Revision: 67599 Removed: pypy/branch/asmgcc-mingw32/ Log: Kill merged branch From cfbolz at codespeak.net Thu Sep 10 11:45:33 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 11:45:33 +0200 (CEST) Subject: [pypy-svn] r67601 - in pypy/branch/spine-of-frames/pypy/interpreter: . test Message-ID: <20090910094533.2D8DD168024@codespeak.net> Author: cfbolz Date: Thu Sep 10 11:45:31 2009 New Revision: 67601 Modified: pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py Log: (cfbolz, pedronis, micke): Add more tests for frames and the ec. Be more subtle about f_forward handling: Only have f_forward point to virtual frames. Modified: pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py Thu Sep 10 11:45:31 2009 @@ -27,15 +27,9 @@ self.profilefunc = None self.w_profilefuncarg = None - def gettopframe(self): - frame = self.some_frame - if frame is not None: - while frame.f_forward is not None: - frame = frame.f_forward - return frame - def gettopframe_nohidden(self): frame = self.gettopframe() + # I guess this should just use getnextframe_nohidden XXX while frame and frame.hide(): frame = frame.f_back() return frame @@ -66,6 +60,13 @@ # the methods below are used for chaining frames in JIT-friendly way # part of that stuff is obscure + def gettopframe(self): + frame = self.some_frame + if frame is not None: + while frame.f_forward is not None: + frame = frame.f_forward + return frame + def _init_frame_chain(self): # 'some_frame' points to any frame from this thread's frame stack # (although in general it should point to the top one). @@ -87,10 +88,10 @@ +---------------+ | real_frame | +---------------+ - | ^ + | | f_back_some - | | - | | f_forward + | + | | +--------------+ | | virtual frame| | +--------------+ @@ -127,19 +128,29 @@ self.framestackdepth += 1 # frame.f_back_some = self.some_frame - curtopframe = self.gettopframe() - if curtopframe is not None: + if self._we_are_jitted(): + curtopframe = self.gettopframe() + assert curtopframe is not None curtopframe.f_forward = frame - if not self._we_are_jitted(): + else: self.some_frame = frame def _unchain(self, frame): #assert frame is self.gettopframe() --- slowish - f_back = frame.f_back() - if f_back is not None: - f_back.f_forward = None - if not self._we_are_jitted() or self.some_frame is frame: + if self.some_frame is frame: self.some_frame = frame.f_back_some + else: + f_back = frame.f_back() + if f_back is not None: + f_back.f_forward = None + + + #f_back = frame.f_back() + #if f_back is not None: + # f_back.f_forward = None # this is the other one, yes # the goal is to set the forward attr only in the jitted case + #if not self._we_are_jitted() or self.some_frame is frame: + # self.some_frame = frame.f_back_some + self.framestackdepth -= 1 @staticmethod @@ -150,9 +161,11 @@ return back_some if back_some is None: return None - while back_some.f_forward is not frame: - back_some = back_some.f_forward - return back_some + while True: + f_forward = back_some.f_forward + if f_forward is frame or f_forward is None: + return back_some + back_some = f_forward @staticmethod def _force_back_of_frame(frame): Modified: pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py Thu Sep 10 11:45:31 2009 @@ -303,6 +303,64 @@ self._f_forward = frame f_forward = property(_get_f_forward, _set_f_forward) + def test_f_back_no_jit(self): + ec = self.EC() + frame = self.Frame(ec) + frame2 = self.Frame(ec) + frame2.f_back_some = frame + + frame3 = self.Frame(ec) + frame3.f_back_some = frame2 + + assert frame3.f_back() is frame2 + assert frame2.f_back() is frame + assert frame.f_back() is None + + def test_f_back_jit(self): + ec = self.EC() + frame = self.Frame(ec) # real frame + frame2 = self.Frame(ec) # virtual frame + frame2.f_back_some = frame + frame.f_forward = frame2 + + frame3 = self.Frame(ec) # virtual frame + frame3.f_back_some = frame + frame2.f_forward = frame3 + + assert frame3.f_back() is frame2 + assert frame2.f_back() is frame + assert frame.f_back() is None + + frame4 = self.Frame(ec) # real frame again + frame4.f_back_some = frame + assert frame4.f_back() is frame3 + + def test_gettopframe_no_jit(self): + ec = self.EC() + frame = self.Frame(ec) + ec.some_frame = frame + assert ec.gettopframe() is frame + + def test_gettopframe_jit(self): + ec = self.EC() + frame = self.Frame(ec) # real frame + ec.some_frame = frame + assert ec.gettopframe() is frame + + frame2 = self.Frame(ec) # virtual frame + frame2.f_back_some = frame + frame.f_forward = frame2 + assert ec.gettopframe() is frame2 + + frame3 = self.Frame(ec) # virtual frame + frame3.f_back_some = frame + frame2.f_forward = frame3 + assert ec.gettopframe() is frame3 + + frame4 = self.Frame(ec) # real frame again + frame4.f_back_some = frame + ec.some_frame = frame4 + assert ec.gettopframe() is frame4 def test_frame_chain(self): @@ -317,28 +375,40 @@ assert ec.framestackdepth == 1 assert frame.f_back_some is None assert frame.f_forward is None + assert ec.gettopframe() is frame + assert ec._extract_back_from_frame(frame) is None frame2 = self.Frame(ec) ec._chain(frame2) assert ec.some_frame is frame2 assert ec.framestackdepth == 2 assert frame2.f_back_some is frame - assert frame.f_forward is frame2 + assert frame.f_forward is None assert frame2.f_forward is None + assert ec.gettopframe() is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None frame3 = self.Frame(ec) ec._chain(frame3) assert ec.some_frame is frame3 assert frame3.f_back_some is frame2 - assert frame2.f_forward is frame3 - # now we should unchain + assert frame2.f_forward is None + assert ec.gettopframe() is frame3 + assert ec._extract_back_from_frame(frame3) is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None assert frame3.f_back() is frame2 + # now we should unchain ec._unchain(frame3) assert ec.some_frame is frame2 assert ec.framestackdepth == 2 assert frame2.f_forward is None assert frame3.f_back_some is frame2 + assert ec.gettopframe() is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None assert frame2.f_back() is frame ec._unchain(frame2) @@ -346,12 +416,15 @@ assert ec.framestackdepth == 1 assert frame.f_forward is None assert frame2.f_back_some is frame + assert ec.gettopframe() is frame + assert ec._extract_back_from_frame(frame) is None assert frame.f_back() is None ec._unchain(frame) assert ec.some_frame is None assert ec.framestackdepth == 0 assert frame.f_back_some is None + assert ec.gettopframe() is None def test_frame_chain_forced(self): @@ -359,30 +432,44 @@ frame = self.Frame(ec) ec._chain(frame) + assert ec.gettopframe() is frame + assert ec._extract_back_from_frame(frame) is None frame2 = self.Frame(ec) ec._chain(frame2) assert ec.some_frame is frame2 assert ec.framestackdepth == 2 assert frame2.f_back_some is frame - assert frame.f_forward is frame2 + assert frame.f_forward is None assert frame2.f_forward is None res = frame2.force_f_back() assert res is frame assert frame.f_back_forced + assert ec.gettopframe() is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None frame3 = self.Frame(ec) ec._chain(frame3) + assert ec.gettopframe() is frame3 + assert ec._extract_back_from_frame(frame3) is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None # now we should unchain assert frame3.f_back() is frame2 ec._unchain(frame3) assert ec.some_frame is frame2 assert frame3.f_back_some is frame2 + assert ec.gettopframe() is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None assert frame2.f_back() is frame ec._unchain(frame2) assert frame2.f_back_some is frame + assert ec.gettopframe() is frame + assert ec._extract_back_from_frame(frame) is None assert frame.f_back() is None ec._unchain(frame) @@ -391,6 +478,7 @@ assert frame2.f_back() is frame assert frame.f_back() is None + assert ec.gettopframe() is None def test_frame_chain_jitted(self): @@ -399,6 +487,7 @@ assert ec.some_frame is None assert ec.framestackdepth == 0 + assert ec.gettopframe() is None frame = self.Frame(ec) ec._chain(frame) @@ -406,6 +495,8 @@ assert ec.framestackdepth == 1 assert frame.f_back_some is None assert frame.f_forward is None + assert ec.gettopframe() is frame + assert ec._extract_back_from_frame(frame) is None ec.jitted = True ec.virtualizable = frame @@ -416,6 +507,9 @@ assert frame2.f_back_some is frame assert frame.f_forward is frame2 assert frame2.f_forward is None + assert ec.gettopframe() is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None # recursive enter/leave seen by the jit frame3 = self.Frame(ec, frame) @@ -423,6 +517,10 @@ assert ec.some_frame is frame assert frame3.f_back_some is frame assert frame2.f_forward is frame3 + assert ec.gettopframe() is frame3 + assert ec._extract_back_from_frame(frame3) is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None # now we should unchain assert frame3.f_back() is frame2 @@ -433,16 +531,23 @@ assert frame3.f_back_some is frame assert not frame3.escaped assert not frame2.escaped + assert ec.gettopframe() is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None # recursive enter/leave not seen by the jit ec.jitted = False ec.virtualizable = None ec._chain(frame3) + assert not frame2.escaped assert ec.some_frame is frame3 assert frame3.f_back_some is frame - assert frame2.f_forward is frame3 + assert frame2.f_forward is None assert frame3.escaped - #assert not frame2.escaped # XXX this is failing! + assert ec.gettopframe() is frame3 + assert ec._extract_back_from_frame(frame3) is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None assert frame3.f_back() is frame2 ec._unchain(frame3) @@ -450,6 +555,10 @@ assert ec.framestackdepth == 2 assert frame2.f_forward is None assert frame3.f_back_some is frame + assert ec.gettopframe() is frame2 + assert ec._extract_back_from_frame(frame2) is frame + assert ec._extract_back_from_frame(frame) is None + ec.jitted = True ec.virtualizable = frame @@ -459,6 +568,8 @@ assert ec.framestackdepth == 1 assert frame.f_forward is None assert frame2.f_back_some is frame + assert ec.gettopframe() is frame + assert ec._extract_back_from_frame(frame) is None ec.jitted = False assert frame.f_back() is None @@ -466,6 +577,7 @@ assert ec.some_frame is None assert ec.framestackdepth == 0 assert frame.f_back_some is None + assert ec.gettopframe() is None def test_frame_chain_jitted_forced(self): @@ -541,7 +653,6 @@ def test_check_escaping_not_all_inlined_enter_leave_not_seen(self): - py.test.skip("escapes") ec, frame, frame2 = self.enter_two_jitted_levels() ec.jitted = False @@ -552,7 +663,6 @@ assert not frame2.escaped assert frame3.escaped - assert frame3.f_back() is frame2 ec._unchain(frame3) ec.jitted = True assert not frame2.escaped From antocuni at codespeak.net Thu Sep 10 12:01:18 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 10 Sep 2009 12:01:18 +0200 (CEST) Subject: [pypy-svn] r67602 - pypy/trunk/pypy/translator/cli Message-ID: <20090910100118.F097E168024@codespeak.net> Author: antocuni Date: Thu Sep 10 12:01:18 2009 New Revision: 67602 Modified: pypy/trunk/pypy/translator/cli/opcodes.py Log: remove this nops. They were introduced for debugging, but obviously they are not needed Modified: pypy/trunk/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/trunk/pypy/translator/cli/opcodes.py (original) +++ pypy/trunk/pypy/translator/cli/opcodes.py Thu Sep 10 12:01:18 2009 @@ -114,9 +114,8 @@ 'ullong_is_true': [PushAllArgs, 'ldc.i8 0', 'cgt.un'], 'ullong_invert': 'not', - # XXX: why nop nop nop? - 'ooisnull': [PushAllArgs, 'nop', 'nop', 'nop', 'ldnull', 'ceq'], - 'oononnull': [PushAllArgs, 'nop', 'nop', 'nop', 'nop', 'ldnull', 'ceq']+Not, + 'ooisnull': [PushAllArgs, 'ldnull', 'ceq'], + 'oononnull': [PushAllArgs, 'ldnull', 'ceq']+Not, # when casting from bool we want that every truth value is casted # to 1: we can't simply DoNothing, because the CLI stack could From antocuni at codespeak.net Thu Sep 10 12:02:51 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 10 Sep 2009 12:02:51 +0200 (CEST) Subject: [pypy-svn] r67603 - in pypy/trunk/pypy/jit: backend/llgraph metainterp/test Message-ID: <20090910100251.6D26A168024@codespeak.net> Author: antocuni Date: Thu Sep 10 12:02:50 2009 New Revision: 67603 Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Log: catch LLException even if we are not llinterpreting a graph but directly calling a method. The point is that LLException could be explicitly raised by ll_portal_runner (which doesn't have a graph) and we want to catch it as well. Test simple_recursion_with_exception now passes on ootype. Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py Thu Sep 10 12:02:50 2009 @@ -1268,15 +1268,15 @@ else: mymethod = meth myargs = args - if hasattr(mymethod, 'graph'): - llinterp = _llinterp # it's a global set here by CPU.__init__() - try: + try: + if hasattr(mymethod, 'graph'): + llinterp = _llinterp # it's a global set here by CPU.__init__() result = llinterp.eval_graph(mymethod.graph, myargs) - except LLException, e: - _last_exception = e - result = get_err_result_for_type(mymethod._TYPE.RESULT) - else: - result = meth(*args) # no exception support in this case + else: + result = meth(*args) + except LLException, e: + _last_exception = e + result = get_err_result_for_type(mymethod._TYPE.RESULT) return result def get_err_result_for_type(T): Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Thu Sep 10 12:02:50 2009 @@ -218,5 +218,4 @@ pass class TestOOtype(RecursiveTests, OOJitMixin): - def test_simple_recursion_with_exc(self): - py.test.skip("Fails") + pass From cfbolz at codespeak.net Thu Sep 10 12:12:41 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 12:12:41 +0200 (CEST) Subject: [pypy-svn] r67604 - in pypy/trunk/pypy: jit/metainterp jit/metainterp/test rlib translator Message-ID: <20090910101241.C7B3B168024@codespeak.net> Author: cfbolz Date: Thu Sep 10 12:12:41 2009 New Revision: 67604 Modified: pypy/trunk/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/test_basic.py pypy/trunk/pypy/jit/metainterp/test/test_recursive.py pypy/trunk/pypy/jit/metainterp/warmspot.py pypy/trunk/pypy/rlib/jit.py pypy/trunk/pypy/translator/driver.py Log: merge agressive-inlining branch Modified: pypy/trunk/pypy/jit/metainterp/history.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py Thu Sep 10 12:12:41 2009 @@ -788,6 +788,7 @@ compiled_count = 0 enter_count = 0 + aborted_count = 0 def __init__(self): self.loops = [] @@ -853,10 +854,9 @@ class Options: logger_noopt = None - def __init__(self, specialize=True, listops=False, inline=False): + def __init__(self, specialize=True, listops=False): self.specialize = specialize self.listops = listops - self.inline = inline def _freeze_(self): return True Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Thu Sep 10 12:12:41 2009 @@ -645,12 +645,12 @@ @arguments("descr", "varargs") def opimpl_recursive_call(self, calldescr, varargs): - if self.metainterp.staticdata.options.inline: + warmrunnerstate = self.metainterp.staticdata.state + if warmrunnerstate.inlining: num_green_args = self.metainterp.staticdata.num_green_args portal_code = self.metainterp.staticdata.portal_code greenkey = varargs[1:num_green_args + 1] if self.metainterp.staticdata.state.can_inline_callable(greenkey): - self.metainterp.in_recursion += 1 return self.perform_call(portal_code, varargs[1:]) return self.execute_with_exc(rop.CALL, varargs, descr=calldescr) @@ -1128,14 +1128,20 @@ def newframe(self, jitcode): if not we_are_translated(): self._debug_history.append(['enter', jitcode, None]) + if jitcode is self.staticdata.portal_code: + self.in_recursion += 1 f = MIFrame(self, jitcode) self.framestack.append(f) return f - def finishframe(self, resultbox): + def popframe(self): frame = self.framestack.pop() if frame.jitcode is self.staticdata.portal_code: self.in_recursion -= 1 + return frame + + def finishframe(self, resultbox): + frame = self.popframe() if not we_are_translated(): self._debug_history.append(['leave', frame.jitcode, None]) if self.framestack: @@ -1178,11 +1184,29 @@ return True if not we_are_translated(): self._debug_history.append(['leave_exc', frame.jitcode, None]) - self.framestack.pop() + self.popframe() if not self.is_blackholing(): self.compile_exit_frame_with_exception(excvaluebox) raise self.staticdata.ExitFrameWithExceptionRef(self.cpu, excvaluebox.getref_base()) + def check_recursion_invariant(self): + in_recursion = -1 + for frame in self.framestack: + jitcode = frame.jitcode + if jitcode is self.staticdata.portal_code: + in_recursion += 1 + if in_recursion != self.in_recursion: + print "in_recursion problem!!!" + print in_recursion, self.in_recursion + for frame in self.framestack: + jitcode = frame.jitcode + if jitcode is self.staticdata.portal_code: + print "P", + else: + print " ", + print jitcode.name + raise Exception + def raise_overflow_error(self): etype, evalue = self.cpu.get_overflow_error() return self.finishframe_exception( @@ -1196,6 +1220,7 @@ self.cpu.ts.get_exc_value_box(evalue)) def create_empty_history(self): + warmrunnerstate = self.staticdata.state self.history = history.History(self.cpu) if self.staticdata.stats is not None: self.staticdata.stats.history = self.history @@ -1245,6 +1270,19 @@ op.pc = self.framestack[-1].pc op.name = self.framestack[-1].jitcode.name + def switch_to_blackhole_if_trace_too_long(self): + if not self.is_blackholing(): + warmrunnerstate = self.staticdata.state + if len(self.history.operations) > warmrunnerstate.trace_limit: + self.history = history.BlackHole(self.cpu) + if not we_are_translated(): + self.staticdata.stats.aborted_count += 1 + history.log.event('ABORTING TRACING' + self.history.extratext) + elif DEBUG: + debug_print('~~~ ABORTING TRACING', self.history.extratext) + self.staticdata.profiler.end_tracing() + self.staticdata.profiler.start_blackhole() + def _interpret(self): # Execute the frames forward until we raise a DoneWithThisFrame, # a ContinueRunningNormally, or a GenerateMergePoint exception. @@ -1256,6 +1294,9 @@ try: while True: self.framestack[-1].run_one_step() + self.switch_to_blackhole_if_trace_too_long() + if not we_are_translated(): + self.check_recursion_invariant() finally: if self.is_blackholing(): self.staticdata.profiler.end_blackhole() @@ -1292,7 +1333,8 @@ return self.designate_target_loop(gmp) def handle_guard_failure(self, exec_result, key): - self.initialize_state_from_guard_failure(exec_result) + from pypy.jit.metainterp.warmspot import ContinueRunningNormallyBase + resumedescr = self.initialize_state_from_guard_failure(exec_result) assert isinstance(key, compile.ResumeGuardDescr) top_history = key.find_toplevel_history() source_loop = top_history.source_link @@ -1302,12 +1344,18 @@ self.resumekey = key self.seen_can_enter_jit = False guard_op = key.get_guard_op() + started_as_blackhole = self.is_blackholing() try: self.prepare_resume_from_failure(guard_op.opnum) self.interpret() assert False, "should always raise" except GenerateMergePoint, gmp: return self.designate_target_loop(gmp) + except ContinueRunningNormallyBase: + if not started_as_blackhole: + warmrunnerstate = self.staticdata.state + warmrunnerstate.reset_counter_from_failure(resumedescr) + raise def forget_consts(self, boxes, startindex=0): for i in range(startindex, len(boxes)): @@ -1499,7 +1547,7 @@ *args[1:]) def initialize_state_from_start(self, *args): - self.in_recursion = 0 + self.in_recursion = -1 # always one portal around self.staticdata._setup_once() self.staticdata.profiler.start_tracing() self.create_empty_history() @@ -1516,7 +1564,7 @@ def initialize_state_from_guard_failure(self, guard_failure): # guard failure: rebuild a complete MIFrame stack - self.in_recursion = 0 + self.in_recursion = -1 # always one portal around resumedescr = guard_failure.descr assert isinstance(resumedescr, compile.ResumeGuardDescr) warmrunnerstate = self.staticdata.state @@ -1542,6 +1590,7 @@ # the BlackHole is invalid because it doesn't start with # guard_failure.key.guard_op.suboperations, but that's fine self.rebuild_state_after_failure(resumedescr, guard_failure.args) + return resumedescr def initialize_virtualizable(self, original_boxes): vinfo = self.staticdata.virtualizable_info @@ -1642,10 +1691,7 @@ jitcode, pc, exception_target = resumereader.consume_frame_info() env = resumereader.consume_boxes() f = self.newframe(jitcode) - if jitcode is self.staticdata.portal_code: - self.in_recursion += 1 f.setup_resume_at_op(pc, exception_target, env) - self.in_recursion -= 1 # always one portal around def check_synchronized_virtualizable(self): if not we_are_translated(): Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Thu Sep 10 12:12:41 2009 @@ -1,4 +1,5 @@ import py +import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats from pypy.jit.backend.llgraph import runner @@ -49,6 +50,8 @@ assert get_stats().enter_count <= count def check_jumps(self, maxcount): assert get_stats().exec_jumps <= maxcount + def check_aborted_count(self, maxcount): + assert get_stats().aborted_count == maxcount def meta_interp(self, *args, **kwds): kwds['CPUClass'] = self.CPUClass @@ -70,6 +73,8 @@ class FakeWarmRunnerDesc: def attach_unoptimized_bridge_from_interp(self, greenkey, newloop): pass + + trace_limit = sys.maxint if policy is None: policy = JitPolicy() Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Thu Sep 10 12:12:41 2009 @@ -4,7 +4,7 @@ from pypy.jit.metainterp import simple_optimize from pypy.jit.metainterp.policy import StopAtXPolicy from pypy.rpython.annlowlevel import hlstr -from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit +from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit, get_stats class RecursiveTests: @@ -213,6 +213,170 @@ res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) assert res == 0 + def test_exception_in_inlined_function(self): + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "l" not in hlstr(code) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], + get_printable_location=p, can_inline=c) + + class Exc(Exception): + pass + + def f(code, n): + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(n=n, code=code, pc=pc) + op = code[pc] + if op == "-": + n -= 1 + elif op == "c": + try: + n = f("---i---", n) + except Exc: + pass + elif op == "i": + if n % 5 == 1: + raise Exc + elif op == "l": + if n > 0: + myjitdriver.can_enter_jit(n=n, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return n + def main(n): + return f("c-l", n) + res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + assert res == main(100) + + def test_recurse_during_blackholing(self): + # this passes, if the blackholing shortcut for calls is turned off + # it fails, it is very delicate in terms of parameters, + # bridge/loop creation order + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "l" not in hlstr(code) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], + get_printable_location=p, can_inline=c) + + def f(code, n): + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(n=n, code=code, pc=pc) + op = code[pc] + if op == "-": + n -= 1 + elif op == "c": + if n < 70 and n % 3 == 1: + print "F" + n = f("--", n) + elif op == "l": + if n > 0: + myjitdriver.can_enter_jit(n=n, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return n + def main(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 5) + return f("c-l", n) + expected = main(100) + res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + assert res == expected + + def check_max_trace_length(self, length): + for loop in get_stats().loops: + assert len(loop.operations) <= length + 5 # because we only check once per metainterp bytecode + for op in loop.operations: + if op.is_guard(): + assert len(op.suboperations) <= length + 5 + + def test_inline_trace_limit(self): + myjitdriver = JitDriver(greens=[], reds=['n']) + def recursive(n): + if n > 0: + return recursive(n - 1) + 1 + return 0 + def loop(n): + myjitdriver.set_param("threshold", 10) + pc = 0 + while n: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + n = recursive(n) + n -= 1 + return n + TRACE_LIMIT = 66 + res = self.meta_interp(loop, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT) + assert res == 0 + self.check_max_trace_length(TRACE_LIMIT) + self.check_enter_count(15) # maybe + self.check_aborted_count(7) + + def test_trace_limit_bridge(self): + def recursive(n): + if n > 0: + return recursive(n - 1) + 1 + return 0 + myjitdriver = JitDriver(greens=[], reds=['n']) + def loop(n): + myjitdriver.set_param("threshold", 4) + myjitdriver.set_param("trace_eagerness", 2) + while n: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + if n % 5 == 0: + n -= 1 + if n < 50: + n = recursive(n) + n -= 1 + TRACE_LIMIT = 20 + res = self.meta_interp(loop, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT) + self.check_max_trace_length(TRACE_LIMIT) + self.check_aborted_count(8) + self.check_enter_count_at_most(30) + + def test_set_param_inlining(self): + myjitdriver = JitDriver(greens=[], reds=['n', 'recurse']) + def loop(n, recurse=False): + while n: + myjitdriver.jit_merge_point(n=n, recurse=recurse) + n -= 1 + if not recurse: + loop(10, True) + myjitdriver.can_enter_jit(n=n, recurse=recurse) + return n + TRACE_LIMIT = 66 + + def main(inline): + myjitdriver.set_param("threshold", 10) + if inline: + myjitdriver.set_param('inlining', True) + else: + myjitdriver.set_param('inlining', False) + return loop(100) + + res = self.meta_interp(main, [0], optimizer=simple_optimize, trace_limit=TRACE_LIMIT) + self.check_loops(call=1) + + res = self.meta_interp(main, [1], optimizer=simple_optimize, trace_limit=TRACE_LIMIT) + self.check_loops(call=0) + + class TestLLtype(RecursiveTests, LLJitMixin): pass Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Thu Sep 10 12:12:41 2009 @@ -26,7 +26,9 @@ # ____________________________________________________________ # Bootstrapping -def apply_jit(translator, backend_name="auto", debug_level="steps", **kwds): +def apply_jit(translator, backend_name="auto", debug_level="steps", + inline=False, + **kwds): if 'CPUClass' not in kwds: from pypy.jit.backend.detect_cpu import getcpuclass kwds['CPUClass'] = getcpuclass(backend_name) @@ -38,9 +40,9 @@ warmrunnerdesc = WarmRunnerDesc(translator, translate_support_code=True, listops=True, - #inline=True, profile=profile, **kwds) + warmrunnerdesc.state.set_param_inlining(inline) warmrunnerdesc.finish() translator.warmrunnerdesc = warmrunnerdesc # for later debugging @@ -52,13 +54,15 @@ clear_tcache() return jittify_and_run(interp, graph, args, backendopt=backendopt, **kwds) -def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False, - **kwds): +def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False, trace_limit=sys.maxint, + inline=False, **kwds): translator = interp.typer.annotator.translator translator.config.translation.gc = "boehm" warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds) warmrunnerdesc.state.set_param_threshold(3) # for tests warmrunnerdesc.state.set_param_trace_eagerness(2) # for tests + warmrunnerdesc.state.set_param_trace_limit(trace_limit) + warmrunnerdesc.state.set_param_inlining(inline) warmrunnerdesc.state.create_tables_now() # for tests if hash_bits: warmrunnerdesc.state.set_param_hash_bits(hash_bits) @@ -120,6 +124,9 @@ class JitException(Exception): _go_through_llinterp_uncaught_ = True # ugh +class ContinueRunningNormallyBase(JitException): + pass + class CannotInlineCanEnterJit(JitException): pass @@ -409,7 +416,7 @@ def __str__(self): return 'ExitFrameWithExceptionRef(%s)' % (self.value,) - class ContinueRunningNormally(JitException): + class ContinueRunningNormally(ContinueRunningNormallyBase): def __init__(self, argboxes): # accepts boxes as argument, but unpacks them immediately # before we raise the exception -- the boxes' values will @@ -728,6 +735,12 @@ def set_param_trace_eagerness(self, value): self.trace_eagerness = value + def set_param_trace_limit(self, value): + self.trace_limit = value + + def set_param_inlining(self, value): + self.inlining = value + def set_param_hash_bits(self, value): if value < 1: value = 1 @@ -772,7 +785,13 @@ self.create_tables_now() return metainterp = MetaInterp(metainterp_sd) - loop = metainterp.compile_and_run_once(*args) + try: + loop = metainterp.compile_and_run_once(*args) + except warmrunnerdesc.ContinueRunningNormally: + # the trace got too long, reset the counter + self.mccounters[argshash] = 0 + raise + else: # machine code was already compiled for these greenargs # (or we have a hash collision) @@ -861,6 +880,9 @@ key.counter += 1 return key.counter >= self.trace_eagerness + def reset_counter_from_failure(self, key): + key.counter = 0 + def attach_unoptimized_bridge_from_interp(self, greenkey, bridge): greenargs = self.unwrap_greenkey(greenkey) newcell = MachineCodeEntryPoint(bridge, *greenargs) Modified: pypy/trunk/pypy/rlib/jit.py ============================================================================== --- pypy/trunk/pypy/rlib/jit.py (original) +++ pypy/trunk/pypy/rlib/jit.py Thu Sep 10 12:12:41 2009 @@ -1,3 +1,4 @@ +import sys from pypy.rpython.extregistry import ExtRegistryEntry from pypy.rlib.objectmodel import CDefinedIntSymbolic from pypy.rlib.unroll import unrolling_iterable @@ -82,6 +83,8 @@ PARAMETERS = {'threshold': 1000, 'trace_eagerness': 200, 'hash_bits': 14, + 'trace_limit': 10000, + 'inlining': False, } unroll_parameters = unrolling_iterable(PARAMETERS.keys()) Modified: pypy/trunk/pypy/translator/driver.py ============================================================================== --- pypy/trunk/pypy/translator/driver.py (original) +++ pypy/trunk/pypy/translator/driver.py Thu Sep 10 12:12:41 2009 @@ -362,7 +362,7 @@ from pypy.jit.metainterp.warmspot import apply_jit apply_jit(self.translator, policy=self.jitpolicy, debug_level=self.config.translation.jit_debug, - backend_name=self.config.translation.jit_backend) + backend_name=self.config.translation.jit_backend, inline=True) # self.log.info("the JIT compiler was generated") # From cfbolz at codespeak.net Thu Sep 10 12:13:03 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 12:13:03 +0200 (CEST) Subject: [pypy-svn] r67605 - pypy/branch/agressive-inlining Message-ID: <20090910101303.43AA2168024@codespeak.net> Author: cfbolz Date: Thu Sep 10 12:13:02 2009 New Revision: 67605 Removed: pypy/branch/agressive-inlining/ Log: kill merged branch From cfbolz at codespeak.net Thu Sep 10 12:40:27 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 12:40:27 +0200 (CEST) Subject: [pypy-svn] r67606 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090910104027.32AA6168025@codespeak.net> Author: cfbolz Date: Thu Sep 10 12:40:25 2009 New Revision: 67606 Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Log: (pedronis, micke, cfbolz) a xfailing test about a hook on leaving the jit before a portal call that we think we need to untangle the escaping frame problems Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Thu Sep 10 12:40:25 2009 @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, we_are_jitted from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin from pypy.jit.metainterp import simple_optimize from pypy.jit.metainterp.policy import StopAtXPolicy @@ -377,6 +377,71 @@ self.check_loops(call=0) + @py.test.mark.xfail + def test_leave_jit_hook(self): + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "l" not in hlstr(code) + + def leave(frame, code): + frame.hookcalled = True + + class ExpectedHook(Exception): + pass + class UnexpectedHook(Exception): + pass + + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['self'], + get_printable_location=p, can_inline=c) + class Frame(object): + def __init__(self, n): + self.n = n + self.hookcalled = False + def f(self, code): + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(self=self, code=code, pc=pc) + op = code[pc] + if op == "-": + self.n -= 1 + elif op == "c": + frame = Frame(self.n) + self.n = frame.f("---i---") + if we_are_jitted(): + if frame.hookcalled: + raise UnexpectedHook + elif op == "C": + frame = Frame(self.n) + self.n = frame.f("cL") + if we_are_jitted(): + if not frame.hookcalled: + raise ExpectedHook + elif op == "i": + if self.n % 5 == 1: + return self.n + elif op == "l": + if self.n > 0: + myjitdriver.can_enter_jit(self=self, code=code, pc=0) + pc = 0 + continue + elif op == "L": + if self.n > 50: + myjitdriver.can_enter_jit(self=self, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return self.n + def main(n): + frame = Frame(n) + return frame.f("C-l") + res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + assert res == main(100) class TestLLtype(RecursiveTests, LLJitMixin): pass From jandem at codespeak.net Thu Sep 10 13:49:13 2009 From: jandem at codespeak.net (jandem at codespeak.net) Date: Thu, 10 Sep 2009 13:49:13 +0200 (CEST) Subject: [pypy-svn] r67608 - pypy/branch/js-refactoring-update Message-ID: <20090910114913.74466168024@codespeak.net> Author: jandem Date: Thu Sep 10 13:49:10 2009 New Revision: 67608 Added: pypy/branch/js-refactoring-update/ (props changed) - copied from r67607, pypy/trunk/ Log: create a branch to update js-refactoring to trunk From jandem at codespeak.net Thu Sep 10 13:51:14 2009 From: jandem at codespeak.net (jandem at codespeak.net) Date: Thu, 10 Sep 2009 13:51:14 +0200 (CEST) Subject: [pypy-svn] r67609 - pypy/trunk/pypy/lang/js Message-ID: <20090910115114.BD967168024@codespeak.net> Author: jandem Date: Thu Sep 10 13:51:14 2009 New Revision: 67609 Removed: pypy/trunk/pypy/lang/js/ Log: delete lang/js From jandem at codespeak.net Thu Sep 10 13:57:28 2009 From: jandem at codespeak.net (jandem at codespeak.net) Date: Thu, 10 Sep 2009 13:57:28 +0200 (CEST) Subject: [pypy-svn] r67610 - pypy/trunk/pypy/lang/js Message-ID: <20090910115728.CDBDC168024@codespeak.net> Author: jandem Date: Thu Sep 10 13:57:28 2009 New Revision: 67610 Added: pypy/trunk/pypy/lang/js/ - copied from r67608, pypy/trunk/pypy/lang/js/ Log: oops, revert previous commit From jandem at codespeak.net Thu Sep 10 14:01:57 2009 From: jandem at codespeak.net (jandem at codespeak.net) Date: Thu, 10 Sep 2009 14:01:57 +0200 (CEST) Subject: [pypy-svn] r67611 - pypy/branch/js-refactoring-update/pypy/lang/js Message-ID: <20090910120157.1E371168024@codespeak.net> Author: jandem Date: Thu Sep 10 14:01:56 2009 New Revision: 67611 Removed: pypy/branch/js-refactoring-update/pypy/lang/js/ Log: remove lang/js From jandem at codespeak.net Thu Sep 10 14:04:41 2009 From: jandem at codespeak.net (jandem at codespeak.net) Date: Thu, 10 Sep 2009 14:04:41 +0200 (CEST) Subject: [pypy-svn] r67612 - pypy/branch/js-refactoring-update/pypy/lang/js Message-ID: <20090910120441.868AD168025@codespeak.net> Author: jandem Date: Thu Sep 10 14:04:41 2009 New Revision: 67612 Added: pypy/branch/js-refactoring-update/pypy/lang/js/ - copied from r67611, pypy/branch/js-refactoring/pypy/lang/js/ Log: copy lang/js from js-refactoring From jandem at codespeak.net Thu Sep 10 14:06:07 2009 From: jandem at codespeak.net (jandem at codespeak.net) Date: Thu, 10 Sep 2009 14:06:07 +0200 (CEST) Subject: [pypy-svn] r67613 - pypy/branch/js-refactoring Message-ID: <20090910120607.79FE6168024@codespeak.net> Author: jandem Date: Thu Sep 10 14:06:07 2009 New Revision: 67613 Removed: pypy/branch/js-refactoring/ Log: delete old branch From jandem at codespeak.net Thu Sep 10 14:06:57 2009 From: jandem at codespeak.net (jandem at codespeak.net) Date: Thu, 10 Sep 2009 14:06:57 +0200 (CEST) Subject: [pypy-svn] r67614 - in pypy/branch: js-refactoring js-refactoring-update Message-ID: <20090910120657.32933168024@codespeak.net> Author: jandem Date: Thu Sep 10 14:06:56 2009 New Revision: 67614 Added: pypy/branch/js-refactoring/ - copied from r67613, pypy/branch/js-refactoring-update/ Removed: pypy/branch/js-refactoring-update/ Log: rename js-refactoring-update to js-refactoring From afa at codespeak.net Thu Sep 10 14:48:28 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Thu, 10 Sep 2009 14:48:28 +0200 (CEST) Subject: [pypy-svn] r67615 - in pypy/branch/windowserror/pypy: rlib rlib/rstruct rpython/module Message-ID: <20090910124828.28026168024@codespeak.net> Author: afa Date: Thu Sep 10 14:48:26 2009 New Revision: 67615 Modified: pypy/branch/windowserror/pypy/rlib/libffi.py pypy/branch/windowserror/pypy/rlib/rstruct/formatiterator.py pypy/branch/windowserror/pypy/rlib/rwin32.py pypy/branch/windowserror/pypy/rpython/module/ll_os.py Log: Raise WindowsError where the Windows API is involved. And use more the rwin32 helper module. Modified: pypy/branch/windowserror/pypy/rlib/libffi.py ============================================================================== --- pypy/branch/windowserror/pypy/rlib/libffi.py (original) +++ pypy/branch/windowserror/pypy/rlib/libffi.py Thu Sep 10 14:48:26 2009 @@ -311,8 +311,6 @@ "Procedure called with too many " "arguments (%d bytes in excess) " % (result,)) - - FormatError = rwin32.FormatError LoadLibrary = rwin32.LoadLibrary get_libc_handle = external('get_libc_handle', [], rwin32.HANDLE) Modified: pypy/branch/windowserror/pypy/rlib/rstruct/formatiterator.py ============================================================================== --- pypy/branch/windowserror/pypy/rlib/rstruct/formatiterator.py (original) +++ pypy/branch/windowserror/pypy/rlib/rstruct/formatiterator.py Thu Sep 10 14:48:26 2009 @@ -103,6 +103,7 @@ def __init__(self, fmtchar, attrs): self.fmtchar = fmtchar self.alignment = 1 # by default + self.mask = self.alignment - 1 self.needcount = False # by default self.__dict__.update(attrs) self.mask = self.alignment - 1 Modified: pypy/branch/windowserror/pypy/rlib/rwin32.py ============================================================================== --- pypy/branch/windowserror/pypy/rlib/rwin32.py (original) +++ pypy/branch/windowserror/pypy/rlib/rwin32.py Thu Sep 10 14:48:26 2009 @@ -55,7 +55,8 @@ "MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)") for name in """FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_FROM_SYSTEM - """.split(): + MAX_PATH + """.split(): locals()[name] = rffi_platform.ConstantInteger(name) @@ -112,10 +113,9 @@ LocalFree(buf[0]) return result - def lastWindowsError(context=None): + def lastWindowsError(context="Windows Error"): code = GetLastError() - message = FormatError(code) - return WindowsError(code, message) + return WindowsError(code, context) def FAILED(hr): return rffi.cast(HRESULT, hr) < 0 @@ -125,7 +125,7 @@ DWORD) def GetModuleFileName(module): - size = 255 # MAX_PATH + size = MAX_PATH buf = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw') try: res = _GetModuleFileName(module, buf, size) Modified: pypy/branch/windowserror/pypy/rpython/module/ll_os.py ============================================================================== --- pypy/branch/windowserror/pypy/rpython/module/ll_os.py (original) +++ pypy/branch/windowserror/pypy/rpython/module/ll_os.py Thu Sep 10 14:48:26 2009 @@ -468,24 +468,22 @@ @registering(os.times) def register_os_times(self): if sys.platform.startswith('win'): - HANDLE = rffi.ULONG - FILETIME = rffi.CStruct('_FILETIME', ('dwLowDateTime', rffi.LONG), - ('dwHighDateTime', rffi.LONG)) + from pypy.rlib import rwin32 GetCurrentProcess = self.llexternal('GetCurrentProcess', [], - HANDLE) + rwin32.HANDLE) GetProcessTimes = self.llexternal('GetProcessTimes', - [HANDLE, - lltype.Ptr(FILETIME), - lltype.Ptr(FILETIME), - lltype.Ptr(FILETIME), - lltype.Ptr(FILETIME)], - lltype.Bool) + [rwin32.HANDLE, + lltype.Ptr(rwin32.FILETIME), + lltype.Ptr(rwin32.FILETIME), + lltype.Ptr(rwin32.FILETIME), + lltype.Ptr(rwin32.FILETIME)], + rwin32.BOOL) def times_lltypeimpl(): - pcreate = lltype.malloc(FILETIME, flavor='raw') - pexit = lltype.malloc(FILETIME, flavor='raw') - pkernel = lltype.malloc(FILETIME, flavor='raw') - puser = lltype.malloc(FILETIME, flavor='raw') + pcreate = lltype.malloc(rwin32.FILETIME, flavor='raw') + pexit = lltype.malloc(rwin32.FILETIME, flavor='raw') + pkernel = lltype.malloc(rwin32.FILETIME, flavor='raw') + puser = lltype.malloc(rwin32.FILETIME, flavor='raw') hProc = GetCurrentProcess() GetProcessTimes(hProc, pcreate, pexit, pkernel, puser) # The fields of a FILETIME structure are the hi and lo parts @@ -904,47 +902,29 @@ @registering_if(posix, '_getfullpathname') def register_posix__getfullpathname(self): + from pypy.rlib import rwin32 # this nt function is not exposed via os, but needed # to get a correct implementation of os.abspath # XXX why do we ignore WINAPI conventions everywhere? - class CConfig: - _compilation_info_ = ExternalCompilationInfo( - includes = ['Windows.h'] - ) - MAX_PATH = platform.ConstantInteger('MAX_PATH') - DWORD = platform.SimpleType("DWORD", rffi.ULONG) - LPCTSTR = platform.SimpleType("LPCTSTR", rffi.CCHARP) - LPTSTR = platform.SimpleType("LPTSTR", rffi.CCHARP) - LPTSTRP = platform.SimpleType("LPTSTR*", rffi.CCHARPP) - - config = platform.configure(CConfig) - MAX_PATH = config['MAX_PATH'] - DWORD = config['DWORD'] - LPCTSTR = config['LPCTSTR'] - LPTSTR = config['LPTSTR'] - LPTSTRP = config['LPTSTRP'] + LPSTRP = rffi.CArrayPtr(rwin32.LPSTR) # XXX unicode? - GetFullPathName = self.llexternal('GetFullPathNameA', - [LPCTSTR, DWORD, LPTSTR, LPTSTRP], DWORD) - GetLastError = self.llexternal('GetLastError', [], DWORD) - ##DWORD WINAPI GetFullPathName( - ## __in LPCTSTR lpFileName, - ## __in DWORD nBufferLength, - ## __out LPTSTR lpBuffer, - ## __out LPTSTR* lpFilePart - ##); + GetFullPathName = self.llexternal( + 'GetFullPathNameA', + [rwin32.LPCSTR, + rwin32.DWORD, + rwin32.LPSTR, + rffi.CArrayPtr(rwin32.LPSTR)], + rwin32.DWORD) def _getfullpathname_llimpl(lpFileName): - nBufferLength = MAX_PATH + 1 - lpBuffer = lltype.malloc(LPTSTR.TO, nBufferLength, flavor='raw') + nBufferLength = rwin32.MAX_PATH + 1 + lpBuffer = lltype.malloc(rwin32.LPSTR.TO, nBufferLength, flavor='raw') try: res = GetFullPathName( - lpFileName, rffi.cast(DWORD, nBufferLength), - lpBuffer, lltype.nullptr(LPTSTRP.TO)) + lpFileName, rffi.cast(rwin32.DWORD, nBufferLength), + lpBuffer, lltype.nullptr(LPSTRP.TO)) if res == 0: - error = GetLastError() - raise OSError(error, "_getfullpathname failed") - # XXX ntpath expects WindowsError :-( + raise rwin32.lastWindowsError("_getfullpathname failed") result = rffi.charp2str(lpBuffer) return result finally: @@ -991,14 +971,13 @@ def register_os_listdir(self): # we need a different approach on Windows and on Posix if sys.platform.startswith('win'): + from pypy.rlib import rwin32 class CConfig: _compilation_info_ = ExternalCompilationInfo( includes = ['windows.h'] ) WIN32_FIND_DATA = platform.Struct('struct _WIN32_FIND_DATAA', [('cFileName', lltype.FixedSizeArray(rffi.CHAR, 1))]) - INVALID_HANDLE_VALUE = platform.ConstantInteger( - 'INVALID_HANDLE_VALUE') ERROR_FILE_NOT_FOUND = platform.ConstantInteger( 'ERROR_FILE_NOT_FOUND') ERROR_NO_MORE_FILES = platform.ConstantInteger( @@ -1006,23 +985,19 @@ config = platform.configure(CConfig) WIN32_FIND_DATA = config['WIN32_FIND_DATA'] - INVALID_HANDLE_VALUE = config['INVALID_HANDLE_VALUE'] ERROR_FILE_NOT_FOUND = config['ERROR_FILE_NOT_FOUND'] ERROR_NO_MORE_FILES = config['ERROR_NO_MORE_FILES'] LPWIN32_FIND_DATA = lltype.Ptr(WIN32_FIND_DATA) - HANDLE = rffi.ULONG - #MAX_PATH = WIN32_FIND_DATA.c_cFileName.length - GetLastError = self.llexternal('GetLastError', [], lltype.Signed) FindFirstFile = self.llexternal('FindFirstFile', - [rffi.CCHARP, LPWIN32_FIND_DATA], - HANDLE) + [rwin32.LPCSTR, LPWIN32_FIND_DATA], + rwin32.HANDLE) FindNextFile = self.llexternal('FindNextFile', - [HANDLE, LPWIN32_FIND_DATA], - rffi.INT) + [rwin32.HANDLE, LPWIN32_FIND_DATA], + rwin32.BOOL) FindClose = self.llexternal('FindClose', - [HANDLE], - rffi.INT) + [rwin32.HANDLE], + rwin32.BOOL) def os_listdir_llimpl(path): if path and path[-1] not in ('/', '\\', ':'): @@ -1032,13 +1007,12 @@ try: result = [] hFindFile = FindFirstFile(path, filedata) - if hFindFile == INVALID_HANDLE_VALUE: - error = GetLastError() + if hFindFile == rwin32.INVALID_HANDLE_VALUE: + error = rwin32.GetLastError() if error == ERROR_FILE_NOT_FOUND: return result else: - # XXX guess error code :-( - raise OSError(errno.ENOENT, "FindFirstFile failed") + raise WindowsError(error, "FindFirstFile failed") while True: name = rffi.charp2str(rffi.cast(rffi.CCHARP, filedata.c_cFileName)) @@ -1048,13 +1022,12 @@ break # FindNextFile sets error to ERROR_NO_MORE_FILES if # it got to the end of the directory - error = GetLastError() + error = rwin32.GetLastError() FindClose(hFindFile) if error == ERROR_NO_MORE_FILES: return result else: - # XXX guess error code :-( - raise OSError(errno.EIO, "FindNextFile failed") + raise WindowsError(error, "FindNextFile failed") finally: lltype.free(filedata, flavor='raw') @@ -1107,28 +1080,31 @@ def register_os_pipe(self): # we need a different approach on Windows and on Posix if sys.platform.startswith('win'): - HANDLE = rffi.ULONG - HANDLEP = lltype.Ptr(lltype.FixedSizeArray(HANDLE, 1)) - CreatePipe = self.llexternal('CreatePipe', [HANDLEP, - HANDLEP, + from pypy.rlib import rwin32 + CreatePipe = self.llexternal('CreatePipe', [rwin32.LPHANDLE, + rwin32.LPHANDLE, rffi.VOIDP, - rffi.ULONG], - rffi.INT) + rwin32.DWORD], + rwin32.BOOL) _open_osfhandle = self.llexternal('_open_osfhandle', [rffi.ULONG, rffi.INT], rffi.INT) null = lltype.nullptr(rffi.VOIDP.TO) def os_pipe_llimpl(): - pread = lltype.malloc(HANDLEP.TO, flavor='raw') - pwrite = lltype.malloc(HANDLEP.TO, flavor='raw') + pread = lltype.malloc(rwin32.LPHANDLE.TO, 1, flavor='raw') + pwrite = lltype.malloc(rwin32.LPHANDLE.TO, 1, flavor='raw') ok = CreatePipe(pread, pwrite, null, 0) + if ok: + error = 0 + else: + error = rwin32.GetLastError() hread = pread[0] hwrite = pwrite[0] lltype.free(pwrite, flavor='raw') lltype.free(pread, flavor='raw') - if not ok: # XXX guess the error, can't use GetLastError() - raise OSError(errno.EMFILE, "os_pipe failed") + if error: + raise WindowsError(error, "os_pipe failed") fdread = _open_osfhandle(hread, 0) fdwrite = _open_osfhandle(hwrite, 1) return (fdread, fdwrite) From jandem at codespeak.net Thu Sep 10 15:10:13 2009 From: jandem at codespeak.net (jandem at codespeak.net) Date: Thu, 10 Sep 2009 15:10:13 +0200 (CEST) Subject: [pypy-svn] r67616 - pypy/branch/js-refactoring/pypy/translator/goal Message-ID: <20090910131013.4CC31168024@codespeak.net> Author: jandem Date: Thu Sep 10 15:10:12 2009 New Revision: 67616 Modified: pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py Log: update targetjsstandalone.py Modified: pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py ============================================================================== --- pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py (original) +++ pypy/branch/js-refactoring/pypy/translator/goal/targetjsstandalone.py Thu Sep 10 15:10:12 2009 @@ -1,26 +1,45 @@ """ A simple standalone target for the javascript interpreter. + +Usage: js-c [-f] jsourcefile [-f] other_source ... """ import sys + from pypy.lang.js.interpreter import * -from pypy.lang.js.jsobj import ExecutionReturned +from pypy.lang.js.console import JSConsole # __________ Entry point __________ -interp = Interpreter() +def run_file(interp, name): + t = load_file(name) + interp.run(t) def entry_point(argv): - if len(argv) == 2: - t = load_file(argv[1]) - interp.run(t) + i = 1 + + if len(argv) == 1: + console = JSConsole() + console.interact() return 0 - elif argv[0] == 'foo': - raise ExecutionReturned(None) - else: - print "Usage: %s jsourcefile" % argv[0] - return 1 - + + interp = Interpreter() + while i < len(argv): + arg = argv[i] + if arg == '-f': + if i == len(argv) - 1: + print __doc__ + return 1 + i += 1 + run_file(interp, argv[i]) + elif arg.startswith('-'): + print "Unsupported option %s" % arg + print __doc__ + return 1 + else: + run_file(interp, argv[i]) + i += 1 + return 0 # _____ Define and setup target ___ def target(driver, args): From fijal at codespeak.net Thu Sep 10 15:13:33 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 10 Sep 2009 15:13:33 +0200 (CEST) Subject: [pypy-svn] r67617 - in pypy/trunk/pypy/rpython: . test Message-ID: <20090910131333.0BD9C168024@codespeak.net> Author: fijal Date: Thu Sep 10 15:13:33 2009 New Revision: 67617 Modified: pypy/trunk/pypy/rpython/rint.py pypy/trunk/pypy/rpython/test/test_rint.py Log: A test and a fix, thanks jandem for reporting Modified: pypy/trunk/pypy/rpython/rint.py ============================================================================== --- pypy/trunk/pypy/rpython/rint.py (original) +++ pypy/trunk/pypy/rpython/rint.py Thu Sep 10 15:13:33 2009 @@ -385,6 +385,7 @@ def rtype_float(_, hop): vlist = hop.inputargs(Float) + hop.exception_cannot_occur() return vlist[0] # version picked by specialisation based on which Modified: pypy/trunk/pypy/rpython/test/test_rint.py ============================================================================== --- pypy/trunk/pypy/rpython/test/test_rint.py (original) +++ pypy/trunk/pypy/rpython/test/test_rint.py Thu Sep 10 15:13:33 2009 @@ -327,6 +327,16 @@ res = self.interpret(f, [sys.maxint]) assert res == 0 + def test_cast_to_float_exc_check(self): + def f(x): + try: + return float(x) + except ValueError: + return 3.0 + + res = self.interpret(f, [3]) + assert res == 3 + class TestLLtype(BaseTestRint, LLRtypeMixin): pass From pedronis at codespeak.net Thu Sep 10 15:27:39 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 10 Sep 2009 15:27:39 +0200 (CEST) Subject: [pypy-svn] r67618 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090910132739.4053516801E@codespeak.net> Author: pedronis Date: Thu Sep 10 15:27:37 2009 New Revision: 67618 Modified: pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py Log: (micke, pedronis) accomodate the trace_limit tests Modified: pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py Thu Sep 10 15:27:37 2009 @@ -90,7 +90,9 @@ pass def check_enter_count_at_most(self, count): pass - def check_jumps(self, maxcount): + def check_jumps(self, maxcount): + pass + def check_aborted_count(self, count): pass def interp_operations(self, *args, **kwds): From pedronis at codespeak.net Thu Sep 10 15:30:38 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 10 Sep 2009 15:30:38 +0200 (CEST) Subject: [pypy-svn] r67619 - in pypy/trunk/pypy: jit/metainterp jit/metainterp/test rlib Message-ID: <20090910133038.3AC2F168014@codespeak.net> Author: pedronis Date: Thu Sep 10 15:30:37 2009 New Revision: 67619 Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/test_recursive.py pypy/trunk/pypy/jit/metainterp/warmspot.py pypy/trunk/pypy/rlib/jit.py Log: (micke, pedronis) implement a driver hook that is traced through before residual recursive calls to the portal, the idea is to be able from there to contain escaping, to be used on spine-of-frames branch Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/codewriter.py Thu Sep 10 15:30:37 2009 @@ -1087,6 +1087,8 @@ calldescr, non_void_args = self.codewriter.getcalldescr(op.args[0], args, op.result) + self.emit('recursion_leave_prep') + self.emit_varargs(non_void_args) self.emit('recursive_call') self.emit(self.get_position(calldescr)) self.emit_varargs([op.args[0]] + non_void_args) Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Thu Sep 10 15:30:37 2009 @@ -643,6 +643,19 @@ def opimpl_residual_call(self, calldescr, varargs): return self.execute_with_exc(rop.CALL, varargs, descr=calldescr) + @arguments("varargs") + def opimpl_recursion_leave_prep(self, varargs): + warmrunnerstate = self.metainterp.staticdata.state + if warmrunnerstate.inlining: + num_green_args = self.metainterp.staticdata.num_green_args + greenkey = varargs[:num_green_args] + if warmrunnerstate.can_inline_callable(greenkey): + return False + leave_code = self.metainterp.staticdata.leave_code + if leave_code is None: + return False + return self.perform_call(leave_code, varargs) + @arguments("descr", "varargs") def opimpl_recursive_call(self, calldescr, varargs): warmrunnerstate = self.metainterp.staticdata.state @@ -650,7 +663,7 @@ num_green_args = self.metainterp.staticdata.num_green_args portal_code = self.metainterp.staticdata.portal_code greenkey = varargs[1:num_green_args + 1] - if self.metainterp.staticdata.state.can_inline_callable(greenkey): + if warmrunnerstate.can_inline_callable(greenkey): return self.perform_call(portal_code, varargs[1:]) return self.execute_with_exc(rop.CALL, varargs, descr=calldescr) @@ -1005,7 +1018,8 @@ virtualizable_info = None def __init__(self, portal_graph, graphs, cpu, stats, options, - optimizer=None, profile=None, warmrunnerdesc=None): + optimizer=None, profile=None, warmrunnerdesc=None, + leave_graph=None): self.portal_graph = portal_graph self.cpu = cpu self.stats = stats @@ -1039,6 +1053,8 @@ self.jit_starting_line = 'JIT starting (%s, %s)' % (optmodule, backendmodule) + self.leave_graph = leave_graph + def _freeze_(self): return True @@ -1075,6 +1091,11 @@ self._codewriter = codewriter.CodeWriter(self, policy) self.portal_code = self._codewriter.make_portal_bytecode( self.portal_graph) + self.leave_code = None + if self.leave_graph: + self.leave_code = self._codewriter.make_one_bytecode( + (self.leave_graph, None), + False) self._class_sizes = self._codewriter.class_sizes # ---------- construction-time interface ---------- Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Thu Sep 10 15:30:37 2009 @@ -376,17 +376,15 @@ res = self.meta_interp(main, [1], optimizer=simple_optimize, trace_limit=TRACE_LIMIT) self.check_loops(call=0) - - @py.test.mark.xfail def test_leave_jit_hook(self): from pypy.rpython.annlowlevel import hlstr def p(code, pc): code = hlstr(code) return "%s %d %s" % (code, pc, code[pc]) def c(code, pc): - return "l" not in hlstr(code) + return "L" not in hlstr(code) - def leave(frame, code): + def leave(code, pc, frame): frame.hookcalled = True class ExpectedHook(Exception): @@ -395,8 +393,11 @@ pass myjitdriver = JitDriver(greens=['code', 'pc'], reds=['self'], - get_printable_location=p, can_inline=c) + get_printable_location=p, can_inline=c, + leave=leave) class Frame(object): + hookcalled = True + def __init__(self, n): self.n = n self.hookcalled = False Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Thu Sep 10 15:30:37 2009 @@ -141,6 +141,7 @@ policy = JitPolicy() self.set_translator(translator) self.find_portal() + self.make_leave_jit_graph() graphs = find_all_graphs(self.portal_graph, policy, self.translator, CPUClass.supports_floats) self.check_access_directly_sanity(graphs) @@ -233,7 +234,8 @@ self.stats, opt, optimizer=optimizer, profile=profile, - warmrunnerdesc=self) + warmrunnerdesc=self, + leave_graph=self.leave_graph) def make_enter_function(self): WarmEnterState = make_state_class(self) @@ -268,6 +270,21 @@ self.maybe_enter_jit_fn = maybe_enter_jit + def make_leave_jit_graph(self): + self.leave_graph = None + if self.jitdriver.leave: + graph, block, index = self.jit_merge_point_pos + op = block.operations[index] + args = op.args[2:] + s_binding = self.translator.annotator.binding + args_s = [s_binding(v) for v in args] + from pypy.annotation import model as annmodel + annhelper = MixLevelHelperAnnotator(self.translator.rtyper) + s_result = annmodel.s_None + self.leave_graph = annhelper.getgraph(self.jitdriver.leave, + args_s, s_result) + annhelper.finish() + def make_driverhook_graph(self): self.can_inline_ptr = self._make_hook_graph( self.jitdriver.can_inline, bool) Modified: pypy/trunk/pypy/rlib/jit.py ============================================================================== --- pypy/trunk/pypy/rlib/jit.py (original) +++ pypy/trunk/pypy/rlib/jit.py Thu Sep 10 15:30:37 2009 @@ -100,7 +100,8 @@ virtualizables = [] def __init__(self, greens=None, reds=None, virtualizables=None, - can_inline=None, get_printable_location=None): + can_inline=None, get_printable_location=None, + leave=None): if greens is not None: self.greens = greens if reds is not None: @@ -115,6 +116,7 @@ self._make_extregistryentries() self.get_printable_location = get_printable_location self.can_inline = can_inline + self.leave = leave def _freeze_(self): return True From afa at codespeak.net Thu Sep 10 16:10:28 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Thu, 10 Sep 2009 16:10:28 +0200 (CEST) Subject: [pypy-svn] r67620 - in pypy/branch/windowserror/pypy: module/posix translator/c translator/c/src translator/tool Message-ID: <20090910141028.11C13168021@codespeak.net> Author: afa Date: Thu Sep 10 16:10:27 2009 New Revision: 67620 Modified: pypy/branch/windowserror/pypy/module/posix/interp_posix.py pypy/branch/windowserror/pypy/translator/c/genc.py pypy/branch/windowserror/pypy/translator/c/src/thread_nt.h pypy/branch/windowserror/pypy/translator/tool/cbuild.py Log: I *think* this is the correct fix for the winsock.h / winsock2.h mess: #define WIN32_LEAN_AND_MEAN prevents windows.h to include winsock.h (and some others) so we may include winsock2.h anywhere. pypy-c still translates and compiles, it is possible that some unit tests are missing some #includes Modified: pypy/branch/windowserror/pypy/module/posix/interp_posix.py ============================================================================== --- pypy/branch/windowserror/pypy/module/posix/interp_posix.py (original) +++ pypy/branch/windowserror/pypy/module/posix/interp_posix.py Thu Sep 10 16:10:27 2009 @@ -843,7 +843,7 @@ from pypy.rlib import rwin32 eci = ExternalCompilationInfo( - includes = ['windows.h'], + includes = ['windows.h', 'wincrypt.h'], libraries = ['advapi32'], ) Modified: pypy/branch/windowserror/pypy/translator/c/genc.py ============================================================================== --- pypy/branch/windowserror/pypy/translator/c/genc.py (original) +++ pypy/branch/windowserror/pypy/translator/c/genc.py Thu Sep 10 16:10:27 2009 @@ -785,7 +785,10 @@ for key, value in defines.items(): print >> fi, '#define %s %s' % (key, value) - print >> fi, '#define Py_BUILD_CORE /* for Windows: avoid pulling libs in */' + if sys.platform == 'win32': + print >> fi, '#define Py_BUILD_CORE /* avoid pulling python libs in */' + print >> fi, '#define WIN32_LEAN_AND_MEAN /* winsock/winsock2 mess */' + print >> fi, '#include "pyconfig.h"' eci.write_c_header(fi) @@ -838,6 +841,9 @@ for key, value in defines.items(): print >> fi, '#define %s %s' % (key, value) + if sys.platform == 'win32': + print >> fi, '#define WIN32_LEAN_AND_MEAN /* winsock/winsock2 mess */' + print >> fi, '#include "pyconfig.h"' eci.write_c_header(fi) Modified: pypy/branch/windowserror/pypy/translator/c/src/thread_nt.h ============================================================================== --- pypy/branch/windowserror/pypy/translator/c/src/thread_nt.h (original) +++ pypy/branch/windowserror/pypy/translator/c/src/thread_nt.h Thu Sep 10 16:10:27 2009 @@ -4,12 +4,6 @@ /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch at iso.ru */ /* Eliminated some memory leaks, gsw at agere.com */ -/* Windows.h includes winsock.h, but the socket module needs */ -/* winsock2.h. So I include it before. Ugly. */ - -#include -#include - #include #include #include Modified: pypy/branch/windowserror/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/branch/windowserror/pypy/translator/tool/cbuild.py (original) +++ pypy/branch/windowserror/pypy/translator/tool/cbuild.py Thu Sep 10 16:10:27 2009 @@ -249,6 +249,8 @@ f = filename.open("w") if being_main: f.write("#define PYPY_NOT_MAIN_FILE\n") + if sys.platform == 'win32': + f.write("#define WIN32_LEAN_AND_MEAN\n") self.write_c_header(f) source = str(source) f.write(source) From cfbolz at codespeak.net Thu Sep 10 16:13:35 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 16:13:35 +0200 (CEST) Subject: [pypy-svn] r67621 - pypy/branch/spine-of-frames/pypy/interpreter Message-ID: <20090910141335.66D1E168024@codespeak.net> Author: cfbolz Date: Thu Sep 10 16:13:34 2009 New Revision: 67621 Modified: pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py Log: kill commented out code Modified: pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py Thu Sep 10 16:13:34 2009 @@ -144,13 +144,6 @@ if f_back is not None: f_back.f_forward = None - - #f_back = frame.f_back() - #if f_back is not None: - # f_back.f_forward = None # this is the other one, yes # the goal is to set the forward attr only in the jitted case - #if not self._we_are_jitted() or self.some_frame is frame: - # self.some_frame = frame.f_back_some - self.framestackdepth -= 1 @staticmethod From cfbolz at codespeak.net Thu Sep 10 16:41:54 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 16:41:54 +0200 (CEST) Subject: [pypy-svn] r67622 - in pypy/branch/spine-of-frames/pypy/interpreter: . test Message-ID: <20090910144154.99BE3168021@codespeak.net> Author: cfbolz Date: Thu Sep 10 16:41:52 2009 New Revision: 67622 Modified: pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py Log: Add a new method on the executioncontext that will be called by the new jit-leaving hook that was introduced on trunk in 67619. Modified: pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py Thu Sep 10 16:41:52 2009 @@ -11,7 +11,7 @@ space.wrap(frame), space.wrap(event), w_arg) -class ExecutionContext: +class ExecutionContext(object): """An ExecutionContext holds the state of an execution thread in the Python interpreter.""" @@ -146,6 +146,15 @@ self.framestackdepth -= 1 + def _jit_rechain_frame(self, frame): + # this method is called after the jit has seen enter (and thus _chain) + # of a frame, but then does not actually inline it. This method thus + # needs to make sure that the state is as if the _chain method had been + # executed outside of the jit. Note that this makes it important that + # _unchain does not call we_are_jitted + frame.f_back().f_forward = None + self.some_frame = frame + @staticmethod def _extract_back_from_frame(frame): back_some = frame.f_back_some Modified: pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py Thu Sep 10 16:41:52 2009 @@ -235,14 +235,13 @@ def _we_are_jitted(self): return self.jitted - def _get_some_frame(self): if self._some_frame: self._some_frame.look_at() return self._some_frame def _set_some_frame(self, frame): - if frame.virtual_with_base_frame: - frame.escaped = True + if frame is not None: + frame.force() self._some_frame = frame some_frame = property(_get_some_frame, _set_some_frame) @@ -400,7 +399,6 @@ assert ec._extract_back_from_frame(frame) is None assert frame3.f_back() is frame2 - # now we should unchain ec._unchain(frame3) assert ec.some_frame is frame2 assert ec.framestackdepth == 2 @@ -455,7 +453,6 @@ assert ec._extract_back_from_frame(frame3) is frame2 assert ec._extract_back_from_frame(frame2) is frame assert ec._extract_back_from_frame(frame) is None - # now we should unchain assert frame3.f_back() is frame2 ec._unchain(frame3) @@ -521,7 +518,6 @@ assert ec._extract_back_from_frame(frame3) is frame2 assert ec._extract_back_from_frame(frame2) is frame assert ec._extract_back_from_frame(frame) is None - # now we should unchain assert frame3.f_back() is frame2 ec._unchain(frame3) @@ -675,6 +671,7 @@ # recursive enter/leave seen by the jit frame3 = self.Frame(ec, frame) ec._chain(frame3) + ec._jit_rechain_frame(frame3) ec.jitted = False frame3.look_at() assert not frame2.escaped @@ -689,15 +686,15 @@ def test_check_escaping_multi_non_jitted_levels(self): - py.test.skip("escapes") ec, frame, frame2 = self.enter_two_jitted_levels() # recursive enter/leave seen by the jit frame3 = self.Frame(ec, frame) ec._chain(frame3) + ec._jit_rechain_frame(frame3) ec.jitted = False - frame3.look_at() + assert frame3.escaped assert not frame2.escaped assert frame3.escaped @@ -717,22 +714,23 @@ self.leave_two_jitted_levels(ec, frame, frame2) def test_check_escaping_jitted_with_two_differen_virtualizables(self): - py.test.skip("escapes") ec, frame, frame2 = self.enter_two_jitted_levels() frame3 = self.Frame(ec, frame) ec._chain(frame3) # frame3 is not inlined, but contains a loop itself, for which code has # been generated + ec._jit_rechain_frame(frame3) ec.virtualizable = frame3 frame3.look_at() assert not frame2.escaped assert frame3.escaped - frame4 = self.Frame(ec) + frame4 = self.Frame(ec, frame3) ec._chain(frame4) assert ec.framestackdepth == 4 + assert not frame4.escaped ec._unchain(frame4) assert frame3.escaped From afa at codespeak.net Thu Sep 10 16:42:20 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Thu, 10 Sep 2009 16:42:20 +0200 (CEST) Subject: [pypy-svn] r67623 - in pypy/trunk/pypy: annotation interpreter module/posix module/posix/test rlib rpython rpython/module translator/c translator/c/src translator/c/test translator/tool Message-ID: <20090910144220.E767B168021@codespeak.net> Author: afa Date: Thu Sep 10 16:42:20 2009 New Revision: 67623 Modified: pypy/trunk/pypy/annotation/builtin.py pypy/trunk/pypy/annotation/classdef.py pypy/trunk/pypy/interpreter/error.py pypy/trunk/pypy/module/posix/interp_posix.py pypy/trunk/pypy/module/posix/test/test_posix2.py pypy/trunk/pypy/rlib/libffi.py pypy/trunk/pypy/rlib/rwin32.py pypy/trunk/pypy/rpython/module/ll_os.py pypy/trunk/pypy/rpython/rbuiltin.py pypy/trunk/pypy/translator/c/genc.py pypy/trunk/pypy/translator/c/src/thread_nt.h pypy/trunk/pypy/translator/c/test/test_extfunc.py pypy/trunk/pypy/translator/tool/cbuild.py Log: Merge windowserror branch: Better WindowsError support in RPython: like OSError, it allows the throw site to store the windows error code (=GetLastError()) in the exception. Now the posix module raises WindowsError with the correct winerror and errno attributes, this is important at least when pypy-c runs py.test. Modified: pypy/trunk/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/pypy/annotation/builtin.py (original) +++ pypy/trunk/pypy/annotation/builtin.py Thu Sep 10 16:42:20 2009 @@ -270,6 +270,9 @@ def OSError_init(s_self, *args): pass +def WindowsError_init(s_self, *args): + pass + def termios_error_init(s_self, *args): pass @@ -386,6 +389,15 @@ BUILTIN_ANALYZERS[getattr(OSError.__init__, 'im_func', OSError.__init__)] = ( OSError_init) +try: + WindowsError +except NameError: + pass +else: + BUILTIN_ANALYZERS[getattr(WindowsError.__init__, 'im_func', + WindowsError.__init__)] = ( + WindowsError_init) + BUILTIN_ANALYZERS[sys.getdefaultencoding] = conf try: import unicodedata Modified: pypy/trunk/pypy/annotation/classdef.py ============================================================================== --- pypy/trunk/pypy/annotation/classdef.py (original) +++ pypy/trunk/pypy/annotation/classdef.py Thu Sep 10 16:42:20 2009 @@ -442,6 +442,13 @@ } try: + WindowsError +except NameError: + pass +else: + FORCE_ATTRIBUTES_INTO_CLASSES[WindowsError] = {'winerror': SomeInteger()} + +try: import termios except ImportError: pass Modified: pypy/trunk/pypy/interpreter/error.py ============================================================================== --- pypy/trunk/pypy/interpreter/error.py (original) +++ pypy/trunk/pypy/interpreter/error.py Thu Sep 10 16:42:20 2009 @@ -262,8 +262,33 @@ # 31: ANSI color code "red" ansi_print(text, esc="31", file=file, newline=newline) +try: + WindowsError +except NameError: + _WINDOWS = False +else: + _WINDOWS = True + + def wrap_windowserror(space, e): + from pypy.rlib import rwin32 + + winerror = e.winerror + try: + msg = rwin32.FormatError(winerror) + except ValueError: + msg = 'Windows Error %d' % winerror + exc = space.w_WindowsError + w_error = space.call_function(exc, + space.wrap(winerror), + space.wrap(msg)) + return OperationError(exc, w_error) + def wrap_oserror(space, e, exception_name='w_OSError'): assert isinstance(e, OSError) + + if _WINDOWS and isinstance(e, WindowsError): + return wrap_windowserror(space, e) + errno = e.errno try: msg = os.strerror(errno) Modified: pypy/trunk/pypy/module/posix/interp_posix.py ============================================================================== --- pypy/trunk/pypy/module/posix/interp_posix.py (original) +++ pypy/trunk/pypy/module/posix/interp_posix.py Thu Sep 10 16:42:20 2009 @@ -843,7 +843,7 @@ from pypy.rlib import rwin32 eci = ExternalCompilationInfo( - includes = ['windows.h'], + includes = ['windows.h', 'wincrypt.h'], libraries = ['advapi32'], ) Modified: pypy/trunk/pypy/module/posix/test/test_posix2.py ============================================================================== --- pypy/trunk/pypy/module/posix/test/test_posix2.py (original) +++ pypy/trunk/pypy/module/posix/test/test_posix2.py Thu Sep 10 16:42:20 2009 @@ -129,6 +129,19 @@ assert st.st_mtime == 42.1 assert st.st_ctime == 43 + def test_stat_exception(self): + import sys, errno + try: + self.posix.stat("nonexistentdir/nonexistentfile") + except OSError, e: + assert e.errno == errno.ENOENT + # On Windows, when the parent directory does not exist, + # the winerror is 3 (cannot find the path specified) + # instead of 2 (cannot find the file specified) + if sys.platform == 'win32': + assert isinstance(e, WindowsError) + assert e.winerror == 3 + def test_pickle(self): import pickle, os st = self.posix.stat(os.curdir) Modified: pypy/trunk/pypy/rlib/libffi.py ============================================================================== --- pypy/trunk/pypy/rlib/libffi.py (original) +++ pypy/trunk/pypy/rlib/libffi.py Thu Sep 10 16:42:20 2009 @@ -311,8 +311,6 @@ "Procedure called with too many " "arguments (%d bytes in excess) " % (result,)) - - FormatError = rwin32.FormatError LoadLibrary = rwin32.LoadLibrary get_libc_handle = external('get_libc_handle', [], rwin32.HANDLE) Modified: pypy/trunk/pypy/rlib/rwin32.py ============================================================================== --- pypy/trunk/pypy/rlib/rwin32.py (original) +++ pypy/trunk/pypy/rlib/rwin32.py Thu Sep 10 16:42:20 2009 @@ -55,7 +55,8 @@ "MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)") for name in """FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_FROM_SYSTEM - """.split(): + MAX_PATH + """.split(): locals()[name] = rffi_platform.ConstantInteger(name) @@ -112,10 +113,9 @@ LocalFree(buf[0]) return result - def lastWindowsError(context=None): + def lastWindowsError(context="Windows Error"): code = GetLastError() - message = FormatError(code) - return WindowsError(code, message) + return WindowsError(code, context) def FAILED(hr): return rffi.cast(HRESULT, hr) < 0 @@ -125,7 +125,7 @@ DWORD) def GetModuleFileName(module): - size = 255 # MAX_PATH + size = MAX_PATH buf = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw') try: res = _GetModuleFileName(module, buf, size) Modified: pypy/trunk/pypy/rpython/module/ll_os.py ============================================================================== --- pypy/trunk/pypy/rpython/module/ll_os.py (original) +++ pypy/trunk/pypy/rpython/module/ll_os.py Thu Sep 10 16:42:20 2009 @@ -468,24 +468,22 @@ @registering(os.times) def register_os_times(self): if sys.platform.startswith('win'): - HANDLE = rffi.ULONG - FILETIME = rffi.CStruct('_FILETIME', ('dwLowDateTime', rffi.LONG), - ('dwHighDateTime', rffi.LONG)) + from pypy.rlib import rwin32 GetCurrentProcess = self.llexternal('GetCurrentProcess', [], - HANDLE) + rwin32.HANDLE) GetProcessTimes = self.llexternal('GetProcessTimes', - [HANDLE, - lltype.Ptr(FILETIME), - lltype.Ptr(FILETIME), - lltype.Ptr(FILETIME), - lltype.Ptr(FILETIME)], - lltype.Bool) + [rwin32.HANDLE, + lltype.Ptr(rwin32.FILETIME), + lltype.Ptr(rwin32.FILETIME), + lltype.Ptr(rwin32.FILETIME), + lltype.Ptr(rwin32.FILETIME)], + rwin32.BOOL) def times_lltypeimpl(): - pcreate = lltype.malloc(FILETIME, flavor='raw') - pexit = lltype.malloc(FILETIME, flavor='raw') - pkernel = lltype.malloc(FILETIME, flavor='raw') - puser = lltype.malloc(FILETIME, flavor='raw') + pcreate = lltype.malloc(rwin32.FILETIME, flavor='raw') + pexit = lltype.malloc(rwin32.FILETIME, flavor='raw') + pkernel = lltype.malloc(rwin32.FILETIME, flavor='raw') + puser = lltype.malloc(rwin32.FILETIME, flavor='raw') hProc = GetCurrentProcess() GetProcessTimes(hProc, pcreate, pexit, pkernel, puser) # The fields of a FILETIME structure are the hi and lo parts @@ -904,47 +902,29 @@ @registering_if(posix, '_getfullpathname') def register_posix__getfullpathname(self): + from pypy.rlib import rwin32 # this nt function is not exposed via os, but needed # to get a correct implementation of os.abspath # XXX why do we ignore WINAPI conventions everywhere? - class CConfig: - _compilation_info_ = ExternalCompilationInfo( - includes = ['Windows.h'] - ) - MAX_PATH = platform.ConstantInteger('MAX_PATH') - DWORD = platform.SimpleType("DWORD", rffi.ULONG) - LPCTSTR = platform.SimpleType("LPCTSTR", rffi.CCHARP) - LPTSTR = platform.SimpleType("LPTSTR", rffi.CCHARP) - LPTSTRP = platform.SimpleType("LPTSTR*", rffi.CCHARPP) - - config = platform.configure(CConfig) - MAX_PATH = config['MAX_PATH'] - DWORD = config['DWORD'] - LPCTSTR = config['LPCTSTR'] - LPTSTR = config['LPTSTR'] - LPTSTRP = config['LPTSTRP'] + LPSTRP = rffi.CArrayPtr(rwin32.LPSTR) # XXX unicode? - GetFullPathName = self.llexternal('GetFullPathNameA', - [LPCTSTR, DWORD, LPTSTR, LPTSTRP], DWORD) - GetLastError = self.llexternal('GetLastError', [], DWORD) - ##DWORD WINAPI GetFullPathName( - ## __in LPCTSTR lpFileName, - ## __in DWORD nBufferLength, - ## __out LPTSTR lpBuffer, - ## __out LPTSTR* lpFilePart - ##); + GetFullPathName = self.llexternal( + 'GetFullPathNameA', + [rwin32.LPCSTR, + rwin32.DWORD, + rwin32.LPSTR, + rffi.CArrayPtr(rwin32.LPSTR)], + rwin32.DWORD) def _getfullpathname_llimpl(lpFileName): - nBufferLength = MAX_PATH + 1 - lpBuffer = lltype.malloc(LPTSTR.TO, nBufferLength, flavor='raw') + nBufferLength = rwin32.MAX_PATH + 1 + lpBuffer = lltype.malloc(rwin32.LPSTR.TO, nBufferLength, flavor='raw') try: res = GetFullPathName( - lpFileName, rffi.cast(DWORD, nBufferLength), - lpBuffer, lltype.nullptr(LPTSTRP.TO)) + lpFileName, rffi.cast(rwin32.DWORD, nBufferLength), + lpBuffer, lltype.nullptr(LPSTRP.TO)) if res == 0: - error = GetLastError() - raise OSError(error, "_getfullpathname failed") - # XXX ntpath expects WindowsError :-( + raise rwin32.lastWindowsError("_getfullpathname failed") result = rffi.charp2str(lpBuffer) return result finally: @@ -991,14 +971,13 @@ def register_os_listdir(self): # we need a different approach on Windows and on Posix if sys.platform.startswith('win'): + from pypy.rlib import rwin32 class CConfig: _compilation_info_ = ExternalCompilationInfo( includes = ['windows.h'] ) WIN32_FIND_DATA = platform.Struct('struct _WIN32_FIND_DATAA', [('cFileName', lltype.FixedSizeArray(rffi.CHAR, 1))]) - INVALID_HANDLE_VALUE = platform.ConstantInteger( - 'INVALID_HANDLE_VALUE') ERROR_FILE_NOT_FOUND = platform.ConstantInteger( 'ERROR_FILE_NOT_FOUND') ERROR_NO_MORE_FILES = platform.ConstantInteger( @@ -1006,23 +985,19 @@ config = platform.configure(CConfig) WIN32_FIND_DATA = config['WIN32_FIND_DATA'] - INVALID_HANDLE_VALUE = config['INVALID_HANDLE_VALUE'] ERROR_FILE_NOT_FOUND = config['ERROR_FILE_NOT_FOUND'] ERROR_NO_MORE_FILES = config['ERROR_NO_MORE_FILES'] LPWIN32_FIND_DATA = lltype.Ptr(WIN32_FIND_DATA) - HANDLE = rffi.ULONG - #MAX_PATH = WIN32_FIND_DATA.c_cFileName.length - GetLastError = self.llexternal('GetLastError', [], lltype.Signed) FindFirstFile = self.llexternal('FindFirstFile', - [rffi.CCHARP, LPWIN32_FIND_DATA], - HANDLE) + [rwin32.LPCSTR, LPWIN32_FIND_DATA], + rwin32.HANDLE) FindNextFile = self.llexternal('FindNextFile', - [HANDLE, LPWIN32_FIND_DATA], - rffi.INT) + [rwin32.HANDLE, LPWIN32_FIND_DATA], + rwin32.BOOL) FindClose = self.llexternal('FindClose', - [HANDLE], - rffi.INT) + [rwin32.HANDLE], + rwin32.BOOL) def os_listdir_llimpl(path): if path and path[-1] not in ('/', '\\', ':'): @@ -1032,13 +1007,12 @@ try: result = [] hFindFile = FindFirstFile(path, filedata) - if hFindFile == INVALID_HANDLE_VALUE: - error = GetLastError() + if hFindFile == rwin32.INVALID_HANDLE_VALUE: + error = rwin32.GetLastError() if error == ERROR_FILE_NOT_FOUND: return result else: - # XXX guess error code :-( - raise OSError(errno.ENOENT, "FindFirstFile failed") + raise WindowsError(error, "FindFirstFile failed") while True: name = rffi.charp2str(rffi.cast(rffi.CCHARP, filedata.c_cFileName)) @@ -1048,13 +1022,12 @@ break # FindNextFile sets error to ERROR_NO_MORE_FILES if # it got to the end of the directory - error = GetLastError() + error = rwin32.GetLastError() FindClose(hFindFile) if error == ERROR_NO_MORE_FILES: return result else: - # XXX guess error code :-( - raise OSError(errno.EIO, "FindNextFile failed") + raise WindowsError(error, "FindNextFile failed") finally: lltype.free(filedata, flavor='raw') @@ -1107,28 +1080,31 @@ def register_os_pipe(self): # we need a different approach on Windows and on Posix if sys.platform.startswith('win'): - HANDLE = rffi.ULONG - HANDLEP = lltype.Ptr(lltype.FixedSizeArray(HANDLE, 1)) - CreatePipe = self.llexternal('CreatePipe', [HANDLEP, - HANDLEP, + from pypy.rlib import rwin32 + CreatePipe = self.llexternal('CreatePipe', [rwin32.LPHANDLE, + rwin32.LPHANDLE, rffi.VOIDP, - rffi.ULONG], - rffi.INT) + rwin32.DWORD], + rwin32.BOOL) _open_osfhandle = self.llexternal('_open_osfhandle', [rffi.ULONG, rffi.INT], rffi.INT) null = lltype.nullptr(rffi.VOIDP.TO) def os_pipe_llimpl(): - pread = lltype.malloc(HANDLEP.TO, flavor='raw') - pwrite = lltype.malloc(HANDLEP.TO, flavor='raw') + pread = lltype.malloc(rwin32.LPHANDLE.TO, 1, flavor='raw') + pwrite = lltype.malloc(rwin32.LPHANDLE.TO, 1, flavor='raw') ok = CreatePipe(pread, pwrite, null, 0) + if ok: + error = 0 + else: + error = rwin32.GetLastError() hread = pread[0] hwrite = pwrite[0] lltype.free(pwrite, flavor='raw') lltype.free(pread, flavor='raw') - if not ok: # XXX guess the error, can't use GetLastError() - raise OSError(errno.EMFILE, "os_pipe failed") + if error: + raise WindowsError(error, "os_pipe failed") fdread = _open_osfhandle(hread, 0) fdwrite = _open_osfhandle(hwrite, 1) return (fdread, fdwrite) Modified: pypy/trunk/pypy/rpython/rbuiltin.py ============================================================================== --- pypy/trunk/pypy/rpython/rbuiltin.py (original) +++ pypy/trunk/pypy/rpython/rbuiltin.py Thu Sep 10 16:42:20 2009 @@ -268,6 +268,16 @@ v_errno = hop.inputarg(lltype.Signed, arg=1) r_self.setfield(v_self, 'errno', v_errno, hop.llops) +def rtype_WindowsError__init__(hop): + if hop.nb_args == 2: + raise TyperError("WindowsError() should not be called with " + "a single argument") + if hop.nb_args >= 3: + v_self = hop.args_v[0] + r_self = hop.args_r[0] + v_error = hop.inputarg(lltype.Signed, arg=1) + r_self.setfield(v_self, 'winerror', v_error, hop.llops) + def rtype_we_are_translated(hop): hop.exception_cannot_occur() return hop.inputconst(lltype.Bool, True) @@ -318,6 +328,15 @@ BUILTIN_TYPER[getattr(OSError.__init__, 'im_func', OSError.__init__)] = ( rtype_OSError__init__) +try: + WindowsError +except NameError: + pass +else: + BUILTIN_TYPER[ + getattr(WindowsError.__init__, 'im_func', WindowsError.__init__)] = ( + rtype_WindowsError__init__) + BUILTIN_TYPER[object.__init__] = rtype_object__init__ # annotation of low-level types Modified: pypy/trunk/pypy/translator/c/genc.py ============================================================================== --- pypy/trunk/pypy/translator/c/genc.py (original) +++ pypy/trunk/pypy/translator/c/genc.py Thu Sep 10 16:42:20 2009 @@ -791,7 +791,10 @@ for key, value in defines.items(): print >> fi, '#define %s %s' % (key, value) - print >> fi, '#define Py_BUILD_CORE /* for Windows: avoid pulling libs in */' + if sys.platform == 'win32': + print >> fi, '#define Py_BUILD_CORE /* avoid pulling python libs in */' + print >> fi, '#define WIN32_LEAN_AND_MEAN /* winsock/winsock2 mess */' + print >> fi, '#include "pyconfig.h"' eci.write_c_header(fi) @@ -844,6 +847,9 @@ for key, value in defines.items(): print >> fi, '#define %s %s' % (key, value) + if sys.platform == 'win32': + print >> fi, '#define WIN32_LEAN_AND_MEAN /* winsock/winsock2 mess */' + print >> fi, '#include "pyconfig.h"' eci.write_c_header(fi) Modified: pypy/trunk/pypy/translator/c/src/thread_nt.h ============================================================================== --- pypy/trunk/pypy/translator/c/src/thread_nt.h (original) +++ pypy/trunk/pypy/translator/c/src/thread_nt.h Thu Sep 10 16:42:20 2009 @@ -4,12 +4,6 @@ /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch at iso.ru */ /* Eliminated some memory leaks, gsw at agere.com */ -/* Windows.h includes winsock.h, but the socket module needs */ -/* winsock2.h. So I include it before. Ugly. */ - -#include -#include - #include #include #include Modified: pypy/trunk/pypy/translator/c/test/test_extfunc.py ============================================================================== --- pypy/trunk/pypy/translator/c/test/test_extfunc.py (original) +++ pypy/trunk/pypy/translator/c/test/test_extfunc.py Thu Sep 10 16:42:20 2009 @@ -173,6 +173,19 @@ if has_blocks: assert res[4] == os.stat(filename).st_blocks +def test_os_stat_raises_winerror(): + if sys.platform != 'win32': + py.test.skip("no WindowsError on this platform") + def call_stat(): + try: + os.stat("nonexistentdir/nonexistentfile") + except WindowsError, e: + return e.winerror + f = compile(call_stat, []) + res = f() + expected = call_stat() + assert res == expected + def test_os_fstat(): if os.environ.get('PYPY_CC', '').startswith('tcc'): py.test.skip("segfault with tcc :-(") Modified: pypy/trunk/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/trunk/pypy/translator/tool/cbuild.py (original) +++ pypy/trunk/pypy/translator/tool/cbuild.py Thu Sep 10 16:42:20 2009 @@ -249,6 +249,8 @@ f = filename.open("w") if being_main: f.write("#define PYPY_NOT_MAIN_FILE\n") + if sys.platform == 'win32': + f.write("#define WIN32_LEAN_AND_MEAN\n") self.write_c_header(f) source = str(source) f.write(source) From cfbolz at codespeak.net Thu Sep 10 16:45:17 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 16:45:17 +0200 (CEST) Subject: [pypy-svn] r67624 - in pypy/branch/spine-of-frames/pypy: annotation annotation/test config doc/config interpreter interpreter/astcompiler/tools interpreter/test jit/backend jit/backend/llgraph jit/backend/llsupport jit/backend/llsupport/test jit/backend/test jit/backend/x86 jit/backend/x86/test jit/metainterp jit/metainterp/test jit/tl module/__builtin__ module/_ast module/_ast/test module/_pickle_support module/_testing module/parser module/parser/test module/posix module/posix/test module/pypyjit module/pypyjit/test/loops module/token module/token/test objspace/std objspace/std/test rlib rlib/test rpython rpython/lltypesystem rpython/lltypesystem/test rpython/memory/gc rpython/memory/gctransform rpython/module rpython/ootypesystem rpython/ootypesystem/test rpython/test translator translator/c translator/c/gcc translator/c/gcc/test translator/c/src translator/c/test translator/cli translator/jvm translator/platform translator/tool Message-ID: <20090910144517.104C5168021@codespeak.net> Author: cfbolz Date: Thu Sep 10 16:45:13 2009 New Revision: 67624 Added: pypy/branch/spine-of-frames/pypy/doc/config/objspace.std.newshortcut.txt - copied unchanged from r67623, pypy/trunk/pypy/doc/config/objspace.std.newshortcut.txt pypy/branch/spine-of-frames/pypy/jit/backend/x86/test/test_gc_integration.py - copied unchanged from r67623, pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py pypy/branch/spine-of-frames/pypy/jit/backend/x86/test/test_recompilation.py - copied unchanged from r67623, pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_executor.py - copied unchanged from r67623, pypy/trunk/pypy/jit/metainterp/test/test_executor.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_float.py - copied unchanged from r67623, pypy/trunk/pypy/jit/metainterp/test/test_float.py pypy/branch/spine-of-frames/pypy/rlib/rweakref.py - copied unchanged from r67623, pypy/trunk/pypy/rlib/rweakref.py pypy/branch/spine-of-frames/pypy/rlib/rweakrefimpl.py - copied unchanged from r67623, pypy/trunk/pypy/rlib/rweakrefimpl.py pypy/branch/spine-of-frames/pypy/rlib/test/test_rweakref.py - copied unchanged from r67623, pypy/trunk/pypy/rlib/test/test_rweakref.py Modified: pypy/branch/spine-of-frames/pypy/annotation/bookkeeper.py pypy/branch/spine-of-frames/pypy/annotation/builtin.py pypy/branch/spine-of-frames/pypy/annotation/classdef.py pypy/branch/spine-of-frames/pypy/annotation/model.py pypy/branch/spine-of-frames/pypy/annotation/test/test_annrpython.py pypy/branch/spine-of-frames/pypy/annotation/unaryop.py pypy/branch/spine-of-frames/pypy/config/pypyoption.py pypy/branch/spine-of-frames/pypy/interpreter/astcompiler/tools/ (props changed) pypy/branch/spine-of-frames/pypy/interpreter/error.py pypy/branch/spine-of-frames/pypy/interpreter/function.py pypy/branch/spine-of-frames/pypy/interpreter/pycode.py pypy/branch/spine-of-frames/pypy/interpreter/test/test_compiler.py pypy/branch/spine-of-frames/pypy/interpreter/test/test_zzpickle_and_slow.py pypy/branch/spine-of-frames/pypy/jit/backend/llgraph/llimpl.py pypy/branch/spine-of-frames/pypy/jit/backend/llgraph/runner.py pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/gc.py pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/llmodel.py pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/test/test_gc.py pypy/branch/spine-of-frames/pypy/jit/backend/model.py pypy/branch/spine-of-frames/pypy/jit/backend/test/runner_test.py pypy/branch/spine-of-frames/pypy/jit/backend/test/test_random.py pypy/branch/spine-of-frames/pypy/jit/backend/x86/assembler.py pypy/branch/spine-of-frames/pypy/jit/backend/x86/regalloc.py pypy/branch/spine-of-frames/pypy/jit/backend/x86/runner.py pypy/branch/spine-of-frames/pypy/jit/backend/x86/test/test_regalloc.py pypy/branch/spine-of-frames/pypy/jit/backend/x86/test/test_virtual.py pypy/branch/spine-of-frames/pypy/jit/metainterp/codewriter.py pypy/branch/spine-of-frames/pypy/jit/metainterp/compile.py pypy/branch/spine-of-frames/pypy/jit/metainterp/executor.py pypy/branch/spine-of-frames/pypy/jit/metainterp/history.py pypy/branch/spine-of-frames/pypy/jit/metainterp/jitprof.py pypy/branch/spine-of-frames/pypy/jit/metainterp/optimizeopt.py pypy/branch/spine-of-frames/pypy/jit/metainterp/policy.py pypy/branch/spine-of-frames/pypy/jit/metainterp/pyjitpl.py pypy/branch/spine-of-frames/pypy/jit/metainterp/resoperation.py pypy/branch/spine-of-frames/pypy/jit/metainterp/support.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/oparser.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_basic.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_del.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_oparser.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_policy.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_pyjitpl.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_recursive.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_virtual.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_zrpy_basic.py pypy/branch/spine-of-frames/pypy/jit/metainterp/warmspot.py pypy/branch/spine-of-frames/pypy/jit/tl/pypyjit_child.py pypy/branch/spine-of-frames/pypy/module/__builtin__/__init__.py pypy/branch/spine-of-frames/pypy/module/__builtin__/app_functional.py pypy/branch/spine-of-frames/pypy/module/__builtin__/functional.py pypy/branch/spine-of-frames/pypy/module/_ast/ (props changed) pypy/branch/spine-of-frames/pypy/module/_ast/__init__.py (props changed) pypy/branch/spine-of-frames/pypy/module/_ast/test/ (props changed) pypy/branch/spine-of-frames/pypy/module/_ast/test/__init__.py (props changed) pypy/branch/spine-of-frames/pypy/module/_ast/test/test_ast.py (props changed) pypy/branch/spine-of-frames/pypy/module/_pickle_support/__init__.py pypy/branch/spine-of-frames/pypy/module/_pickle_support/maker.py pypy/branch/spine-of-frames/pypy/module/_testing/ (props changed) pypy/branch/spine-of-frames/pypy/module/parser/ (props changed) pypy/branch/spine-of-frames/pypy/module/parser/test/ (props changed) pypy/branch/spine-of-frames/pypy/module/posix/interp_posix.py pypy/branch/spine-of-frames/pypy/module/posix/test/test_posix2.py pypy/branch/spine-of-frames/pypy/module/pypyjit/policy.py pypy/branch/spine-of-frames/pypy/module/pypyjit/test/loops/ (props changed) pypy/branch/spine-of-frames/pypy/module/pypyjit/test/loops/dict_lookup.py (props changed) pypy/branch/spine-of-frames/pypy/module/pypyjit/test/loops/simple_add.py (props changed) pypy/branch/spine-of-frames/pypy/module/token/ (props changed) pypy/branch/spine-of-frames/pypy/module/token/test/ (props changed) pypy/branch/spine-of-frames/pypy/objspace/std/dictmultiobject.py pypy/branch/spine-of-frames/pypy/objspace/std/test/test_typeobject.py pypy/branch/spine-of-frames/pypy/objspace/std/typeobject.py pypy/branch/spine-of-frames/pypy/rlib/jit.py pypy/branch/spine-of-frames/pypy/rlib/libffi.py pypy/branch/spine-of-frames/pypy/rlib/objectmodel.py pypy/branch/spine-of-frames/pypy/rlib/rarithmetic.py pypy/branch/spine-of-frames/pypy/rlib/rwin32.py pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/ll2ctypes.py pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/llarena.py pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/lltype.py pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/rdict.py pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/test/test_ll2ctypes.py pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/test/test_lltype.py pypy/branch/spine-of-frames/pypy/rpython/memory/gc/base.py pypy/branch/spine-of-frames/pypy/rpython/memory/gc/generation.py pypy/branch/spine-of-frames/pypy/rpython/memory/gc/hybrid.py pypy/branch/spine-of-frames/pypy/rpython/memory/gc/markcompact.py pypy/branch/spine-of-frames/pypy/rpython/memory/gc/marksweep.py pypy/branch/spine-of-frames/pypy/rpython/memory/gc/semispace.py pypy/branch/spine-of-frames/pypy/rpython/memory/gctransform/framework.py pypy/branch/spine-of-frames/pypy/rpython/module/ll_os.py pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/ootype.py pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/rpbc.py pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/test/test_ootype.py pypy/branch/spine-of-frames/pypy/rpython/rbuiltin.py pypy/branch/spine-of-frames/pypy/rpython/rint.py pypy/branch/spine-of-frames/pypy/rpython/rpbc.py pypy/branch/spine-of-frames/pypy/rpython/rtyper.py pypy/branch/spine-of-frames/pypy/rpython/test/test_llann.py pypy/branch/spine-of-frames/pypy/rpython/test/test_rclass.py pypy/branch/spine-of-frames/pypy/rpython/test/test_rint.py pypy/branch/spine-of-frames/pypy/translator/c/gcc/test/test_asmgcroot.py pypy/branch/spine-of-frames/pypy/translator/c/gcc/trackgcroot.py pypy/branch/spine-of-frames/pypy/translator/c/genc.py pypy/branch/spine-of-frames/pypy/translator/c/src/thread_nt.h pypy/branch/spine-of-frames/pypy/translator/c/test/test_extfunc.py pypy/branch/spine-of-frames/pypy/translator/cli/opcodes.py pypy/branch/spine-of-frames/pypy/translator/driver.py pypy/branch/spine-of-frames/pypy/translator/jvm/cmpopcodes.py pypy/branch/spine-of-frames/pypy/translator/platform/__init__.py pypy/branch/spine-of-frames/pypy/translator/platform/posix.py pypy/branch/spine-of-frames/pypy/translator/platform/windows.py pypy/branch/spine-of-frames/pypy/translator/tool/cbuild.py Log: merge in changes from revisions r67429 through r67623 of trunk. Modified: pypy/branch/spine-of-frames/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/annotation/bookkeeper.py (original) +++ pypy/branch/spine-of-frames/pypy/annotation/bookkeeper.py Thu Sep 10 16:45:13 2009 @@ -11,8 +11,8 @@ SomeLLADTMeth, SomeBool, SomeTuple, SomeOOClass, SomeImpossibleValue, \ SomeUnicodeString, SomeList, SomeObject, HarmlesslyBlocked, \ SomeWeakRef, lltype_to_annotation -from pypy.annotation.classdef import InstanceSource -from pypy.annotation.listdef import ListDef +from pypy.annotation.classdef import InstanceSource, ClassDef +from pypy.annotation.listdef import ListDef, ListItem from pypy.annotation.dictdef import DictDef from pypy.annotation import description from pypy.annotation.signature import annotationoftype @@ -228,6 +228,38 @@ finally: self.leave() + # sanity check: no flags attached to heap stored instances + + seen = set() + + def check_no_flags(s_value_or_def): + if isinstance(s_value_or_def, SomeInstance): + assert not s_value_or_def.flags, "instance annotation with flags escaped to the heap" + check_no_flags(s_value_or_def.classdef) + elif isinstance(s_value_or_def, SomeList): + check_no_flags(s_value_or_def.listdef.listitem) + elif isinstance(s_value_or_def, SomeDict): + check_no_flags(s_value_or_def.dictdef.dictkey) + check_no_flags(s_value_or_def.dictdef.dictvalue) + elif isinstance(s_value_or_def, SomeTuple): + for s_item in s_value_or_def.items: + check_no_flags(s_item) + elif isinstance(s_value_or_def, ClassDef): + if s_value_or_def in seen: + return + seen.add(s_value_or_def) + for attr in s_value_or_def.attrs.values(): + s_attr = attr.s_value + check_no_flags(s_attr) + elif isinstance(s_value_or_def, ListItem): + if s_value_or_def in seen: + return + seen.add(s_value_or_def) + check_no_flags(s_value_or_def.s_value) + + for clsdef in self.classdefs: + check_no_flags(clsdef) + def consider_call_site(self, call_op): binding = self.annotator.binding s_callable = binding(call_op.args[0]) Modified: pypy/branch/spine-of-frames/pypy/annotation/builtin.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/annotation/builtin.py (original) +++ pypy/branch/spine-of-frames/pypy/annotation/builtin.py Thu Sep 10 16:45:13 2009 @@ -270,6 +270,9 @@ def OSError_init(s_self, *args): pass +def WindowsError_init(s_self, *args): + pass + def termios_error_init(s_self, *args): pass @@ -386,6 +389,15 @@ BUILTIN_ANALYZERS[getattr(OSError.__init__, 'im_func', OSError.__init__)] = ( OSError_init) +try: + WindowsError +except NameError: + pass +else: + BUILTIN_ANALYZERS[getattr(WindowsError.__init__, 'im_func', + WindowsError.__init__)] = ( + WindowsError_init) + BUILTIN_ANALYZERS[sys.getdefaultencoding] = conf try: import unicodedata Modified: pypy/branch/spine-of-frames/pypy/annotation/classdef.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/annotation/classdef.py (original) +++ pypy/branch/spine-of-frames/pypy/annotation/classdef.py Thu Sep 10 16:45:13 2009 @@ -442,6 +442,13 @@ } try: + WindowsError +except NameError: + pass +else: + FORCE_ATTRIBUTES_INTO_CLASSES[WindowsError] = {'winerror': SomeInteger()} + +try: import termios except ImportError: pass Modified: pypy/branch/spine-of-frames/pypy/annotation/model.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/annotation/model.py (original) +++ pypy/branch/spine-of-frames/pypy/annotation/model.py Thu Sep 10 16:45:13 2009 @@ -632,15 +632,6 @@ # i think we can only get here in the case of void-returning # functions return s_None - if isinstance(v, MethodType): - ll_ptrtype = lltype.typeOf(v.im_self) - assert isinstance(ll_ptrtype, (lltype.Ptr, lltype.InteriorPtr)) - return SomeLLADTMeth(ll_ptrtype, v.im_func) - if isinstance(v, FunctionType): - # this case should only be for staticmethod instances used in - # adtmeths: the getattr() result is then a plain FunctionType object. - from pypy.annotation.bookkeeper import getbookkeeper - return getbookkeeper().immutablevalue(v) if isinstance(v, lltype._interior_ptr): ob = v._parent if ob is None: Modified: pypy/branch/spine-of-frames/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/annotation/test/test_annrpython.py (original) +++ pypy/branch/spine-of-frames/pypy/annotation/test/test_annrpython.py Thu Sep 10 16:45:13 2009 @@ -2785,6 +2785,64 @@ assert isinstance(s.items[2], annmodel.SomeInstance) assert s.items[2].flags == {} + def test_no_access_directly_on_heap(self): + from pypy.rlib.jit import hint + + class A: + _virtualizable2_ = [] + + class I: + pass + + def f(): + x = A() + x = hint(x, access_directly=True) + i = I() + i.x = x + + a = self.RPythonAnnotator() + py.test.raises(Exception, a.build_types, f, []) + + + class M: + def __init__(self): + self.l = [] + self.d = {} + + class C: + def _freeze_(self): + return True + + def __init__(self): + self.m = M() + self.l2 = [] + + c = C() + + def f(): + x = A() + x = hint(x, access_directly=True) + c.m.l.append(x) + + a = self.RPythonAnnotator() + py.test.raises(AssertionError, a.build_types, f, []) + + def f(): + x = A() + x = hint(x, access_directly=True) + c.m.d[None] = x + + a = self.RPythonAnnotator() + py.test.raises(AssertionError, a.build_types, f, []) + + def f(): + x = A() + x = hint(x, access_directly=True) + c.m.d[x] = None + + a = self.RPythonAnnotator() + py.test.raises(AssertionError, a.build_types, f, []) + def test_ctr_location(self): from pypy.rlib.jit import hint Modified: pypy/branch/spine-of-frames/pypy/annotation/unaryop.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/annotation/unaryop.py (original) +++ pypy/branch/spine-of-frames/pypy/annotation/unaryop.py Thu Sep 10 16:45:13 2009 @@ -2,6 +2,7 @@ Unary operations on SomeValues. """ +from types import MethodType from pypy.annotation.model import \ SomeObject, SomeInteger, SomeBool, SomeString, SomeChar, SomeList, \ SomeDict, SomeTuple, SomeImpossibleValue, \ @@ -727,8 +728,19 @@ def getattr(p, s_attr): assert s_attr.is_constant(), "getattr on ptr %r with non-constant field-name" % p.ll_ptrtype - v = getattr(p.ll_ptrtype._example(), s_attr.const) - return ll_to_annotation(v) + example = p.ll_ptrtype._example() + try: + v = example._lookup_adtmeth(s_attr.const) + except AttributeError: + v = getattr(example, s_attr.const) + return ll_to_annotation(v) + else: + if isinstance(v, MethodType): + from pypy.rpython.lltypesystem import lltype + ll_ptrtype = lltype.typeOf(v.im_self) + assert isinstance(ll_ptrtype, (lltype.Ptr, lltype.InteriorPtr)) + return SomeLLADTMeth(ll_ptrtype, v.im_func) + return getbookkeeper().immutablevalue(v) getattr.can_only_throw = [] def len(p): Modified: pypy/branch/spine-of-frames/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/config/pypyoption.py (original) +++ pypy/branch/spine-of-frames/pypy/config/pypyoption.py Thu Sep 10 16:45:13 2009 @@ -328,6 +328,9 @@ BoolOption("getattributeshortcut", "track types that override __getattribute__", default=False), + BoolOption("newshortcut", + "cache and shortcut calling __new__ from builtin types", + default=False), BoolOption("logspaceoptypes", "a instrumentation option: before exit, print the types seen by " @@ -369,6 +372,7 @@ config.objspace.std.suggest(builtinshortcut=True) config.objspace.std.suggest(optimized_list_getitem=True) config.objspace.std.suggest(getattributeshortcut=True) + config.objspace.std.suggest(newshortcut=True) # extra costly optimizations only go in level 3 if level == '3': @@ -396,7 +400,8 @@ # extra optimizations with the JIT if level == 'jit': - config.objspace.std.suggest(withsharingdict=True) + if type_system != 'ootype': + config.objspace.std.suggest(withsharingdict=True) config.objspace.std.suggest(withcelldict=True) Modified: pypy/branch/spine-of-frames/pypy/interpreter/error.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/error.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/error.py Thu Sep 10 16:45:13 2009 @@ -262,8 +262,33 @@ # 31: ANSI color code "red" ansi_print(text, esc="31", file=file, newline=newline) +try: + WindowsError +except NameError: + _WINDOWS = False +else: + _WINDOWS = True + + def wrap_windowserror(space, e): + from pypy.rlib import rwin32 + + winerror = e.winerror + try: + msg = rwin32.FormatError(winerror) + except ValueError: + msg = 'Windows Error %d' % winerror + exc = space.w_WindowsError + w_error = space.call_function(exc, + space.wrap(winerror), + space.wrap(msg)) + return OperationError(exc, w_error) + def wrap_oserror(space, e, exception_name='w_OSError'): assert isinstance(e, OSError) + + if _WINDOWS and isinstance(e, WindowsError): + return wrap_windowserror(space, e) + errno = e.errno try: msg = os.strerror(errno) Modified: pypy/branch/spine-of-frames/pypy/interpreter/function.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/function.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/function.py Thu Sep 10 16:45:13 2009 @@ -39,11 +39,11 @@ def call_args(self, args): # delegate activation to code - return self.code.funcrun(self, args) + return self.getcode().funcrun(self, args) def call_obj_args(self, w_obj, args): # delegate activation to code - return self.code.funcrun_obj(self, w_obj, args) + return self.getcode().funcrun_obj(self, w_obj, args) def getcode(self): return hint(self.code, promote=True) Modified: pypy/branch/spine-of-frames/pypy/interpreter/pycode.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/pycode.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/pycode.py Thu Sep 10 16:45:13 2009 @@ -184,28 +184,30 @@ self.fast_natural_arity = PyCode.FLATPYCALL | self.co_argcount - @jit.dont_look_inside def funcrun(self, func, args): frame = self.space.createframe(self, func.w_func_globals, func.closure) sig = self._signature # speed hack - args_matched = args.parse_into_scope(None, frame.fastlocals_w, + fresh_frame = jit.hint(frame, access_directly=True, + fresh_virtualizable=True) + args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w, func.name, sig, func.defs_w) - frame.init_cells() + fresh_frame.init_cells() return frame.run() - @jit.dont_look_inside def funcrun_obj(self, func, w_obj, args): frame = self.space.createframe(self, func.w_func_globals, func.closure) sig = self._signature # speed hack - args_matched = args.parse_into_scope(w_obj, frame.fastlocals_w, + fresh_frame = jit.hint(frame, access_directly=True, + fresh_virtualizable=True) + args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w, func.name, sig, func.defs_w) - frame.init_cells() + fresh_frame.init_cells() return frame.run() def getvarnames(self): Modified: pypy/branch/spine-of-frames/pypy/interpreter/test/test_compiler.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/test/test_compiler.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/test/test_compiler.py Thu Sep 10 16:45:13 2009 @@ -641,21 +641,17 @@ def setup_method(self, method): self.compiler = CPythonCompiler(self.space) - _unicode_error_kind = "w_SyntaxError" - - if sys.version_info < (2, 4): - def skip_on_2_3(self): - py.test.skip("syntax not supported by the CPython 2.3 compiler") - test_unicodeliterals = skip_on_2_3 - test_none_assignment = skip_on_2_3 - test_import = skip_on_2_3 - elif sys.version_info < (2, 5): + if sys.version_info < (2, 5): def skip_on_2_4(self): py.test.skip("syntax not supported by the CPython 2.4 compiler") _unicode_error_kind = "w_UnicodeError" test_continue_in_nested_finally = skip_on_2_4 test_try_except_finally = skip_on_2_4 test_yield_in_finally = skip_on_2_4 + elif sys.version_info < (2, 6): + _unicode_error_kind = "w_UnicodeDecodeError" + else: + _unicode_error_kind = "w_SyntaxError" class TestPythonAstCompiler_25_grammar(BaseTestCompiler): def setup_method(self, method): Modified: pypy/branch/spine-of-frames/pypy/interpreter/test/test_zzpickle_and_slow.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/interpreter/test/test_zzpickle_and_slow.py (original) +++ pypy/branch/spine-of-frames/pypy/interpreter/test/test_zzpickle_and_slow.py Thu Sep 10 16:45:13 2009 @@ -374,7 +374,19 @@ result = pickle.loads(pckl) raises(TypeError, len, diter) assert list(diter) == list(result) - + + def test_pickle_reversed(self): + import pickle + r = reversed(tuple(range(10))) + r.next() + r.next() + pickled = pickle.dumps(r) + result = pickle.loads(pickled) + result.next() + r.next() + assert type(r) is type(result) + assert list(r) == list(result) + def test_pickle_enum(self): import pickle e = enumerate(range(10)) Modified: pypy/branch/spine-of-frames/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/llgraph/llimpl.py Thu Sep 10 16:45:13 2009 @@ -8,7 +8,8 @@ from pypy.objspace.flow.model import Variable, Constant from pypy.annotation import model as annmodel from pypy.jit.metainterp.history import (ConstInt, ConstPtr, ConstAddr, - BoxInt, BoxPtr, BoxObj, REF) + BoxInt, BoxPtr, BoxObj, BoxFloat, + REF, INT, FLOAT) from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr from pypy.rpython.ootypesystem import ootype from pypy.rpython.module.support import LLSupport, OOSupport @@ -82,6 +83,21 @@ 'uint_ge' : (('int', 'int'), 'bool'), 'uint_xor' : (('int', 'int'), 'int'), 'uint_rshift' : (('int', 'int'), 'int'), + 'float_add' : (('float', 'float'), 'float'), + 'float_sub' : (('float', 'float'), 'float'), + 'float_mul' : (('float', 'float'), 'float'), + 'float_truediv' : (('float', 'float'), 'float'), + 'float_lt' : (('float', 'float'), 'bool'), + 'float_le' : (('float', 'float'), 'bool'), + 'float_eq' : (('float', 'float'), 'bool'), + 'float_ne' : (('float', 'float'), 'bool'), + 'float_gt' : (('float', 'float'), 'bool'), + 'float_ge' : (('float', 'float'), 'bool'), + 'float_neg' : (('float',), 'float'), + 'float_abs' : (('float',), 'float'), + 'float_is_true' : (('float',), 'bool'), + 'cast_float_to_int':(('float',), 'int'), + 'cast_int_to_float':(('int',), 'float'), 'same_as' : (('int',), 'int'), # could also be ptr=>ptr 'new_with_vtable' : (('ref',), 'ref'), 'new' : ((), 'ref'), @@ -124,7 +140,6 @@ 'unicodegetitem' : (('ref', 'int'), 'int'), 'unicodesetitem' : (('ref', 'int', 'int'), 'int'), 'cast_ptr_to_int' : (('ref',), 'int'), - 'cast_int_to_ptr' : (('int',), 'ref'), 'debug_merge_point': (('ref',), None), #'getitem' : (('void', 'ref', 'int'), 'int'), #'setitem' : (('void', 'ref', 'int', 'int'), None), @@ -249,6 +264,8 @@ return str(bool(x)) #elif tp == 'fieldname': # return str(symbolic.TokenToField[x...][1]) + elif tp == 'float': + return str(x) else: raise NotImplementedError("tp = %s" % tp) @@ -259,14 +276,10 @@ return _to_opaque(CompiledLoop()) def compile_start_int_var(loop): - loop = _from_opaque(loop) - assert not loop.operations - v = Variable() - v.concretetype = lltype.Signed - loop.inputargs.append(v) - r = len(_variables) - _variables.append(v) - return r + return compile_start_ref_var(loop, lltype.Signed) + +def compile_start_float_var(loop): + return compile_start_ref_var(loop, lltype.Float) def compile_start_ref_var(loop, TYPE): loop = _from_opaque(loop) @@ -295,11 +308,10 @@ op.args.append(_variables[intvar]) def compile_add_int_const(loop, value): - loop = _from_opaque(loop) - const = Constant(value) - const.concretetype = lltype.Signed - op = loop.operations[-1] - op.args.append(const) + compile_add_ref_const(loop, value, lltype.Signed) + +def compile_add_float_const(loop, value): + compile_add_ref_const(loop, value, lltype.Float) def compile_add_ref_const(loop, value, TYPE): loop = _from_opaque(loop) @@ -309,14 +321,10 @@ op.args.append(const) def compile_add_int_result(loop): - loop = _from_opaque(loop) - v = Variable() - v.concretetype = lltype.Signed - op = loop.operations[-1] - op.result = v - r = len(_variables) - _variables.append(v) - return r + return compile_add_ref_result(loop, lltype.Signed) + +def compile_add_float_result(loop): + return compile_add_ref_result(loop, lltype.Float) def compile_add_ref_result(loop, TYPE): loop = _from_opaque(loop) @@ -411,6 +419,8 @@ x = self.as_ptr(result) elif RESTYPE is ootype.Object: x = self.as_object(result) + elif RESTYPE is lltype.Float: + x = self.as_float(result) else: raise Exception("op.result.concretetype is %r" % (RESTYPE,)) @@ -473,6 +483,9 @@ def as_object(self, x): return ootype.cast_to_object(x) + def as_float(self, x): + return cast_to_float(x) + def log_progress(self): count = sum(_stats.exec_counters.values()) count_jumps = _stats.exec_jumps @@ -501,6 +514,8 @@ for x in args: if type(x) is int: boxedargs.append(BoxInt(x)) + elif type(x) is float: + boxedargs.append(BoxFloat(x)) elif isinstance(ootype.typeOf(x), ootype.OOType): boxedargs.append(BoxObj(ootype.cast_to_object(x))) else: @@ -617,24 +632,36 @@ def op_getarrayitem_gc(self, arraydescr, array, index): if arraydescr.typeinfo == REF: return do_getarrayitem_gc_ptr(array, index) - else: + elif arraydescr.typeinfo == INT: return do_getarrayitem_gc_int(array, index, self.memocast) + elif arraydescr.typeinfo == FLOAT: + return do_getarrayitem_gc_float(array, index) + else: + raise NotImplementedError op_getarrayitem_gc_pure = op_getarrayitem_gc def op_getfield_gc(self, fielddescr, struct): if fielddescr.typeinfo == REF: return do_getfield_gc_ptr(struct, fielddescr.ofs) - else: + elif fielddescr.typeinfo == INT: return do_getfield_gc_int(struct, fielddescr.ofs, self.memocast) + elif fielddescr.typeinfo == FLOAT: + return do_getfield_gc_float(struct, fielddescr.ofs) + else: + raise NotImplementedError op_getfield_gc_pure = op_getfield_gc def op_getfield_raw(self, fielddescr, struct): if fielddescr.typeinfo == REF: return do_getfield_raw_ptr(struct, fielddescr.ofs, self.memocast) - else: + elif fielddescr.typeinfo == INT: return do_getfield_raw_int(struct, fielddescr.ofs, self.memocast) + elif fielddescr.typeinfo == FLOAT: + return do_getfield_raw_float(struct, fielddescr.ofs, self.memocast) + else: + raise NotImplementedError def op_new(self, size): return do_new(size.ofs) @@ -650,23 +677,36 @@ def op_setarrayitem_gc(self, arraydescr, array, index, newvalue): if arraydescr.typeinfo == REF: do_setarrayitem_gc_ptr(array, index, newvalue) - else: + elif arraydescr.typeinfo == INT: do_setarrayitem_gc_int(array, index, newvalue, self.memocast) + elif arraydescr.typeinfo == FLOAT: + do_setarrayitem_gc_float(array, index, newvalue) + else: + raise NotImplementedError def op_setfield_gc(self, fielddescr, struct, newvalue): if fielddescr.typeinfo == REF: do_setfield_gc_ptr(struct, fielddescr.ofs, newvalue) - else: + elif fielddescr.typeinfo == INT: do_setfield_gc_int(struct, fielddescr.ofs, newvalue, self.memocast) + elif fielddescr.typeinfo == FLOAT: + do_setfield_gc_float(struct, fielddescr.ofs, newvalue) + else: + raise NotImplementedError def op_setfield_raw(self, fielddescr, struct, newvalue): if fielddescr.typeinfo == REF: do_setfield_raw_ptr(struct, fielddescr.ofs, newvalue, self.memocast) - else: + elif fielddescr.typeinfo == INT: do_setfield_raw_int(struct, fielddescr.ofs, newvalue, self.memocast) + elif fielddescr.typeinfo == FLOAT: + do_setfield_raw_float(struct, fielddescr.ofs, newvalue, + self.memocast) + else: + raise NotImplementedError def op_call(self, calldescr, func, *args): _call_args[:] = args @@ -674,9 +714,12 @@ err_result = None elif calldescr.typeinfo == REF: err_result = lltype.nullptr(llmemory.GCREF.TO) - else: - assert calldescr.typeinfo == 'i' + elif calldescr.typeinfo == INT: err_result = 0 + elif calldescr.typeinfo == FLOAT: + err_result = 0.0 + else: + raise NotImplementedError return _do_call_common(func, self.memocast, err_result) op_call_pure = op_call @@ -696,9 +739,6 @@ def op_cast_ptr_to_int(self, descr, ptr): return cast_to_int(ptr, self.memocast) - def op_cast_int_to_ptr(self, descr, val): - return cast_from_int(llmemory.GCREF, val, self.memocast) - def op_uint_xor(self, descr, arg1, arg2): return arg1 ^ arg2 @@ -735,6 +775,8 @@ obj = ootype.cast_from_object(TYPE, obj) if isinstance(ootype.typeOf(newvalue), ootype.OOType): newvalue = ootype.cast_from_object(T, newvalue) + elif isinstance(T, lltype.Primitive): + newvalue = lltype.cast_primitive(T, newvalue) setattr(obj, fieldname, newvalue) def op_getarrayitem_gc(self, typedescr, obj, index): @@ -834,6 +876,15 @@ def cast_from_ptr(TYPE, x): return lltype.cast_opaque_ptr(TYPE, x) +def cast_to_float(x): # not really a cast, just a type check + assert isinstance(x, float) + return x + +def cast_from_float(TYPE, x): # not really a cast, just a type check + assert TYPE is lltype.Float + assert isinstance(x, float) + return x + def new_frame(memocast, is_oo): if is_oo: @@ -857,9 +908,10 @@ del _future_values[:] def set_future_value_int(index, value): - del _future_values[index:] - assert len(_future_values) == index - _future_values.append(value) + set_future_value_ref(index, value) + +def set_future_value_float(index, value): + set_future_value_ref(index, value) def set_future_value_ref(index, value): del _future_values[index:] @@ -890,6 +942,10 @@ frame = _from_opaque(frame) return frame.fail_args[num] +def frame_float_getvalue(frame, num): + frame = _from_opaque(frame) + return frame.fail_args[num] + def frame_ptr_getvalue(frame, num): frame = _from_opaque(frame) result = frame.fail_args[num] @@ -1013,33 +1069,41 @@ array = array._obj.container return cast_to_int(array.getitem(index), memocast) +def do_getarrayitem_gc_float(array, index): + array = array._obj.container + return cast_to_float(array.getitem(index)) + def do_getarrayitem_gc_ptr(array, index): array = array._obj.container return cast_to_ptr(array.getitem(index)) -def do_getfield_gc_int(struct, fieldnum, memocast): +def _getfield_gc(struct, fieldnum): STRUCT, fieldname = symbolic.TokenToField[fieldnum] ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct) - x = getattr(ptr, fieldname) - return cast_to_int(x, memocast) + return getattr(ptr, fieldname) + +def do_getfield_gc_int(struct, fieldnum, memocast): + return cast_to_int(_getfield_gc(struct, fieldnum), memocast) + +def do_getfield_gc_float(struct, fieldnum): + return cast_to_float(_getfield_gc(struct, fieldnum)) def do_getfield_gc_ptr(struct, fieldnum): - STRUCT, fieldname = symbolic.TokenToField[fieldnum] - ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct) - x = getattr(ptr, fieldname) - return cast_to_ptr(x) + return cast_to_ptr(_getfield_gc(struct, fieldnum)) -def do_getfield_raw_int(struct, fieldnum, memocast): +def _getfield_raw(struct, fieldnum, memocast): STRUCT, fieldname = symbolic.TokenToField[fieldnum] ptr = cast_from_int(lltype.Ptr(STRUCT), struct, memocast) - x = getattr(ptr, fieldname) - return cast_to_int(x, memocast) + return getattr(ptr, fieldname) + +def do_getfield_raw_int(struct, fieldnum, memocast): + return cast_to_int(_getfield_raw(struct, fieldnum, memocast), memocast) + +def do_getfield_raw_float(struct, fieldnum, memocast): + return cast_to_float(_getfield_raw(struct, fieldnum, memocast)) def do_getfield_raw_ptr(struct, fieldnum, memocast): - STRUCT, fieldname = symbolic.TokenToField[fieldnum] - ptr = cast_from_int(lltype.Ptr(STRUCT), struct, memocast) - x = getattr(ptr, fieldname) - return cast_to_ptr(x) + return cast_to_ptr(_getfield_raw(struct, fieldnum, memocast)) def do_new(size): TYPE = symbolic.Size2Type[size] @@ -1057,6 +1121,12 @@ newvalue = cast_from_int(ITEMTYPE, newvalue, memocast) array.setitem(index, newvalue) +def do_setarrayitem_gc_float(array, index, newvalue): + array = array._obj.container + ITEMTYPE = lltype.typeOf(array).OF + newvalue = cast_from_float(ITEMTYPE, newvalue) + array.setitem(index, newvalue) + def do_setarrayitem_gc_ptr(array, index, newvalue): array = array._obj.container ITEMTYPE = lltype.typeOf(array).OF @@ -1070,6 +1140,13 @@ newvalue = cast_from_int(FIELDTYPE, newvalue, memocast) setattr(ptr, fieldname, newvalue) +def do_setfield_gc_float(struct, fieldnum, newvalue): + STRUCT, fieldname = symbolic.TokenToField[fieldnum] + ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct) + FIELDTYPE = getattr(STRUCT, fieldname) + newvalue = cast_from_float(FIELDTYPE, newvalue) + setattr(ptr, fieldname, newvalue) + def do_setfield_gc_ptr(struct, fieldnum, newvalue): STRUCT, fieldname = symbolic.TokenToField[fieldnum] ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct) @@ -1084,6 +1161,13 @@ newvalue = cast_from_int(FIELDTYPE, newvalue, memocast) setattr(ptr, fieldname, newvalue) +def do_setfield_raw_float(struct, fieldnum, newvalue, memocast): + STRUCT, fieldname = symbolic.TokenToField[fieldnum] + ptr = cast_from_int(lltype.Ptr(STRUCT), struct, memocast) + FIELDTYPE = getattr(STRUCT, fieldname) + newvalue = cast_from_float(FIELDTYPE, newvalue) + setattr(ptr, fieldname, newvalue) + def do_setfield_raw_ptr(struct, fieldnum, newvalue, memocast): STRUCT, fieldname = symbolic.TokenToField[fieldnum] ptr = cast_from_int(lltype.Ptr(STRUCT), struct, memocast) @@ -1113,6 +1197,9 @@ def do_call_pushint(x): _call_args.append(x) +def do_call_pushfloat(x): + _call_args.append(x) + def do_call_pushptr(x): _call_args.append(x) @@ -1143,6 +1230,10 @@ x = _do_call_common(f, memocast, 0) return cast_to_int(x, memocast) +def do_call_float(f, memocast): + x = _do_call_common(f, memocast, 0) + return cast_to_float(x) + def do_call_ptr(f, memocast): x = _do_call_common(f, memocast, lltype.nullptr(llmemory.GCREF.TO)) return cast_to_ptr(x) @@ -1159,6 +1250,8 @@ x = ootype.cast_from_object(TYPE, x) elif isinstance(TYPE, lltype.Ptr) and TYPE.TO._gckind == 'gc': x = cast_from_ptr(TYPE, x) + elif TYPE is lltype.Float: + x = cast_from_float(TYPE, x) else: x = cast_from_int(TYPE, x, memocast) args.append(x) @@ -1175,15 +1268,15 @@ else: mymethod = meth myargs = args - if hasattr(mymethod, 'graph'): - llinterp = _llinterp # it's a global set here by CPU.__init__() - try: + try: + if hasattr(mymethod, 'graph'): + llinterp = _llinterp # it's a global set here by CPU.__init__() result = llinterp.eval_graph(mymethod.graph, myargs) - except LLException, e: - _last_exception = e - result = get_err_result_for_type(mymethod._TYPE.RESULT) - else: - result = meth(*args) # no exception support in this case + else: + result = meth(*args) + except LLException, e: + _last_exception = e + result = get_err_result_for_type(mymethod._TYPE.RESULT) return result def get_err_result_for_type(T): @@ -1248,13 +1341,16 @@ setannotation(compile_start, s_CompiledLoop) setannotation(compile_start_int_var, annmodel.SomeInteger()) setannotation(compile_start_ref_var, annmodel.SomeInteger()) +setannotation(compile_start_float_var, annmodel.SomeInteger()) setannotation(compile_add, annmodel.s_None) setannotation(compile_add_descr, annmodel.s_None) setannotation(compile_add_var, annmodel.s_None) setannotation(compile_add_int_const, annmodel.s_None) setannotation(compile_add_ref_const, annmodel.s_None) +setannotation(compile_add_float_const, annmodel.s_None) setannotation(compile_add_int_result, annmodel.SomeInteger()) setannotation(compile_add_ref_result, annmodel.SomeInteger()) +setannotation(compile_add_float_result, annmodel.SomeInteger()) setannotation(compile_add_jump_target, annmodel.s_None) setannotation(compile_add_fail, annmodel.s_None) setannotation(compile_suboperations, s_CompiledLoop) @@ -1264,9 +1360,11 @@ setannotation(frame_clear, annmodel.s_None) setannotation(set_future_value_int, annmodel.s_None) setannotation(set_future_value_ref, annmodel.s_None) +setannotation(set_future_value_float, annmodel.s_None) setannotation(frame_execute, annmodel.SomeInteger()) setannotation(frame_int_getvalue, annmodel.SomeInteger()) setannotation(frame_ptr_getvalue, annmodel.SomePtr(llmemory.GCREF)) +setannotation(frame_float_getvalue, annmodel.SomeFloat()) setannotation(get_exception, annmodel.SomeAddress()) setannotation(get_exc_value, annmodel.SomePtr(llmemory.GCREF)) @@ -1288,18 +1386,24 @@ setannotation(do_unicodegetitem, annmodel.SomeInteger()) setannotation(do_getarrayitem_gc_int, annmodel.SomeInteger()) setannotation(do_getarrayitem_gc_ptr, annmodel.SomePtr(llmemory.GCREF)) +setannotation(do_getarrayitem_gc_float, annmodel.SomeFloat()) setannotation(do_getfield_gc_int, annmodel.SomeInteger()) setannotation(do_getfield_gc_ptr, annmodel.SomePtr(llmemory.GCREF)) +setannotation(do_getfield_gc_float, annmodel.SomeFloat()) setannotation(do_getfield_raw_int, annmodel.SomeInteger()) setannotation(do_getfield_raw_ptr, annmodel.SomePtr(llmemory.GCREF)) +setannotation(do_getfield_raw_float, annmodel.SomeFloat()) setannotation(do_new, annmodel.SomePtr(llmemory.GCREF)) setannotation(do_new_array, annmodel.SomePtr(llmemory.GCREF)) setannotation(do_setarrayitem_gc_int, annmodel.s_None) setannotation(do_setarrayitem_gc_ptr, annmodel.s_None) +setannotation(do_setarrayitem_gc_float, annmodel.s_None) setannotation(do_setfield_gc_int, annmodel.s_None) setannotation(do_setfield_gc_ptr, annmodel.s_None) +setannotation(do_setfield_gc_float, annmodel.s_None) setannotation(do_setfield_raw_int, annmodel.s_None) setannotation(do_setfield_raw_ptr, annmodel.s_None) +setannotation(do_setfield_raw_float, annmodel.s_None) setannotation(do_newstr, annmodel.SomePtr(llmemory.GCREF)) setannotation(do_strsetitem, annmodel.s_None) setannotation(do_newunicode, annmodel.SomePtr(llmemory.GCREF)) @@ -1308,4 +1412,5 @@ setannotation(do_call_pushptr, annmodel.s_None) setannotation(do_call_int, annmodel.SomeInteger()) setannotation(do_call_ptr, annmodel.SomePtr(llmemory.GCREF)) +setannotation(do_call_float, annmodel.SomeFloat()) setannotation(do_call_void, annmodel.s_None) Modified: pypy/branch/spine-of-frames/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/llgraph/runner.py Thu Sep 10 16:45:13 2009 @@ -8,7 +8,7 @@ from pypy.rpython.ootypesystem import ootype from pypy.rpython.llinterp import LLInterpreter from pypy.jit.metainterp import history -from pypy.jit.metainterp.history import REF +from pypy.jit.metainterp.history import REF, INT, FLOAT from pypy.jit.metainterp.warmspot import unwrap from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.backend import model @@ -74,6 +74,7 @@ class BaseCPU(model.AbstractCPU): + supports_floats = True def __init__(self, rtyper, stats=None, translate_support_code=False, annmixlevel=None, gcdescr=None): @@ -118,6 +119,8 @@ elif isinstance(box, self.ts.BoxRef): TYPE = self.ts.BASETYPE var2index[box] = llimpl.compile_start_ref_var(c, TYPE) + elif isinstance(box, history.BoxFloat): + var2index[box] = llimpl.compile_start_float_var(c) else: raise Exception("box is: %r" % (box,)) self._compile_branch(c, loop.operations, var2index) @@ -144,6 +147,8 @@ llimpl.compile_add_ref_const(c, x.value, self.ts.BASETYPE) elif isinstance(x, history.ConstAddr): llimpl.compile_add_int_const(c, x.getint()) + elif isinstance(x, history.ConstFloat): + llimpl.compile_add_float_const(c, x.value) else: raise Exception("%s args contain: %r" % (op.getopname(), x)) @@ -156,6 +161,8 @@ var2index[x] = llimpl.compile_add_int_result(c) elif isinstance(x, self.ts.BoxRef): var2index[x] = llimpl.compile_add_ref_result(c, self.ts.BASETYPE) + elif isinstance(x, history.BoxFloat): + var2index[x] = llimpl.compile_add_float_result(c) else: raise Exception("%s.result contain: %r" % (op.getopname(), x)) @@ -186,12 +193,18 @@ def set_future_value_ref(self, index, objvalue): llimpl.set_future_value_ref(index, objvalue) + def set_future_value_float(self, index, floatvalue): + llimpl.set_future_value_float(index, floatvalue) + def get_latest_value_int(self, index): return llimpl.frame_int_getvalue(self.latest_frame, index) def get_latest_value_ref(self, index): return llimpl.frame_ptr_getvalue(self.latest_frame, index) + def get_latest_value_float(self, index): + return llimpl.frame_float_getvalue(self.latest_frame, index) + # ---------- def get_exception(self): @@ -228,6 +241,9 @@ def cast_int_to_adr(self, int): return llimpl.cast_int_to_adr(self.memo_cast, int) + def cast_gcref_to_int(self, gcref): + return self.cast_adr_to_int(llmemory.cast_ptr_to_adr(gcref)) + class LLtypeCPU(BaseCPU): @@ -299,9 +315,14 @@ index = args[1].getint() if arraydescr.typeinfo == REF: return history.BoxPtr(llimpl.do_getarrayitem_gc_ptr(array, index)) - else: + elif arraydescr.typeinfo == INT: return history.BoxInt(llimpl.do_getarrayitem_gc_int(array, index, self.memo_cast)) + elif arraydescr.typeinfo == FLOAT: + return history.BoxFloat(llimpl.do_getarrayitem_gc_float(array, + index)) + else: + raise NotImplementedError def do_getfield_gc(self, args, fielddescr): assert isinstance(fielddescr, Descr) @@ -309,10 +330,16 @@ if fielddescr.typeinfo == REF: return history.BoxPtr(llimpl.do_getfield_gc_ptr(struct, fielddescr.ofs)) - else: + elif fielddescr.typeinfo == INT: return history.BoxInt(llimpl.do_getfield_gc_int(struct, fielddescr.ofs, self.memo_cast)) + elif fielddescr.typeinfo == FLOAT: + return history.BoxFloat(llimpl.do_getfield_gc_float(struct, + fielddescr.ofs)) + else: + raise NotImplementedError + def do_getfield_raw(self, args, fielddescr): assert isinstance(fielddescr, Descr) struct = self.cast_int_to_adr(args[0].getint()) @@ -320,10 +347,16 @@ return history.BoxPtr(llimpl.do_getfield_raw_ptr(struct, fielddescr.ofs, self.memo_cast)) - else: + elif fielddescr.typeinfo == INT: return history.BoxInt(llimpl.do_getfield_raw_int(struct, fielddescr.ofs, self.memo_cast)) + elif fielddescr.typeinfo == FLOAT: + return history.BoxFloat(llimpl.do_getfield_raw_float(struct, + fielddescr.ofs, + self.memo_cast)) + else: + raise NotImplementedError def do_new(self, args, size): assert isinstance(size, Descr) @@ -350,10 +383,15 @@ if arraydescr.typeinfo == REF: newvalue = args[2].getref_base() llimpl.do_setarrayitem_gc_ptr(array, index, newvalue) - else: + elif arraydescr.typeinfo == INT: newvalue = args[2].getint() llimpl.do_setarrayitem_gc_int(array, index, newvalue, self.memo_cast) + elif arraydescr.typeinfo == FLOAT: + newvalue = args[2].getfloat() + llimpl.do_setarrayitem_gc_float(array, index, newvalue) + else: + raise NotImplementedError def do_setfield_gc(self, args, fielddescr): assert isinstance(fielddescr, Descr) @@ -361,10 +399,15 @@ if fielddescr.typeinfo == REF: newvalue = args[1].getref_base() llimpl.do_setfield_gc_ptr(struct, fielddescr.ofs, newvalue) - else: + elif fielddescr.typeinfo == INT: newvalue = args[1].getint() llimpl.do_setfield_gc_int(struct, fielddescr.ofs, newvalue, self.memo_cast) + elif fielddescr.typeinfo == FLOAT: + newvalue = args[1].getfloat() + llimpl.do_setfield_gc_float(struct, fielddescr.ofs, newvalue) + else: + raise NotImplementedError def do_setfield_raw(self, args, fielddescr): assert isinstance(fielddescr, Descr) @@ -373,10 +416,16 @@ newvalue = args[1].getref_base() llimpl.do_setfield_raw_ptr(struct, fielddescr.ofs, newvalue, self.memo_cast) - else: + elif fielddescr.typeinfo == INT: newvalue = args[1].getint() llimpl.do_setfield_raw_int(struct, fielddescr.ofs, newvalue, self.memo_cast) + elif fielddescr.typeinfo == FLOAT: + newvalue = args[1].getfloat() + llimpl.do_setfield_raw_float(struct, fielddescr.ofs, newvalue, + self.memo_cast) + else: + raise NotImplementedError def do_same_as(self, args, descr=None): return args[0].clonebox() @@ -416,16 +465,14 @@ llimpl.do_call_pushint(arg.getint()) if calldescr.typeinfo == REF: return history.BoxPtr(llimpl.do_call_ptr(func, self.memo_cast)) - elif calldescr.typeinfo == 'i': + elif calldescr.typeinfo == INT: return history.BoxInt(llimpl.do_call_int(func, self.memo_cast)) - else: # calldescr.typeinfo == 'v' # void + elif calldescr.typeinfo == FLOAT: + return history.BoxFloat(llimpl.do_call_float(func, self.memo_cast)) + elif calldescr.typeinfo == 'v': # void llimpl.do_call_void(func, self.memo_cast) - - def do_cast_int_to_ptr(self, args, descr=None): - assert descr is None - return history.BoxPtr(llimpl.cast_from_int(llmemory.GCREF, - args[0].getint(), - self.memo_cast)) + else: + raise NotImplementedError def do_cast_ptr_to_int(self, args, descr=None): assert descr is None @@ -573,6 +620,8 @@ def boxresult(RESULT, result): if isinstance(RESULT, ootype.OOType): return history.BoxObj(ootype.cast_to_object(result)) + elif RESULT is lltype.Float: + return history.BoxFloat(result) else: return history.BoxInt(lltype.cast_primitive(ootype.Signed, result)) boxresult._annspecialcase_ = 'specialize:arg(0)' Modified: pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/gc.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/gc.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/gc.py Thu Sep 10 16:45:13 2009 @@ -343,7 +343,7 @@ return llop1.do_malloc_varsize_clear( llmemory.GCREF, type_id, num_elem, self.array_basesize, itemsize, - self.array_length_ofs, True, False) + self.array_length_ofs, True) self.malloc_array = malloc_array self.GC_MALLOC_ARRAY = lltype.Ptr(lltype.FuncType( [lltype.Signed] * 3, llmemory.GCREF)) @@ -359,12 +359,12 @@ return llop1.do_malloc_varsize_clear( llmemory.GCREF, str_type_id, length, str_basesize, str_itemsize, - str_ofs_length, True, False) + str_ofs_length, True) def malloc_unicode(length): return llop1.do_malloc_varsize_clear( llmemory.GCREF, unicode_type_id, length, unicode_basesize, unicode_itemsize, - unicode_ofs_length, True, False) + unicode_ofs_length, True) self.malloc_str = malloc_str self.malloc_unicode = malloc_unicode self.GC_MALLOC_STR_UNICODE = lltype.Ptr(lltype.FuncType( Modified: pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/llmodel.py Thu Sep 10 16:45:13 2009 @@ -1,8 +1,10 @@ import sys from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr +from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.llinterp import LLInterpreter +from pypy.rpython.annlowlevel import llhelper from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.jit.metainterp.history import BoxInt, BoxPtr, set_future_values -from pypy.jit.metainterp.typesystem import llhelper from pypy.jit.backend.model import AbstractCPU from pypy.jit.backend.llsupport import symbolic from pypy.jit.backend.llsupport.symbolic import WORD, unroll_basic_sizes @@ -19,7 +21,7 @@ class AbstractLLCPU(AbstractCPU): - ts = llhelper + from pypy.jit.metainterp.typesystem import llhelper as ts def __init__(self, rtyper, stats, translate_support_code=False, gcdescr=None): @@ -37,6 +39,11 @@ translate_support_code) self._setup_prebuilt_error('ovf', OverflowError) self._setup_prebuilt_error('zer', ZeroDivisionError) + if translate_support_code: + self._setup_exception_handling_translated() + else: + self._setup_exception_handling_untranslated() + self.clear_exception() def set_class_sizes(self, class_sizes): self.class_sizes = class_sizes @@ -54,13 +61,99 @@ immortal=True) setattr(self, '_%s_error_vtable' % prefix, llmemory.cast_ptr_to_adr(ll_inst.typeptr)) - setattr(self, '_%s_error_inst' % prefix, - llmemory.cast_ptr_to_adr(ll_inst)) + setattr(self, '_%s_error_inst' % prefix, ll_inst) + + + def _setup_exception_handling_untranslated(self): + # for running un-translated only, all exceptions occurring in the + # llinterpreter are stored in '_exception_emulator', which is then + # read back by the machine code reading at the address given by + # pos_exception() and pos_exc_value(). + _exception_emulator = lltype.malloc(rffi.CArray(lltype.Signed), 2, + zero=True, flavor='raw') + self._exception_emulator = _exception_emulator + + def _store_exception(lle): + self._last_exception = lle # keepalive + tp_i = rffi.cast(lltype.Signed, lle.args[0]) + v_i = rffi.cast(lltype.Signed, lle.args[1]) + _exception_emulator[0] = tp_i + _exception_emulator[1] = v_i + + self.debug_ll_interpreter = LLInterpreter(self.rtyper) + self.debug_ll_interpreter._store_exception = _store_exception + + def pos_exception(): + return rffi.cast(lltype.Signed, _exception_emulator) + + def pos_exc_value(): + return (rffi.cast(lltype.Signed, _exception_emulator) + + rffi.sizeof(lltype.Signed)) + + def save_exception(): + # copy from _exception_emulator to the real attributes on self + tp_i = _exception_emulator[0] + v_i = _exception_emulator[1] + _exception_emulator[0] = 0 + _exception_emulator[1] = 0 + self.saved_exception = tp_i + self.saved_exc_value = self._cast_int_to_gcref(v_i) + + self.pos_exception = pos_exception + self.pos_exc_value = pos_exc_value + self.save_exception = save_exception + + + def _setup_exception_handling_translated(self): + + def pos_exception(): + addr = llop.get_exception_addr(llmemory.Address) + return llmemory.cast_adr_to_int(addr) + + def pos_exc_value(): + addr = llop.get_exc_value_addr(llmemory.Address) + return llmemory.cast_adr_to_int(addr) + + def save_exception(): + addr = llop.get_exception_addr(llmemory.Address) + exception = rffi.cast(lltype.Signed, addr.address[0]) + addr.address[0] = llmemory.NULL + addr = llop.get_exc_value_addr(llmemory.Address) + exc_value = rffi.cast(llmemory.GCREF, addr.address[0]) + addr.address[0] = llmemory.NULL + # from now on, the state is again consistent -- no more RPython + # exception is set. The following code produces a write barrier + # in the assignment to self.saved_exc_value, as needed. + self.saved_exception = exception + self.saved_exc_value = exc_value + + self.pos_exception = pos_exception + self.pos_exc_value = pos_exc_value + self.save_exception = save_exception + + _SAVE_EXCEPTION_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) + + def get_save_exception_int(self): + f = llhelper(self._SAVE_EXCEPTION_FUNC, self.save_exception) + return rffi.cast(lltype.Signed, f) + + def get_exception(self): + return self.saved_exception + + def get_exc_value(self): + return self.saved_exc_value + + def clear_exception(self): + self.saved_exception = 0 + self.saved_exc_value = lltype.nullptr(llmemory.GCREF.TO) + # ------------------- helpers and descriptions -------------------- @staticmethod - def cast_int_to_gcref(x): + def _cast_int_to_gcref(x): + # dangerous! only use if you are sure no collection could occur + # between reading the integer and casting it to a pointer if not we_are_translated(): _check_addr_range(x) return rffi.cast(llmemory.GCREF, x) @@ -109,14 +202,14 @@ def get_overflow_error(self): ovf_vtable = self.cast_adr_to_int(self._ovf_error_vtable) - ovf_inst = self.cast_int_to_gcref( - self.cast_adr_to_int(self._ovf_error_inst)) + ovf_inst = lltype.cast_opaque_ptr(llmemory.GCREF, + self._ovf_error_inst) return ovf_vtable, ovf_inst def get_zero_division_error(self): zer_vtable = self.cast_adr_to_int(self._zer_error_vtable) - zer_inst = self.cast_int_to_gcref( - self.cast_adr_to_int(self._zer_error_inst)) + zer_inst = lltype.cast_opaque_ptr(llmemory.GCREF, + self._zer_error_inst) return zer_vtable, zer_inst # ____________________________________________________________ @@ -142,7 +235,7 @@ else: raise NotImplementedError("size = %d" % size) if ptr: - return BoxPtr(self.cast_int_to_gcref(val)) + return BoxPtr(self._cast_int_to_gcref(val)) else: return BoxInt(val) @@ -207,7 +300,7 @@ else: raise NotImplementedError("size = %d" % size) if ptr: - return BoxPtr(self.cast_int_to_gcref(val)) + return BoxPtr(self._cast_int_to_gcref(val)) else: return BoxInt(val) @@ -311,9 +404,6 @@ def do_cast_ptr_to_int(self, args, descr=None): return BoxInt(self.cast_gcref_to_int(args[0].getref_base())) - def do_cast_int_to_ptr(self, args, descr=None): - return BoxPtr(self.cast_int_to_gcref(args[0].getint())) - import pypy.jit.metainterp.executor pypy.jit.metainterp.executor.make_execute_list(AbstractLLCPU) Modified: pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/test/test_gc.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/test/test_gc.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/llsupport/test/test_gc.py Thu Sep 10 16:45:13 2009 @@ -124,10 +124,8 @@ return p def do_malloc_varsize_clear(self, RESTYPE, type_id, length, size, - itemsize, offset_to_length, can_collect, - has_finalizer): + itemsize, offset_to_length, can_collect): assert can_collect - assert not has_finalizer p = llmemory.raw_malloc(size + itemsize * length) (p + offset_to_length).signed[0] = length p = llmemory.cast_adr_to_ptr(p, RESTYPE) Modified: pypy/branch/spine-of-frames/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/model.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/model.py Thu Sep 10 16:45:13 2009 @@ -1,4 +1,5 @@ class AbstractCPU(object): + supports_floats = False def set_class_sizes(self, class_sizes): self.class_sizes = class_sizes @@ -160,9 +161,6 @@ def do_cond_call_gc_malloc(self, args, calldescr): xxx - def do_cast_int_to_ptr(self, args, descr=None): - raise NotImplementedError - def do_cast_ptr_to_int(self, args, descr=None): raise NotImplementedError Modified: pypy/branch/spine-of-frames/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/test/runner_test.py Thu Sep 10 16:45:13 2009 @@ -1,8 +1,8 @@ import py, sys, random from pypy.jit.metainterp.history import (BoxInt, Box, BoxPtr, TreeLoop, - ConstInt, ConstPtr, BoxObj, - ConstObj) + ConstInt, ConstPtr, BoxObj, Const, + ConstObj, BoxFloat, ConstFloat) from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.typesystem import deref from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi, rclass @@ -26,6 +26,11 @@ elif isinstance(box, (BoxPtr, BoxObj)): self.cpu.set_future_value_ref(j, box.getref_base()) j += 1 + elif isinstance(box, BoxFloat): + self.cpu.set_future_value_float(j, box.getfloat()) + j += 1 + else: + assert isinstance(box, Const) res = self.cpu.execute_operations(loop) if res is loop.operations[-1]: self.guard_failed = False @@ -35,6 +40,8 @@ return BoxInt(self.cpu.get_latest_value_int(0)) elif result_type == 'ref': return BoxPtr(self.cpu.get_latest_value_ref(0)) + elif result_type == 'float': + return BoxFloat(self.cpu.get_latest_value_float(0)) elif result_type == 'void': return None else: @@ -48,6 +55,8 @@ result = BoxInt() elif result_type == 'ref': result = BoxPtr() + elif result_type == 'float': + result = BoxFloat() else: raise ValueError(result_type) if result is None: @@ -210,6 +219,19 @@ 'int') assert res.value == y + def test_float_operations(self): + from pypy.jit.metainterp.test.test_executor import get_float_tests + for opnum, boxargs, rettype, retvalue in get_float_tests(self.cpu): + if len(boxargs) == 2: + args_variants = [(boxargs[0], boxargs[1]), + (boxargs[0], boxargs[1].constbox()), + (boxargs[0].constbox(), boxargs[1])] + else: + args_variants = [boxargs] + for argboxes in args_variants: + res = self.execute_operation(opnum, argboxes, rettype) + assert res.value == retvalue + def test_ovf_operations(self, reversed=False): minint = -sys.maxint-1 boom = 'boom' @@ -620,14 +642,10 @@ x = lltype.cast_opaque_ptr(llmemory.GCREF, x) res = self.execute_operation(rop.CAST_PTR_TO_INT, [BoxPtr(x)], 'int').value - res2 = self.execute_operation(rop.CAST_INT_TO_PTR, - [BoxInt(res)], 'ref').value - x = lltype.cast_opaque_ptr(llmemory.GCREF, x) + assert res == self.cpu.cast_gcref_to_int(x) res = self.execute_operation(rop.CAST_PTR_TO_INT, [ConstPtr(x)], 'int').value - res2 = self.execute_operation(rop.CAST_INT_TO_PTR, - [ConstInt(res)], 'ref').value - assert res2 == x + assert res == self.cpu.cast_gcref_to_int(x) def test_ooops_non_gc(self): x = lltype.malloc(lltype.Struct('x'), flavor='raw') @@ -851,9 +869,7 @@ x = cpu.do_newstr([BoxInt(5)]) y = cpu.do_cast_ptr_to_int([x]) assert isinstance(y, BoxInt) - z = cpu.do_cast_int_to_ptr([y]) - assert isinstance(z, BoxPtr) - assert z.value == x.value + assert y.value == cpu.cast_gcref_to_int(x.value) def test_sorting_of_fields(self): S = self.S Modified: pypy/branch/spine-of-frames/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/test/test_random.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/test/test_random.py Thu Sep 10 16:45:13 2009 @@ -502,6 +502,7 @@ bridge_builder = self.builder.fork(self.builder.cpu, subloop, op.args[:]) self.generate_ops(bridge_builder, r, subloop, op.args[:]) + dont_compile = False if r.random() < 0.1: subset = bridge_builder.subset_of_intvars(r) if len(subset) == 0: @@ -517,17 +518,22 @@ if self.guard_op is None: guard_op.suboperations[-1] = jump_op else: + self.guard_op.suboperations[0].args.extend(subset) + self.builder.cpu.compile_operations(self.loop, guard_op) if self.guard_op.is_guard_exception(): # exception clearing self.guard_op.suboperations.insert(-1, exc_handling( self.guard_op)) self.guard_op.suboperations[-1] = jump_op + self.builder.cpu.compile_operations(self.loop, self.guard_op) + dont_compile = True self.guard_op = jump_target.guard_op self.prebuilt_ptr_consts += jump_target.prebuilt_ptr_consts self.dont_generate_more = True if r.random() < .05: return False - self.builder.cpu.compile_operations(self.loop) + if not dont_compile: + self.builder.cpu.compile_operations(self.loop, guard_op) return True def check_random_function(cpu, BuilderClass, r, num=None, max=None): Modified: pypy/branch/spine-of-frames/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/x86/assembler.py Thu Sep 10 16:45:13 2009 @@ -5,7 +5,6 @@ from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory from pypy.rpython.lltypesystem.rclass import OBJECT from pypy.rpython.lltypesystem.lloperation import llop -from pypy.annotation import model as annmodel from pypy.tool.uid import fixid from pypy.jit.backend.logger import Logger from pypy.jit.backend.x86.regalloc import (RegAlloc, WORD, REGS, TempBox, @@ -15,9 +14,13 @@ from pypy.jit.backend.x86.ri386 import * from pypy.jit.metainterp.resoperation import rop -# our calling convention - we pass three first args as edx, ecx and eax + + +# our calling convention - we pass first 6 args in registers # and the rest stays on the stack +RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words + MAX_FAIL_BOXES = 1000 if sys.platform == 'darwin': # darwin requires the stack to be 16 bytes aligned on calls @@ -60,24 +63,6 @@ if name.upper() == name: setattr(MachineCodeBlockWrapper, name, _new_method(name)) -class MachineCodeStack(object): - def __init__(self): - self.mcstack = [] - self.counter = 0 - - def next_mc(self): - if len(self.mcstack) == self.counter: - mc = MachineCodeBlockWrapper() - self.mcstack.append(mc) - else: - mc = self.mcstack[self.counter] - self.counter += 1 - return mc - - def give_mc_back(self, mc): - mc.done() - assert self.mcstack[self.counter - 1] is mc - self.counter -= 1 class Assembler386(object): mc = None @@ -92,9 +77,6 @@ self.malloc_array_func_addr = 0 self.malloc_str_func_addr = 0 self.malloc_unicode_func_addr = 0 - self._exception_data = lltype.nullptr(rffi.CArray(lltype.Signed)) - self._exception_addr = 0 - self.mcstack = MachineCodeStack() self.logger = Logger(cpu.ts) self.fail_boxes_int = lltype.malloc(lltype.GcArray(lltype.Signed), MAX_FAIL_BOXES, zero=True) @@ -111,22 +93,6 @@ lltype.direct_arrayitems(self.fail_boxes_ptr)) self.logger.create_log() - # we generate the loop body in 'mc' - # 'mc2' is for guard recovery code - if we_are_translated(): - addr = llop.get_exception_addr(llmemory.Address) - self._exception_data = llmemory.cast_adr_to_ptr(addr, rffi.CArrayPtr(lltype.Signed)) - else: - self._exception_data = lltype.malloc(rffi.CArray(lltype.Signed), 2, - zero=True, flavor='raw') - self._exception_addr = self.cpu.cast_ptr_to_int( - self._exception_data) - # a backup, in case our exception can be somehow mangled, - # by a handling code - self._exception_bck = lltype.malloc(rffi.CArray(lltype.Signed), 2, - zero=True, flavor='raw') - self._exception_bck_addr = self.cpu.cast_ptr_to_int( - self._exception_bck) # the address of the function called by 'new' gc_ll_descr = self.cpu.gc_ll_descr gc_ll_descr.initialize() @@ -145,9 +111,10 @@ self.malloc_unicode_func_addr = rffi.cast(lltype.Signed, ll_new_unicode) # done - self.mc2 = self.mcstack.next_mc() - self.mc = self.mcstack.next_mc() - + # we generate the loop body in 'mc' + # 'mc2' is for guard recovery code + self.mc = MachineCodeBlockWrapper() + self.mc2 = MachineCodeBlockWrapper() def _compute_longest_fail_op(self, ops): max_so_far = 0 @@ -160,48 +127,57 @@ assert max_so_far < MAX_FAIL_BOXES return max_so_far - def assemble(self, tree): - self.places_to_patch_framesize = [] - self.jumps_to_look_at = [] + def assemble_loop(self, loop): + self.assemble(loop, loop.operations, None) + + def assemble_from_guard(self, tree, guard_op): + newaddr = self.assemble(tree, guard_op.suboperations, guard_op) + # patch the jump from original guard + addr = guard_op._x86_addr + mc = codebuf.InMemoryCodeBuilder(addr, addr + 128) + mc.write(packimm32(newaddr - addr - 4)) + mc.done() + + def assemble(self, tree, operations, guard_op): # the last operation can be 'jump', 'return' or 'guard_pause'; # a 'jump' can either close a loop, or end a bridge to some # previously-compiled code. - self._compute_longest_fail_op(tree.operations) + self._compute_longest_fail_op(operations) self.tree = tree self.make_sure_mc_exists() - inputargs = tree.inputargs - self.logger.log_loop(tree) - regalloc = RegAlloc(self, tree, self.cpu.translate_support_code) + newpos = self.mc.tell() + regalloc = RegAlloc(self, tree, self.cpu.translate_support_code, + guard_op) self._regalloc = regalloc - regalloc.walk_operations(tree) - self.sanitize_tree(tree.operations) + adr_lea = 0 + if guard_op is None: + inputargs = tree.inputargs + self.logger.log_loop(tree) + regalloc.walk_operations(tree) + else: + inputargs = regalloc.inputargs + self.logger.log_operations(inputargs, guard_op.suboperations, {}) + mc = self.mc._mc + adr_lea = mc.tell() + mc.LEA(esp, fixedsize_ebp_ofs(0)) + regalloc._walk_operations(operations) + stack_depth = regalloc.max_stack_depth self.mc.done() self.mc2.done() - stack_words = regalloc.max_stack_depth # possibly align, e.g. for Mac OS X - RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words - stack_words = align_stack_words(stack_words+RET_BP) - tree._x86_stack_depth = stack_words-RET_BP - for place in self.places_to_patch_framesize: - mc = codebuf.InMemoryCodeBuilder(place, place + 128) - mc.ADD(esp, imm32(tree._x86_stack_depth * WORD)) + if guard_op is None: + tree._x86_stack_depth = stack_depth + else: + if not we_are_translated(): + # for the benefit of tests + guard_op._x86_bridge_stack_depth = stack_depth + mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) + + mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) mc.done() - for op, pos in self.jumps_to_look_at: - if op.jump_target._x86_stack_depth != tree._x86_stack_depth: - tl = op.jump_target - self.patch_jump(pos, tl._x86_compiled, tl.arglocs, tl.arglocs, - tree._x86_stack_depth, tl._x86_stack_depth) if we_are_translated(): self._regalloc = None # else keep it around for debugging - - def sanitize_tree(self, operations): - """ Cleans up all attributes attached by regalloc and backend - """ - for op in operations: - if op.is_guard(): - op.inputargs = None - op.longevity = None - self.sanitize_tree(op.suboperations) + return newpos def assemble_bootstrap_code(self, jumpaddr, arglocs, args, framesize): self.make_sure_mc_exists() @@ -272,14 +248,14 @@ def regalloc_perform_discard(self, op, arglocs): genop_discard_list[op.opnum](self, op, arglocs) - def regalloc_perform_with_guard(self, op, guard_op, regalloc, + def regalloc_perform_with_guard(self, op, guard_op, faillocs, arglocs, resloc): - addr = self.implement_guard_recovery(guard_op, regalloc) + addr = self.implement_guard_recovery(guard_op, faillocs) genop_guard_list[op.opnum](self, op, guard_op, addr, arglocs, resloc) - def regalloc_perform_guard(self, op, regalloc, arglocs, resloc): - addr = self.implement_guard_recovery(op, regalloc) + def regalloc_perform_guard(self, op, faillocs, arglocs, resloc): + addr = self.implement_guard_recovery(op, faillocs) genop_guard_list[op.opnum](self, op, None, addr, arglocs, resloc) @@ -339,9 +315,7 @@ nargs = len(args) extra_on_stack = self.align_stack_for_call(nargs) for i in range(nargs-1, -1, -1): - arg = args[i] - assert not isinstance(arg, MODRM) - self.mc.PUSH(arg) + self.mc.PUSH(args[i]) self.mc.CALL(rel32(addr)) self.mark_gc_roots() self.mc.ADD(esp, imm(extra_on_stack * WORD)) @@ -444,7 +418,6 @@ def genop_same_as(self, op, arglocs, resloc): self.mc.MOV(resloc, arglocs[0]) - genop_cast_int_to_ptr = genop_same_as genop_cast_ptr_to_int = genop_same_as def genop_int_mod(self, op, arglocs, resloc): @@ -599,40 +572,9 @@ def make_merge_point(self, tree, locs): pos = self.mc.tell() tree._x86_compiled = pos - #tree.comeback_bootstrap_addr = self.assemble_comeback_bootstrap(pos, - # locs, stacklocs) - - def patch_jump(self, old_pos, new_pos, oldlocs, newlocs, olddepth, newdepth): - for i in range(len(oldlocs)): - oldloc = oldlocs[i] - newloc = newlocs[i] - if isinstance(newloc, MODRM): - assert isinstance(oldloc, MODRM) - assert newloc.position == oldloc.position - else: - assert newloc is oldloc - # newlocs should be sorted in acending order, excluding the regs - if not we_are_translated(): - locs = [loc.position for loc in newlocs if isinstance(loc, MODRM)] - assert locs == sorted(locs) - # - mc = codebuf.InMemoryCodeBuilder(old_pos, old_pos + - MachineCodeBlockWrapper.MC_SIZE) - mc.SUB(esp, imm(WORD * (newdepth - olddepth))) - mc.JMP(rel32(new_pos)) - mc.done() def genop_discard_jump(self, op, locs): - targetmp = op.jump_target - # don't break the following code sequence! - mc = self.mc._mc - if op.jump_target is not self.tree: - self.jumps_to_look_at.append((op, mc.tell())) - mc.JMP(rel32(targetmp._x86_compiled)) - if op.jump_target is not self.tree: - # Reserve 6 bytes for a possible later patch by patch_jump(). - # Put them after the JMP by default, as it's not doing anything. - mc.SUB(esp, imm32(0)) + self.mc.JMP(rel32(op.jump_target._x86_compiled)) def genop_guard_guard_true(self, op, ign_1, addr, locs, ign_2): loc = locs[0] @@ -640,19 +582,19 @@ self.implement_guard(addr, op, self.mc.JZ) def genop_guard_guard_no_exception(self, op, ign_1, addr, locs, ign_2): - self.mc.CMP(heap(self._exception_addr), imm(0)) + self.mc.CMP(heap(self.cpu.pos_exception()), imm(0)) self.implement_guard(addr, op, self.mc.JNZ) def genop_guard_guard_exception(self, op, ign_1, addr, locs, resloc): loc = locs[0] loc1 = locs[1] - self.mc.MOV(loc1, heap(self._exception_addr)) + self.mc.MOV(loc1, heap(self.cpu.pos_exception())) self.mc.CMP(loc1, loc) self.implement_guard(addr, op, self.mc.JNE) if resloc is not None: - self.mc.MOV(resloc, addr_add(imm(self._exception_addr), imm(WORD))) - self.mc.MOV(heap(self._exception_addr), imm(0)) - self.mc.MOV(addr_add(imm(self._exception_addr), imm(WORD)), imm(0)) + self.mc.MOV(resloc, heap(self.cpu.pos_exc_value())) + self.mc.MOV(heap(self.cpu.pos_exception()), imm(0)) + self.mc.MOV(heap(self.cpu.pos_exc_value()), imm(0)) def genop_guard_guard_no_overflow(self, op, ign_1, addr, locs, resloc): self.implement_guard(addr, op, self.mc.JO) @@ -674,27 +616,21 @@ self.mc.CMP(mem(locs[0], offset), locs[1]) self.implement_guard(addr, op, self.mc.JNE) - def implement_guard_recovery(self, guard_op, regalloc): - oldmc = self.mc - self.mc = self.mc2 - self.mc2 = self.mcstack.next_mc() - addr = self.mc.tell() + def implement_guard_recovery(self, guard_op, fail_locs): + addr = self.mc2.tell() exc = (guard_op.opnum == rop.GUARD_EXCEPTION or guard_op.opnum == rop.GUARD_NO_EXCEPTION) - # XXX this is a heuristics to detect whether we're handling this - # exception or not. We should have a bit better interface to deal - # with that I fear - if (exc and (guard_op.suboperations[0].opnum == rop.GUARD_EXCEPTION or - guard_op.suboperations[0].opnum == rop.GUARD_NO_EXCEPTION)): - exc = False - regalloc.walk_guard_ops(guard_op.inputargs, guard_op.suboperations, exc) - self.mcstack.give_mc_back(self.mc2) - self.mc2 = self.mc - self.mc = oldmc + guard_op._x86_faillocs = fail_locs + # XXX horrible hack that allows us to preserve order + # of inputargs to bridge + guard_op._fail_op = guard_op.suboperations[0] + self.generate_failure(self.mc2, guard_op.suboperations[0], fail_locs, + exc) return addr - def generate_failure(self, op, locs, exc): - pos = self.mc.tell() + def generate_failure(self, mc, op, locs, exc): + assert op.opnum == rop.FAIL + pos = mc.tell() for i in range(len(locs)): loc = locs[i] if isinstance(loc, REG): @@ -702,7 +638,7 @@ base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr - self.mc.MOV(addr_add(imm(base), imm(i*WORD)), loc) + mc.MOV(addr_add(imm(base), imm(i*WORD)), loc) for i in range(len(locs)): loc = locs[i] if not isinstance(loc, REG): @@ -710,19 +646,20 @@ base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr - self.mc.MOV(eax, loc) - self.mc.MOV(addr_add(imm(base), imm(i*WORD)), eax) + mc.MOV(eax, loc) + mc.MOV(addr_add(imm(base), imm(i*WORD)), eax) if self.debug_markers: - self.mc.MOV(eax, imm(pos)) - self.mc.MOV(addr_add(imm(self.fail_box_int_addr), + mc.MOV(eax, imm(pos)) + mc.MOV(addr_add(imm(self.fail_box_int_addr), imm(len(locs) * WORD)), eax) if exc: - self.generate_exception_handling(eax) + # note that we don't have to save and restore eax, ecx and edx here + addr = self.cpu.get_save_exception_int() + mc.CALL(rel32(addr)) # don't break the following code sequence! - mc = self.mc._mc - self.places_to_patch_framesize.append(mc.tell()) - mc.ADD(esp, imm32(0)) + mc = mc._mc + mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD)) guard_index = self.cpu.make_guard_index(op) mc.MOV(eax, imm(guard_index)) mc.POP(edi) @@ -731,19 +668,10 @@ mc.POP(ebp) mc.RET() - def generate_exception_handling(self, loc): - self.mc.MOV(loc, heap(self._exception_addr)) - self.mc.MOV(heap(self._exception_bck_addr), loc) - self.mc.MOV(loc, addr_add(imm(self._exception_addr), imm(WORD))) - self.mc.MOV(addr_add(imm(self._exception_bck_addr), imm(WORD)), loc) - # clean up the original exception, we don't want - # to enter more rpython code with exc set - self.mc.MOV(heap(self._exception_addr), imm(0)) - self.mc.MOV(addr_add(imm(self._exception_addr), imm(WORD)), imm(0)) - @specialize.arg(3) def implement_guard(self, addr, guard_op, emit_jump): emit_jump(rel32(addr)) + guard_op._x86_addr = self.mc.tell() - 4 def genop_call(self, op, arglocs, resloc): sizeloc = arglocs[0] @@ -808,15 +736,6 @@ print "not implemented operation (guard): %s" % op.getopname() raise NotImplementedError - #def genop_call__1(self, op, arglocs, resloc): - # self.gen_call(op, arglocs, resloc) - # self.mc.MOVZX(eax, al) - - #def genop_call__2(self, op, arglocs, resloc): - # # XXX test it test it test it - # self.gen_call(op, arglocs, resloc) - # self.mc.MOVZX(eax, eax) - def mark_gc_roots(self): gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap: Modified: pypy/branch/spine-of-frames/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/x86/regalloc.py Thu Sep 10 16:45:13 2009 @@ -18,6 +18,9 @@ REGS = [eax, ecx, edx, ebx, esi, edi] WORD = 4 +class NoVariableToSpill(Exception): + pass + class TempBox(Box): def __init__(self): pass @@ -54,46 +57,56 @@ exc = False def __init__(self, assembler, tree, translate_support_code=False, - regalloc=None, guard_op=None): + guard_op=None): # variables that have place in register self.assembler = assembler self.translate_support_code = translate_support_code - if regalloc is None: - cpu = self.assembler.cpu + cpu = self.assembler.cpu + self.reg_bindings = newcheckdict() + self.stack_bindings = newcheckdict() + self.tree = tree + if guard_op is not None: + locs = guard_op._x86_faillocs + cpu.gc_ll_descr.rewrite_assembler(cpu, guard_op.suboperations) + inpargs = [arg for arg in guard_op._fail_op.args if + isinstance(arg, Box)] + self._compute_vars_longevity(inpargs, guard_op.suboperations) + self.inputargs = inpargs + self.position = -1 + self._update_bindings(locs, inpargs) + self.current_stack_depth = guard_op._x86_current_stack_depth + self.loop_consts = {} + else: cpu.gc_ll_descr.rewrite_assembler(cpu, tree.operations) - self.tree = tree - self.reg_bindings = newcheckdict() - self.stack_bindings = newcheckdict() - # compute longevity of variables self._compute_vars_longevity(tree.inputargs, tree.operations) - self.free_regs = REGS[:] + # compute longevity of variables jump = tree.operations[-1] loop_consts = self._compute_loop_consts(tree.inputargs, jump) self.loop_consts = loop_consts self.current_stack_depth = 0 - else: - inp = guard_op.inputargs - assert inp is not None - self.reg_bindings = {} - self.stack_bindings = {} - for arg in inp: - if arg in regalloc.reg_bindings: - self.reg_bindings[arg] = regalloc.reg_bindings[arg] - if arg in regalloc.stack_bindings: - self.stack_bindings[arg] = regalloc.stack_bindings[arg] - else: - assert arg in regalloc.reg_bindings - allocated_regs = self.reg_bindings.values() - self.free_regs = [v for v in REGS if v not in allocated_regs] - self.current_stack_depth = regalloc.current_stack_depth - self.longevity = guard_op.longevity - jump_or_fail = guard_op.suboperations[-1] - self.loop_consts = {} - self.tree = regalloc.tree + self.free_regs = REGS[:] - def regalloc_for_guard(self, guard_op): - return RegAlloc(self.assembler, None, self.translate_support_code, - self, guard_op) + def _update_bindings(self, locs, args): + newlocs = [] + for loc in locs: + if not isinstance(loc, IMM8) and not isinstance(loc, IMM32): + newlocs.append(loc) + locs = newlocs + assert len(locs) == len(args) + used = {} + for i in range(len(locs)): + v = args[i] + loc = locs[i] + if isinstance(loc, REG) and self.longevity[v][1] > -1: + self.reg_bindings[v] = loc + used[loc] = None + else: + self.stack_bindings[v] = loc + self.free_regs = [] + for reg in REGS: + if reg not in used: + self.free_regs.append(reg) + self._check_invariants() def _compute_loop_consts(self, inputargs, jump): if jump.opnum != rop.JUMP or jump.jump_target is not self.tree: @@ -136,24 +149,22 @@ self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) self.assembler.regalloc_perform(op, arglocs, result_loc) - def perform_with_guard(self, op, guard_op, regalloc, arglocs, result_loc): + def perform_with_guard(self, op, guard_op, locs, arglocs, result_loc): + guard_op._x86_current_stack_depth = self.current_stack_depth if not we_are_translated(): self.assembler.dump('%s <- %s(%s) [GUARDED]' % (result_loc, op, arglocs)) - self.assembler.regalloc_perform_with_guard(op, guard_op, regalloc, + self.assembler.regalloc_perform_with_guard(op, guard_op, locs, arglocs, result_loc) - self.max_stack_depth = max(self.max_stack_depth, - regalloc.max_stack_depth) - def perform_guard(self, op, regalloc, arglocs, result_loc): + def perform_guard(self, op, locs, arglocs, result_loc): + op._x86_current_stack_depth = self.current_stack_depth if not we_are_translated(): if result_loc is not None: self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) else: self.assembler.dump('%s(%s)' % (op, arglocs)) - self.assembler.regalloc_perform_guard(op, regalloc, arglocs, result_loc) - self.max_stack_depth = max(self.max_stack_depth, - regalloc.max_stack_depth) + self.assembler.regalloc_perform_guard(op, locs, arglocs, result_loc) def PerformDiscard(self, op, arglocs): if not we_are_translated(): @@ -170,25 +181,24 @@ if operations[i + 1].args[0] is not op.result: return False if (self.longevity[op.result][1] > i + 1 or - op.result in operations[i + 1].inputargs): - print "!!!! boolean flag not optimized away !!!!" + op.result in operations[i + 1].suboperations[0].args): return False return True def walk_operations(self, tree): # first pass - walk along the operations in order to find # load/store places - operations = tree.operations self.position = -1 + operations = tree.operations self.process_inputargs(tree) self._walk_operations(operations) - def walk_guard_ops(self, inputargs, operations, exc): - self.exc = exc - old_regalloc = self.assembler._regalloc - self.assembler._regalloc = self - self._walk_operations(operations) - self.assembler._regalloc = old_regalloc + #def walk_guard_ops(self, inputargs, operations, exc): + # self.exc = exc + # old_regalloc = self.assembler._regalloc + # self.assembler._regalloc = self + # self._walk_operations(operations) + # self.assembler._regalloc = old_regalloc def _walk_operations(self, operations): i = 0 @@ -210,11 +220,8 @@ i += 1 assert not self.reg_bindings jmp = operations[-1] - #if jmp.opnum == rop.JUMP and jmp.jump_target is not self.tree: - # self.max_stack_depth = max(jmp.jump_target._x86_stack_depth, - # self.max_stack_depth) - self.max_stack_depth = max(self.max_stack_depth, - self.current_stack_depth + 1) + self.max_stack_depth = max(self.current_stack_depth, + self.max_stack_depth) def _compute_vars_longevity(self, inputargs, operations): # compute a dictionary that maps variables to index in @@ -234,8 +241,7 @@ raise AssertionError longevity[arg] = (start_live[arg], i) if op.is_guard(): - self._compute_inpargs(op) - for arg in op.inputargs: + for arg in op.suboperations[0].args: if isinstance(arg, Box): if arg not in start_live: print "Bogus arg in guard %d at %d" % (op.opnum, i) @@ -248,35 +254,32 @@ assert isinstance(arg, Box) self.longevity = longevity - def _compute_inpargs(self, guard): - if guard.inputargs is not None: - return - operations = guard.suboperations - longevity = {} - end = {} - for i in range(len(operations)-1, -1, -1): - op = operations[i] - if op.is_guard(): - self._compute_inpargs(op) - for arg in op.inputargs: - if isinstance(arg, Box) and arg not in end: - end[arg] = i - for arg in op.args: - if isinstance(arg, Box) and arg not in end: - end[arg] = i - if op.result: - if op.result in end: - longevity[op.result] = (i, end[op.result]) - del end[op.result] - # otherwise this var is never ever used - for v, e in end.items(): - longevity[v] = (0, e) - guard.longevity = longevity - guard.inputargs = end.keys() - for arg in longevity: - assert isinstance(arg, Box) - for arg in guard.inputargs: - assert isinstance(arg, Box) +# def _compute_inpargs(self, guard): +# operations = guard.suboperations +# longevity = {} +# end = {} +# for i in range(len(operations)-1, -1, -1): +# op = operations[i] +# if op.is_guard(): +# for arg in op.suboperations[0].args: +# if isinstance(arg, Box) and arg not in end: +# end[arg] = i +# for arg in op.args: +# if isinstance(arg, Box) and arg not in end: +# end[arg] = i +# if op.result: +# if op.result in end: +# longevity[op.result] = (i, end[op.result]) +# del end[op.result] +# # otherwise this var is never ever used +# for v, e in end.items(): +# longevity[v] = (0, e) +# inputargs = end.keys() +# for arg in longevity: +# assert isinstance(arg, Box) +# for arg in inputargs: +# assert isinstance(arg, Box) +# return inputargs, longevity def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): assert not isinstance(v, Const) @@ -424,24 +427,30 @@ reg = self.reg_bindings[next] if next in forbidden_vars: continue - if selected_reg is not None and reg is selected_reg: - return next + if selected_reg is not None: + if reg is selected_reg: + return next + else: + continue if need_lower_byte and (reg is esi or reg is edi): continue - candidates.append(next) - assert candidates - if len(candidates) == 1: - return candidates[0] - max = 0 - chosen = None - for one in candidates: - next_usage = self._compute_next_usage(one, self.position) - if next_usage == -1: - return one - elif next_usage > max: - next_usage = max - chosen = one - return chosen + return next + raise NoVariableToSpill + # below is the slightly better (even optimal, under certain + # assumptions) algorithm, which is slow. Just go with the + # first hit + #if len(candidates) == 1: + # return candidates[0] + #max = 0 + #chosen = None + #for one in candidates: + # next_usage = self._compute_next_usage(one, self.position) + # if next_usage == -1: + # return one + # elif next_usage > max: + # next_usage = max + # chosen = one + #return chosen def move_variable_away(self, v, prev_loc): reg = None @@ -482,6 +491,10 @@ loc = self.reg_bindings[result_v] return loc + def locs_for_fail(self, guard_op): + assert len(guard_op.suboperations) == 1 + return [self.loc(v) for v in guard_op.suboperations[0].args] + def process_inputargs(self, tree): # XXX we can sort out here by longevity if we need something # more optimal @@ -504,16 +517,17 @@ locs[i] = loc # otherwise we have it saved on stack, so no worry self.free_regs.insert(0, tmpreg) + assert tmpreg not in locs tree.arglocs = locs self.assembler.make_merge_point(tree, locs) self.eventually_free_vars(inputargs) def _consider_guard(self, op, ignored): loc = self.make_sure_var_in_reg(op.args[0], []) - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [loc], None) + locs = self.locs_for_fail(op) + self.perform_guard(op, locs, [loc], None) self.eventually_free_var(op.args[0]) - self.eventually_free_vars(op.inputargs) + self.eventually_free_vars(op.suboperations[0].args) consider_guard_true = _consider_guard consider_guard_false = _consider_guard @@ -521,13 +535,13 @@ def consider_fail(self, op, ignored): # make sure all vars are on stack locs = [self.loc(arg) for arg in op.args] - self.assembler.generate_failure(op, locs, self.exc) + self.assembler.generate_failure(self.assembler.mc, op, locs, self.exc) self.eventually_free_vars(op.args) def consider_guard_no_exception(self, op, ignored): - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [], None) - self.eventually_free_vars(op.inputargs) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [], None) + self.eventually_free_vars(op.suboperations[0].args) def consider_guard_exception(self, op, ignored): loc = self.make_sure_var_in_reg(op.args[0], []) @@ -538,9 +552,9 @@ resloc = self.force_allocate_reg(op.result, op.args + [box]) else: resloc = None - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [loc, loc1], resloc) - self.eventually_free_vars(op.inputargs) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [loc, loc1], resloc) + self.eventually_free_vars(op.suboperations[0].args) self.eventually_free_vars(op.args) self.eventually_free_var(box) @@ -550,18 +564,18 @@ def consider_guard_value(self, op, ignored): x = self.make_sure_var_in_reg(op.args[0], []) y = self.loc(op.args[1]) - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [x, y], None) - self.eventually_free_vars(op.inputargs) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [x, y], None) + self.eventually_free_vars(op.suboperations[0].args) self.eventually_free_vars(op.args) def consider_guard_class(self, op, ignored): assert isinstance(op.args[0], Box) x = self.make_sure_var_in_reg(op.args[0], []) y = self.loc(op.args[1]) - regalloc = self.regalloc_for_guard(op) - self.perform_guard(op, regalloc, [x, y], None) - self.eventually_free_vars(op.inputargs) + faillocs = self.locs_for_fail(op) + self.perform_guard(op, faillocs, [x, y], None) + self.eventually_free_vars(op.suboperations[0].args) self.eventually_free_vars(op.args) def _consider_binop_part(self, op, ignored): @@ -640,11 +654,11 @@ need_lower_byte=True) self.Perform(op, arglocs, loc) else: - regalloc = self.regalloc_for_guard(guard_op) + faillocs = self.locs_for_fail(guard_op) self.position += 1 - self.perform_with_guard(op, guard_op, regalloc, arglocs, None) + self.perform_with_guard(op, guard_op, faillocs, arglocs, None) self.eventually_free_var(op.result) - self.eventually_free_vars(guard_op.inputargs) + self.eventually_free_vars(guard_op.suboperations[0].args) consider_int_lt = _consider_compop consider_int_gt = _consider_compop @@ -864,11 +878,11 @@ if guard_op is not None: argloc = self.make_sure_var_in_reg(op.args[0], []) self.eventually_free_var(op.args[0]) - regalloc = self.regalloc_for_guard(guard_op) + faillocs = self.locs_for_fail(guard_op) self.position += 1 - self.perform_with_guard(op, guard_op, regalloc, [argloc], None) + self.perform_with_guard(op, guard_op, faillocs, [argloc], None) self.eventually_free_var(op.result) - self.eventually_free_vars(guard_op.inputargs) + self.eventually_free_vars(guard_op.suboperations[0].args) else: argloc = self.loc(op.args[0]) self.eventually_free_var(op.args[0]) @@ -885,7 +899,6 @@ self.eventually_free_var(op.args[0]) resloc = self.force_allocate_reg(op.result, []) self.Perform(op, [argloc], resloc) - consider_cast_int_to_ptr = consider_same_as consider_cast_ptr_to_int = consider_same_as def consider_strlen(self, op, ignored): @@ -926,6 +939,7 @@ dst_locations, tmploc) self.eventually_free_var(box) self.eventually_free_vars(op.args) + self.max_stack_depth = op.jump_target._x86_stack_depth self.PerformDiscard(op, []) def consider_debug_merge_point(self, op, ignored): Modified: pypy/branch/spine-of-frames/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/x86/runner.py Thu Sep 10 16:45:13 2009 @@ -10,7 +10,7 @@ history.TreeLoop._x86_compiled = 0 history.TreeLoop._x86_bootstrap_code = 0 - +history.TreeLoop._x86_stack_depth = 0 class CPU386(AbstractLLCPU): debug = True @@ -21,16 +21,6 @@ gcdescr=None): AbstractLLCPU.__init__(self, rtyper, stats, translate_support_code, gcdescr) - if not translate_support_code: - self.current_interpreter = LLInterpreter(self.rtyper) - - def _store_exception(lle): - tp_i = self.cast_ptr_to_int(lle.args[0]) - v_i = self.cast_gcref_to_int(lle.args[1]) - self.assembler._exception_data[0] = tp_i - self.assembler._exception_data[1] = v_i - - self.current_interpreter._store_exception = _store_exception TP = lltype.GcArray(llmemory.GCREF) self._bootstrap_cache = {} self._guard_list = [] @@ -45,34 +35,12 @@ def setup_once(self): pass - def get_exception(self): - self.assembler.make_sure_mc_exists() - return self.assembler._exception_bck[0] - - def get_exc_value(self): - self.assembler.make_sure_mc_exists() - return self.cast_int_to_gcref(self.assembler._exception_bck[1]) - - def clear_exception(self): - self.assembler.make_sure_mc_exists() - self.assembler._exception_bck[0] = 0 - self.assembler._exception_bck[1] = 0 - - def compile_operations(self, tree, bridge=None): - old_loop = tree._x86_compiled - if old_loop: - olddepth = tree._x86_stack_depth - oldlocs = tree.arglocs + def compile_operations(self, tree, guard_op=None): + if guard_op is not None: + self.assembler.assemble_from_guard(tree, guard_op) else: - oldlocs = None - olddepth = 0 - stack_depth = self.assembler.assemble(tree) - newlocs = tree.arglocs - if old_loop != 0: - self.assembler.patch_jump(old_loop, tree._x86_compiled, - oldlocs, newlocs, olddepth, - tree._x86_stack_depth) - + self.assembler.assemble_loop(tree) + def get_bootstrap_code(self, loop): addr = loop._x86_bootstrap_code if not addr: @@ -119,7 +87,7 @@ prev_interpreter = None if not self.translate_support_code: prev_interpreter = LLInterpreter.current_interpreter - LLInterpreter.current_interpreter = self.current_interpreter + LLInterpreter.current_interpreter = self.debug_ll_interpreter res = 0 try: self.caught_exception = None Modified: pypy/branch/spine-of-frames/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/x86/test/test_regalloc.py Thu Sep 10 16:45:13 2009 @@ -2,6 +2,7 @@ """ Tests for register allocation for common constructs """ +import py from pypy.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ BoxPtr, ConstPtr, TreeLoop from pypy.jit.metainterp.resoperation import rop, ResOperation @@ -14,20 +15,33 @@ from pypy.rpython.lltypesystem import rclass, rstr from pypy.jit.backend.x86.ri386 import * + class DummyTree(object): operations = [ResOperation(rop.FAIL, [], None)] inputargs = [] +class MockGcDescr(GcCache): + def get_funcptr_for_new(self): + return 123 + get_funcptr_for_newarray = get_funcptr_for_new + get_funcptr_for_newstr = get_funcptr_for_new + get_funcptr_for_newunicode = get_funcptr_for_new + + def rewrite_assembler(self, cpu, operations): + pass + class MockAssembler(object): gcrefs = None - def __init__(self, cpu=None): + def __init__(self, cpu=None, gc_ll_descr=None): self.loads = [] self.stores = [] self.performs = [] self.lea = [] self.cpu = cpu or CPU(None, None) - self.cpu.gc_ll_descr = MockGcDescr(False) + if gc_ll_descr is None: + gc_ll_descr = MockGcDescr(False) + self.cpu.gc_ll_descr = gc_ll_descr def dump(self, *args): pass @@ -47,55 +61,25 @@ def load_effective_addr(self, *args): self.lea.append(args) -class MockGcRootMap(object): - def get_basic_shape(self): - return ['shape'] - def add_ebp_offset(self, shape, offset): - shape.append(offset) - def add_ebx(self, shape): - shape.append('ebx') - def add_esi(self, shape): - shape.append('esi') - def add_edi(self, shape): - shape.append('edi') - def compress_callshape(self, shape): - assert shape[0] == 'shape' - return ['compressed'] + shape[1:] - -class MockGcDescr(GcCache): - def get_funcptr_for_new(self): - return 123 - get_funcptr_for_newarray = get_funcptr_for_new - get_funcptr_for_newstr = get_funcptr_for_new - get_funcptr_for_newunicode = get_funcptr_for_new +def fill_regs(regalloc, cls=BoxInt): + allboxes = [] + for reg in REGS: + box = cls() + allboxes.append(box) + regalloc.reg_bindings[box] = reg + regalloc.free_regs = [] + return allboxes - moving_gc = True - gcrootmap = MockGcRootMap() - - def initialize(self): - pass - def rewrite_assembler(self, cpu, operations): - pass - - class RegAllocForTests(RegAlloc): position = 0 def _compute_next_usage(self, v, _): return -1 class TestRegallocDirect(object): - def fill_regs(self, regalloc, cls=BoxInt): - allboxes = [] - for reg in REGS: - box = cls() - allboxes.append(box) - regalloc.reg_bindings[box] = reg - regalloc.free_regs = [] - return allboxes - + def test_make_sure_var_in_reg(self): regalloc = RegAlloc(MockAssembler(), DummyTree()) - boxes = self.fill_regs(regalloc) + boxes = fill_regs(regalloc) box = boxes[-1] oldloc = regalloc.loc(box) newloc = regalloc.make_sure_var_in_reg(box, []) @@ -136,7 +120,7 @@ def test_registers_around_call(self): cpu = CPU(None, None) regalloc = RegAlloc(MockAssembler(cpu), DummyTree()) - boxes = self.fill_regs(regalloc) + boxes = fill_regs(regalloc) TP = lltype.FuncType([], lltype.Void) calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) regalloc._check_invariants() @@ -149,31 +133,10 @@ assert len(regalloc.assembler.stores) == 3 regalloc._check_invariants() - def test_mark_gc_roots(self): - cpu = CPU(None, None) - regalloc = RegAlloc(MockAssembler(cpu), DummyTree()) - cpu = regalloc.assembler.cpu - boxes = self.fill_regs(regalloc, cls=BoxPtr) - TP = lltype.FuncType([], lltype.Signed) - calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) - regalloc._check_invariants() - for box in boxes: - regalloc.longevity[box] = (0, 1) - box = boxes[0] - regalloc.position = 0 - regalloc.consider_call(ResOperation(rop.CALL, [box], BoxInt(), - calldescr), None) - assert len(regalloc.assembler.stores) == 3 - # - mark = regalloc.get_mark_gc_roots(cpu.gc_ll_descr.gcrootmap) - assert mark[0] == 'compressed' - expected = ['ebx', 'esi', 'edi', -16, -20, -24] - assert dict.fromkeys(mark[1:]) == dict.fromkeys(expected) - def test_registers_around_newstr(self): cpu = CPU(None, None) regalloc = RegAllocForTests(MockAssembler(cpu), DummyTree()) - boxes = self.fill_regs(regalloc) + boxes = fill_regs(regalloc) regalloc._check_invariants() for box in boxes: regalloc.longevity[box] = (0, 1) @@ -247,9 +210,9 @@ gcref = self.cpu.get_latest_value_ref(index) return lltype.cast_opaque_ptr(T, gcref) - def attach_bridge(self, ops, loop, guard_op): + def attach_bridge(self, ops, loop, guard_op, **kwds): assert guard_op.is_guard() - bridge = self.parse(ops) + bridge = self.parse(ops, **kwds) guard_op.suboperations = bridge.operations self.cpu.compile_operations(loop, guard_op) return bridge @@ -268,34 +231,6 @@ self.interpret(ops, [0]) assert self.getint(0) == 20 - def test_compile_and_recompile(self): - ops = ''' - [i0] - i1 = int_add(i0, 1) - i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) - jump(i1) - ''' - loop = self.interpret(ops, [0]) - assert self.getint(0) == 20 - ops = ''' - [i1] - i3 = int_add(i1, 1) - i4 = int_add(i3, 1) - i5 = int_add(i4, 1) - i6 = int_add(i5, 1) - fail(i3, i4, i5, i6) - ''' - bridge = self.attach_bridge(ops, loop, loop.operations[-2]) - self.cpu.set_future_value_int(0, 0) - op = self.cpu.execute_operations(loop) - assert op is bridge.operations[-1] - assert self.getint(0) == 21 - assert self.getint(1) == 22 - assert self.getint(2) == 23 - assert self.getint(3) == 24 - def test_two_loops_and_a_bridge(self): ops = ''' [i0, i1, i2, i3] @@ -305,7 +240,7 @@ fail(i4, i1, i2, i3) jump(i4, i1, i2, i3) ''' - loop = self.interpret(ops, [0]) + loop = self.interpret(ops, [0, 0, 0, 0]) ops2 = ''' [i5] i1 = int_add(i5, 1) @@ -313,10 +248,18 @@ i4 = int_add(i3, 1) i2 = int_lt(i4, 30) guard_true(i2) - jump(i4, i4, i4, i4) + fail(i4) jump(i4) ''' - loop2 = self.interpret(ops2, [0], jump_targets=[loop, 'self']) + loop2 = self.interpret(ops2, [0]) + bridge_ops = ''' + [i4] + jump(i4, i4, i4, i4) + ''' + bridge = self.attach_bridge(bridge_ops, loop2, loop2.operations[4], + jump_targets=[loop]) + self.cpu.set_future_value_int(0, 0) + self.cpu.execute_operations(loop2) assert self.getint(0) == 31 assert self.getint(1) == 30 assert self.getint(2) == 30 @@ -339,18 +282,24 @@ assert not self.cpu.assembler.fail_boxes_ptr[1] def test_exception_bridge_no_exception(self): - - ops = ''' [i0] call(ConstClass(raising_fptr), i0, descr=raising_calldescr) guard_exception(ConstClass(zero_division_error)) - guard_no_exception() - fail(2) fail(1) fail(0) ''' - self.interpret(ops, [0]) + bridge_ops = ''' + [] + guard_no_exception() + fail(2) + fail(1) + ''' + loop = self.interpret(ops, [0]) + assert self.getint(0) == 1 + bridge = self.attach_bridge(bridge_ops, loop, loop.operations[1]) + self.cpu.set_future_value_int(0, 0) + self.cpu.execute_operations(loop) assert self.getint(0) == 1 def test_inputarg_unused(self): @@ -365,15 +314,43 @@ ops = ''' [i0, i1] guard_true(i0) - guard_true(i0) - fail(i0, i1) - fail(3) + fail(i0, i1) fail(4) ''' - self.interpret(ops, [0, 10]) + bridge_ops = ''' + [i0, i1] + guard_true(i0) + fail(i0, i1) + fail(3) + ''' + loop = self.interpret(ops, [0, 10]) + assert self.getint(0) == 0 + assert self.getint(1) == 10 + bridge = self.attach_bridge(bridge_ops, loop, loop.operations[0]) + self.cpu.set_future_value_int(0, 0) + self.cpu.set_future_value_int(1, 10) + self.cpu.execute_operations(loop) assert self.getint(0) == 0 assert self.getint(1) == 10 + def test_nested_unused_arg(self): + ops = ''' + [i0, i1] + guard_true(i0) + fail(i0, i1) + fail(1) + ''' + loop = self.interpret(ops, [0, 1]) + assert self.getint(0) == 0 + bridge_ops = ''' + [i0, i1] + fail(1, 2) + ''' + self.attach_bridge(bridge_ops, loop, loop.operations[0]) + self.cpu.set_future_value_int(0, 0) + self.cpu.set_future_value_int(1, 1) + self.cpu.execute_operations(loop) + def test_spill_for_constant(self): ops = ''' [i0, i1, i2, i3] @@ -476,6 +453,26 @@ self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0]) assert self.getint(0) == 0 + def test_bug_wrong_stack_adj(self): + ops = ''' + [i0, i1, i2, i3, i4, i5, i6, i7, i8] + guard_true(i0) + fail(0, i0, i1, i2, i3, i4, i5, i6, i7, i8) + fail(1, i0, i1, i2, i3, i4, i5, i6, i7, i8) + ''' + loop = self.interpret(ops, [0, 1, 2, 3, 4, 5, 6, 7, 8]) + assert self.getint(0) == 0 + bridge_ops = ''' + [i0, i1, i2, i3, i4, i5, i6, i7, i8] + call(ConstClass(raising_fptr), 0, descr=raising_calldescr) + fail(i0, i1, i2, i3, i4, i5, i6, i7, i8) + ''' + self.attach_bridge(bridge_ops, loop, loop.operations[0]) + for i in range(9): + self.cpu.set_future_value_int(i, i) + self.cpu.execute_operations(loop) + assert self.getints(9) == range(9) + class TestRegallocCompOps(BaseTestRegalloc): def test_cmp_op_0(self): @@ -574,99 +571,3 @@ s = lltype.malloc(self.A, 3) self.interpret(ops, [s, ord('a')]) assert s[1] == 'a' - - -class TestRegallocGc(BaseTestRegalloc): - cpu = CPU(None, None) - cpu.gc_ll_descr = MockGcDescr(False) - - S = lltype.GcForwardReference() - S.become(lltype.GcStruct('S', ('field', lltype.Ptr(S)), - ('int', lltype.Signed))) - - fielddescr = cpu.fielddescrof(S, 'field') - - struct_ptr = lltype.malloc(S) - struct_ref = lltype.cast_opaque_ptr(llmemory.GCREF, struct_ptr) - child_ptr = lltype.nullptr(S) - struct_ptr.field = child_ptr - - - descr0 = cpu.fielddescrof(S, 'int') - ptr0 = struct_ref - - namespace = locals().copy() - - def test_basic(self): - ops = ''' - [p0] - p1 = getfield_gc(p0, descr=fielddescr) - fail(p1) - ''' - self.interpret(ops, [self.struct_ptr]) - assert not self.getptr(0, lltype.Ptr(self.S)) - - def test_rewrite_constptr(self): - ops = ''' - [] - p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) - fail(p1) - ''' - self.interpret(ops, []) - assert not self.getptr(0, lltype.Ptr(self.S)) - - def test_rewrite_constptr_in_brdige(self): - ops = ''' - [i0] - guard_true(i0) - p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) - fail(p1) - fail(0) - ''' - self.interpret(ops, [0]) - assert not self.getptr(0, lltype.Ptr(self.S)) - - def test_bug_0(self): - ops = ''' - [i0, i1, i2, i3, i4, i5, i6, i7, i8] - guard_value(i2, 1) - fail(i2, i3, i4, i5, i6, i7, i0, i1, i8) - guard_class(i4, 138998336) - fail(i4, i5, i6, i7, i0, i1, i8) - i11 = getfield_gc(i4, descr=descr0) - i12 = ooisnull(i11) - guard_false(i12) - fail(i4, i5, i6, i7, i0, i1, i11, i8) - i13 = getfield_gc(i11, descr=descr0) - i14 = ooisnull(i13) - guard_true(i14) - fail(i4, i5, i6, i7, i0, i1, i11, i8) - i15 = getfield_gc(i4, descr=descr0) - i17 = int_lt(i15, 0) - guard_false(i17) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) - i18 = getfield_gc(i11, descr=descr0) - i19 = int_ge(i15, i18) - guard_false(i19) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) - i20 = int_lt(i15, 0) - guard_false(i20) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) - i21 = getfield_gc(i11, descr=descr0) - i22 = getfield_gc(i11, descr=descr0) - i23 = int_mul(i15, i22) - i24 = int_add(i21, i23) - i25 = getfield_gc(i4, descr=descr0) - i27 = int_add(i25, 1) - setfield_gc(i4, i27, descr=descr0) - i29 = getfield_raw(144839744, descr=descr0) - i31 = int_and(i29, -2141192192) - i32 = int_is_true(i31) - guard_false(i32) - fail(i4, i6, i7, i0, i1, i24) - i33 = getfield_gc(i0, descr=descr0) - guard_value(i33, ConstPtr(ptr0)) - fail(i4, i6, i7, i0, i1, i33, i24) - jump(i0, i1, 1, 17, i4, ConstPtr(ptr0), i6, i7, i24) - ''' - self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0, 0], run=False) Modified: pypy/branch/spine-of-frames/pypy/jit/backend/x86/test/test_virtual.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/x86/test/test_virtual.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/x86/test/test_virtual.py Thu Sep 10 16:45:13 2009 @@ -8,6 +8,7 @@ # for the individual tests see # ====> ../../../metainterp/test/test_virtual.py _new_op = 'new_with_vtable' + _field_prefix = 'inst_' @staticmethod def _new(): Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/codewriter.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/codewriter.py Thu Sep 10 16:45:13 2009 @@ -251,7 +251,8 @@ graph, oosend_methdescr = graph_key self.bytecode = self.codewriter.get_jitcode(graph, oosend_methdescr=oosend_methdescr) - if not codewriter.policy.look_inside_graph(graph): + if not codewriter.policy.look_inside_graph(graph, + self.cpu.supports_floats): assert not portal, "portal has been hidden!" graph = make_calling_stub(codewriter.rtyper, graph) self.graph = graph @@ -612,6 +613,9 @@ def serialize_op_uint_xor(self, op): self._defl(op, 'int_xor') def serialize_op_uint_lshift(self, op): self._defl(op, 'int_lshift') + def serialize_op_cast_bool_to_float(self, op): + self.default_serialize_op(op, 'cast_int_to_float') + serialize_op_unichar_eq = serialize_op_char_eq serialize_op_unichar_ne = serialize_op_char_ne @@ -717,7 +721,8 @@ pass else: if hasattr(rtti._obj, 'destructor_funcptr'): - self.handle_builtin_call(op) + c_vtable = Constant(vtable, lltype.typeOf(vtable)) + self._do_builtin_call(op, 'alloc_with_del', [c_vtable]) return # store the vtable as an address -- that's fine, because the # GC doesn't need to follow them @@ -751,6 +756,21 @@ self.const_position(cls)) self.codewriter.register_known_ooclass(cls, TYPE) self.register_var(op.result) + # initialize fields with a non-default value: while in ootype it's + # new() that takes care of it, for the jit we explicitly insert the + # corresponding setfields(). This way, the backends don't need to care + # about default fields and moreover the resulting code is more similar + # to the lltype version, so the optimizer doesn't need to take special + # care for them. + if isinstance(TYPE, ootype.Instance): + fields = TYPE._get_fields_with_different_default() + var_inst = self.var_position(op.result) + for name, (T, value) in fields: + descr = self.cpu.fielddescrof(TYPE, name) + self.emit('setfield_gc') + self.emit(var_inst) + self.emit(self.get_position(descr)) + self.emit(self.var_position(Constant(value))) def serialize_op_oonewarray(self, op): ARRAY = op.args[0].value @@ -1003,20 +1023,24 @@ self.emit('can_enter_jit') def serialize_op_direct_call(self, op): - kind = self.codewriter.policy.guess_call_kind(op) + kind = self.codewriter.policy.guess_call_kind(op, + self.codewriter.cpu.supports_floats) return getattr(self, 'handle_%s_call' % kind)(op) def serialize_op_indirect_call(self, op): - kind = self.codewriter.policy.guess_call_kind(op) + kind = self.codewriter.policy.guess_call_kind(op, + self.codewriter.cpu.supports_floats) return getattr(self, 'handle_%s_indirect_call' % kind)(op) def serialize_op_oosend(self, op): - kind = self.codewriter.policy.guess_call_kind(op) + kind = self.codewriter.policy.guess_call_kind(op, + self.codewriter.cpu.supports_floats) return getattr(self, 'handle_%s_oosend' % kind)(op) def handle_regular_call(self, op, oosend_methdescr=None): self.minimize_variables() - [targetgraph] = self.codewriter.policy.graphs_from(op) + [targetgraph] = self.codewriter.policy.graphs_from(op, + self.codewriter.cpu.supports_floats) jitbox = self.codewriter.get_jitcode(targetgraph, self.graph, oosend_methdescr=oosend_methdescr) if oosend_methdescr: @@ -1063,6 +1087,8 @@ calldescr, non_void_args = self.codewriter.getcalldescr(op.args[0], args, op.result) + self.emit('recursion_leave_prep') + self.emit_varargs(non_void_args) self.emit('recursive_call') self.emit(self.get_position(calldescr)) self.emit_varargs([op.args[0]] + non_void_args) @@ -1071,7 +1097,8 @@ handle_residual_indirect_call = handle_residual_call def handle_regular_indirect_call(self, op): - targets = self.codewriter.policy.graphs_from(op) + targets = self.codewriter.policy.graphs_from(op, + self.codewriter.cpu.supports_floats) assert targets is not None self.minimize_variables() indirectcallset = self.codewriter.get_indirectcallset(targets) @@ -1101,6 +1128,9 @@ def handle_builtin_call(self, op): oopspec_name, args = support.decode_builtin_call(op) + return self._do_builtin_call(op, oopspec_name, args) + + def _do_builtin_call(self, op, oopspec_name, args): argtypes = [v.concretetype for v in args] resulttype = op.result.concretetype c_func, TP = support.builtin_func_for_spec(self.codewriter.rtyper, Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/compile.py Thu Sep 10 16:45:13 2009 @@ -7,7 +7,7 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.history import TreeLoop, log, Box, History from pypy.jit.metainterp.history import AbstractDescr, BoxInt, BoxPtr, BoxObj,\ - Const + BoxFloat, Const from pypy.jit.metainterp import history from pypy.jit.metainterp.specnode import NotSpecNode from pypy.jit.metainterp.typesystem import llhelper, oohelper @@ -163,6 +163,17 @@ result = resultbox.getref_base() raise metainterp_sd.DoneWithThisFrameRef(cpu, result) +class DoneWithThisFrameDescrFloat(AbstractDescr): + def handle_fail_op(self, metainterp_sd, fail_op): + assert metainterp_sd.result_type == 'float' + resultbox = fail_op.args[0] + if isinstance(resultbox, BoxFloat): + result = metainterp_sd.cpu.get_latest_value_float(0) + else: + assert isinstance(resultbox, history.Const) + result = resultbox.getfloat() + raise metainterp_sd.DoneWithThisFrameFloat(result) + class ExitFrameWithExceptionDescrRef(AbstractDescr): def handle_fail_op(self, metainterp_sd, fail_op): assert len(fail_op.args) == 1 @@ -178,6 +189,7 @@ done_with_this_frame_descr_void = DoneWithThisFrameDescrVoid() done_with_this_frame_descr_int = DoneWithThisFrameDescrInt() done_with_this_frame_descr_ref = DoneWithThisFrameDescrRef() +done_with_this_frame_descr_float = DoneWithThisFrameDescrFloat() exit_frame_with_exception_descr_ref = ExitFrameWithExceptionDescrRef() class TerminatingLoop(TreeLoop): @@ -204,6 +216,12 @@ _loop.finishdescr = done_with_this_frame_descr_ref oohelper.loops_done_with_this_frame_ref = [_loop] +_loop = TerminatingLoop('done_with_this_frame_float') +_loop.specnodes = [prebuiltNotSpecNode] +_loop.inputargs = [BoxFloat()] +_loop.finishdescr = done_with_this_frame_descr_float +loops_done_with_this_frame_float = [_loop] + _loop = TerminatingLoop('done_with_this_frame_void') _loop.specnodes = [] _loop.inputargs = [] Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/executor.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/executor.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/executor.py Thu Sep 10 16:45:13 2009 @@ -7,7 +7,7 @@ from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib.rarithmetic import ovfcheck, r_uint, intmask from pypy.jit.metainterp.history import BoxInt, ConstInt, check_descr -from pypy.jit.metainterp.history import INT, REF +from pypy.jit.metainterp.history import INT, REF, ConstFloat from pypy.jit.metainterp.resoperation import rop @@ -218,6 +218,53 @@ cpu._overflow_flag = ovf return BoxInt(z) +# ---------- + +def do_float_neg(cpu, args, descr=None): + return ConstFloat(-args[0].getfloat()) + +def do_float_abs(cpu, args, descr=None): + return ConstFloat(abs(args[0].getfloat())) + +def do_float_is_true(cpu, args, descr=None): + return ConstInt(bool(args[0].getfloat())) + +def do_float_add(cpu, args, descr=None): + return ConstFloat(args[0].getfloat() + args[1].getfloat()) + +def do_float_sub(cpu, args, descr=None): + return ConstFloat(args[0].getfloat() - args[1].getfloat()) + +def do_float_mul(cpu, args, descr=None): + return ConstFloat(args[0].getfloat() * args[1].getfloat()) + +def do_float_truediv(cpu, args, descr=None): + return ConstFloat(args[0].getfloat() / args[1].getfloat()) + +def do_float_lt(cpu, args, descr=None): + return ConstInt(args[0].getfloat() < args[1].getfloat()) + +def do_float_le(cpu, args, descr=None): + return ConstInt(args[0].getfloat() <= args[1].getfloat()) + +def do_float_eq(cpu, args, descr=None): + return ConstInt(args[0].getfloat() == args[1].getfloat()) + +def do_float_ne(cpu, args, descr=None): + return ConstInt(args[0].getfloat() != args[1].getfloat()) + +def do_float_gt(cpu, args, descr=None): + return ConstInt(args[0].getfloat() > args[1].getfloat()) + +def do_float_ge(cpu, args, descr=None): + return ConstInt(args[0].getfloat() >= args[1].getfloat()) + +def do_cast_float_to_int(cpu, args, descr=None): + return ConstInt(int(args[0].getfloat())) + +def do_cast_int_to_float(cpu, args, descr=None): + return ConstFloat(float(args[0].getint())) + # ____________________________________________________________ def do_debug_merge_point(cpu, args, descr=None): Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/history.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/history.py Thu Sep 10 16:45:13 2009 @@ -16,13 +16,16 @@ # ____________________________________________________________ -INT = 'i' -REF = 'r' +INT = 'i' +REF = 'r' +FLOAT = 'f' -def getkind(TYPE): +def getkind(TYPE, supports_floats=True): if TYPE is lltype.Void: return "void" elif isinstance(TYPE, lltype.Primitive): + if TYPE is lltype.Float and supports_floats: + return 'float' if TYPE in (lltype.Float, lltype.SingleFloat): raise NotImplementedError("type %s not supported" % TYPE) # XXX fix this for oo... @@ -68,7 +71,7 @@ self.seen = {} def repr_rpython(self, box, typechars): n = self.seen.setdefault(box, len(self.seen)) - return '%s/%s%d' % (box.get_(), typechars, n) + return '%s/%s%d' % (box._get_hash_(), typechars, n) repr_rpython = ReprRPython().repr_rpython @@ -79,6 +82,9 @@ def getint(self): raise NotImplementedError + def getfloat(self): + raise NotImplementedError + def getref_base(self): raise NotImplementedError @@ -86,7 +92,7 @@ raise NotImplementedError getref._annspecialcase_ = 'specialize:arg(1)' - def get_(self): + def _get_hash_(self): raise NotImplementedError def nonnull(self): @@ -157,6 +163,8 @@ return ConstInt(intval) elif kind == "ref": return cpu.ts.new_ConstRef(x) + elif kind == "float": + return ConstFloat(x) else: raise NotImplementedError(kind) @@ -212,7 +220,7 @@ def getaddr(self, cpu): return cpu.cast_int_to_adr(self.value) - def get_(self): + def _get_hash_(self): return self.value def nonnull(self): @@ -258,7 +266,7 @@ def getaddr(self, cpu): return self.value - def get_(self): + def _get_hash_(self): return llmemory.cast_adr_to_int(self.value) def nonnull(self): @@ -276,6 +284,38 @@ def repr_rpython(self): return repr_rpython(self, 'ca') +class ConstFloat(Const): + type = FLOAT + value = 0.0 + _attrs_ = ('value',) + + def __init__(self, floatval): + assert isinstance(floatval, float) + self.value = floatval + + def clonebox(self): + return BoxFloat(self.value) + + nonconstbox = clonebox + + def getfloat(self): + return self.value + + def _get_hash_(self): + return hash(self.value) + + def set_future_value(self, cpu, j): + cpu.set_future_value_float(j, self.getfloat()) + + def equals(self, other): + return self.value == other.getfloat() + + def _getrepr_(self): + return self.value + + def repr_rpython(self): + return repr_rpython(self, 'cf') + class ConstPtr(Const): type = REF value = lltype.nullptr(llmemory.GCREF.TO) @@ -297,7 +337,7 @@ return lltype.cast_opaque_ptr(PTR, self.getref_base()) getref._annspecialcase_ = 'specialize:arg(1)' - def get_(self): + def _get_hash_(self): return lltype.cast_ptr_to_int(self.value) def getaddr(self, cpu): @@ -343,9 +383,9 @@ return ootype.cast_from_object(OBJ, self.getref_base()) getref._annspecialcase_ = 'specialize:arg(1)' - def get_(self): + def _get_hash_(self): if self.value: - return ootype.ooidentityhash(self.value) # XXX: check me + return ootype.ooidentityhash(self.value) else: return 0 @@ -390,6 +430,8 @@ # XXX add ootype support? ptrval = lltype.cast_opaque_ptr(llmemory.GCREF, x) return BoxPtr(ptrval) + elif kind == "float": + return BoxFloat(x) else: raise NotImplementedError(kind) @@ -448,7 +490,7 @@ def getaddr(self, cpu): return cpu.cast_int_to_adr(self.value) - def get_(self): + def _get_hash_(self): return self.value def nonnull(self): @@ -468,6 +510,40 @@ changevalue_int = __init__ +class BoxFloat(Box): + type = FLOAT + _attrs_ = ('value',) + + def __init__(self, floatval=0.0): + assert isinstance(floatval, float) + self.value = floatval + + def clonebox(self): + return BoxFloat(self.value) + + def constbox(self): + return ConstFloat(self.value) + + def getfloat(self): + return self.value + + def _get_hash_(self): + return hash(self.value) + + def set_future_value(self, cpu, j): + cpu.set_future_value_float(j, self.value) + + def _getrepr_(self): + return self.value + + def repr_rpython(self): + return repr_rpython(self, 'bf') + + def changevalue_box(self, srcbox): + self.changevalue_float(srcbox.getfloat()) + + changevalue_float = __init__ + class BoxPtr(Box): type = REF _attrs_ = ('value',) @@ -492,7 +568,7 @@ def getaddr(self, cpu): return llmemory.cast_ptr_to_adr(self.value) - def get_(self): + def _get_hash_(self): return lltype.cast_ptr_to_int(self.value) def nonnull(self): @@ -534,9 +610,9 @@ return ootype.cast_from_object(OBJ, self.getref_base()) getref._annspecialcase_ = 'specialize:arg(1)' - def get_(self): + def _get_hash_(self): if self.value: - return ootype.ooidentityhash(self.value) # XXX: check me + return ootype.ooidentityhash(self.value) else: return 0 @@ -577,7 +653,7 @@ if isinstance(c.value, Symbolic): return id(c.value) try: - return c.get_() + return c._get_hash_() except lltype.DelayedPointer: return -2 # xxx risk of changing hash... @@ -712,6 +788,7 @@ compiled_count = 0 enter_count = 0 + aborted_count = 0 def __init__(self): self.loops = [] @@ -777,10 +854,9 @@ class Options: logger_noopt = None - def __init__(self, specialize=True, listops=False, inline=False): + def __init__(self, specialize=True, listops=False): self.specialize = specialize self.listops = listops - self.inline = inline def _freeze_(self): return True Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/jitprof.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/jitprof.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/jitprof.py Thu Sep 10 16:45:13 2009 @@ -3,6 +3,7 @@ """ import time +from pypy.rlib.debug import debug_print TRACING = 0 BACKEND = 1 @@ -69,11 +70,11 @@ t0 = self.t1 self.t1 = self.timer() if not self.current: - print "BROKEN PROFILER DATA!" + debug_print("BROKEN PROFILER DATA!") return ev1 = self.current.pop() if ev1 != event: - print "BROKEN PROFILER DATA!" + debug_print("BROKEN PROFILER DATA!") return self.times[ev1] += self.t1 - t0 Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/optimizeopt.py Thu Sep 10 16:45:13 2009 @@ -560,7 +560,8 @@ def optimize_GUARD_VALUE(self, op): assert isinstance(op.args[1], Const) - assert op.args[0].get_() == op.args[1].get_() + if not we_are_translated(): + assert op.args[0].value == op.args[1].value self.optimize_guard(op) def optimize_GUARD_TRUE(self, op): Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/policy.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/policy.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/policy.py Thu Sep 10 16:45:13 2009 @@ -16,20 +16,22 @@ return False return True - def look_inside_graph(self, graph): - if contains_unsupported_variable_type(graph): - return False + def look_inside_graph(self, graph, supports_floats): try: func = graph.func except AttributeError: - return True - return self.look_inside_function(func) + see_function = True + else: + see_function = self.look_inside_function(func) + return (see_function and + not contains_unsupported_variable_type(graph, + supports_floats)) - def graphs_from(self, op): + def graphs_from(self, op, supports_floats): if op.opname == 'direct_call': funcobj = get_funcobj(op.args[0].value) graph = funcobj.graph - if self.look_inside_graph(graph): + if self.look_inside_graph(graph, supports_floats): return [graph] # common case: look inside this graph else: assert op.opname in ('indirect_call', 'oosend') @@ -40,13 +42,13 @@ graphs = v_obj._lookup_graphs(op.args[0].value) if graphs is not None: for graph in graphs: - if self.look_inside_graph(graph): + if self.look_inside_graph(graph, supports_floats): return graphs # common case: look inside at # least one of the graphs # residual call case: we don't need to look into any graph return None - def guess_call_kind(self, op): + def guess_call_kind(self, op, supports_floats): if op.opname == 'direct_call': funcobj = get_funcobj(op.args[0].value) if isinstance(lltype.typeOf(funcobj), lltype.Ptr): @@ -69,20 +71,20 @@ return 'builtin' # TODO: return 'recursive' if the oosend ends with calling the # portal - if self.graphs_from(op) is None: + if self.graphs_from(op, supports_floats) is None: return 'residual' return 'regular' -def contains_unsupported_variable_type(graph): +def contains_unsupported_variable_type(graph, supports_floats): getkind = history.getkind try: for block in graph.iterblocks(): for v in block.inputargs: - getkind(v.concretetype) + getkind(v.concretetype, supports_floats) for op in block.operations: for v in op.args: - getkind(v.concretetype) - getkind(op.result.concretetype) + getkind(v.concretetype, supports_floats) + getkind(op.result.concretetype, supports_floats) except NotImplementedError, e: history.log.WARNING('%s, ignoring graph' % (e,)) history.log.WARNING(' %s' % (graph,)) @@ -99,96 +101,3 @@ if func in self.funcs: return False return super(StopAtXPolicy, self).look_inside_function(func) - -# ____________________________________________________________ - -from pypy.annotation.specialize import getuniquenondirectgraph - -class ManualJitPolicy(JitPolicy): - def __init__(self, translator): - self.translator = translator - self.bookkeeper = translator.annotator.bookkeeper - self.enabled_graphs = {} - self.memo = {} - self.fill_seen_graphs() - - def look_inside_graph(self, graph): - if graph in self.enabled_graphs: - return self.enabled_graphs[graph] - res = super(ManualJitPolicy, self).look_inside_graph(graph) - self.enabled_graphs[graph] = res # cache the result - return res - - def fill_seen_graphs(self): - # subclasses should have their own - pass - - def _graph(self, func): - func = getattr(func, 'im_func', func) - desc = self.bookkeeper.getdesc(func) - return getuniquenondirectgraph(desc) - - def seefunc(self, fromfunc, *tofuncs): - targetgraphs = {} - for tofunc in tofuncs: - targetgraphs[self._graph(tofunc)] = True - graphs = graphs_on_the_path_to(self.translator, self._graph(fromfunc), - targetgraphs, self.memo) - for graph in graphs: - if graph not in self.enabled_graphs: - self.enabled_graphs[graph] = True - print '++', graph - - def seepath(self, *path): - assert len(path) >= 2 - for i in range(1, len(path)): - self.seefunc(path[i-1], path[i]) - - def seegraph(self, func, look=True): - graph = self._graph(func) - self.enabled_graphs[graph] = look - if look: - print '++', graph - else: - print '--', graph - -def enumerate_reachable_graphs(translator, startgraph, memo=None): - from pypy.translator.backendopt.support import find_calls_from - pending = [(startgraph, None)] - yield pending[0] - seen = {startgraph: True} - while pending: - yield None # hack: a separator meaning "length increases now" - nextlengthlist = [] - nextseen = {} - for node in pending: - head, tail = node - for block, callee in find_calls_from(translator, head, memo): - if callee not in seen: - newnode = callee, node - yield newnode - nextlengthlist.append(newnode) - nextseen[callee] = True - pending = nextlengthlist - seen.update(nextseen) - yield None - -def graphs_on_the_path_to(translator, startgraph, targetgraphs, memo=None): - targetgraphs = targetgraphs.copy() - result = {} - found = {} - for node in enumerate_reachable_graphs(translator, startgraph, memo): - if node is None: # hack: a separator meaning "length increases now" - for graph in found: - del targetgraphs[graph] - found.clear() - if not targetgraphs: - return result - elif node[0] in targetgraphs: - found[node[0]] = True - while node is not None: - head, tail = node - result[head] = True - node = tail - raise Exception("did not reach all targets:\nmissing %r" % ( - targetgraphs.keys(),)) Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/pyjitpl.py Thu Sep 10 16:45:13 2009 @@ -227,6 +227,9 @@ 'int_and', 'int_or', 'int_xor', 'int_rshift', 'int_lshift', 'uint_rshift', 'uint_lt', 'uint_le', 'uint_gt', 'uint_ge', + 'float_add', 'float_sub', 'float_mul', 'float_truediv', + 'float_lt', 'float_le', 'float_eq', + 'float_ne', 'float_gt', 'float_ge', ]: exec py.code.Source(''' @arguments("box", "box") @@ -243,7 +246,9 @@ ''' % (_opimpl, _opimpl.upper())).compile() for _opimpl in ['int_is_true', 'int_neg', 'int_invert', 'bool_not', - 'cast_ptr_to_int', 'cast_int_to_ptr', + 'cast_ptr_to_int', 'cast_float_to_int', + 'cast_int_to_float', 'float_neg', 'float_abs', + 'float_is_true', ]: exec py.code.Source(''' @arguments("box") @@ -470,9 +475,8 @@ def opimpl_ptr_iszero(self, box): self.execute(rop.OOISNULL, [box]) - @arguments("box") - def opimpl_oononnull(self, box): - self.execute(rop.OONONNULL, [box]) + opimpl_oononnull = opimpl_ptr_nonzero + opimpl_ooisnull = opimpl_ptr_iszero @arguments("box", "box") def opimpl_ptr_eq(self, box1, box2): @@ -483,6 +487,7 @@ self.execute(rop.OOISNOT, [box1, box2]) opimpl_oois = opimpl_ptr_eq + opimpl_ooisnot = opimpl_ptr_ne @arguments("box", "descr") def opimpl_getfield_gc(self, box, fielddesc): @@ -638,14 +643,27 @@ def opimpl_residual_call(self, calldescr, varargs): return self.execute_with_exc(rop.CALL, varargs, descr=calldescr) + @arguments("varargs") + def opimpl_recursion_leave_prep(self, varargs): + warmrunnerstate = self.metainterp.staticdata.state + if warmrunnerstate.inlining: + num_green_args = self.metainterp.staticdata.num_green_args + greenkey = varargs[:num_green_args] + if warmrunnerstate.can_inline_callable(greenkey): + return False + leave_code = self.metainterp.staticdata.leave_code + if leave_code is None: + return False + return self.perform_call(leave_code, varargs) + @arguments("descr", "varargs") def opimpl_recursive_call(self, calldescr, varargs): - if self.metainterp.staticdata.options.inline: + warmrunnerstate = self.metainterp.staticdata.state + if warmrunnerstate.inlining: num_green_args = self.metainterp.staticdata.num_green_args portal_code = self.metainterp.staticdata.portal_code greenkey = varargs[1:num_green_args + 1] - if self.metainterp.staticdata.state.can_inline_callable(greenkey): - self.metainterp.in_recursion += 1 + if warmrunnerstate.can_inline_callable(greenkey): return self.perform_call(portal_code, varargs[1:]) return self.execute_with_exc(rop.CALL, varargs, descr=calldescr) @@ -1000,7 +1018,8 @@ virtualizable_info = None def __init__(self, portal_graph, graphs, cpu, stats, options, - optimizer=None, profile=None, warmrunnerdesc=None): + optimizer=None, profile=None, warmrunnerdesc=None, + leave_graph=None): self.portal_graph = portal_graph self.cpu = cpu self.stats = stats @@ -1034,6 +1053,8 @@ self.jit_starting_line = 'JIT starting (%s, %s)' % (optmodule, backendmodule) + self.leave_graph = leave_graph + def _freeze_(self): return True @@ -1070,6 +1091,11 @@ self._codewriter = codewriter.CodeWriter(self, policy) self.portal_code = self._codewriter.make_portal_bytecode( self.portal_graph) + self.leave_code = None + if self.leave_graph: + self.leave_code = self._codewriter.make_one_bytecode( + (self.leave_graph, None), + False) self._class_sizes = self._codewriter.class_sizes # ---------- construction-time interface ---------- @@ -1123,14 +1149,20 @@ def newframe(self, jitcode): if not we_are_translated(): self._debug_history.append(['enter', jitcode, None]) + if jitcode is self.staticdata.portal_code: + self.in_recursion += 1 f = MIFrame(self, jitcode) self.framestack.append(f) return f - def finishframe(self, resultbox): + def popframe(self): frame = self.framestack.pop() if frame.jitcode is self.staticdata.portal_code: self.in_recursion -= 1 + return frame + + def finishframe(self, resultbox): + frame = self.popframe() if not we_are_translated(): self._debug_history.append(['leave', frame.jitcode, None]) if self.framestack: @@ -1148,6 +1180,8 @@ raise sd.DoneWithThisFrameInt(resultbox.getint()) elif sd.result_type == 'ref': raise sd.DoneWithThisFrameRef(self.cpu, resultbox.getref_base()) + elif sd.result_type == 'float': + raise sd.DoneWithThisFrameFloat(resultbox.getfloat()) else: assert False @@ -1171,11 +1205,29 @@ return True if not we_are_translated(): self._debug_history.append(['leave_exc', frame.jitcode, None]) - self.framestack.pop() + self.popframe() if not self.is_blackholing(): self.compile_exit_frame_with_exception(excvaluebox) raise self.staticdata.ExitFrameWithExceptionRef(self.cpu, excvaluebox.getref_base()) + def check_recursion_invariant(self): + in_recursion = -1 + for frame in self.framestack: + jitcode = frame.jitcode + if jitcode is self.staticdata.portal_code: + in_recursion += 1 + if in_recursion != self.in_recursion: + print "in_recursion problem!!!" + print in_recursion, self.in_recursion + for frame in self.framestack: + jitcode = frame.jitcode + if jitcode is self.staticdata.portal_code: + print "P", + else: + print " ", + print jitcode.name + raise Exception + def raise_overflow_error(self): etype, evalue = self.cpu.get_overflow_error() return self.finishframe_exception( @@ -1189,6 +1241,7 @@ self.cpu.ts.get_exc_value_box(evalue)) def create_empty_history(self): + warmrunnerstate = self.staticdata.state self.history = history.History(self.cpu) if self.staticdata.stats is not None: self.staticdata.stats.history = self.history @@ -1238,6 +1291,19 @@ op.pc = self.framestack[-1].pc op.name = self.framestack[-1].jitcode.name + def switch_to_blackhole_if_trace_too_long(self): + if not self.is_blackholing(): + warmrunnerstate = self.staticdata.state + if len(self.history.operations) > warmrunnerstate.trace_limit: + self.history = history.BlackHole(self.cpu) + if not we_are_translated(): + self.staticdata.stats.aborted_count += 1 + history.log.event('ABORTING TRACING' + self.history.extratext) + elif DEBUG: + debug_print('~~~ ABORTING TRACING', self.history.extratext) + self.staticdata.profiler.end_tracing() + self.staticdata.profiler.start_blackhole() + def _interpret(self): # Execute the frames forward until we raise a DoneWithThisFrame, # a ContinueRunningNormally, or a GenerateMergePoint exception. @@ -1249,6 +1315,9 @@ try: while True: self.framestack[-1].run_one_step() + self.switch_to_blackhole_if_trace_too_long() + if not we_are_translated(): + self.check_recursion_invariant() finally: if self.is_blackholing(): self.staticdata.profiler.end_blackhole() @@ -1285,7 +1354,8 @@ return self.designate_target_loop(gmp) def handle_guard_failure(self, exec_result, key): - self.initialize_state_from_guard_failure(exec_result) + from pypy.jit.metainterp.warmspot import ContinueRunningNormallyBase + resumedescr = self.initialize_state_from_guard_failure(exec_result) assert isinstance(key, compile.ResumeGuardDescr) top_history = key.find_toplevel_history() source_loop = top_history.source_link @@ -1295,12 +1365,18 @@ self.resumekey = key self.seen_can_enter_jit = False guard_op = key.get_guard_op() + started_as_blackhole = self.is_blackholing() try: self.prepare_resume_from_failure(guard_op.opnum) self.interpret() assert False, "should always raise" except GenerateMergePoint, gmp: return self.designate_target_loop(gmp) + except ContinueRunningNormallyBase: + if not started_as_blackhole: + warmrunnerstate = self.staticdata.state + warmrunnerstate.reset_counter_from_failure(resumedescr) + raise def forget_consts(self, boxes, startindex=0): for i in range(startindex, len(boxes)): @@ -1456,6 +1532,9 @@ elif sd.result_type == 'ref': exits = [exitbox] loops = sd.cpu.ts.loops_done_with_this_frame_ref + elif sd.result_type == 'float': + exits = [exitbox] + loops = compile.loops_done_with_this_frame_float else: assert False self.history.record(rop.JUMP, exits, None) @@ -1489,7 +1568,7 @@ *args[1:]) def initialize_state_from_start(self, *args): - self.in_recursion = 0 + self.in_recursion = -1 # always one portal around self.staticdata._setup_once() self.staticdata.profiler.start_tracing() self.create_empty_history() @@ -1506,7 +1585,7 @@ def initialize_state_from_guard_failure(self, guard_failure): # guard failure: rebuild a complete MIFrame stack - self.in_recursion = 0 + self.in_recursion = -1 # always one portal around resumedescr = guard_failure.descr assert isinstance(resumedescr, compile.ResumeGuardDescr) warmrunnerstate = self.staticdata.state @@ -1532,6 +1611,7 @@ # the BlackHole is invalid because it doesn't start with # guard_failure.key.guard_op.suboperations, but that's fine self.rebuild_state_after_failure(resumedescr, guard_failure.args) + return resumedescr def initialize_virtualizable(self, original_boxes): vinfo = self.staticdata.virtualizable_info @@ -1632,10 +1712,7 @@ jitcode, pc, exception_target = resumereader.consume_frame_info() env = resumereader.consume_boxes() f = self.newframe(jitcode) - if jitcode is self.staticdata.portal_code: - self.in_recursion += 1 f.setup_resume_at_op(pc, exception_target, env) - self.in_recursion -= 1 # always one portal around def check_synchronized_virtualizable(self): if not we_are_translated(): Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/resoperation.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/resoperation.py Thu Sep 10 16:45:13 2009 @@ -126,7 +126,6 @@ 'OOSEND_PURE', # ootype operation 'CALL_PURE', # - 'CAST_INT_TO_PTR', 'CAST_PTR_TO_INT', 'INT_ADD', 'INT_SUB', @@ -139,6 +138,15 @@ 'INT_RSHIFT', 'INT_LSHIFT', 'UINT_RSHIFT', + 'FLOAT_ADD', + 'FLOAT_SUB', + 'FLOAT_MUL', + 'FLOAT_TRUEDIV', + 'FLOAT_NEG', + 'FLOAT_ABS', + 'FLOAT_IS_TRUE', + 'CAST_FLOAT_TO_INT', + 'CAST_INT_TO_FLOAT', # '_COMPARISON_FIRST', 'INT_LT', @@ -152,6 +160,12 @@ 'UINT_GT', 'UINT_GE', '_COMPARISON_LAST', + 'FLOAT_LT', # maybe these ones should be comparisons too + 'FLOAT_LE', + 'FLOAT_EQ', + 'FLOAT_NE', + 'FLOAT_GT', + 'FLOAT_GE', # 'INT_IS_TRUE', 'INT_NEG', Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/support.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/support.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/support.py Thu Sep 10 16:45:13 2009 @@ -186,9 +186,11 @@ # ---------- malloc with del ---------- - def _ll_0_alloc_with_del(RESULT): - return lltype.malloc(RESULT) - _ll_0_alloc_with_del.need_result_type = True + def _ll_1_alloc_with_del(RESULT, vtable): + p = lltype.malloc(RESULT) + lltype.cast_pointer(rclass.OBJECTPTR, p).typeptr = vtable + return p + _ll_1_alloc_with_del.need_result_type = True class OOtypeHelpers: @@ -341,10 +343,6 @@ else: raise Exception("oohash() of type %r" % (T,)) -def get_malloc_oopspec(op): - assert op.args[1].value == {'flavor': 'gc'} - return 'alloc_with_del', [] - RENAMED_ADT_NAME = { 'list': { @@ -375,8 +373,6 @@ return get_oostring_oopspec(op) elif op.opname == 'oohash': return get_oohash_oopspec(op) - elif op.opname == 'malloc': # for malloc with a __del__ - return get_malloc_oopspec(op) else: raise ValueError(op.opname) Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/test/oparser.py Thu Sep 10 16:45:13 2009 @@ -97,6 +97,8 @@ return vars def getvar(self, arg): + if not arg: + return ConstInt(0) try: return ConstInt(int(arg)) except ValueError: @@ -145,7 +147,10 @@ argspec = line[num + 1:endnum] if not argspec.strip(): return opnum, [], None - allargs = argspec.split(",") + if opname == 'debug_merge_point': + allargs = [argspec] + else: + allargs = argspec.split(",") args = [] descr = None poss_descr = allargs[-1].strip() @@ -195,8 +200,15 @@ ops = [] newlines = [] for line in lines: - if '#' in line: - line = line[:line.index('#')] # remove comment + # for simplicity comments are not allowed on + # debug_merge_point lines + if '#' in line and 'debug_merge_point(' not in line: + if line.lstrip()[0] == '#': # comment only + continue + comm = line.rfind('#') + rpar = line.find(')') # assume there's a op(...) + if comm > rpar: + line = line[:comm].rstrip() if not line.strip(): continue # a comment or empty line newlines.append(line) Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_basic.py Thu Sep 10 16:45:13 2009 @@ -1,4 +1,5 @@ import py +import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats from pypy.jit.backend.llgraph import runner @@ -49,6 +50,8 @@ assert get_stats().enter_count <= count def check_jumps(self, maxcount): assert get_stats().exec_jumps <= maxcount + def check_aborted_count(self, maxcount): + assert get_stats().aborted_count == maxcount def meta_interp(self, *args, **kwds): kwds['CPUClass'] = self.CPUClass @@ -70,6 +73,8 @@ class FakeWarmRunnerDesc: def attach_unoptimized_bridge_from_interp(self, greenkey, newloop): pass + + trace_limit = sys.maxint if policy is None: policy = JitPolicy() @@ -89,6 +94,7 @@ metainterp.staticdata.state = FakeWarmRunnerDesc() metainterp.staticdata.DoneWithThisFrameInt = DoneWithThisFrame metainterp.staticdata.DoneWithThisFrameRef = DoneWithThisFrameRef + metainterp.staticdata.DoneWithThisFrameFloat = DoneWithThisFrame self.metainterp = metainterp try: metainterp.compile_and_run_once(*args) @@ -402,6 +408,24 @@ assert res == 210 self.check_history_(getfield_gc=0) + def test_setfield_bool(self): + class A: + def __init__(self): + self.flag = True + myjitdriver = JitDriver(greens = [], reds = ['n', 'obj']) + def f(n): + obj = A() + res = False + while n > 0: + myjitdriver.can_enter_jit(n=n, obj=obj) + myjitdriver.jit_merge_point(n=n, obj=obj) + obj.flag = False + n -= 1 + return res + res = self.meta_interp(f, [7]) + assert type(res) == bool + assert not res + def test_switch_dict(self): def f(x): if x == 1: return 61 @@ -915,16 +939,21 @@ lltype.free(x, flavor='raw') def test_casts(self): + if not self.basic: + py.test.skip("test written in a style that " + "means it's frontend only") from pypy.rpython.lltypesystem import lltype, llmemory TP = lltype.GcStruct('x') def f(p): n = lltype.cast_ptr_to_int(p) - return lltype.cast_int_to_ptr(lltype.Ptr(TP), n) + return n x = lltype.malloc(TP) - expected = lltype.cast_opaque_ptr(llmemory.GCREF, x) - assert self.interp_operations(f, [x]) == expected + res = self.interp_operations(f, [x]) + expected = self.metainterp.cpu.do_cast_ptr_to_int( + [history.BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, x))]).value + assert res == expected class TestLLtype(BaseLLtypeTests, LLJitMixin): pass Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_del.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_del.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_del.py Thu Sep 10 16:45:13 2009 @@ -27,6 +27,33 @@ 'guard_true': 1, 'jump': 1}) + def test_class_of_allocated(self): + myjitdriver = JitDriver(greens = [], reds = ['n', 'x']) + class Foo: + def __del__(self): + pass + def f(self): + return self.meth() + class X(Foo): + def meth(self): + return 456 + class Y(Foo): + def meth(self): + return 123 + def f(n): + x = None + while n > 0: + myjitdriver.can_enter_jit(x=x, n=n) + myjitdriver.jit_merge_point(x=x, n=n) + x = X() + y = Y() + assert x.f() == 456 + assert y.f() == 123 + n -= 1 + return 42 + res = self.meta_interp(f, [20]) + assert res == 42 + class TestLLtype(DelTests, LLJitMixin): def test_signal_action(self): @@ -52,6 +79,6 @@ self.check_loops(getfield_raw=1, call=0, call_pure=0) class TestOOtype(DelTests, OOJitMixin): - def test_del_keep_obj(self): + def setup_class(cls): py.test.skip("XXX dels are not implemented in the" " static CLI or JVM backend") Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_oparser.py Thu Sep 10 16:45:13 2009 @@ -8,10 +8,10 @@ def test_basic_parse(): x = """ [i0, i1] - i2 = int_add(i0, i1) # a comment - i3 = int_sub(i2, 3) - fail() + i2 = int_add(i0, i1) + i3 = int_sub(i2, 3) # another comment + fail() # (tricky) """ loop = parse(x) assert len(loop.operations) == 3 @@ -146,10 +146,15 @@ [] debug_merge_point("info") debug_merge_point('info') + debug_merge_point(' info') + debug_merge_point('(stuff) #1') ''' loop = parse(x) assert loop.operations[0].args[0]._get_str() == 'info' assert loop.operations[1].args[0]._get_str() == 'info' + assert loop.operations[2].args[0]._get_str() == " info" + assert loop.operations[3].args[0]._get_str() == "(stuff) #1" + def test_descr_with_obj_print(): x = ''' Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_policy.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_policy.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_policy.py Thu Sep 10 16:45:13 2009 @@ -19,11 +19,29 @@ jitpolicy = policy.JitPolicy() translator = rtyper.annotator.translator - res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator) + res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator, + True) funcs = [graph.func for graph in res] assert funcs == [i, f] +def test_find_all_graphs_without_floats(): + def g(x): + return int(x * 12.5) + def f(x): + return g(x) + 1 + rtyper = support.annotate(f, [7]) + jitpolicy = policy.JitPolicy() + translator = rtyper.annotator.translator + res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator, + supports_floats=True) + funcs = [graph.func for graph in res] + assert funcs == [f, g] + res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator, + supports_floats=False) + funcs = [graph.func for graph in res] + assert funcs == [f] + def test_find_all_graphs_str_join(): def i(x, y): return "hello".join([str(x), str(y), "bye"]) @@ -32,7 +50,8 @@ jitpolicy = policy.JitPolicy() translator = rtyper.annotator.translator - res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator) + res = warmspot.find_all_graphs(translator.graphs[0], jitpolicy, translator, + True) funcs = [graph.func for graph in res] assert funcs[:1] == [i] Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_pyjitpl.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_pyjitpl.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_pyjitpl.py Thu Sep 10 16:45:13 2009 @@ -1,7 +1,7 @@ # some unit tests for the bytecode decoding -from pypy.jit.metainterp import pyjitpl, codewriter +from pypy.jit.metainterp import pyjitpl, codewriter, resoperation def make_frame(code): bytecode = codewriter.JitCode("hello") @@ -24,3 +24,11 @@ frame = make_frame("\x01") assert frame.load_bool() + +def test_simple_opimpl_exist(): + rop = resoperation.rop + for opnum, opname in resoperation.opname.items(): + if opnum in (rop.SAME_AS, rop.CALL_PURE, rop.OOSEND_PURE): + continue + if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST: + assert hasattr(pyjitpl.MIFrame, 'opimpl_' + opname.lower()), opname Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_recursive.py Thu Sep 10 16:45:13 2009 @@ -1,10 +1,10 @@ import py -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, we_are_jitted from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin from pypy.jit.metainterp import simple_optimize from pypy.jit.metainterp.policy import StopAtXPolicy from pypy.rpython.annlowlevel import hlstr -from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit +from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit, get_stats class RecursiveTests: @@ -213,10 +213,239 @@ res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) assert res == 0 + def test_exception_in_inlined_function(self): + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "l" not in hlstr(code) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], + get_printable_location=p, can_inline=c) + + class Exc(Exception): + pass + + def f(code, n): + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(n=n, code=code, pc=pc) + op = code[pc] + if op == "-": + n -= 1 + elif op == "c": + try: + n = f("---i---", n) + except Exc: + pass + elif op == "i": + if n % 5 == 1: + raise Exc + elif op == "l": + if n > 0: + myjitdriver.can_enter_jit(n=n, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return n + def main(n): + return f("c-l", n) + res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + assert res == main(100) + + def test_recurse_during_blackholing(self): + # this passes, if the blackholing shortcut for calls is turned off + # it fails, it is very delicate in terms of parameters, + # bridge/loop creation order + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "l" not in hlstr(code) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n'], + get_printable_location=p, can_inline=c) + + def f(code, n): + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(n=n, code=code, pc=pc) + op = code[pc] + if op == "-": + n -= 1 + elif op == "c": + if n < 70 and n % 3 == 1: + print "F" + n = f("--", n) + elif op == "l": + if n > 0: + myjitdriver.can_enter_jit(n=n, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return n + def main(n): + myjitdriver.set_param('threshold', 3) + myjitdriver.set_param('trace_eagerness', 5) + return f("c-l", n) + expected = main(100) + res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + assert res == expected + + def check_max_trace_length(self, length): + for loop in get_stats().loops: + assert len(loop.operations) <= length + 5 # because we only check once per metainterp bytecode + for op in loop.operations: + if op.is_guard(): + assert len(op.suboperations) <= length + 5 + + def test_inline_trace_limit(self): + myjitdriver = JitDriver(greens=[], reds=['n']) + def recursive(n): + if n > 0: + return recursive(n - 1) + 1 + return 0 + def loop(n): + myjitdriver.set_param("threshold", 10) + pc = 0 + while n: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + n = recursive(n) + n -= 1 + return n + TRACE_LIMIT = 66 + res = self.meta_interp(loop, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT) + assert res == 0 + self.check_max_trace_length(TRACE_LIMIT) + self.check_enter_count(15) # maybe + self.check_aborted_count(7) + + def test_trace_limit_bridge(self): + def recursive(n): + if n > 0: + return recursive(n - 1) + 1 + return 0 + myjitdriver = JitDriver(greens=[], reds=['n']) + def loop(n): + myjitdriver.set_param("threshold", 4) + myjitdriver.set_param("trace_eagerness", 2) + while n: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + if n % 5 == 0: + n -= 1 + if n < 50: + n = recursive(n) + n -= 1 + TRACE_LIMIT = 20 + res = self.meta_interp(loop, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT) + self.check_max_trace_length(TRACE_LIMIT) + self.check_aborted_count(8) + self.check_enter_count_at_most(30) + + def test_set_param_inlining(self): + myjitdriver = JitDriver(greens=[], reds=['n', 'recurse']) + def loop(n, recurse=False): + while n: + myjitdriver.jit_merge_point(n=n, recurse=recurse) + n -= 1 + if not recurse: + loop(10, True) + myjitdriver.can_enter_jit(n=n, recurse=recurse) + return n + TRACE_LIMIT = 66 + + def main(inline): + myjitdriver.set_param("threshold", 10) + if inline: + myjitdriver.set_param('inlining', True) + else: + myjitdriver.set_param('inlining', False) + return loop(100) + + res = self.meta_interp(main, [0], optimizer=simple_optimize, trace_limit=TRACE_LIMIT) + self.check_loops(call=1) + + res = self.meta_interp(main, [1], optimizer=simple_optimize, trace_limit=TRACE_LIMIT) + self.check_loops(call=0) + + def test_leave_jit_hook(self): + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "L" not in hlstr(code) + + def leave(code, pc, frame): + frame.hookcalled = True + + class ExpectedHook(Exception): + pass + class UnexpectedHook(Exception): + pass + + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['self'], + get_printable_location=p, can_inline=c, + leave=leave) + class Frame(object): + hookcalled = True + + def __init__(self, n): + self.n = n + self.hookcalled = False + def f(self, code): + pc = 0 + while pc < len(code): + + myjitdriver.jit_merge_point(self=self, code=code, pc=pc) + op = code[pc] + if op == "-": + self.n -= 1 + elif op == "c": + frame = Frame(self.n) + self.n = frame.f("---i---") + if we_are_jitted(): + if frame.hookcalled: + raise UnexpectedHook + elif op == "C": + frame = Frame(self.n) + self.n = frame.f("cL") + if we_are_jitted(): + if not frame.hookcalled: + raise ExpectedHook + elif op == "i": + if self.n % 5 == 1: + return self.n + elif op == "l": + if self.n > 0: + myjitdriver.can_enter_jit(self=self, code=code, pc=0) + pc = 0 + continue + elif op == "L": + if self.n > 50: + myjitdriver.can_enter_jit(self=self, code=code, pc=0) + pc = 0 + continue + else: + assert 0 + pc += 1 + return self.n + def main(n): + frame = Frame(n) + return frame.f("C-l") + res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + assert res == main(100) class TestLLtype(RecursiveTests, LLJitMixin): pass class TestOOtype(RecursiveTests, OOJitMixin): - def test_simple_recursion_with_exc(self): - py.test.skip("Fails") + pass Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_virtual.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_virtual.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_virtual.py Thu Sep 10 16:45:13 2009 @@ -4,6 +4,7 @@ from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin from pypy.rpython.lltypesystem import lltype, rclass from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp import heaptracker class VirtualTests: @@ -272,9 +273,9 @@ return f res = self.meta_interp(f, [21], repeat=7) - # hack - assert (getattr(res, "inst_value", -100) == f(21).value or - getattr(res, "value", -100) == f(21).value) + + fieldname = self._field_prefix + 'value' + assert getattr(res, fieldname, -100) == f(21).value self.check_tree_loop_count(2) # the loop and the entry path # we get: @@ -285,9 +286,6 @@ self.check_enter_count(4) -##class TestOOtype(VirtualTests, OOJitMixin): -## _new = staticmethod(ootype.new) - # ____________________________________________________________ # Run 1: all the tests instantiate a real RPython class @@ -296,10 +294,47 @@ class TestLLtype_Instance(VirtualTests, LLJitMixin): _new_op = 'new_with_vtable' + _field_prefix = 'inst_' + + @staticmethod + def _new(): + return MyClass() + + def test_class_with_default_fields(self): + class MyClass: + value = 2 + + myjitdriver = JitDriver(greens = [], reds = ['n', 'res']) + def f(n): + res = 0 + node = MyClass() + node.value = n # so that the annotator doesn't think that value is constant + while n > 0: + myjitdriver.can_enter_jit(n=n, res=res) + myjitdriver.jit_merge_point(n=n, res=res) + node = MyClass() + res += node.value + n -= 1 + return res + assert f(10) == 20 + res = self.meta_interp(f, [10]) + assert res == 20 + self.check_loop_count(1) + self.check_loops(new=0, new_with_vtable=0, + getfield_gc=0, setfield_gc=0) + + + +class TestOOtype_Instance(VirtualTests, OOJitMixin): + _new_op = 'new_with_vtable' + _field_prefix = 'o' + @staticmethod def _new(): return MyClass() + test_class_with_default_fields = TestLLtype_Instance.test_class_with_default_fields.im_func + # ____________________________________________________________ # Run 2: all the tests use lltype.malloc to make a NODE @@ -308,11 +343,25 @@ class TestLLtype_NotObject(VirtualTests, LLJitMixin): _new_op = 'new' - + _field_prefix = '' + @staticmethod def _new(): return lltype.malloc(NODE) + +OONODE = ootype.Instance('NODE', ootype.ROOT, {}) +OONODE._add_fields({'value': ootype.Signed, + 'extra': ootype.Signed}) + +class TestOOtype_NotObject(VirtualTests, OOJitMixin): + _new_op = 'new_with_vtable' + _field_prefix = '' + + @staticmethod + def _new(): + return ootype.new(OONODE) + # ____________________________________________________________ # Run 3: all the tests use lltype.malloc to make a NODE2 # (same as Run 2 but it is part of the OBJECT hierarchy) @@ -326,6 +375,8 @@ class TestLLtype_Object(VirtualTests, LLJitMixin): _new_op = 'new_with_vtable' + _field_prefix = '' + @staticmethod def _new(): p = lltype.malloc(NODE2) Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_zrpy_basic.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_zrpy_basic.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_zrpy_basic.py Thu Sep 10 16:45:13 2009 @@ -90,7 +90,9 @@ pass def check_enter_count_at_most(self, count): pass - def check_jumps(self, maxcount): + def check_jumps(self, maxcount): + pass + def check_aborted_count(self, count): pass def interp_operations(self, *args, **kwds): Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/warmspot.py Thu Sep 10 16:45:13 2009 @@ -26,7 +26,9 @@ # ____________________________________________________________ # Bootstrapping -def apply_jit(translator, backend_name="auto", debug_level="steps", **kwds): +def apply_jit(translator, backend_name="auto", debug_level="steps", + inline=False, + **kwds): if 'CPUClass' not in kwds: from pypy.jit.backend.detect_cpu import getcpuclass kwds['CPUClass'] = getcpuclass(backend_name) @@ -38,9 +40,9 @@ warmrunnerdesc = WarmRunnerDesc(translator, translate_support_code=True, listops=True, - #inline=True, profile=profile, **kwds) + warmrunnerdesc.state.set_param_inlining(inline) warmrunnerdesc.finish() translator.warmrunnerdesc = warmrunnerdesc # for later debugging @@ -52,13 +54,15 @@ clear_tcache() return jittify_and_run(interp, graph, args, backendopt=backendopt, **kwds) -def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False, - **kwds): +def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False, trace_limit=sys.maxint, + inline=False, **kwds): translator = interp.typer.annotator.translator translator.config.translation.gc = "boehm" warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds) warmrunnerdesc.state.set_param_threshold(3) # for tests warmrunnerdesc.state.set_param_trace_eagerness(2) # for tests + warmrunnerdesc.state.set_param_trace_limit(trace_limit) + warmrunnerdesc.state.set_param_inlining(inline) warmrunnerdesc.state.create_tables_now() # for tests if hash_bits: warmrunnerdesc.state.set_param_hash_bits(hash_bits) @@ -120,6 +124,9 @@ class JitException(Exception): _go_through_llinterp_uncaught_ = True # ugh +class ContinueRunningNormallyBase(JitException): + pass + class CannotInlineCanEnterJit(JitException): pass @@ -127,18 +134,21 @@ class WarmRunnerDesc: - def __init__(self, translator, policy=None, backendopt=True, **kwds): + def __init__(self, translator, policy=None, backendopt=True, CPUClass=None, + **kwds): pyjitpl._warmrunnerdesc = self # this is a global for debugging only! if policy is None: policy = JitPolicy() self.set_translator(translator) self.find_portal() - graphs = find_all_graphs(self.portal_graph, policy, self.translator) + self.make_leave_jit_graph() + graphs = find_all_graphs(self.portal_graph, policy, self.translator, + CPUClass.supports_floats) self.check_access_directly_sanity(graphs) if backendopt: self.prejit_optimizations(policy, graphs) - self.build_meta_interp(**kwds) + self.build_meta_interp(CPUClass, **kwds) self.make_args_specification() self.rewrite_jit_merge_point() self.make_driverhook_graph() @@ -206,7 +216,7 @@ remove_asserts=True, really_remove_asserts=True) - def build_meta_interp(self, CPUClass=None, translate_support_code=False, + def build_meta_interp(self, CPUClass, translate_support_code=False, view="auto", optimizer=None, profile=None, **kwds): assert CPUClass is not None opt = history.Options(**kwds) @@ -224,7 +234,8 @@ self.stats, opt, optimizer=optimizer, profile=profile, - warmrunnerdesc=self) + warmrunnerdesc=self, + leave_graph=self.leave_graph) def make_enter_function(self): WarmEnterState = make_state_class(self) @@ -259,6 +270,21 @@ self.maybe_enter_jit_fn = maybe_enter_jit + def make_leave_jit_graph(self): + self.leave_graph = None + if self.jitdriver.leave: + graph, block, index = self.jit_merge_point_pos + op = block.operations[index] + args = op.args[2:] + s_binding = self.translator.annotator.binding + args_s = [s_binding(v) for v in args] + from pypy.annotation import model as annmodel + annhelper = MixLevelHelperAnnotator(self.translator.rtyper) + s_result = annmodel.s_None + self.leave_graph = annhelper.getgraph(self.jitdriver.leave, + args_s, s_result) + annhelper.finish() + def make_driverhook_graph(self): self.can_inline_ptr = self._make_hook_graph( self.jitdriver.can_inline, bool) @@ -393,6 +419,13 @@ def __str__(self): return 'DoneWithThisFrameRef(%s)' % (self.result,) + class DoneWithThisFrameFloat(JitException): + def __init__(self, cpu, result): + assert lltype.typeOf(result) is lltype.Float + self.result = result + def __str__(self): + return 'DoneWithThisFrameFloat(%s)' % (self.result,) + class ExitFrameWithExceptionRef(JitException): def __init__(self, cpu, value): assert lltype.typeOf(value) == cpu.ts.BASETYPE @@ -400,7 +433,7 @@ def __str__(self): return 'ExitFrameWithExceptionRef(%s)' % (self.value,) - class ContinueRunningNormally(JitException): + class ContinueRunningNormally(ContinueRunningNormallyBase): def __init__(self, argboxes): # accepts boxes as argument, but unpacks them immediately # before we raise the exception -- the boxes' values will @@ -416,11 +449,13 @@ self.DoneWithThisFrameVoid = DoneWithThisFrameVoid self.DoneWithThisFrameInt = DoneWithThisFrameInt self.DoneWithThisFrameRef = DoneWithThisFrameRef + self.DoneWithThisFrameFloat = DoneWithThisFrameFloat self.ExitFrameWithExceptionRef = ExitFrameWithExceptionRef self.ContinueRunningNormally = ContinueRunningNormally self.metainterp_sd.DoneWithThisFrameVoid = DoneWithThisFrameVoid self.metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrameInt self.metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef + self.metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrameFloat self.metainterp_sd.ExitFrameWithExceptionRef = ExitFrameWithExceptionRef self.metainterp_sd.ContinueRunningNormally = ContinueRunningNormally rtyper = self.translator.rtyper @@ -447,6 +482,9 @@ except DoneWithThisFrameRef, e: assert result_kind == 'ref' return ts.cast_from_ref(RESULT, e.result) + except DoneWithThisFrameFloat, e: + assert result_kind == 'float' + return e.result except ExitFrameWithExceptionRef, e: value = ts.cast_to_baseclass(e.value) if not we_are_translated(): @@ -510,7 +548,7 @@ op.args[:3] = [closures[funcname]] -def find_all_graphs(portal, policy, translator): +def find_all_graphs(portal, policy, translator, supports_floats): from pypy.translator.simplify import get_graph all_graphs = [portal] seen = set([portal]) @@ -520,13 +558,13 @@ for _, op in top_graph.iterblockops(): if op.opname not in ("direct_call", "indirect_call", "oosend"): continue - kind = policy.guess_call_kind(op) + kind = policy.guess_call_kind(op, supports_floats) if kind != "regular": continue - for graph in policy.graphs_from(op): + for graph in policy.graphs_from(op, supports_floats): if graph in seen: continue - if policy.look_inside_graph(graph): + if policy.look_inside_graph(graph, supports_floats): todo.append(graph) all_graphs.append(graph) seen.add(graph) @@ -552,6 +590,8 @@ return box.getref(TYPE) if isinstance(TYPE, ootype.OOType): return box.getref(TYPE) + if TYPE == lltype.Float: + return box.getfloat() else: return lltype.cast_primitive(TYPE, box.getint()) unwrap._annspecialcase_ = 'specialize:arg(0)' @@ -574,6 +614,11 @@ return history.ConstObj(value) else: return history.BoxObj(value) + elif isinstance(value, float): + if in_const_box: + return history.ConstFloat(value) + else: + return history.BoxFloat(value) else: value = intmask(value) if in_const_box: @@ -683,6 +728,9 @@ elif typecode == 'int': intvalue = lltype.cast_primitive(lltype.Signed, value) cpu.set_future_value_int(j, intvalue) + elif typecode == 'float': + assert isinstance(value, float) + cpu.set_future_value_float(j, value) else: assert False set_future_value._annspecialcase_ = 'specialize:ll_and_arg(2)' @@ -704,6 +752,12 @@ def set_param_trace_eagerness(self, value): self.trace_eagerness = value + def set_param_trace_limit(self, value): + self.trace_limit = value + + def set_param_inlining(self, value): + self.inlining = value + def set_param_hash_bits(self, value): if value < 1: value = 1 @@ -748,7 +802,13 @@ self.create_tables_now() return metainterp = MetaInterp(metainterp_sd) - loop = metainterp.compile_and_run_once(*args) + try: + loop = metainterp.compile_and_run_once(*args) + except warmrunnerdesc.ContinueRunningNormally: + # the trace got too long, reset the counter + self.mccounters[argshash] = 0 + raise + else: # machine code was already compiled for these greenargs # (or we have a hash collision) @@ -837,6 +897,9 @@ key.counter += 1 return key.counter >= self.trace_eagerness + def reset_counter_from_failure(self, key): + key.counter = 0 + def attach_unoptimized_bridge_from_interp(self, greenkey, bridge): greenargs = self.unwrap_greenkey(greenkey) newcell = MachineCodeEntryPoint(bridge, *greenargs) Modified: pypy/branch/spine-of-frames/pypy/jit/tl/pypyjit_child.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/tl/pypyjit_child.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/tl/pypyjit_child.py Thu Sep 10 16:45:13 2009 @@ -38,6 +38,7 @@ print 'warmspot.jittify_and_run() started...' from pypy.jit.backend.llgraph.runner import LLtypeCPU + LLtypeCPU.supports_floats = False # for now policy = PyPyJitPolicy(interp.typer.annotator.translator) option.view = True warmspot.jittify_and_run(interp, graph, [], policy=policy, Modified: pypy/branch/spine-of-frames/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/__builtin__/__init__.py (original) +++ pypy/branch/spine-of-frames/pypy/module/__builtin__/__init__.py Thu Sep 10 16:45:13 2009 @@ -27,23 +27,11 @@ 'raw_input' : 'app_io.raw_input', 'input' : 'app_io.input', - 'sum' : 'app_functional.sum', 'apply' : 'app_functional.apply', - 'map' : 'app_functional.map', - 'filter' : 'app_functional.filter', - 'zip' : 'app_functional.zip', - 'reduce' : 'app_functional.reduce', #'range' : 'app_functional.range', # redirected to functional.py, applevel version # is still needed and should stay where it is. - 'min' : 'app_functional.min', - 'max' : 'app_functional.max', - 'enumerate' : 'app_functional.enumerate', 'sorted' : 'app_functional.sorted', - 'reversed' : 'app_functional.reversed', - '_install_pickle_support_for_reversed_iterator': - 'app_functional._install_pickle_support_for_reversed_iterator', - 'globals' : 'app_inspect.globals', 'locals' : 'app_inspect.locals', 'vars' : 'app_inspect.vars', @@ -106,8 +94,17 @@ 'range' : 'functional.range_int', 'xrange' : 'functional.W_XRange', + 'enumerate' : 'functional.W_Enumerate', 'all' : 'functional.all', 'any' : 'functional.any', + 'min' : 'functional.min', + 'max' : 'functional.max', + 'sum' : 'functional.sum', + 'map' : 'functional.map', + 'zip' : 'functional.zip', + 'reduce' : 'functional.reduce', + 'reversed' : 'functional.reversed', + 'filter' : 'functional.filter', 'super' : 'descriptor.W_Super', 'staticmethod' : 'descriptor.StaticMethod', 'classmethod' : 'descriptor.ClassMethod', Modified: pypy/branch/spine-of-frames/pypy/module/__builtin__/app_functional.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/__builtin__/app_functional.py (original) +++ pypy/branch/spine-of-frames/pypy/module/__builtin__/app_functional.py Thu Sep 10 16:45:13 2009 @@ -3,151 +3,12 @@ functional programming. """ - -def sum(sequence, total=0): - """sum(sequence, start=0) -> value - -Returns the sum of a sequence of numbers (NOT strings) plus the value -of parameter 'start'. When the sequence is empty, returns start.""" - # must forbid "summing" strings, per specs of built-in 'sum' - if isinstance(total, str): raise TypeError - for item in sequence: - total = total + item - return total - # ____________________________________________________________ def apply(function, args=(), kwds={}): """call a function (or other callable object) and return its result""" return function(*args, **kwds) -def map(function, *collections): - """does 3 separate things, hence this enormous docstring. - 1. if function is None, return a list of tuples, each with one - item from each collection. If the collections have different - lengths, shorter ones are padded with None. - - 2. if function is not None, and there is only one collection, - apply function to every item in the collection and return a - list of the results. - - 3. if function is not None, and there are several collections, - repeatedly call the function with one argument from each - collection. If the collections have different lengths, - shorter ones are padded with None - """ - - if len(collections) == 0: - raise TypeError, "map() requires at least one sequence" - - if len(collections) == 1: - #it's the most common case, so make it faster - if function is None: - return list(collections[0]) - return [function(x) for x in collections[0]] - - iterators = [ iter(collection) for collection in collections ] - res = [] - while 1: - cont = False #is any collection not empty? - args = [] - for iterator in iterators: - try: - elem = iterator.next() - cont = True - except StopIteration: - elem = None - args.append(elem) - if cont: - if function is None: - res.append(tuple(args)) - else: - res.append(function(*args)) - else: - return res - -def filterstring(function, collection, str_type): - if function is None and type(collection) is str_type: - return collection - res = [] - for i in xrange(len(collection)): - c = collection[i] - if function is None or function(c): - if not isinstance(c, str_type): - raise TypeError("can't filter %s to %s: __getitem__ returned different type", str_type.__name__, str_type.__name__) - res.append(c) - return str_type().join(res) - -def filtertuple(function, collection): - if function is None: - function = bool - res = [] - for i in xrange(len(collection)): - c = collection[i] - if function(c): - res.append(c) - return tuple(res) - -def filter(function, collection): - """construct a list of those elements of collection for which function - is True. If function is None, then return the items in the sequence - which are True.""" - if isinstance(collection, str): - return filterstring(function, collection, str) - elif isinstance(collection, unicode): - return filterstring(function, collection, unicode) - elif isinstance(collection, tuple): - return filtertuple(function, collection) - - if function is None: - return [item for item in collection if item] - else: - return [item for item in collection if function(item)] - -def zip(*collections): - """return a list of tuples, where the nth tuple contains every - nth item of each collection. If the collections have different - lengths, zip returns a list as long as the shortest collection, - ignoring the trailing items in the other collections.""" - - if len(collections) == 0: - import sys - if sys.version_info < (2,4): - raise TypeError("zip() requires at least one sequence") - return [] - res = [] - iterators = [ iter(collection) for collection in collections ] - while 1: - try: - elems = [] - for iterator in iterators: - elems.append(iterator.next()) - res.append(tuple(elems)) - except StopIteration: - return res - -def reduce(function, seq, *initialt): - """ Apply function of two arguments cumulatively to the items of - sequence, from left to right, so as to reduce the sequence to a - single value. Optionally begin with an initial value.""" - - seqiter = iter(seq) - if initialt: - initial, = initialt - else: - try: - initial = seqiter.next() - except StopIteration: - raise TypeError, "reduce() of empty sequence with no initial value" - while 1: - try: - arg = seqiter.next() - except StopIteration: - break - initial = function(initial, arg) - - return initial - # ____________________________________________________________ """ @@ -206,135 +67,10 @@ # ____________________________________________________________ - -def _identity(arg): - return arg - - -def min(*arr, **kwargs): - """return the smallest number in a list, - or its smallest argument if more than one is given.""" - from operator import gt - - return min_max(gt, "min", *arr, **kwargs) - -def min_max(comp, funcname, *arr, **kwargs): - key = kwargs.pop("key", _identity) - if len(kwargs): - raise TypeError, '%s() got an unexpected keyword argument' % funcname - - if not arr: - raise TypeError, '%s() takes at least one argument' % funcname - - if len(arr) == 1: - arr = arr[0] - - iterator = iter(arr) - try: - min_max_val = iterator.next() - except StopIteration: - raise ValueError, '%s() arg is an empty sequence' % funcname - - keyed_min_max_val = key(min_max_val) - - for i in iterator: - keyed = key(i) - if comp(keyed_min_max_val, keyed): - min_max_val = i - keyed_min_max_val = keyed - return min_max_val - -def max(*arr, **kwargs): - """return the largest number in a list, - or its largest argument if more than one is given.""" - from operator import lt - - return min_max(lt, "max", *arr, **kwargs) - -class enumerate(object): - """enumerate(iterable) -> iterator for (index, value) of iterable. - -Return an enumerate object. iterable must be an other object that supports -iteration. The enumerate object yields pairs containing a count (from -zero) and a value yielded by the iterable argument. enumerate is useful -for obtaining an indexed list: (0, seq[0]), (1, seq[1]), (2, seq[2]), ...""" - - def __init__(self, collection): - self._iter = iter(collection) - self._index = 0 - - def next(self): - try: - next = self._iter.next - except AttributeError: - # CPython raises a TypeError when next() is not defined - raise TypeError('%s object has no next() method' % - (type(self._iter).__name__,)) - result = self._index, next() - self._index += 1 - return result - - def __iter__(self): - return self - - -# ____________________________________________________________ - def sorted(lst, cmp=None, key=None, reverse=None): "sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list" sorted_lst = list(lst) sorted_lst.sort(cmp, key, reverse) return sorted_lst -def reversed(sequence): - "reversed(sequence) -> reverse iterator over values of the sequence" - if hasattr(sequence, '__reversed__'): - return sequence.__reversed__() - if not hasattr(sequence, '__getitem__'): - raise TypeError("argument to reversed() must be a sequence") - return reversed_iterator(sequence) - - -class reversed_iterator(object): - - def __init__(self, seq): - self.seq = seq - self.remaining = len(seq) - - def __iter__(self): - return self - - def next(self): - if self.remaining > len(self.seq): - self.remaining = 0 - i = self.remaining - if i > 0: - i -= 1 - item = self.seq[i] - self.remaining = i - return item - raise StopIteration - -# XXX __length_hint__() -## def __len__(self): -## if self.remaining > len(self.seq): -## self.remaining = 0 -## return self.remaining - - def __reduce__(self): - tup = (self.seq, self.remaining) - return (make_reversed_iterator, tup) - -def make_reversed_iterator(seq, remaining): - ri = reversed_iterator.__new__(reversed_iterator) - ri.seq = seq - #or "ri = reversed_iterator(seq)" but that executes len(seq) - ri.remaining = remaining - return ri - -def _install_pickle_support_for_reversed_iterator(): - import _pickle_support - make_reversed_iterator.__module__ = '_pickle_support' - _pickle_support.make_reversed_iterator = make_reversed_iterator - Modified: pypy/branch/spine-of-frames/pypy/module/__builtin__/functional.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/__builtin__/functional.py (original) +++ pypy/branch/spine-of-frames/pypy/module/__builtin__/functional.py Thu Sep 10 16:45:13 2009 @@ -8,7 +8,9 @@ from pypy.interpreter.gateway import interp2app from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.argument import Arguments from pypy.rlib.rarithmetic import r_uint, intmask +from pypy.rlib.objectmodel import specialize from pypy.module.__builtin__.app_functional import range as app_range from inspect import getsource, getfile @@ -100,7 +102,239 @@ return W_ListMultiObject(space, impl) + at specialize.arg(2) +def min_max(space, arguments, implementation_of): + if implementation_of == "max": + compare = space.gt + else: + compare = space.lt + args, kwargs = arguments.unpack() + if len(args) > 1: + w_sequence = space.newtuple(args) + elif len(args): + w_sequence = args[0] + else: + msg = "%s() expects at least one argument" % (implementation_of,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + try: + w_key = kwargs["key"] + except KeyError: + w_key = None + else: + del kwargs["key"] + if kwargs: + msg = "%s() got unexpected keyword argument" % (implementation_of,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_iter = space.iter(w_sequence) + w_max_item = None + w_max_val = None + while True: + try: + w_item = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if w_key is not None: + w_compare_with = space.call_function(w_key, w_item) + else: + w_compare_with = w_item + if w_max_item is None or \ + space.is_true(compare(w_compare_with, w_max_val)): + w_max_item = w_item + w_max_val = w_compare_with + if w_max_item is None: + msg = "arg is an empty sequence" + raise OperationError(space.w_ValueError, space.wrap(msg)) + return w_max_item + +def max(space, __args__): + """Return the largest item in a sequence. + + If more than one argument is passed, return the maximum of them. + """ + return min_max(space, __args__, "max") +max.unwrap_spec = [ObjSpace, Arguments] + +def min(space, __args__): + """Return the smallest item in a sequence. + + If more than one argument is passed, return the minimum of them. + """ + return min_max(space, __args__, "min") +min.unwrap_spec = [ObjSpace, Arguments] + +def map(space, w_func, collections_w): + """does 3 separate things, hence this enormous docstring. + 1. if function is None, return a list of tuples, each with one + item from each collection. If the collections have different + lengths, shorter ones are padded with None. + + 2. if function is not None, and there is only one collection, + apply function to every item in the collection and return a + list of the results. + + 3. if function is not None, and there are several collections, + repeatedly call the function with one argument from each + collection. If the collections have different lengths, + shorter ones are padded with None + """ + if not collections_w: + msg = "map() requires at least two arguments" + raise OperationError(space.w_TypeError, space.wrap(msg)) + num_collections = len(collections_w) + none_func = space.is_w(w_func, space.w_None) + if none_func and num_collections == 1: + return space.call_function(space.w_list, collections_w[0]) + result_w = [] + iterators_w = [space.iter(w_seq) for w_seq in collections_w] + num_iterators = len(iterators_w) + while True: + cont = False + args_w = [space.w_None] * num_iterators + for i in range(len(iterators_w)): + try: + args_w[i] = space.next(iterators_w[i]) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + else: + cont = True + w_args = space.newtuple(args_w) + if cont: + if none_func: + result_w.append(w_args) + else: + w_res = space.call(w_func, w_args) + result_w.append(w_res) + else: + return space.newlist(result_w) +map.unwrap_spec = [ObjSpace, W_Root, "args_w"] +def sum(space, w_sequence, w_start=None): + if space.is_w(w_start, space.w_None): + w_start = space.wrap(0) + elif space.is_true(space.isinstance(w_start, space.w_basestring)): + msg = "sum() can't sum strings" + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_iter = space.iter(w_sequence) + w_last = w_start + while True: + try: + w_next = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + w_last = space.add(w_last, w_next) + return w_last +sum.unwrap_spec = [ObjSpace, W_Root, W_Root] + +def zip(space, sequences_w): + """Return a list of tuples, where the nth tuple contains every nth item of + each collection. + + If the collections have different lengths, zip returns a list as long as the + shortest collection, ignoring the trailing items in the other collections. + """ + if not sequences_w: + return space.newlist([]) + result_w = [] + iterators_w = [space.iter(w_seq) for w_seq in sequences_w] + while True: + try: + items_w = [space.next(w_it) for w_it in iterators_w] + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + return space.newlist(result_w) + result_w.append(space.newtuple(items_w)) +zip.unwrap_spec = [ObjSpace, "args_w"] + +def reduce(space, w_func, w_sequence, w_initial=NoneNotWrapped): + """ Apply function of two arguments cumulatively to the items of sequence, + from left to right, so as to reduce the sequence to a single value. + Optionally begin with an initial value. + """ + w_iter = space.iter(w_sequence) + if w_initial is None: + try: + w_initial = space.next(w_iter) + except OperationError, e: + if e.match(space, space.w_StopIteration): + msg = "reduce() of empty sequence with no initial value" + raise OperationError(space.w_TypeError, space.wrap(msg)) + raise + w_result = w_initial + while True: + try: + w_next = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + w_result = space.call_function(w_func, w_result, w_next) + return w_result +reduce.unwrap_spec = [ObjSpace, W_Root, W_Root, W_Root] + +def filter(space, w_func, w_seq): + """construct a list of those elements of collection for which function + is True. If function is None, then return the items in the sequence + which are True. + """ + if space.is_true(space.isinstance(w_seq, space.w_str)): + return _filter_string(space, w_func, w_seq, space.w_str) + if space.is_true(space.isinstance(w_seq, space.w_unicode)): + return _filter_string(space, w_func, w_seq, space.w_unicode) + if space.is_true(space.isinstance(w_seq, space.w_tuple)): + return _filter_tuple(space, w_func, w_seq) + w_iter = space.iter(w_seq) + result_w = [] + none_func = space.is_w(w_func, space.w_None) + while True: + try: + w_next = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if none_func: + w_keep = w_next + else: + w_keep = space.call_function(w_func, w_next) + if space.is_true(w_keep): + result_w.append(w_next) + return space.newlist(result_w) + +def _filter_tuple(space, w_func, w_tuple): + none_func = space.is_w(w_func, space.w_None) + length = space.int_w(space.len(w_tuple)) + result_w = [] + for i in range(length): + w_item = space.getitem(w_tuple, space.wrap(i)) + if none_func: + w_keep = w_item + else: + w_keep = space.call_function(w_func, w_item) + if space.is_true(w_keep): + result_w.append(w_item) + return space.newtuple(result_w) + +def _filter_string(space, w_func, w_string, w_str_type): + none_func = space.is_w(w_func, space.w_None) + if none_func and space.is_w(space.type(w_string), w_str_type): + return w_string + length = space.int_w(space.len(w_string)) + result_w = [] + for i in range(length): + w_item = space.getitem(w_string, space.wrap(i)) + if none_func or space.is_true(space.call_function(w_func, w_item)): + if not space.is_true(space.isinstance(w_item, w_str_type)): + msg = "__getitem__ returned a non-string type" + raise OperationError(space.w_TypeError, space.wrap(msg)) + result_w.append(w_item) + w_empty = space.call_function(w_str_type) + return space.call_method(w_empty, "join", space.newlist(result_w)) def all(space, w_S): """all(iterable) -> bool @@ -138,6 +372,110 @@ any.unwrap_spec = [ObjSpace, W_Root] +class W_Enumerate(Wrappable): + + def __init__(self, w_iter, w_start): + self.w_iter = w_iter + self.w_index = w_start + + def descr___new__(space, w_subtype, w_iterable): + self = space.allocate_instance(W_Enumerate, w_subtype) + self.__init__(space.iter(w_iterable), space.wrap(0)) + return space.wrap(self) + + def descr___iter__(self, space): + return space.wrap(self) + descr___iter__.unwrap_spec = ["self", ObjSpace] + + def descr_next(self, space): + w_item = space.next(self.w_iter) + w_index = self.w_index + self.w_index = space.add(w_index, space.wrap(1)) + return space.newtuple([w_index, w_item]) + descr_next.unwrap_spec = ["self", ObjSpace] + + def descr___reduce__(self, space): + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + w_new_inst = mod.get('enumerate_new') + w_info = space.newtuple([self.w_iter, self.w_index]) + return space.newtuple([w_new_inst, w_info]) + descr___reduce__.unwrap_spec = ["self", ObjSpace] + +# exported through _pickle_support +def _make_enumerate(space, w_iter, w_index): + return space.wrap(W_Enumerate(w_iter, w_index)) + +W_Enumerate.typedef = TypeDef("enumerate", + __new__=interp2app(W_Enumerate.descr___new__.im_func), + __iter__=interp2app(W_Enumerate.descr___iter__), + next=interp2app(W_Enumerate.descr_next), + __reduce__=interp2app(W_Enumerate.descr___reduce__), +) + + +def reversed(space, w_sequence): + """Return a iterator that yields items of sequence in reverse.""" + w_reversed_descr = space.lookup(w_sequence, "__reversed__") + if w_reversed_descr is None: + return space.wrap(W_ReversedIterator(space, w_sequence)) + return space.get_and_call_function(w_reversed_descr, w_sequence) +reversed.unwrap_spec = [ObjSpace, W_Root] + +class W_ReversedIterator(Wrappable): + + def __init__(self, space, w_sequence): + self.remaining = space.int_w(space.len(w_sequence)) - 1 + self.w_sequence = w_sequence + + def descr___iter__(self, space): + return space.wrap(self) + descr___iter__.unwrap_spec = ["self", ObjSpace] + + def descr_next(self, space): + if self.remaining >= 0: + w_index = space.wrap(self.remaining) + try: + w_item = space.getitem(self.w_sequence, w_index) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + else: + self.remaining -= 1 + return w_item + + # Done + self.remaining = -1 + raise OperationError(space.w_StopIteration, space.w_None) + descr_next.unwrap_spec = ["self", ObjSpace] + + def descr___reduce__(self, space): + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + w_new_inst = mod.get('reversed_new') + info_w = [self.w_sequence, space.wrap(self.remaining)] + w_info = space.newtuple(info_w) + return space.newtuple([w_new_inst, w_info]) + descr___reduce__.unwrap_spec = ["self", ObjSpace] + +W_ReversedIterator.typedef = TypeDef("reversed", + __iter__=interp2app(W_ReversedIterator.descr___iter__), + next=interp2app(W_ReversedIterator.descr_next), + __reduce__=interp2app(W_ReversedIterator.descr___reduce__), +) + +# exported through _pickle_support +def _make_reversed(space, w_seq, w_remaining): + w_type = space.gettypeobject(W_ReversedIterator.typedef) + iterator = space.allocate_instance(W_ReversedIterator, w_type) + iterator.w_sequence = w_seq + iterator.remaining = space.int_w(w_remaining) + return space.wrap(iterator) + + + class W_XRange(Wrappable): def __init__(self, space, start, len, step): self.space = space Modified: pypy/branch/spine-of-frames/pypy/module/_pickle_support/__init__.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/_pickle_support/__init__.py (original) +++ pypy/branch/spine-of-frames/pypy/module/_pickle_support/__init__.py Thu Sep 10 16:45:13 2009 @@ -22,4 +22,6 @@ 'xrangeiter_new': 'maker.xrangeiter_new', 'builtin_code': 'maker.builtin_code', 'builtin_function' : 'maker.builtin_function', + 'enumerate_new': 'maker.enumerate_new', + 'reversed_new': 'maker.reversed_new' } Modified: pypy/branch/spine-of-frames/pypy/module/_pickle_support/maker.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/_pickle_support/maker.py (original) +++ pypy/branch/spine-of-frames/pypy/module/_pickle_support/maker.py Thu Sep 10 16:45:13 2009 @@ -100,6 +100,17 @@ builtin_function.unwrap_spec = [ObjSpace, str] +def enumerate_new(space, w_iter, w_index): + from pypy.module.__builtin__.functional import _make_enumerate + return _make_enumerate(space, w_iter, w_index) +enumerate_new.unwrap_spec = [ObjSpace, W_Root, W_Root] + +def reversed_new(space, w_seq, w_remaining): + from pypy.module.__builtin__.functional import _make_reversed + return _make_reversed(space, w_seq, w_remaining) +reversed_new.unwrap_spec = [ObjSpace, W_Root, W_Root] + + # ___________________________________________________________________ # Helper functions for internal use Modified: pypy/branch/spine-of-frames/pypy/module/posix/interp_posix.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/posix/interp_posix.py (original) +++ pypy/branch/spine-of-frames/pypy/module/posix/interp_posix.py Thu Sep 10 16:45:13 2009 @@ -843,7 +843,7 @@ from pypy.rlib import rwin32 eci = ExternalCompilationInfo( - includes = ['windows.h'], + includes = ['windows.h', 'wincrypt.h'], libraries = ['advapi32'], ) Modified: pypy/branch/spine-of-frames/pypy/module/posix/test/test_posix2.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/posix/test/test_posix2.py (original) +++ pypy/branch/spine-of-frames/pypy/module/posix/test/test_posix2.py Thu Sep 10 16:45:13 2009 @@ -129,6 +129,19 @@ assert st.st_mtime == 42.1 assert st.st_ctime == 43 + def test_stat_exception(self): + import sys, errno + try: + self.posix.stat("nonexistentdir/nonexistentfile") + except OSError, e: + assert e.errno == errno.ENOENT + # On Windows, when the parent directory does not exist, + # the winerror is 3 (cannot find the path specified) + # instead of 2 (cannot find the file specified) + if sys.platform == 'win32': + assert isinstance(e, WindowsError) + assert e.winerror == 3 + def test_pickle(self): import pickle, os st = self.posix.stat(os.curdir) Modified: pypy/branch/spine-of-frames/pypy/module/pypyjit/policy.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/pypyjit/policy.py (original) +++ pypy/branch/spine-of-frames/pypy/module/pypyjit/policy.py Thu Sep 10 16:45:13 2009 @@ -1,6 +1,9 @@ -from pypy.jit.metainterp.policy import ManualJitPolicy +from pypy.jit.metainterp.policy import JitPolicy -class PyPyJitPolicy(ManualJitPolicy): +class PyPyJitPolicy(JitPolicy): + + def __init__(self, translator=None): + pass # xxx def look_inside_function(self, func): mod = func.__module__ or '?' @@ -53,6 +56,9 @@ # string builder interface if mod == 'pypy.rpython.lltypesystem.rbuilder': return False + # rweakvaluedict implementation + if mod == 'pypy.rlib.rweakrefimpl': + return False #if (mod == 'pypy.rpython.rlist' or # mod == 'pypy.rpython.lltypesystem.rdict' or # mod == 'pypy.rpython.lltypesystem.rlist'): Modified: pypy/branch/spine-of-frames/pypy/objspace/std/dictmultiobject.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/objspace/std/dictmultiobject.py (original) +++ pypy/branch/spine-of-frames/pypy/objspace/std/dictmultiobject.py Thu Sep 10 16:45:13 2009 @@ -5,6 +5,7 @@ from pypy.rlib.objectmodel import r_dict, we_are_translated from pypy.rlib.jit import purefunction +from pypy.rlib.rweakref import RWeakValueDictionary def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -687,7 +688,6 @@ class SharedStructure(object): def __init__(self, keys=None, length=0, - other_structs=None, last_key=None, back_struct=None): if keys is None: @@ -695,20 +695,18 @@ self.keys = keys self.length = length self.back_struct = back_struct - if other_structs is None: - other_structs = {} + other_structs = RWeakValueDictionary(SharedStructure) self.other_structs = other_structs self.last_key = last_key if last_key is not None: assert back_struct is not None - self.propagating = False def new_structure(self, added_key): keys = self.keys.copy() keys[added_key] = len(self.keys) new_structure = SharedStructure(keys, self.length + 1, - {}, added_key, self) - self.other_structs[added_key] = new_structure + added_key, self) + self.other_structs.set(added_key, new_structure) return new_structure def lookup_position(self, key): @@ -725,7 +723,6 @@ class State(object): def __init__(self, space): self.empty_structure = SharedStructure() - self.empty_structure.propagating = True class SharedDictImplementation(DictImplementation): @@ -762,13 +759,9 @@ if i != -1: self.entries[i] = w_value return self - if not self.structure.propagating: - return self._as_rdict(as_strdict=True).setitem_str(w_key, w_value) - new_structure = self.structure.other_structs.get(key, None) + new_structure = self.structure.other_structs.get(key) if new_structure is None: new_structure = self.structure.new_structure(key) - else: - new_structure.propagating = True self.entries.append(w_value) assert self.structure.length + 1 == new_structure.length self.structure = new_structure Modified: pypy/branch/spine-of-frames/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/branch/spine-of-frames/pypy/objspace/std/test/test_typeobject.py Thu Sep 10 16:45:13 2009 @@ -948,3 +948,125 @@ del list.a raises(AttributeError, "l.a") +class AppTestGetattributeShortcut: + + def setup_class(cls): + cls.space = gettestobjspace( + **{"objspace.std.getattributeshortcut": True}) + + def test_reset_logic(self): + class X(object): + pass + + class Y(X): + pass + + y = Y() + y.x = 3 + assert y.x == 3 + + def ga(self, name): + return 'GA' + + X.__getattribute__ = ga + + assert y.x == 'GA' + + class M(type): + pass + + class X(object): + __metaclass__ = M + + class Y(X): + pass + + y = Y() + y.x = 3 + assert y.x == 3 + + def ga(self, name): + return 'GA' + + X.__getattribute__ = ga + + assert y.x == 'GA' + +class TestNewShortcut: + + def setup_class(cls): + cls.space = gettestobjspace( + **{"objspace.std.newshortcut": True}) + + def test_mechanics(self): + space = self.space + w_tup = space.appexec([], """(): + class A(object): + pass + class B(object): + __new__ = staticmethod(lambda t: 1) + class M(type): + pass + return A, B, M +""") + w_A, w_B, w_M = space.unpackiterable(w_tup) + + assert w_A.w_bltin_new is None + assert w_B.w_bltin_new is None + assert w_M.w_bltin_new is None + + _, w_object_newdescr = space.lookup_in_type_where(space.w_object, + '__new__') + w_object___new__ = space.get(w_object_newdescr, None, + w_type=space.w_object) + + w_a = space.call_function(w_A) + assert w_A.w_bltin_new is w_object___new__ + + # will shortcut + w_a = space.call_function(w_A) + + w_b = space.call_function(w_B) + assert w_B.w_bltin_new is None + + w_m = space.call_function(w_M, space.wrap('C'), space.newlist([]), + space.newdict()) + assert w_M.w_bltin_new is None + + +class AppTestNewShortcut: + + def setup_class(cls): + cls.space = gettestobjspace( + **{"objspace.std.newshortcut": True}) + + def test_reset_logic(self): + class X(object): + pass + + class Y(X): + pass + + y = Y() + + assert isinstance(y, Y) + + + X.__new__ = staticmethod(lambda t: 1) + + y = Y() + + assert y == 1 + + def test_dont_explode_on_non_types(self): + class A: + __new__ = staticmethod(lambda t: 1) + + class B(A, object): + pass + + b = B() + + assert b == 1 + + Modified: pypy/branch/spine-of-frames/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/objspace/std/typeobject.py (original) +++ pypy/branch/spine-of-frames/pypy/objspace/std/typeobject.py Thu Sep 10 16:45:13 2009 @@ -50,11 +50,19 @@ lazyloaders = {} # can be overridden by specific instances version_tag = None - _immutable_fields_ = ["__flags__"] + _immutable_fields_ = ["__flags__", + 'needsdel', + 'weakrefable', + 'hasdict'] - uses_object_getattribute = False - # ^^^ for config.objspace.std.getattributeshortcut + # for config.objspace.std.getattributeshortcut # (False is a conservative default, fixed during real usage) + uses_object_getattribute = False + + # used to cache the type __new__ function if it comes from a builtin type + # != 'type', in that case call__Type will also assumes the result + # of the __new__ is an instance of the type + w_bltin_new = None def __init__(w_self, space, name, bases_w, dict_w, overridetypedef=None): @@ -86,24 +94,26 @@ def mutated(w_self): space = w_self.space + if (not space.config.objspace.std.withtypeversion and + not space.config.objspace.std.getattributeshortcut and + not space.config.objspace.std.newshortcut): + return + if space.config.objspace.std.getattributeshortcut: w_self.uses_object_getattribute = False # ^^^ conservative default, fixed during real usage - if not space.config.objspace.std.withtypeversion: - return - # Invariant: version_tag is None if and only if - # 'w_self.instancetypedef.hasdict' is True, which is the case - # for a built-in type that provides its instances with their own - # __dict__. If 'hasdict' is True for a type T then it is also - # True for all subtypes of T; so we don't need to look for - # version_tags to update in the subclasses of a type T whose - # version_tag is None. - if w_self.version_tag is not None: + + if space.config.objspace.std.newshortcut: + w_self.w_bltin_new = None + + if (space.config.objspace.std.withtypeversion + and w_self.version_tag is not None): w_self.version_tag = VersionTag() - subclasses_w = w_self.get_subclasses() - for w_subclass in subclasses_w: - assert isinstance(w_subclass, W_TypeObject) - w_subclass.mutated() + + subclasses_w = w_self.get_subclasses() + for w_subclass in subclasses_w: + assert isinstance(w_subclass, W_TypeObject) + w_subclass.mutated() def ready(w_self): for w_base in w_self.bases_w: @@ -572,10 +582,23 @@ else: return space.type(w_obj) # invoke the __new__ of the type - w_newfunc = space.getattr(w_type, space.wrap('__new__')) - w_newobject = space.call_obj_args(w_newfunc, w_type, __args__) + w_bltin_new = w_type.w_bltin_new + call_init = True + if w_bltin_new is not None: + w_newobject = space.call_obj_args(w_bltin_new, w_type, __args__) + else: + w_newtype, w_newdescr = w_type.lookup_where('__new__') + w_newfunc = space.get(w_newdescr, w_type) + if (space.config.objspace.std.newshortcut and + isinstance(w_newtype, W_TypeObject) and + not w_newtype.is_heaptype() and + not space.is_w(w_newtype, space.w_type)): + w_type.w_bltin_new = w_newfunc + w_newobject = space.call_obj_args(w_newfunc, w_type, __args__) + call_init = space.is_true(space.isinstance(w_newobject, w_type)) + # maybe invoke the __init__ of the type - if space.is_true(space.isinstance(w_newobject, w_type)): + if call_init: w_descr = space.lookup(w_newobject, '__init__') w_result = space.get_and_call_args(w_descr, w_newobject, __args__) if not space.is_w(w_result, space.w_None): Modified: pypy/branch/spine-of-frames/pypy/rlib/jit.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rlib/jit.py (original) +++ pypy/branch/spine-of-frames/pypy/rlib/jit.py Thu Sep 10 16:45:13 2009 @@ -1,3 +1,4 @@ +import sys from pypy.rpython.extregistry import ExtRegistryEntry from pypy.rlib.objectmodel import CDefinedIntSymbolic from pypy.rlib.unroll import unrolling_iterable @@ -82,6 +83,8 @@ PARAMETERS = {'threshold': 1000, 'trace_eagerness': 200, 'hash_bits': 14, + 'trace_limit': 10000, + 'inlining': False, } unroll_parameters = unrolling_iterable(PARAMETERS.keys()) @@ -97,7 +100,8 @@ virtualizables = [] def __init__(self, greens=None, reds=None, virtualizables=None, - can_inline=None, get_printable_location=None): + can_inline=None, get_printable_location=None, + leave=None): if greens is not None: self.greens = greens if reds is not None: @@ -112,6 +116,7 @@ self._make_extregistryentries() self.get_printable_location = get_printable_location self.can_inline = can_inline + self.leave = leave def _freeze_(self): return True Modified: pypy/branch/spine-of-frames/pypy/rlib/libffi.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rlib/libffi.py (original) +++ pypy/branch/spine-of-frames/pypy/rlib/libffi.py Thu Sep 10 16:45:13 2009 @@ -311,8 +311,6 @@ "Procedure called with too many " "arguments (%d bytes in excess) " % (result,)) - - FormatError = rwin32.FormatError LoadLibrary = rwin32.LoadLibrary get_libc_handle = external('get_libc_handle', [], rwin32.HANDLE) Modified: pypy/branch/spine-of-frames/pypy/rlib/objectmodel.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rlib/objectmodel.py (original) +++ pypy/branch/spine-of-frames/pypy/rlib/objectmodel.py Thu Sep 10 16:45:13 2009 @@ -31,6 +31,7 @@ specialcase = "specialize:%s%s" % (self.tag, args) def specialize_decorator(func): + "NOT_RPYTHON" func._annspecialcase_ = specialcase return func Modified: pypy/branch/spine-of-frames/pypy/rlib/rarithmetic.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rlib/rarithmetic.py (original) +++ pypy/branch/spine-of-frames/pypy/rlib/rarithmetic.py Thu Sep 10 16:45:13 2009 @@ -67,6 +67,7 @@ return int(n) # possibly bool->int if isinstance(n, objectmodel.Symbolic): return n # assume Symbolics don't overflow + assert not isinstance(n, float) n = long(n) n &= LONG_MASK if n >= LONG_TEST: Modified: pypy/branch/spine-of-frames/pypy/rlib/rwin32.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rlib/rwin32.py (original) +++ pypy/branch/spine-of-frames/pypy/rlib/rwin32.py Thu Sep 10 16:45:13 2009 @@ -55,7 +55,8 @@ "MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)") for name in """FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_FROM_SYSTEM - """.split(): + MAX_PATH + """.split(): locals()[name] = rffi_platform.ConstantInteger(name) @@ -112,10 +113,9 @@ LocalFree(buf[0]) return result - def lastWindowsError(context=None): + def lastWindowsError(context="Windows Error"): code = GetLastError() - message = FormatError(code) - return WindowsError(code, message) + return WindowsError(code, context) def FAILED(hr): return rffi.cast(HRESULT, hr) < 0 @@ -125,7 +125,7 @@ DWORD) def GetModuleFileName(module): - size = 255 # MAX_PATH + size = MAX_PATH buf = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw') try: res = _GetModuleFileName(module, buf, size) Modified: pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/ll2ctypes.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/ll2ctypes.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/ll2ctypes.py Thu Sep 10 16:45:13 2009 @@ -370,15 +370,18 @@ self._storage = None def __eq__(self, other): - if not isinstance(other, lltype._parentable): - return False - if self._storage is None or other._storage is None: - raise RuntimeError("pointer comparison with a freed structure") - if other._storage is True: - return False # the other container is not ctypes-based + if isinstance(other, _llgcopaque): + addressof_other = other.intval + else: + if not isinstance(other, lltype._parentable): + return False + if self._storage is None or other._storage is None: + raise RuntimeError("pointer comparison with a freed structure") + if other._storage is True: + return False # the other container is not ctypes-based + addressof_other = ctypes.addressof(other._storage) # both containers are ctypes-based, compare by address - return (ctypes.addressof(self._storage) == - ctypes.addressof(other._storage)) + return (ctypes.addressof(self._storage) == addressof_other) def __ne__(self, other): return not (self == other) @@ -624,6 +627,7 @@ if isinstance(container, lltype._subarray): topmost, index = _find_parent(container) container = topmost + T = lltype.Ptr(lltype.typeOf(container)) if container._storage is None: raise RuntimeError("attempting to pass a freed structure to C") @@ -1099,7 +1103,13 @@ def __eq__(self, other): if isinstance(other, _llgcopaque): return self.intval == other.intval - if other.container._storage in (None, True): + storage = object() + if hasattr(other, 'container'): + storage = other.container._storage + else: + storage = other._storage + + if storage in (None, True): return False return force_cast(lltype.Signed, other._as_ptr()) == self.intval Modified: pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/llarena.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/llarena.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/llarena.py Thu Sep 10 16:45:13 2009 @@ -94,6 +94,8 @@ return addr2 def setobject(self, objaddr, offset, bytes): + assert bytes > 0, ("llarena does not support GcStructs with no field" + " or empty arrays") assert offset not in self.objectptrs self.objectptrs[offset] = objaddr.ptr self.objectsizes[offset] = bytes Modified: pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/lltype.py Thu Sep 10 16:45:13 2009 @@ -994,25 +994,31 @@ return (type(self._obj0) not in (type(None), int) and self._getobj(check=False)._was_freed()) - def __getattr__(self, field_name): # ! can only return basic or ptr ! - if isinstance(self._T, Struct): - if field_name in self._T._flds: - o = self._obj._getattr(field_name) - return self._expose(field_name, o) + def _lookup_adtmeth(self, member_name): if isinstance(self._T, ContainerType): try: - adtmeth = self._T._adtmeths[field_name] + adtmember = self._T._adtmeths[member_name] except KeyError: pass else: try: - getter = adtmeth.__get__ + getter = adtmember.__get__ except AttributeError: - return adtmeth + return adtmember else: return getter(self) - raise AttributeError("%r instance has no field %r" % (self._T, - field_name)) + raise AttributeError + + def __getattr__(self, field_name): # ! can only return basic or ptr ! + if isinstance(self._T, Struct): + if field_name in self._T._flds: + o = self._obj._getattr(field_name) + return self._expose(field_name, o) + try: + return self._lookup_adtmeth(field_name) + except AttributeError: + raise AttributeError("%r instance has no field %r" % (self._T, + field_name)) def __setattr__(self, field_name, val): if isinstance(self._T, Struct): Modified: pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/rdict.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/rdict.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/rdict.py Thu Sep 10 16:45:13 2009 @@ -507,7 +507,6 @@ PERTURB_SHIFT = 5 def ll_dict_lookup(d, key, hash): - DICT = lltype.typeOf(d).TO entries = d.entries mask = len(entries) - 1 i = hash & mask @@ -520,7 +519,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if DICT.paranoia: + if d.paranoia: if (entries != d.entries or not entries.valid(i) or entries[i].key != checkingkey): # the compare did major nasty stuff to the dict: start over @@ -555,7 +554,7 @@ # correct hash, maybe the key is e.g. a different pointer to # an equal object found = d.keyeq(checkingkey, key) - if DICT.paranoia: + if d.paranoia: if (entries != d.entries or not entries.valid(i) or entries[i].key != checkingkey): # the compare did major nasty stuff to the dict: Modified: pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/test/test_ll2ctypes.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/test/test_ll2ctypes.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Thu Sep 10 16:45:13 2009 @@ -1091,8 +1091,38 @@ assert ref1 == ref2 assert ref2 == ref1 assert not (ref1 != ref2) - assert not (ref2 != ref1) - + assert not (ref2 != ref1) + + def test_convert_subarray(self): + A = lltype.GcArray(lltype.Signed) + a = lltype.malloc(A, 20) + inside = lltype.direct_ptradd(lltype.direct_arrayitems(a), 3) + + lltype2ctypes(inside) + + start = rffi.cast(lltype.Signed, lltype.direct_arrayitems(a)) + inside_int = rffi.cast(lltype.Signed, inside) + + assert inside_int == start+rffi.sizeof(lltype.Signed)*3 + + def test_gcref_comparisons_through_addresses(self): + NODE = lltype.GcStruct('NODE') + n0 = lltype.malloc(NODE) + adr0 = llmemory.cast_ptr_to_adr(n0) + + n1 = lltype.malloc(NODE) + i1 = rffi.cast(lltype.Signed, n1) + ref1 = rffi.cast(llmemory.GCREF, i1) + adr1 = llmemory.cast_ptr_to_adr(ref1) + + assert adr1 != adr0 + assert adr0 != adr1 + + adr1_2 = llmemory.cast_ptr_to_adr(n1) + + #import pdb; pdb.set_trace() + assert adr1_2 == adr1 + assert adr1 == adr1_2 class TestPlatform(object): def test_lib_on_libpaths(self): Modified: pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/test/test_lltype.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/test/test_lltype.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/lltypesystem/test/test_lltype.py Thu Sep 10 16:45:13 2009 @@ -528,7 +528,8 @@ A = GcArray(Signed, adtmeths={"h_alloc": h_alloc, - "h_length": h_length}) + "h_length": h_length, + "stuff": 12}) a = A.h_alloc(10) @@ -536,6 +537,9 @@ assert len(a) == 10 assert a.h_length() == 10 + assert a._lookup_adtmeth("h_length")() == 10 + assert a.stuff == 12 + assert a._lookup_adtmeth("stuff") == 12 def test_adt_typemethod(): def h_newstruct(S): Modified: pypy/branch/spine-of-frames/pypy/rpython/memory/gc/base.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/memory/gc/base.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/memory/gc/base.py Thu Sep 10 16:45:13 2009 @@ -100,6 +100,7 @@ assert not (needs_finalizer and contains_weakptr) if self.is_varsize(typeid): assert not contains_weakptr + assert not needs_finalizer itemsize = self.varsize_item_sizes(typeid) offset_to_length = self.varsize_offset_to_length(typeid) if zero or not hasattr(self, 'malloc_varsize'): @@ -107,7 +108,7 @@ else: malloc_varsize = self.malloc_varsize ref = malloc_varsize(typeid, length, size, itemsize, - offset_to_length, True, needs_finalizer) + offset_to_length, True) else: if zero or not hasattr(self, 'malloc_fixedsize'): malloc_fixedsize = self.malloc_fixedsize_clear Modified: pypy/branch/spine-of-frames/pypy/rpython/memory/gc/generation.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/memory/gc/generation.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/memory/gc/generation.py Thu Sep 10 16:45:13 2009 @@ -160,8 +160,7 @@ return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect, - has_finalizer=False): + offset_to_length, can_collect): # Only use the nursery if there are not too many items. if not raw_malloc_usage(itemsize): too_many_items = False @@ -180,7 +179,7 @@ maxlength = maxlength_for_minimal_nursery << self.nursery_scale too_many_items = length > maxlength - if (has_finalizer or not can_collect or + if (not can_collect or too_many_items or (raw_malloc_usage(size) > self.lb_young_var_basesize and raw_malloc_usage(size) > self.largest_young_var_basesize)): @@ -190,7 +189,7 @@ # second comparison as well. return SemiSpaceGC.malloc_varsize_clear(self, typeid, length, size, itemsize, offset_to_length, - can_collect, has_finalizer) + can_collect) # with the above checks we know now that totalsize cannot be more # than about half of the nursery size; in particular, the + and * # cannot overflow @@ -392,6 +391,9 @@ if self.is_in_nursery(pointer.address[0]): pointer.address[0] = self.copy(pointer.address[0]) + # The code relies on the fact that no weakref can be an old object + # weakly pointing to a young object. Indeed, weakrefs are immutable + # so they cannot point to an object that was created after it. def invalidate_young_weakrefs(self): # walk over the list of objects that contain weakrefs and are in the # nursery. if the object it references survives then update the Modified: pypy/branch/spine-of-frames/pypy/rpython/memory/gc/hybrid.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/memory/gc/hybrid.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/memory/gc/hybrid.py Thu Sep 10 16:45:13 2009 @@ -132,12 +132,11 @@ # 'large'. def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect, - has_finalizer=False): - if has_finalizer or not can_collect: + offset_to_length, can_collect): + if not can_collect: return SemiSpaceGC.malloc_varsize_clear(self, typeid, length, size, itemsize, offset_to_length, - can_collect, has_finalizer) + can_collect) size_gc_header = self.gcheaderbuilder.size_gc_header nonvarsize = size_gc_header + size Modified: pypy/branch/spine-of-frames/pypy/rpython/memory/gc/markcompact.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/memory/gc/markcompact.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/memory/gc/markcompact.py Thu Sep 10 16:45:13 2009 @@ -131,8 +131,7 @@ return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect, - has_finalizer=False): + offset_to_length, can_collect): size_gc_header = self.gcheaderbuilder.size_gc_header nonvarsize = size_gc_header + size try: @@ -147,8 +146,6 @@ self.init_gc_object(result, typeid) (result + size_gc_header + offset_to_length).signed[0] = length self.free = result + llarena.round_up_for_allocation(totalsize) - if has_finalizer: - self.objects_with_finalizers.append(result + size_gc_header) return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def obtain_free_space(self, totalsize): Modified: pypy/branch/spine-of-frames/pypy/rpython/memory/gc/marksweep.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/memory/gc/marksweep.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/memory/gc/marksweep.py Thu Sep 10 16:45:13 2009 @@ -151,7 +151,7 @@ malloc_fixedsize_clear._dont_inline_ = True def malloc_varsize(self, typeid, length, size, itemsize, offset_to_length, - can_collect, has_finalizer=False): + can_collect): if can_collect: self.maybe_collect() size_gc_header = self.gcheaderbuilder.size_gc_header @@ -170,12 +170,8 @@ (result + size_gc_header + offset_to_length).signed[0] = length hdr = llmemory.cast_adr_to_ptr(result, self.HDRPTR) hdr.typeid = typeid << 1 - if has_finalizer: - hdr.next = self.malloced_objects_with_finalizer - self.malloced_objects_with_finalizer = hdr - else: - hdr.next = self.malloced_objects - self.malloced_objects = hdr + hdr.next = self.malloced_objects + self.malloced_objects = hdr self.bytes_malloced = bytes_malloced result += size_gc_header @@ -187,8 +183,7 @@ malloc_varsize._dont_inline_ = True def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect, - has_finalizer=False): + offset_to_length, can_collect): if can_collect: self.maybe_collect() size_gc_header = self.gcheaderbuilder.size_gc_header @@ -208,12 +203,8 @@ (result + size_gc_header + offset_to_length).signed[0] = length hdr = llmemory.cast_adr_to_ptr(result, self.HDRPTR) hdr.typeid = typeid << 1 - if has_finalizer: - hdr.next = self.malloced_objects_with_finalizer - self.malloced_objects_with_finalizer = hdr - else: - hdr.next = self.malloced_objects - self.malloced_objects = hdr + hdr.next = self.malloced_objects + self.malloced_objects = hdr self.bytes_malloced = bytes_malloced result += size_gc_header Modified: pypy/branch/spine-of-frames/pypy/rpython/memory/gc/semispace.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/memory/gc/semispace.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/memory/gc/semispace.py Thu Sep 10 16:45:13 2009 @@ -83,8 +83,7 @@ return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def malloc_varsize_clear(self, typeid, length, size, itemsize, - offset_to_length, can_collect, - has_finalizer=False): + offset_to_length, can_collect): size_gc_header = self.gcheaderbuilder.size_gc_header nonvarsize = size_gc_header + size try: @@ -101,8 +100,6 @@ self.init_gc_object(result, typeid) (result + size_gc_header + offset_to_length).signed[0] = length self.free = result + llarena.round_up_for_allocation(totalsize) - if has_finalizer: - self.objects_with_finalizers.append(result + size_gc_header) return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF) def obtain_free_space(self, needed): Modified: pypy/branch/spine-of-frames/pypy/rpython/memory/gctransform/framework.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/memory/gctransform/framework.py Thu Sep 10 16:45:13 2009 @@ -235,7 +235,7 @@ self.malloc_varsize_clear_ptr = getfn( GCClass.malloc_varsize_clear.im_func, [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)] - + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref) + + [annmodel.SomeBool()], s_gcref) self.collect_ptr = getfn(GCClass.collect.im_func, [s_gc], annmodel.s_None) self.can_move_ptr = getfn(GCClass.can_move.im_func, @@ -285,7 +285,7 @@ annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), annmodel.SomeInteger(nonneg=True), - s_True, s_False], s_gcref, + s_True], s_gcref, inline = True) else: self.malloc_varsize_clear_fast_ptr = None @@ -524,30 +524,28 @@ args = [self.c_const_gc, c_type_id, c_size, c_can_collect, c_has_finalizer, rmodel.inputconst(lltype.Bool, False)] else: + assert not c_has_finalizer.value v_length = op.args[-1] c_ofstolength = rmodel.inputconst(lltype.Signed, info.ofstolength) c_varitemsize = rmodel.inputconst(lltype.Signed, info.varitemsize) if flags.get('resizable') and self.malloc_varsize_resizable_ptr: assert c_can_collect.value - assert not c_has_finalizer.value malloc_ptr = self.malloc_varsize_resizable_ptr args = [self.c_const_gc, c_type_id, v_length] elif flags.get('nonmovable') and self.malloc_varsize_nonmovable_ptr: # we don't have tests for such cases, let's fail # explicitely assert c_can_collect.value - assert not c_has_finalizer.value malloc_ptr = self.malloc_varsize_nonmovable_ptr args = [self.c_const_gc, c_type_id, v_length] else: if (self.malloc_varsize_clear_fast_ptr is not None and - c_can_collect.value and not c_has_finalizer.value): + c_can_collect.value): malloc_ptr = self.malloc_varsize_clear_fast_ptr else: malloc_ptr = self.malloc_varsize_clear_ptr args = [self.c_const_gc, c_type_id, v_length, c_size, - c_varitemsize, c_ofstolength, c_can_collect, - c_has_finalizer] + c_varitemsize, c_ofstolength, c_can_collect] keep_current_args = flags.get('keep_current_args', False) livevars = self.push_roots(hop, keep_current_args=keep_current_args) v_result = hop.genop("direct_call", [malloc_ptr] + args, @@ -623,12 +621,12 @@ # used by the JIT (see pypy.jit.backend.llsupport.gc) op = hop.spaceop [v_typeid, v_length, v_size, v_itemsize, - v_offset_to_length, v_can_collect, v_has_finalizer] = op.args + v_offset_to_length, v_can_collect] = op.args livevars = self.push_roots(hop) hop.genop("direct_call", [self.malloc_varsize_clear_ptr, self.c_const_gc, v_typeid, v_length, v_size, v_itemsize, - v_offset_to_length, v_can_collect, v_has_finalizer], + v_offset_to_length, v_can_collect], resultvar=op.result) self.pop_roots(hop, livevars) Modified: pypy/branch/spine-of-frames/pypy/rpython/module/ll_os.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/module/ll_os.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/module/ll_os.py Thu Sep 10 16:45:13 2009 @@ -468,24 +468,22 @@ @registering(os.times) def register_os_times(self): if sys.platform.startswith('win'): - HANDLE = rffi.ULONG - FILETIME = rffi.CStruct('_FILETIME', ('dwLowDateTime', rffi.LONG), - ('dwHighDateTime', rffi.LONG)) + from pypy.rlib import rwin32 GetCurrentProcess = self.llexternal('GetCurrentProcess', [], - HANDLE) + rwin32.HANDLE) GetProcessTimes = self.llexternal('GetProcessTimes', - [HANDLE, - lltype.Ptr(FILETIME), - lltype.Ptr(FILETIME), - lltype.Ptr(FILETIME), - lltype.Ptr(FILETIME)], - lltype.Bool) + [rwin32.HANDLE, + lltype.Ptr(rwin32.FILETIME), + lltype.Ptr(rwin32.FILETIME), + lltype.Ptr(rwin32.FILETIME), + lltype.Ptr(rwin32.FILETIME)], + rwin32.BOOL) def times_lltypeimpl(): - pcreate = lltype.malloc(FILETIME, flavor='raw') - pexit = lltype.malloc(FILETIME, flavor='raw') - pkernel = lltype.malloc(FILETIME, flavor='raw') - puser = lltype.malloc(FILETIME, flavor='raw') + pcreate = lltype.malloc(rwin32.FILETIME, flavor='raw') + pexit = lltype.malloc(rwin32.FILETIME, flavor='raw') + pkernel = lltype.malloc(rwin32.FILETIME, flavor='raw') + puser = lltype.malloc(rwin32.FILETIME, flavor='raw') hProc = GetCurrentProcess() GetProcessTimes(hProc, pcreate, pexit, pkernel, puser) # The fields of a FILETIME structure are the hi and lo parts @@ -904,47 +902,29 @@ @registering_if(posix, '_getfullpathname') def register_posix__getfullpathname(self): + from pypy.rlib import rwin32 # this nt function is not exposed via os, but needed # to get a correct implementation of os.abspath # XXX why do we ignore WINAPI conventions everywhere? - class CConfig: - _compilation_info_ = ExternalCompilationInfo( - includes = ['Windows.h'] - ) - MAX_PATH = platform.ConstantInteger('MAX_PATH') - DWORD = platform.SimpleType("DWORD", rffi.ULONG) - LPCTSTR = platform.SimpleType("LPCTSTR", rffi.CCHARP) - LPTSTR = platform.SimpleType("LPTSTR", rffi.CCHARP) - LPTSTRP = platform.SimpleType("LPTSTR*", rffi.CCHARPP) - - config = platform.configure(CConfig) - MAX_PATH = config['MAX_PATH'] - DWORD = config['DWORD'] - LPCTSTR = config['LPCTSTR'] - LPTSTR = config['LPTSTR'] - LPTSTRP = config['LPTSTRP'] + LPSTRP = rffi.CArrayPtr(rwin32.LPSTR) # XXX unicode? - GetFullPathName = self.llexternal('GetFullPathNameA', - [LPCTSTR, DWORD, LPTSTR, LPTSTRP], DWORD) - GetLastError = self.llexternal('GetLastError', [], DWORD) - ##DWORD WINAPI GetFullPathName( - ## __in LPCTSTR lpFileName, - ## __in DWORD nBufferLength, - ## __out LPTSTR lpBuffer, - ## __out LPTSTR* lpFilePart - ##); + GetFullPathName = self.llexternal( + 'GetFullPathNameA', + [rwin32.LPCSTR, + rwin32.DWORD, + rwin32.LPSTR, + rffi.CArrayPtr(rwin32.LPSTR)], + rwin32.DWORD) def _getfullpathname_llimpl(lpFileName): - nBufferLength = MAX_PATH + 1 - lpBuffer = lltype.malloc(LPTSTR.TO, nBufferLength, flavor='raw') + nBufferLength = rwin32.MAX_PATH + 1 + lpBuffer = lltype.malloc(rwin32.LPSTR.TO, nBufferLength, flavor='raw') try: res = GetFullPathName( - lpFileName, rffi.cast(DWORD, nBufferLength), - lpBuffer, lltype.nullptr(LPTSTRP.TO)) + lpFileName, rffi.cast(rwin32.DWORD, nBufferLength), + lpBuffer, lltype.nullptr(LPSTRP.TO)) if res == 0: - error = GetLastError() - raise OSError(error, "_getfullpathname failed") - # XXX ntpath expects WindowsError :-( + raise rwin32.lastWindowsError("_getfullpathname failed") result = rffi.charp2str(lpBuffer) return result finally: @@ -991,14 +971,13 @@ def register_os_listdir(self): # we need a different approach on Windows and on Posix if sys.platform.startswith('win'): + from pypy.rlib import rwin32 class CConfig: _compilation_info_ = ExternalCompilationInfo( includes = ['windows.h'] ) WIN32_FIND_DATA = platform.Struct('struct _WIN32_FIND_DATAA', [('cFileName', lltype.FixedSizeArray(rffi.CHAR, 1))]) - INVALID_HANDLE_VALUE = platform.ConstantInteger( - 'INVALID_HANDLE_VALUE') ERROR_FILE_NOT_FOUND = platform.ConstantInteger( 'ERROR_FILE_NOT_FOUND') ERROR_NO_MORE_FILES = platform.ConstantInteger( @@ -1006,23 +985,19 @@ config = platform.configure(CConfig) WIN32_FIND_DATA = config['WIN32_FIND_DATA'] - INVALID_HANDLE_VALUE = config['INVALID_HANDLE_VALUE'] ERROR_FILE_NOT_FOUND = config['ERROR_FILE_NOT_FOUND'] ERROR_NO_MORE_FILES = config['ERROR_NO_MORE_FILES'] LPWIN32_FIND_DATA = lltype.Ptr(WIN32_FIND_DATA) - HANDLE = rffi.ULONG - #MAX_PATH = WIN32_FIND_DATA.c_cFileName.length - GetLastError = self.llexternal('GetLastError', [], lltype.Signed) FindFirstFile = self.llexternal('FindFirstFile', - [rffi.CCHARP, LPWIN32_FIND_DATA], - HANDLE) + [rwin32.LPCSTR, LPWIN32_FIND_DATA], + rwin32.HANDLE) FindNextFile = self.llexternal('FindNextFile', - [HANDLE, LPWIN32_FIND_DATA], - rffi.INT) + [rwin32.HANDLE, LPWIN32_FIND_DATA], + rwin32.BOOL) FindClose = self.llexternal('FindClose', - [HANDLE], - rffi.INT) + [rwin32.HANDLE], + rwin32.BOOL) def os_listdir_llimpl(path): if path and path[-1] not in ('/', '\\', ':'): @@ -1032,13 +1007,12 @@ try: result = [] hFindFile = FindFirstFile(path, filedata) - if hFindFile == INVALID_HANDLE_VALUE: - error = GetLastError() + if hFindFile == rwin32.INVALID_HANDLE_VALUE: + error = rwin32.GetLastError() if error == ERROR_FILE_NOT_FOUND: return result else: - # XXX guess error code :-( - raise OSError(errno.ENOENT, "FindFirstFile failed") + raise WindowsError(error, "FindFirstFile failed") while True: name = rffi.charp2str(rffi.cast(rffi.CCHARP, filedata.c_cFileName)) @@ -1048,13 +1022,12 @@ break # FindNextFile sets error to ERROR_NO_MORE_FILES if # it got to the end of the directory - error = GetLastError() + error = rwin32.GetLastError() FindClose(hFindFile) if error == ERROR_NO_MORE_FILES: return result else: - # XXX guess error code :-( - raise OSError(errno.EIO, "FindNextFile failed") + raise WindowsError(error, "FindNextFile failed") finally: lltype.free(filedata, flavor='raw') @@ -1107,28 +1080,31 @@ def register_os_pipe(self): # we need a different approach on Windows and on Posix if sys.platform.startswith('win'): - HANDLE = rffi.ULONG - HANDLEP = lltype.Ptr(lltype.FixedSizeArray(HANDLE, 1)) - CreatePipe = self.llexternal('CreatePipe', [HANDLEP, - HANDLEP, + from pypy.rlib import rwin32 + CreatePipe = self.llexternal('CreatePipe', [rwin32.LPHANDLE, + rwin32.LPHANDLE, rffi.VOIDP, - rffi.ULONG], - rffi.INT) + rwin32.DWORD], + rwin32.BOOL) _open_osfhandle = self.llexternal('_open_osfhandle', [rffi.ULONG, rffi.INT], rffi.INT) null = lltype.nullptr(rffi.VOIDP.TO) def os_pipe_llimpl(): - pread = lltype.malloc(HANDLEP.TO, flavor='raw') - pwrite = lltype.malloc(HANDLEP.TO, flavor='raw') + pread = lltype.malloc(rwin32.LPHANDLE.TO, 1, flavor='raw') + pwrite = lltype.malloc(rwin32.LPHANDLE.TO, 1, flavor='raw') ok = CreatePipe(pread, pwrite, null, 0) + if ok: + error = 0 + else: + error = rwin32.GetLastError() hread = pread[0] hwrite = pwrite[0] lltype.free(pwrite, flavor='raw') lltype.free(pread, flavor='raw') - if not ok: # XXX guess the error, can't use GetLastError() - raise OSError(errno.EMFILE, "os_pipe failed") + if error: + raise WindowsError(error, "os_pipe failed") fdread = _open_osfhandle(hread, 0) fdwrite = _open_osfhandle(hwrite, 1) return (fdread, fdwrite) Modified: pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/ootype.py Thu Sep 10 16:45:13 2009 @@ -258,6 +258,14 @@ graphs.update(SUBTYPE._lookup_graphs(meth_name)) return graphs + def _get_fields_with_different_default(self): + fields = [] + example = self._example() + for field in self._allfields().iteritems(): + name, (T, value) = field + if T._defl() != value: + fields.append(field) + return fields class SpecializableType(OOType): Modified: pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/rpbc.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/rpbc.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/rpbc.py Thu Sep 10 16:45:13 2009 @@ -21,9 +21,7 @@ if robj1 == none_frozen_pbc_repr: return hop.inputconst(ootype.Bool, True) v1 = hop.inputarg(robj1, pos) - v2 = hop.genop('oononnull', [v1], resulttype=ootype.Bool) - v3 = hop.genop('bool_not', [v2], resulttype=ootype.Bool) - return v3 + return hop.genop('ooisnull', [v1], resulttype=ootype.Bool) class FunctionsPBCRepr(AbstractFunctionsPBCRepr): Modified: pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/test/test_ootype.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/test/test_ootype.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/ootypesystem/test/test_ootype.py Thu Sep 10 16:45:13 2009 @@ -654,3 +654,11 @@ SM = StaticMethod([], Void) sm = SM._defl() assert not bool(sm) + +def test_get_fields_with_different_default(): + A = Instance("A", ROOT, {"a": (Signed, 3), + "b": (Signed, 0), + "c": (ROOT, ROOT._defl()) + }) + fields = A._get_fields_with_different_default() + assert fields == [("a", (Signed, 3))] Modified: pypy/branch/spine-of-frames/pypy/rpython/rbuiltin.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/rbuiltin.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/rbuiltin.py Thu Sep 10 16:45:13 2009 @@ -268,6 +268,16 @@ v_errno = hop.inputarg(lltype.Signed, arg=1) r_self.setfield(v_self, 'errno', v_errno, hop.llops) +def rtype_WindowsError__init__(hop): + if hop.nb_args == 2: + raise TyperError("WindowsError() should not be called with " + "a single argument") + if hop.nb_args >= 3: + v_self = hop.args_v[0] + r_self = hop.args_r[0] + v_error = hop.inputarg(lltype.Signed, arg=1) + r_self.setfield(v_self, 'winerror', v_error, hop.llops) + def rtype_we_are_translated(hop): hop.exception_cannot_occur() return hop.inputconst(lltype.Bool, True) @@ -318,6 +328,15 @@ BUILTIN_TYPER[getattr(OSError.__init__, 'im_func', OSError.__init__)] = ( rtype_OSError__init__) +try: + WindowsError +except NameError: + pass +else: + BUILTIN_TYPER[ + getattr(WindowsError.__init__, 'im_func', WindowsError.__init__)] = ( + rtype_WindowsError__init__) + BUILTIN_TYPER[object.__init__] = rtype_object__init__ # annotation of low-level types Modified: pypy/branch/spine-of-frames/pypy/rpython/rint.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/rint.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/rint.py Thu Sep 10 16:45:13 2009 @@ -385,6 +385,7 @@ def rtype_float(_, hop): vlist = hop.inputargs(Float) + hop.exception_cannot_occur() return vlist[0] # version picked by specialisation based on which Modified: pypy/branch/spine-of-frames/pypy/rpython/rpbc.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/rpbc.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/rpbc.py Thu Sep 10 16:45:13 2009 @@ -834,7 +834,15 @@ "classes with no common base: %r" % (mdescs,)) self.methodname = methodname - self.classdef = classdef.locate_attribute(methodname) + # for ootype, the right thing to do is to always keep the most precise + # type of the instance, while for lltype we want to cast it to the + # type where the method is actually defined. See also + # test_rclass.test_method_specialized_with_subclass and + # rtyper.attach_methods_to_subclasses + if self.rtyper.type_system.name == 'ootypesystem': + self.classdef = classdef + else: + self.classdef = classdef.locate_attribute(methodname) # the low-level representation is just the bound 'self' argument. self.s_im_self = annmodel.SomeInstance(self.classdef, flags=flags) self.r_im_self = rclass.getinstancerepr(rtyper, self.classdef) Modified: pypy/branch/spine-of-frames/pypy/rpython/rtyper.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/rtyper.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/rtyper.py Thu Sep 10 16:45:13 2009 @@ -198,7 +198,9 @@ if self.exceptiondata is not None: self.exceptiondata.make_helpers(self) self.specialize_more_blocks() # for the helpers just made - + if self.type_system.name == 'ootypesystem': + self.attach_methods_to_subclasses() + # from pypy.annotation import listdef ldef = listdef.ListDef(None, annmodel.SomeString()) @@ -268,6 +270,40 @@ if annmixlevel is not None: annmixlevel.finish() + def attach_methods_to_subclasses(self): + # in ootype, it might happen that a method is defined in the + # superclass but the annotator discovers that it's always called + # through instances of a subclass (e.g. because of specialization, see + # test_rclass.test_method_specialized_with_subclass). In that cases, + # we copy the method also in the ootype.Instance of the subclass, so + # that the type of v_self coincides with the type returned by + # _lookup(). + assert self.type_system.name == 'ootypesystem' + def allclasses(TYPE, seen): + '''Yield TYPE and all its subclasses''' + if TYPE in seen: + return + seen.add(TYPE) + yield TYPE + for SUB in TYPE._subclasses: + for T in allclasses(SUB, seen): + yield T + + for TYPE in allclasses(ootype.ROOT, set()): + for methname, meth in TYPE._methods.iteritems(): + try: + graph = meth.graph + except AttributeError: + continue + SELF = graph.getargs()[0].concretetype + if TYPE != SELF and ootype.isSubclass(SELF, TYPE): + # the annotator found that this method has a more precise + # type. Attach it to the proper subclass, so that the type + # of 'self' coincides with the type returned by _lookup(), + # else we might have type errors + if methname not in SELF._methods: + ootype.addMethods(SELF, {methname: meth}) + def dump_typererrors(self, num=None, minimize=True, to_log=False): c = 0 bc = 0 Modified: pypy/branch/spine-of-frames/pypy/rpython/test/test_llann.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/test/test_llann.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/test/test_llann.py Thu Sep 10 16:45:13 2009 @@ -389,6 +389,26 @@ lst.append(6) self.annotate(llf, []) + def test_adtmeths(self): + def h_length(s): + return s.foo + S = GcStruct("S", ('foo', Signed), + adtmeths={"h_length": h_length, + "stuff": 12}) + def llf(): + s = malloc(S) + s.foo = 321 + return s.h_length() + s = self.annotate(llf, []) + assert s.knowntype == int and not s.is_constant() + + def llf(): + s = malloc(S) + return s.stuff + s = self.annotate(llf, []) + assert s.is_constant() and s.const == 12 + + def test_pseudohighlevelcallable(): t = TranslationContext() t.buildannotator() Modified: pypy/branch/spine-of-frames/pypy/rpython/test/test_rclass.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/test/test_rclass.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/test/test_rclass.py Thu Sep 10 16:45:13 2009 @@ -266,6 +266,25 @@ res = self.interpret(f, []) assert res == 246 + def test_method_specialized_with_subclass(self): + class A: + def meth(self, n): + return -1 + meth._annspecialcase_ = 'specialize:arg(1)' + + class B(A): + pass + + def f(): + a = A() + b = B() + a.meth(1) # the self of this variant is annotated with A + b.meth(2) # the self of this variant is annotated with B + return 42 + + res = self.interpret(f, []) + assert res == 42 + def test_issubclass_type(self): class Abstract: pass Modified: pypy/branch/spine-of-frames/pypy/rpython/test/test_rint.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/rpython/test/test_rint.py (original) +++ pypy/branch/spine-of-frames/pypy/rpython/test/test_rint.py Thu Sep 10 16:45:13 2009 @@ -327,6 +327,16 @@ res = self.interpret(f, [sys.maxint]) assert res == 0 + def test_cast_to_float_exc_check(self): + def f(x): + try: + return float(x) + except ValueError: + return 3.0 + + res = self.interpret(f, [3]) + assert res == 3 + class TestLLtype(BaseTestRint, LLRtypeMixin): pass Modified: pypy/branch/spine-of-frames/pypy/translator/c/gcc/test/test_asmgcroot.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/c/gcc/test/test_asmgcroot.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/c/gcc/test/test_asmgcroot.py Thu Sep 10 16:45:13 2009 @@ -7,7 +7,9 @@ from pypy import conftest if sys.platform == 'win32': - py.test.skip("No asmgcc on Windows") + if not ('mingw' in os.popen('gcc --version').read() and + 'GNU' in os.popen('make --version').read()): + py.test.skip("mingw32 and MSYS are required for asmgcc on Windows") class AbstractTestAsmGCRoot: # the asmgcroot gc transformer doesn't generate gc_reload_possibly_moved @@ -30,6 +32,8 @@ config = get_pypy_config(translating=True) config.translation.gc = self.gcpolicy config.translation.gcrootfinder = "asmgcc" + if sys.platform == 'win32': + config.translation.cc = 'mingw32' t = TranslationContext(config=config) self.t = t a = t.buildannotator() @@ -48,7 +52,7 @@ def run(): lines = [] print >> sys.stderr, 'RUN: starting', exe_name - g = os.popen("'%s'" % (exe_name,), 'r') + g = os.popen('"%s"' % (exe_name,), 'r') for line in g: print >> sys.stderr, 'RUN:', line.rstrip() lines.append(line) Modified: pypy/branch/spine-of-frames/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/c/gcc/trackgcroot.py Thu Sep 10 16:45:13 2009 @@ -23,15 +23,16 @@ r_functionstart_darwin = re.compile(r"_(\w+):\s*$") # inside functions -r_label = re.compile(r"([.]?\w+)[:]\s*$") +LABEL = r'([.]?[\w$@]+)' +r_label = re.compile(LABEL+"[:]\s*$") r_globl = re.compile(r"\t[.]globl\t(\w+)\s*$") r_insn = re.compile(r"\t([a-z]\w*)\s") -r_jump = re.compile(r"\tj\w+\s+([.]?[\w$]+)\s*$") +r_jump = re.compile(r"\tj\w+\s+"+LABEL+"\s*$") OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' r_unaryinsn = re.compile(r"\t[a-z]\w*\s+("+OPERAND+")\s*$") r_unaryinsn_star= re.compile(r"\t[a-z]\w*\s+([*]"+OPERAND+")\s*$") -r_jmp_switch = re.compile(r"\tjmp\t[*]([.]?\w+)[(]") -r_jmptable_item = re.compile(r"\t.long\t([.]?\w+)\s*$") +r_jmp_switch = re.compile(r"\tjmp\t[*]"+LABEL+"[(]") +r_jmptable_item = re.compile(r"\t.long\t"+LABEL+"\s*$") r_jmptable_end = re.compile(r"\t.text|\t.section\s+.text") r_binaryinsn = re.compile(r"\t[a-z]\w*\s+("+OPERAND+"),\s*("+OPERAND+")\s*$") LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|\d*[(]%esp[)]" @@ -75,23 +76,22 @@ shapelines = [] shapeofs = 0 def _globalname(name): - if self.format == 'darwin': + if self.format in ('darwin', 'mingw32'): return '_' + name return name def _globl(name): print >> output, "\t.globl %s" % _globalname(name) def _label(name): print >> output, "%s:" % _globalname(name) - def _variant(elf, darwin): - if self.format == 'darwin': - txt = darwin - else: - txt = elf + def _variant(**kwargs): + txt = kwargs[self.format] print >> output, "\t%s" % txt - + print >> output, "\t.text" _globl('pypy_asm_stackwalk') - _variant('.type pypy_asm_stackwalk, @function', '') + _variant(elf='.type pypy_asm_stackwalk, @function', + darwin='', + mingw32='') _label('pypy_asm_stackwalk') print >> output, """\ /* See description in asmgcroot.py */ @@ -114,7 +114,9 @@ popl %eax ret """ - _variant('.size pypy_asm_stackwalk, .-pypy_asm_stackwalk', '') + _variant(elf='.size pypy_asm_stackwalk, .-pypy_asm_stackwalk', + darwin='', + mingw32='') print >> output, '\t.data' print >> output, '\t.align\t4' _globl('__gcmapstart') @@ -135,7 +137,9 @@ print >> output, '\t.long\t%d' % (n,) _globl('__gcmapend') _label('__gcmapend') - _variant('.section\t.rodata', '.const') + _variant(elf='.section\t.rodata', + darwin='.const', + mingw32='') _globl('__gccallshapes') _label('__gccallshapes') output.writelines(shapelines) @@ -188,8 +192,10 @@ if functionlines: yield in_function, functionlines + _find_functions_mingw32 = _find_functions_darwin + def process(self, iterlines, newfile, entrypoint='main', filename='?'): - if self.format == 'darwin': + if self.format in ('darwin', 'mingw32'): entrypoint = '_' + entrypoint for in_function, lines in self.find_functions(iterlines): if in_function: @@ -232,6 +238,9 @@ elif format == 'darwin': match = r_functionstart_darwin.match(lines[0]) funcname = '_'+match.group(1) + elif format == 'mingw32': + match = r_functionstart_darwin.match(lines[0]) + funcname = '_'+match.group(1) else: assert False, "unknown format: %s" % format @@ -738,8 +747,15 @@ if lineoffset >= 0: assert lineoffset in (1,2) return [InsnStackAdjust(-4)] - return [InsnCall(self.currentlineno), - InsnSetLocal('%eax')] # the result is there + insns = [InsnCall(self.currentlineno), + InsnSetLocal('%eax')] # the result is there + if sys.platform == 'win32': + # handle __stdcall calling convention: + # Stack cleanup is performed by the called function, + # Function name is decorated with "@N" where N is the stack size + if match and '@' in target: + insns.append(InsnStackAdjust(int(target.split('@')[1]))) + return insns class UnrecognizedOperation(Exception): @@ -1108,6 +1124,8 @@ break if sys.platform == 'darwin': format = 'darwin' + elif sys.platform == 'win32': + format = 'mingw32' else: format = 'elf' tracker = GcRootTracker(verbose=verbose, shuffle=shuffle, format=format) Modified: pypy/branch/spine-of-frames/pypy/translator/c/genc.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/c/genc.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/c/genc.py Thu Sep 10 16:45:13 2009 @@ -492,8 +492,14 @@ mk.definition('GCMAPFILES', gcmapfiles) mk.definition('OBJECTS', '$(ASMLBLFILES) gcmaptable.s') mk.rule('%.s', '%.c', '$(CC) $(CFLAGS) -frandom-seed=$< -o $@ -S $< $(INCLUDEDIRS)') - mk.rule('%.lbl.s %.gcmap', '%.s', '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -t $< > $*.gcmap') - mk.rule('gcmaptable.s', '$(GCMAPFILES)', '$(PYPYDIR)/translator/c/gcc/trackgcroot.py $(GCMAPFILES) > $@') + if sys.platform == 'win32': + python = sys.executable.replace('\\', '/') + ' ' + else: + python = "" + mk.rule('%.lbl.s %.gcmap', '%.s', + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -t $< > $*.gcmap') + mk.rule('gcmaptable.s', '$(GCMAPFILES)', + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py $(GCMAPFILES) > $@') mk.write() #self.translator.platform, @@ -785,7 +791,10 @@ for key, value in defines.items(): print >> fi, '#define %s %s' % (key, value) - print >> fi, '#define Py_BUILD_CORE /* for Windows: avoid pulling libs in */' + if sys.platform == 'win32': + print >> fi, '#define Py_BUILD_CORE /* avoid pulling python libs in */' + print >> fi, '#define WIN32_LEAN_AND_MEAN /* winsock/winsock2 mess */' + print >> fi, '#include "pyconfig.h"' eci.write_c_header(fi) @@ -838,6 +847,9 @@ for key, value in defines.items(): print >> fi, '#define %s %s' % (key, value) + if sys.platform == 'win32': + print >> fi, '#define WIN32_LEAN_AND_MEAN /* winsock/winsock2 mess */' + print >> fi, '#include "pyconfig.h"' eci.write_c_header(fi) Modified: pypy/branch/spine-of-frames/pypy/translator/c/src/thread_nt.h ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/c/src/thread_nt.h (original) +++ pypy/branch/spine-of-frames/pypy/translator/c/src/thread_nt.h Thu Sep 10 16:45:13 2009 @@ -4,12 +4,6 @@ /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch at iso.ru */ /* Eliminated some memory leaks, gsw at agere.com */ -/* Windows.h includes winsock.h, but the socket module needs */ -/* winsock2.h. So I include it before. Ugly. */ - -#include -#include - #include #include #include @@ -61,7 +55,7 @@ return GetCurrentThreadId(); } -static int +static void bootstrap(void *call) { callobj *obj = (callobj*)call; @@ -71,7 +65,6 @@ obj->id = RPyThreadGetIdent(); ReleaseSemaphore(obj->done, 1, NULL); func(); - return 0; } long RPyThreadStart(void (*func)(void)) @@ -130,69 +123,14 @@ /************************************************************/ -typedef PVOID WINAPI interlocked_cmp_xchg_t(PVOID *dest, PVOID exc, PVOID comperand) ; - -/* Sorry mate, but we haven't got InterlockedCompareExchange in Win95! */ -static PVOID WINAPI interlocked_cmp_xchg(PVOID *dest, PVOID exc, PVOID comperand) -{ - static LONG spinlock = 0 ; - PVOID result ; - DWORD dwSleep = 0; - - /* Acqire spinlock (yielding control to other threads if cant aquire for the moment) */ - while(InterlockedExchange(&spinlock, 1)) - { - // Using Sleep(0) can cause a priority inversion. - // Sleep(0) only yields the processor if there's - // another thread of the same priority that's - // ready to run. If a high-priority thread is - // trying to acquire the lock, which is held by - // a low-priority thread, then the low-priority - // thread may never get scheduled and hence never - // free the lock. NT attempts to avoid priority - // inversions by temporarily boosting the priority - // of low-priority runnable threads, but the problem - // can still occur if there's a medium-priority - // thread that's always runnable. If Sleep(1) is used, - // then the thread unconditionally yields the CPU. We - // only do this for the second and subsequent even - // iterations, since a millisecond is a long time to wait - // if the thread can be scheduled in again sooner - // (~100,000 instructions). - // Avoid priority inversion: 0, 1, 0, 1,... - Sleep(dwSleep); - dwSleep = !dwSleep; - } - result = *dest ; - if (result == comperand) - *dest = exc ; - /* Release spinlock */ - spinlock = 0 ; - return result ; -} ; - -static interlocked_cmp_xchg_t *ixchg ; BOOL InitializeNonRecursiveMutex(PNRMUTEX mutex) { - if (!ixchg) - { - /* Sorely, Win95 has no InterlockedCompareExchange API (Win98 has), so we have to use emulation */ - HANDLE kernel = GetModuleHandle("kernel32.dll") ; - if (!kernel || (ixchg = (interlocked_cmp_xchg_t *)GetProcAddress(kernel, "InterlockedCompareExchange")) == NULL) - ixchg = interlocked_cmp_xchg ; - } - mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */ mutex->thread_id = 0 ; mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ; return mutex->hevent != NULL ; /* TRUE if the mutex is created */ } -#ifdef InterlockedCompareExchange -#undef InterlockedCompareExchange -#endif -#define InterlockedCompareExchange(dest,exchange,comperand) (ixchg((dest), (exchange), (comperand))) - VOID DeleteNonRecursiveMutex(PNRMUTEX mutex) { /* No in-use check */ @@ -208,7 +146,7 @@ /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */ if (!wait) { - if (InterlockedCompareExchange((PVOID *)&mutex->owned, (PVOID)0, (PVOID)-1) != (PVOID)-1) + if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1) return WAIT_TIMEOUT ; ret = WAIT_OBJECT_0 ; } Modified: pypy/branch/spine-of-frames/pypy/translator/c/test/test_extfunc.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/c/test/test_extfunc.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/c/test/test_extfunc.py Thu Sep 10 16:45:13 2009 @@ -173,6 +173,19 @@ if has_blocks: assert res[4] == os.stat(filename).st_blocks +def test_os_stat_raises_winerror(): + if sys.platform != 'win32': + py.test.skip("no WindowsError on this platform") + def call_stat(): + try: + os.stat("nonexistentdir/nonexistentfile") + except WindowsError, e: + return e.winerror + f = compile(call_stat, []) + res = f() + expected = call_stat() + assert res == expected + def test_os_fstat(): if os.environ.get('PYPY_CC', '').startswith('tcc'): py.test.skip("segfault with tcc :-(") Modified: pypy/branch/spine-of-frames/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/cli/opcodes.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/cli/opcodes.py Thu Sep 10 16:45:13 2009 @@ -114,9 +114,8 @@ 'ullong_is_true': [PushAllArgs, 'ldc.i8 0', 'cgt.un'], 'ullong_invert': 'not', - # XXX: why nop nop nop? - 'ooisnull': [PushAllArgs, 'nop', 'nop', 'nop', 'ldnull', 'ceq'], - 'oononnull': [PushAllArgs, 'nop', 'nop', 'nop', 'nop', 'ldnull', 'ceq']+Not, + 'ooisnull': [PushAllArgs, 'ldnull', 'ceq'], + 'oononnull': [PushAllArgs, 'ldnull', 'ceq']+Not, # when casting from bool we want that every truth value is casted # to 1: we can't simply DoNothing, because the CLI stack could Modified: pypy/branch/spine-of-frames/pypy/translator/driver.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/driver.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/driver.py Thu Sep 10 16:45:13 2009 @@ -362,7 +362,7 @@ from pypy.jit.metainterp.warmspot import apply_jit apply_jit(self.translator, policy=self.jitpolicy, debug_level=self.config.translation.jit_debug, - backend_name=self.config.translation.jit_backend) + backend_name=self.config.translation.jit_backend, inline=True) # self.log.info("the JIT compiler was generated") # Modified: pypy/branch/spine-of-frames/pypy/translator/jvm/cmpopcodes.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/jvm/cmpopcodes.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/jvm/cmpopcodes.py Thu Sep 10 16:45:13 2009 @@ -1,6 +1,6 @@ from pypy.translator.jvm.typesystem import \ IFLT, IFLE, IFEQ, IFNE, IFGT, IFGE, \ - IFNONNULL, IF_ACMPEQ, GOTO, ICONST, \ + IFNONNULL, IFNULL, IF_ACMPEQ, GOTO, ICONST, \ DCONST_0, DCMPG, LCONST_0, LCMP, \ IF_ICMPLT, IF_ICMPLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPGT, IF_ICMPGE, \ PYPYUINTCMP, PYPYULONGCMP @@ -52,6 +52,7 @@ # Double operand entries: 'oononnull': [IFNONNULL], + 'ooisnull': [IFNULL], 'oois': [IF_ACMPEQ], 'unichar_eq': [IF_ICMPEQ], Modified: pypy/branch/spine-of-frames/pypy/translator/platform/__init__.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/platform/__init__.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/platform/__init__.py Thu Sep 10 16:45:13 2009 @@ -110,9 +110,9 @@ errorfile = outname.new(ext='errors') errorfile.write(stderr) stderrlines = stderr.splitlines() - for line in stderrlines[:20]: + for line in stderrlines[:50]: log.ERROR(line) - if len(stderrlines) > 20: + if len(stderrlines) > 50: log.ERROR('...') raise CompilationError(stdout, stderr) Modified: pypy/branch/spine-of-frames/pypy/translator/platform/posix.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/platform/posix.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/platform/posix.py Thu Sep 10 16:45:13 2009 @@ -121,6 +121,7 @@ def write(self, f): def write_list(prefix, lst): for i, fn in enumerate(lst): + fn = fn.replace('\\', '\\\\') print >> f, prefix, fn, if i < len(lst)-1: print >> f, '\\' @@ -129,7 +130,7 @@ prefix = ' ' * len(prefix) name, value = self.name, self.value if isinstance(value, str): - f.write('%s = %s\n' % (name, value)) + f.write('%s = %s\n' % (name, value.replace('\\', '\\\\'))) else: write_list('%s =' % (name,), value) if value: @@ -171,7 +172,8 @@ if fpath.dirpath() == self.makefile_dir: return fpath.basename elif fpath.dirpath().dirpath() == self.makefile_dir.dirpath(): - return '../' + fpath.relto(self.makefile_dir.dirpath()) + path = '../' + fpath.relto(self.makefile_dir.dirpath()) + return path.replace('\\', '/') else: return str(fpath) Modified: pypy/branch/spine-of-frames/pypy/translator/platform/windows.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/platform/windows.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/platform/windows.py Thu Sep 10 16:45:13 2009 @@ -281,4 +281,7 @@ def library_dirs_for_libffi(self): return [] - + def _handle_error(self, returncode, stderr, stdout, outname): + # Mingw tools write compilation errors to stdout + super(MingwPlatform, self)._handle_error( + returncode, stderr + stdout, '', outname) Modified: pypy/branch/spine-of-frames/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/translator/tool/cbuild.py (original) +++ pypy/branch/spine-of-frames/pypy/translator/tool/cbuild.py Thu Sep 10 16:45:13 2009 @@ -249,6 +249,8 @@ f = filename.open("w") if being_main: f.write("#define PYPY_NOT_MAIN_FILE\n") + if sys.platform == 'win32': + f.write("#define WIN32_LEAN_AND_MEAN\n") self.write_c_header(f) source = str(source) f.write(source) From afa at codespeak.net Thu Sep 10 18:31:27 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Thu, 10 Sep 2009 18:31:27 +0200 (CEST) Subject: [pypy-svn] r67625 - pypy/trunk/pypy/lib/app_test/ctypes_tests Message-ID: <20090910163127.231CF168026@codespeak.net> Author: afa Date: Thu Sep 10 18:31:25 2009 New Revision: 67625 Modified: pypy/trunk/pypy/lib/app_test/ctypes_tests/conftest.py Log: Build _ctypes_test.so after all the test options are set (at least the temp dir), not when loading the conftest module. This change fixes pypy-c test_all.py lib\app_test\ctypes_tests Modified: pypy/trunk/pypy/lib/app_test/ctypes_tests/conftest.py ============================================================================== --- pypy/trunk/pypy/lib/app_test/ctypes_tests/conftest.py (original) +++ pypy/trunk/pypy/lib/app_test/ctypes_tests/conftest.py Thu Sep 10 18:31:25 2009 @@ -16,4 +16,6 @@ return platform.compile([cfile], eci, str(udir.join('_ctypes_test')), standalone=False) -sofile = compile_so_file() +def pytest_configure(config): + global sofile + sofile = compile_so_file() From pedronis at codespeak.net Thu Sep 10 18:49:16 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 10 Sep 2009 18:49:16 +0200 (CEST) Subject: [pypy-svn] r67626 - in pypy/trunk/pypy: jit/backend/x86/test jit/metainterp jit/metainterp/test jit/tl jit/tl/tla rlib Message-ID: <20090910164916.9E2E5168024@codespeak.net> Author: pedronis Date: Thu Sep 10 18:49:15 2009 New Revision: 67626 Added: pypy/trunk/pypy/jit/metainterp/test/test_zrpy_set_param.py (contents, props changed) Modified: pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/test_basic.py pypy/trunk/pypy/jit/metainterp/test/test_exception.py pypy/trunk/pypy/jit/metainterp/test/test_loop_dummy.py pypy/trunk/pypy/jit/metainterp/test/test_recursive.py pypy/trunk/pypy/jit/metainterp/test/test_slist.py pypy/trunk/pypy/jit/metainterp/test/test_tl.py pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py pypy/trunk/pypy/jit/metainterp/warmspot.py pypy/trunk/pypy/jit/tl/pypyjit_child.py pypy/trunk/pypy/jit/tl/tla/test_tla.py pypy/trunk/pypy/rlib/jit.py Log: (micke, pedronis) make the optimizer switchable at runtime with jitdrive.set_param('optimizer', jit.OPTIMIZER_FULL|jit.OPTIMIZER_SIMPLE) full is the default corresponding to pypy.metainterp.optimize, simpe is simple_optimize Modified: pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py Thu Sep 10 18:49:15 2009 @@ -9,7 +9,7 @@ from pypy.rlib import rgc from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE from pypy.jit.backend.x86.runner import CPU386 from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc from pypy.jit.backend.x86.regalloc import stack_pos @@ -58,7 +58,6 @@ from pypy.annotation.listdef import s_list_of_strings from pypy.translator.translator import TranslationContext from pypy.jit.metainterp.warmspot import apply_jit - from pypy.jit.metainterp import simple_optimize from pypy.translator.c import genc # t = TranslationContext() @@ -69,7 +68,7 @@ t.buildannotator().build_types(f, [s_list_of_strings]) t.buildrtyper().specialize() if kwds['jit']: - apply_jit(t, CPUClass=CPU386, optimizer=simple_optimize) + apply_jit(t, CPUClass=CPU386, optimizer=OPTIMIZER_SIMPLE) cbuilder = genc.CStandaloneBuilder(t, f, t.config) cbuilder.generate_source() cbuilder.compile() Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Thu Sep 10 18:49:15 2009 @@ -104,8 +104,8 @@ loop.operations = history.operations loop.operations[-1].jump_target = loop metainterp_sd = metainterp.staticdata - old_loop = metainterp_sd.optimize_loop(metainterp_sd.options, old_loops, - loop, metainterp.cpu) + old_loop = metainterp_sd.state.optimize_loop(metainterp_sd.options, old_loops, + loop, metainterp.cpu) if old_loop is not None: if we_are_translated() and DEBUG > 0: debug_print("reusing old loop") @@ -374,9 +374,9 @@ new_loop = create_empty_loop(metainterp) new_loop.operations = metainterp.history.operations metainterp_sd = metainterp.staticdata - target_loop = metainterp_sd.optimize_bridge(metainterp_sd.options, - old_loops, new_loop, - metainterp.cpu) + target_loop = metainterp_sd.state.optimize_bridge(metainterp_sd.options, + old_loops, new_loop, + metainterp.cpu) # Did it work? If not, prepare_loop_from_bridge() will probably be used. if target_loop is not None: # Yes, we managed to create a bridge. Dispatch to resumekey to Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Thu Sep 10 18:49:15 2009 @@ -1018,7 +1018,7 @@ virtualizable_info = None def __init__(self, portal_graph, graphs, cpu, stats, options, - optimizer=None, profile=None, warmrunnerdesc=None, + profile=None, warmrunnerdesc=None, leave_graph=None): self.portal_graph = portal_graph self.cpu = cpu @@ -1032,10 +1032,6 @@ self.opcode_implementations = [] self.opcode_names = [] self.opname_to_index = {} - if optimizer is None: - from pypy.jit.metainterp import optimize as optimizer - self.optimize_loop = optimizer.optimize_loop - self.optimize_bridge = optimizer.optimize_bridge if profile is not None: self.profiler = profile() @@ -1046,23 +1042,21 @@ self.warmrunnerdesc = warmrunnerdesc self._op_goto_if_not = self.find_opcode('goto_if_not') - optmodule = self.optimize_loop.__module__ - optmodule = optmodule.split('.')[-1] backendmodule = self.cpu.__module__ backendmodule = backendmodule.split('.')[-2] - self.jit_starting_line = 'JIT starting (%s, %s)' % (optmodule, - backendmodule) - + self.jit_starting_line = 'JIT starting (%s)' % backendmodule self.leave_graph = leave_graph def _freeze_(self): return True - def finish_setup(self): + def finish_setup(self, optimizer=None): warmrunnerdesc = self.warmrunnerdesc if warmrunnerdesc is not None: self.num_green_args = warmrunnerdesc.num_green_args self.state = warmrunnerdesc.state + if optimizer is not None: + self.state.set_param_optimizer(optimizer) else: self.num_green_args = 0 self.state = None Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Thu Sep 10 18:49:15 2009 @@ -1,6 +1,7 @@ import py import sys from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside +from pypy.rlib.jit import OPTIMIZER_FULL, OPTIMIZER_SIMPLE from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats from pypy.jit.backend.llgraph import runner from pypy.jit.metainterp import support, codewriter, pyjitpl, history @@ -12,7 +13,7 @@ from pypy.rpython.ootypesystem import ootype def get_metainterp(func, values, CPUClass, type_system, policy, - listops=False, optimizer=None): + listops=False, optimizer=OPTIMIZER_FULL): from pypy.annotation.policy import AnnotatorPolicy from pypy.annotation.model import lltype_to_annotation from pypy.rpython.test.test_llinterp import gengraph @@ -23,9 +24,8 @@ cpu = CPUClass(rtyper, stats, False) graph = rtyper.annotator.translator.graphs[0] opt = history.Options(specialize=False, listops=listops) - metainterp_sd = pyjitpl.MetaInterpStaticData(graph, [], cpu, stats, opt, - optimizer=optimizer) - metainterp_sd.finish_setup() + metainterp_sd = pyjitpl.MetaInterpStaticData(graph, [], cpu, stats, opt) + metainterp_sd.finish_setup(optimizer=optimizer) metainterp = pyjitpl.MetaInterp(metainterp_sd) return metainterp, rtyper @@ -74,13 +74,17 @@ def attach_unoptimized_bridge_from_interp(self, greenkey, newloop): pass + # pick the optimizer this way + optimize_loop = staticmethod(simple_optimize.optimize_loop) + optimize_bridge = staticmethod(simple_optimize.optimize_bridge) + trace_limit = sys.maxint if policy is None: policy = JitPolicy() metainterp, rtyper = get_metainterp(f, args, self.CPUClass, self.type_system, policy=policy, - optimizer=simple_optimize, + optimizer="bogus", **kwds) cw = codewriter.CodeWriter(metainterp.staticdata, policy) graph = rtyper.annotator.translator.graphs[0] @@ -785,7 +789,6 @@ self.meta_interp(f, [40, 0]) def test_const_inputargs(self): - from pypy.jit.metainterp import simple_optimize myjitdriver = JitDriver(greens = ['m'], reds = ['n', 'x']) def f(n, x): m = 0x7FFFFFFF @@ -798,7 +801,7 @@ return x res = self.meta_interp(f, [50, 1], - optimizer=simple_optimize) + optimizer=OPTIMIZER_SIMPLE) assert res == 42 def test_set_param(self): @@ -832,7 +835,7 @@ res = self.interp_operations(f, [3, 5]) assert res == 8 self.check_history_(int_add=0, call=1) - + class TestOOtype(BasicTests, OOJitMixin): @@ -886,7 +889,6 @@ def test_subclassof(self): - from pypy.jit.metainterp import simple_optimize A = ootype.Instance("A", ootype.ROOT) B = ootype.Instance("B", A) clsA = ootype.runtimeClass(A) @@ -911,12 +913,12 @@ res = self.meta_interp(f, [1, 100], policy=StopAtXPolicy(getcls), - optimizer=simple_optimize) + optimizer=OPTIMIZER_SIMPLE) assert not res res = self.meta_interp(f, [0, 100], policy=StopAtXPolicy(getcls), - optimizer=simple_optimize) + optimizer=OPTIMIZER_SIMPLE) assert res Modified: pypy/trunk/pypy/jit/metainterp/test/test_exception.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_exception.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_exception.py Thu Sep 10 18:49:15 2009 @@ -1,9 +1,8 @@ import py, sys from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask from pypy.jit.metainterp.policy import StopAtXPolicy -from pypy.jit.metainterp import simple_optimize class ExceptionTests: @@ -447,10 +446,10 @@ n += 1 return m - res = self.meta_interp(f, [1, 1, 0], optimizer=simple_optimize) + res = self.meta_interp(f, [1, 1, 0], optimizer=OPTIMIZER_SIMPLE) assert res == f(1, 1, 0) res = self.meta_interp(f, [809644098, 16, 0], - optimizer=simple_optimize) + optimizer=OPTIMIZER_SIMPLE) assert res == f(809644098, 16, 0) def test_int_neg_ovf(self): @@ -471,7 +470,7 @@ return m res = self.meta_interp(f, [-sys.maxint-1+100, 0], - optimizer=simple_optimize) + optimizer=OPTIMIZER_SIMPLE) assert res == 16 def test_reraise_through_portal(self): @@ -554,7 +553,7 @@ return 8 res = self.meta_interp(main, [41], repeat=7, policy=StopAtXPolicy(x), - optimizer=simple_optimize) + optimizer=OPTIMIZER_SIMPLE) assert res == 8 class MyError(Exception): Modified: pypy/trunk/pypy/jit/metainterp/test/test_loop_dummy.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_loop_dummy.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_loop_dummy.py Thu Sep 10 18:49:15 2009 @@ -1,12 +1,12 @@ from pypy.jit.metainterp.test import test_loop, test_send from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.jit.metainterp import simple_optimize +from pypy.rlib.jit import OPTIMIZER_SIMPLE from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin class LoopDummyTest(test_loop.LoopTest, test_send.SendTests): def meta_interp(self, func, args, **kwds): - return ll_meta_interp(func, args, optimizer=simple_optimize, + return ll_meta_interp(func, args, optimizer=OPTIMIZER_SIMPLE, CPUClass=self.CPUClass, type_system=self.type_system, **kwds) Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Thu Sep 10 18:49:15 2009 @@ -1,7 +1,6 @@ import py -from pypy.rlib.jit import JitDriver, we_are_jitted +from pypy.rlib.jit import JitDriver, we_are_jitted, OPTIMIZER_SIMPLE from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin -from pypy.jit.metainterp import simple_optimize from pypy.jit.metainterp.policy import StopAtXPolicy from pypy.rpython.annlowlevel import hlstr from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit, get_stats @@ -23,7 +22,7 @@ return f(n+1) else: return 1 - res = self.meta_interp(main, [20], optimizer=simple_optimize) + res = self.meta_interp(main, [20], optimizer=OPTIMIZER_SIMPLE) assert res == main(20) def test_simple_recursion_with_exc(self): @@ -49,7 +48,7 @@ return f(n+1) else: return 1 - res = self.meta_interp(main, [20], optimizer=simple_optimize) + res = self.meta_interp(main, [20], optimizer=OPTIMIZER_SIMPLE) assert res == main(20) def test_recursion_three_times(self): @@ -72,7 +71,7 @@ print for i in range(1, 11): print '%3d %9d' % (i, f(i)) - res = self.meta_interp(main, [10], optimizer=simple_optimize) + res = self.meta_interp(main, [10], optimizer=OPTIMIZER_SIMPLE) assert res == main(10) self.check_enter_count_at_most(10) @@ -92,7 +91,7 @@ opaque(n, i) i += 1 return stack.pop() - res = self.meta_interp(f, [1], optimizer=simple_optimize, repeat=2, + res = self.meta_interp(f, [1], optimizer=OPTIMIZER_SIMPLE, repeat=2, policy=StopAtXPolicy(opaque)) assert res == 1 @@ -144,9 +143,9 @@ codes = [code, subcode] f = self.get_interpreter(codes) - assert self.meta_interp(f, [0, 0, 0], optimizer=simple_optimize) == 42 + assert self.meta_interp(f, [0, 0, 0], optimizer=OPTIMIZER_SIMPLE) == 42 self.check_loops(int_add = 1, call = 1) - assert self.meta_interp(f, [0, 0, 0], optimizer=simple_optimize, + assert self.meta_interp(f, [0, 0, 0], optimizer=OPTIMIZER_SIMPLE, inline=True) == 42 self.check_loops(int_add = 2, call = 0, guard_no_exception = 0) @@ -157,7 +156,7 @@ f = self.get_interpreter(codes) - assert self.meta_interp(f, [0, 0, 0], optimizer=simple_optimize, + assert self.meta_interp(f, [0, 0, 0], optimizer=OPTIMIZER_SIMPLE, inline=True) == 42 self.check_loops(call = 1) @@ -169,7 +168,7 @@ f = self.get_interpreter(codes, always_inline=True) try: - self.meta_interp(f, [0, 0, 0], optimizer=simple_optimize, + self.meta_interp(f, [0, 0, 0], optimizer=OPTIMIZER_SIMPLE, inline=True) except CannotInlineCanEnterJit: pass @@ -210,7 +209,7 @@ def main(n): return f("c-l", n) print main(100) - res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + res = self.meta_interp(main, [100], optimizer=OPTIMIZER_SIMPLE, inline=True) assert res == 0 def test_exception_in_inlined_function(self): @@ -253,7 +252,7 @@ return n def main(n): return f("c-l", n) - res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + res = self.meta_interp(main, [100], optimizer=OPTIMIZER_SIMPLE, inline=True) assert res == main(100) def test_recurse_during_blackholing(self): @@ -295,7 +294,7 @@ myjitdriver.set_param('trace_eagerness', 5) return f("c-l", n) expected = main(100) - res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + res = self.meta_interp(main, [100], optimizer=OPTIMIZER_SIMPLE, inline=True) assert res == expected def check_max_trace_length(self, length): @@ -321,7 +320,7 @@ n -= 1 return n TRACE_LIMIT = 66 - res = self.meta_interp(loop, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT) + res = self.meta_interp(loop, [100], optimizer=OPTIMIZER_SIMPLE, inline=True, trace_limit=TRACE_LIMIT) assert res == 0 self.check_max_trace_length(TRACE_LIMIT) self.check_enter_count(15) # maybe @@ -345,7 +344,7 @@ n = recursive(n) n -= 1 TRACE_LIMIT = 20 - res = self.meta_interp(loop, [100], optimizer=simple_optimize, inline=True, trace_limit=TRACE_LIMIT) + res = self.meta_interp(loop, [100], optimizer=OPTIMIZER_SIMPLE, inline=True, trace_limit=TRACE_LIMIT) self.check_max_trace_length(TRACE_LIMIT) self.check_aborted_count(8) self.check_enter_count_at_most(30) @@ -370,10 +369,10 @@ myjitdriver.set_param('inlining', False) return loop(100) - res = self.meta_interp(main, [0], optimizer=simple_optimize, trace_limit=TRACE_LIMIT) + res = self.meta_interp(main, [0], optimizer=OPTIMIZER_SIMPLE, trace_limit=TRACE_LIMIT) self.check_loops(call=1) - res = self.meta_interp(main, [1], optimizer=simple_optimize, trace_limit=TRACE_LIMIT) + res = self.meta_interp(main, [1], optimizer=OPTIMIZER_SIMPLE, trace_limit=TRACE_LIMIT) self.check_loops(call=0) def test_leave_jit_hook(self): @@ -441,7 +440,7 @@ def main(n): frame = Frame(n) return frame.f("C-l") - res = self.meta_interp(main, [100], optimizer=simple_optimize, inline=True) + res = self.meta_interp(main, [100], optimizer=OPTIMIZER_SIMPLE, inline=True) assert res == main(100) class TestLLtype(RecursiveTests, LLJitMixin): Modified: pypy/trunk/pypy/jit/metainterp/test/test_slist.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_slist.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_slist.py Thu Sep 10 18:49:15 2009 @@ -1,7 +1,7 @@ import py from pypy.jit.metainterp.policy import StopAtXPolicy from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE class ListTests: @@ -61,7 +61,7 @@ myjitdriver.jit_merge_point(n=n, lst=lst) n -= 1 return lst[n] - res = self.meta_interp(f, [21], listops=True, optimizer=simple_optimize) + res = self.meta_interp(f, [21], listops=True, optimizer=OPTIMIZER_SIMPLE) assert res == 0 def test_getitem(self): Modified: pypy/trunk/pypy/jit/metainterp/test/test_tl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_tl.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_tl.py Thu Sep 10 18:49:15 2009 @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE from pypy.jit.metainterp.policy import StopAtXPolicy from pypy.jit.metainterp.test.test_basic import OOJitMixin, LLJitMixin @@ -144,7 +144,7 @@ def main(num, arg): return interp(codes[num], inputarg=arg) - res = self.meta_interp(main, [0, 20], optimizer=simple_optimize, + res = self.meta_interp(main, [0, 20], optimizer=OPTIMIZER_SIMPLE, listops=listops, backendopt=True, policy=policy) assert res == 0 Modified: pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py Thu Sep 10 18:49:15 2009 @@ -4,12 +4,13 @@ from pypy.rpython.annlowlevel import llhelper from pypy.jit.metainterp.policy import StopAtXPolicy from pypy.rlib.jit import JitDriver, hint, dont_look_inside +from pypy.rlib.jit import OPTIMIZER_SIMPLE, OPTIMIZER_FULL from pypy.rlib.rarithmetic import intmask from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin from pypy.rpython.lltypesystem.rvirtualizable2 import VABLERTIPTR from pypy.rpython.rclass import FieldListAccessor from pypy.jit.metainterp.warmspot import get_stats, get_translator -from pypy.jit.metainterp import history, heaptracker, simple_optimize +from pypy.jit.metainterp import history, heaptracker from pypy.jit.metainterp.test.test_optimizefindnode import LLtypeMixin def promote_virtualizable(*args): @@ -437,7 +438,7 @@ promote_virtualizable(xy2, 'inst_l2') return xy2.inst_l2[0] expected = f(20) - res = self.meta_interp(f, [20], optimizer=simple_optimize) + res = self.meta_interp(f, [20], optimizer=OPTIMIZER_SIMPLE) assert res == expected self.check_loops(getfield_gc=3, setfield_gc=0, arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1) @@ -1021,9 +1022,8 @@ frame = Frame(n) return f("c-l", frame) print main(100) - from pypy.jit.metainterp import optimize - res = self.meta_interp(main, [100], - inline=True, optimizer=optimize) + res = self.meta_interp(main, [100], inline=True, + optimizer=OPTIMIZER_FULL) class TestOOtype(#ExplicitVirtualizableTests, ImplicitVirtualizableTests, Modified: pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py Thu Sep 10 18:49:15 2009 @@ -1,8 +1,10 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp, cast_whatever_to_int from pypy.jit.metainterp.warmspot import get_stats -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, OPTIMIZER_FULL, OPTIMIZER_SIMPLE from pypy.jit.backend.llgraph import runner +from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin + def test_translate_cast_whatever_to_int(): from pypy.rpython.test.test_llinterp import interpret @@ -19,12 +21,6 @@ class WarmspotTests(object): - def meta_interp(self, *args, **kwds): - assert 'CPUClass' not in kwds - assert 'type_system' not in kwds - kwds['CPUClass'] = self.CPUClass - kwds['type_system'] = self.type_system - return ll_meta_interp(*args, **kwds) def test_basic(self): mydriver = JitDriver(reds=['a'], @@ -105,11 +101,62 @@ for loc in get_stats().locations: assert loc == 'GREEN IS 123.' + def test_set_param_optimizer(self): + myjitdriver = JitDriver(greens = [], reds = ['n']) + class A(object): + def m(self, n): + return n-1 + + def g(n): + while n > 0: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + n = A().m(n) + return n + def f(n, optimizer): + myjitdriver.set_param('optimizer', optimizer) + return g(n) + + # check that the set_param will override the default + res = self.meta_interp(f, [10, OPTIMIZER_SIMPLE], + optimizer=OPTIMIZER_FULL) + assert res == 0 + self.check_loops(new_with_vtable=1) + + res = self.meta_interp(f, [10, OPTIMIZER_FULL], + optimizer=OPTIMIZER_SIMPLE) + assert res == 0 + self.check_loops(new_with_vtable=0) + + def test_optimizer_default_choice(self): + myjitdriver = JitDriver(greens = [], reds = ['n']) + def f(n): + while n > 0: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + n -= 1 + return n + + from pypy.rpython.test.test_llinterp import gengraph + t, rtyper, graph = gengraph(f, [int], type_system=self.type_system, + **{'translation.gc': 'boehm'}) + + from pypy.jit.metainterp.warmspot import WarmRunnerDesc + + warmrunnerdescr = WarmRunnerDesc(t, CPUClass=self.CPUClass, + optimizer=None) # pick default + + from pypy.jit.metainterp import optimize + + assert warmrunnerdescr.state.optimize_loop is optimize.optimize_loop + assert warmrunnerdescr.state.optimize_bridge is optimize.optimize_bridge + + -class TestLLWarmspot(WarmspotTests): +class TestLLWarmspot(WarmspotTests, LLJitMixin): CPUClass = runner.LLtypeCPU type_system = 'lltype' -class TestOOWarmspot(WarmspotTests): +class TestOOWarmspot(WarmspotTests, OOJitMixin): CPUClass = runner.OOtypeCPU type_system = 'ootype' Modified: pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py Thu Sep 10 18:49:15 2009 @@ -2,7 +2,7 @@ from pypy.jit.metainterp.warmspot import rpython_ll_meta_interp, ll_meta_interp from pypy.jit.metainterp.test import test_basic from pypy.jit.backend.llgraph import runner -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, OPTIMIZER_FULL from pypy.jit.conftest import option @@ -49,7 +49,7 @@ from pypy.jit.metainterp import optimize res = rpython_ll_meta_interp(f, [17], loops=2, CPUClass=self.CPUClass, type_system=self.type_system, - optimizer=optimize) + optimizer=OPTIMIZER_FULL) assert res == (17+14+11+8+7+6+5+4) * 10 Added: pypy/trunk/pypy/jit/metainterp/test/test_zrpy_set_param.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/jit/metainterp/test/test_zrpy_set_param.py Thu Sep 10 18:49:15 2009 @@ -0,0 +1,10 @@ +import py, sys +from pypy.jit.metainterp.test import test_warmspot, test_basic +from pypy.jit.metainterp.test.test_zrpy_basic import LLInterpJitMixin + + +class TestLLSetParam(LLInterpJitMixin): + + test_set_param = test_basic.BasicTests.test_set_param.im_func + + test_set_param_optimizer = test_warmspot.WarmspotTests.test_set_param_optimizer.im_func Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Thu Sep 10 18:49:15 2009 @@ -10,7 +10,7 @@ from pypy.objspace.flow.model import checkgraph, Link, copygraph from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.unroll import unrolling_iterable -from pypy.rlib.jit import PARAMETERS +from pypy.rlib.jit import PARAMETERS, OPTIMIZER_SIMPLE, OPTIMIZER_FULL from pypy.rlib.rarithmetic import r_uint, intmask from pypy.rlib.debug import debug_print from pypy.rpython.lltypesystem.lloperation import llop @@ -135,7 +135,7 @@ class WarmRunnerDesc: def __init__(self, translator, policy=None, backendopt=True, CPUClass=None, - **kwds): + optimizer=None, **kwds): pyjitpl._warmrunnerdesc = self # this is a global for debugging only! if policy is None: policy = JitPolicy() @@ -160,7 +160,7 @@ self.rewrite_can_enter_jit() self.rewrite_set_param() self.add_profiler_finish() - self.metainterp_sd.finish_setup() + self.metainterp_sd.finish_setup(optimizer=optimizer) def finish(self): vinfo = self.metainterp_sd.virtualizable_info @@ -217,7 +217,7 @@ really_remove_asserts=True) def build_meta_interp(self, CPUClass, translate_support_code=False, - view="auto", optimizer=None, profile=None, **kwds): + view="auto", profile=None, **kwds): assert CPUClass is not None opt = history.Options(**kwds) self.stats = history.Stats() @@ -232,7 +232,6 @@ self.metainterp_sd = MetaInterpStaticData(self.portal_graph, self.translator.graphs, cpu, self.stats, opt, - optimizer=optimizer, profile=profile, warmrunnerdesc=self, leave_graph=self.leave_graph) @@ -772,6 +771,18 @@ # invariant: (self.mccounters[j] < 0) if and only if # (self.mcentrypoints[j] is not None) + def set_param_optimizer(self, optimizer): + if optimizer == OPTIMIZER_SIMPLE: + from pypy.jit.metainterp import simple_optimize + self.optimize_loop = simple_optimize.optimize_loop + self.optimize_bridge = simple_optimize.optimize_bridge + elif optimizer == OPTIMIZER_FULL: + from pypy.jit.metainterp import optimize + self.optimize_loop = optimize.optimize_loop + self.optimize_bridge = optimize.optimize_bridge + else: + raise ValueError("unknown optimizer") + def create_tables_now(self): count = 1 << self.hashbits self.hashtablemask = count - 1 Modified: pypy/trunk/pypy/jit/tl/pypyjit_child.py ============================================================================== --- pypy/trunk/pypy/jit/tl/pypyjit_child.py (original) +++ pypy/trunk/pypy/jit/tl/pypyjit_child.py Thu Sep 10 18:49:15 2009 @@ -1,9 +1,6 @@ from pypy.conftest import option from pypy.rpython.lltypesystem import lltype from pypy.jit.metainterp import warmspot -#from pypy.jit.metainterp import simple_optimize as optimize -from pypy.jit.metainterp import optimize -#from pypy.jit.metainterp import optimize2 as optimize from pypy.module.pypyjit.policy import PyPyJitPolicy # Current output: http://paste.pocoo.org/show/106540/ @@ -43,8 +40,7 @@ option.view = True warmspot.jittify_and_run(interp, graph, [], policy=policy, listops=True, CPUClass=LLtypeCPU, - backendopt=True, - optimizer=optimize) + backendopt=True) def run_child_ootype(glob, loc): @@ -58,5 +54,4 @@ option.view = True warmspot.jittify_and_run(interp, graph, [], policy=policy, listops=True, CPUClass=OOtypeCPU, - backendopt=True, - optimizer=optimize) + backendopt=True) Modified: pypy/trunk/pypy/jit/tl/tla/test_tla.py ============================================================================== --- pypy/trunk/pypy/jit/tl/tla/test_tla.py (original) +++ pypy/trunk/pypy/jit/tl/tla/test_tla.py Thu Sep 10 18:49:15 2009 @@ -156,7 +156,7 @@ # ____________________________________________________________ from pypy.jit.metainterp.test.test_basic import LLJitMixin -from pypy.jit.metainterp import optimize +from pypy.rlib.jit import OPTIMIZER_FULL class TestLLtype(LLJitMixin): def test_loop(self): @@ -172,5 +172,5 @@ assert isinstance(w_result, tla.W_IntObject) return w_result.intvalue res = self.meta_interp(interp_w, [42], listops=True, - optimizer=optimize) + optimizer=OPTIMIZER_FULL) assert res == 0 Modified: pypy/trunk/pypy/rlib/jit.py ============================================================================== --- pypy/trunk/pypy/rlib/jit.py (original) +++ pypy/trunk/pypy/rlib/jit.py Thu Sep 10 18:49:15 2009 @@ -80,11 +80,15 @@ class JitHintError(Exception): """Inconsistency in the JIT hints.""" +OPTIMIZER_SIMPLE = 0 +OPTIMIZER_FULL = 1 + PARAMETERS = {'threshold': 1000, 'trace_eagerness': 200, 'hash_bits': 14, 'trace_limit': 10000, 'inlining': False, + 'optimizer': OPTIMIZER_FULL, } unroll_parameters = unrolling_iterable(PARAMETERS.keys()) From iko at codespeak.net Thu Sep 10 18:56:59 2009 From: iko at codespeak.net (iko at codespeak.net) Date: Thu, 10 Sep 2009 18:56:59 +0200 (CEST) Subject: [pypy-svn] r67627 - in pypy/build/benchmark: . specific specific/test specific/tests test Message-ID: <20090910165659.4911F168021@codespeak.net> Author: iko Date: Thu Sep 10 18:56:58 2009 New Revision: 67627 Added: pypy/build/benchmark/interpreters.py pypy/build/benchmark/specific/tests/ - copied from r67606, pypy/build/benchmark/specific/test/ pypy/build/benchmark/test/test_interpreters.py Removed: pypy/build/benchmark/specific/test/ Modified: pypy/build/benchmark/runner.py pypy/build/benchmark/specific/pystone.py pypy/build/benchmark/test/test_runner.py Log: WIP: benchmark infrastructure Added: pypy/build/benchmark/interpreters.py ============================================================================== --- (empty file) +++ pypy/build/benchmark/interpreters.py Thu Sep 10 18:56:58 2009 @@ -0,0 +1,116 @@ +import os, fcntl, gc, select, fcntl, signal, errno + +BUFSIZ = 8192 + +class RUsage(tuple): + _keys = ['ru_utime', 'ru_stime', 'ru_maxrss', 'ru_ixrss', 'ru_idrss', + 'ru_isrss', 'ru_minflt', 'ru_majflt', 'ru_nswap', 'ru_inblock', + 'ru_outblock', 'ru_msgsnd', 'ru_msgrcv', 'ru_nsignals', + 'ru_nvcsw', 'ru_nivcsw'] + + def __getattr__(self, key): + if key in self._keys: + return self[self._keys.index(key)] + return tuple.__getattr__(self, key) + +class BaseInterpreter(object): + rusage = None + status = None + cpid = None + pid = None + + def __init__(self, script): + self.script = script + + def sighandler(self, sig, frame): + cpid, status, rusage = os.wait4(self.pid, os.WNOHANG) + + if cpid == self.pid: + self.cpid = cpid + self.rusage = RUsage(rusage) + self.status = status + + def run(self): + # Set signal handler to get select to return on exit + signal.signal(signal.SIGCHLD, self.sighandler) + + stdout_r, stdout_w = os.pipe() + stderr_r, stderr_w = os.pipe() + fcntl.fcntl(stdout_r, fcntl.F_SETFL, os.O_NDELAY) + fcntl.fcntl(stderr_r, fcntl.F_SETFL, os.O_NDELAY) + + gc_was_enabled = gc.isenabled() + gc.disable() + try: + self.pid = os.fork() + except: + if gc_was_enabled: + gc.enable() + raise + + if self.pid == 0: + try: + os.dup2(stdout_w, 1) + os.close(stdout_w) + os.dup2(stderr_w, 2) + os.close(stderr_w) + + os.execlp(self.executable, self.executable, *self.script.runargs) + finally: + os._exit(255) + + os.close(stdout_w) + os.close(stderr_w) + + if gc_was_enabled: + gc.enable() + + fdset = set([stdout_r, stderr_r]) + timeout = None + + while fdset or self.cpid != self.pid: + try: + if not fdset: + # XXX race between the signal handler and select + timeout = 0.1 + + rfds, wfds, xfds = select.select(fdset, [], [], timeout) + except select.error, e: + if e.args[0] == errno.EINTR: + continue + else: + raise + + if stdout_r in rfds: + data = os.read(stdout_r, BUFSIZ) + if data == "": + os.close(stdout_r) + fdset.remove(stdout_r) + self.do_stdout(data) + + if stderr_r in rfds: + data = os.read(stderr_r, BUFSIZ) + if data == "": + os.close(stderr_r) + fdset.remove(stderr_r) + self.do_stderr(data) + + + def do_stdout(self, data): + self.script.do_stdout(data) + + def do_stderr(self, data): + self.script.do_stderr(data) + + def failed(self): + if self.status is None: + raise RuntimeError("Process is still running") + if not os.WIFEXITED(self.status): + return True # died but didn't exit normally + return os.WEXITSTATUS(self.status) + +class PythonInterpreter(BaseInterpreter): + executable = "python" + +class PyPyInterpreter(BaseInterpreter): + executable = "pypy-c" Modified: pypy/build/benchmark/runner.py ============================================================================== --- pypy/build/benchmark/runner.py (original) +++ pypy/build/benchmark/runner.py Thu Sep 10 18:56:58 2009 @@ -1,76 +1,62 @@ import sys import py -import re import subprocess -from pypy.tool.udir import udir +import interpreters -class ErrorExecuting(Exception): - pass +class BaseBenchmark(object): + def __init__(self, path): + self.runargs = [str(path)] -class OutputDidNotMatch(Exception): - pass + def do_stdout(self, data): + sys.stdout.write(data) -class AbstractRunner(object): - def run(self, n=1): - """ Runs a benchmark returning list of results - """ - t = [] - for i in range(n): - t.append(self.run_once()) - return t - - def run_once(self): - raise NotImplementedError("abstract base class") - -class ScriptRunner(AbstractRunner): - """ this benchmark runner executes script provided as a source code - """ + def do_stderr(self, data): + sys.stderr.write(data) - tmpdir = None - - def __init__(self, name, source, executable=sys.executable): - self.name = name - self.source = source - self.executable = executable - - @classmethod - def setup_tmpdir(cls): - if cls.tmpdir is None: - cls.tmpdir = udir.join('benchmark_runner') - cls.tmpdir.ensure(dir=True) - - def get_script_name(self): - self.setup_tmpdir() - fname = self.tmpdir.join(self.name + '.py') - fname.write(self.source) - return fname - - def run_once(self): - fname = self.get_script_name() - pipe = subprocess.Popen([sys.executable, str(fname)], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - res = pipe.wait() - if res: - raise ErrorExecuting(res, pipe.stderr, pipe.stdout) - t = self.read_output(pipe.stdout.read()) - return t - - def read_output(self, output): - """ override this - """ - m = re.match("^time: ([\d.]+)$", output) - if not m: - raise OutputDidNotMatch("got %s" % output) - return float(m.group(1)) - -class ProgramRunner(ScriptRunner): - """ this benchmark runner executes an existing python script - """ - def __init__(self, name, path): - self.path = path - self.name = name - - def get_script_name(self): - return str(self.path) +class BenchmarkIterator(object): + """ an iterable of the benchmarks to run """ + def __init__(self, benchmarkdir, factory): + self.benchmarkdir = benchmarkdir + self.factory = factory + + def __iter__(self): + bdir = py.path.local(self.benchmarkdir) + for f in bdir.listdir("*.py"): + if str(f)[-11:] == '__init__.py': + continue + yield self.factory(f) + +# XXX move to interpreters +class InterpreterIterator(list): + """ an iterable of the interpreters to run """ + def __init__(self): + # Introspect interpreters + bi = interpreters.BaseInterpreter + for name in dir(interpreters): + i = getattr(interpreters, name) + if i is not bi and type(i) is type(bi) and issubclass(i, bi): + self.append(i) + +class BenchmarkRunner(object): + """ Run the benchmarks using the defined interpreters """ + def __init__(self, benchmarkdir): + self.benchmarks = BenchmarkIterator(benchmarkdir, BaseBenchmark) + self.interpreters = InterpreterIterator() + + def run(self): + for bm in self.benchmarks: + print 'Benchmark:', bm.runargs + for interp in self.interpreters: + print interp.executable + i = interp(bm) + i.run() + print 'Time: ', (i.rusage.ru_stime + i.rusage.ru_utime) + +if __name__ == '__main__': + if len(sys.argv) >= 2: + benchmarkdir = sys.argv[1] + else: + benchmarkdir = py.path.local(__file__).dirpath().join('specific') + bmr = BenchmarkRunner(benchmarkdir) + bmr.run() Modified: pypy/build/benchmark/specific/pystone.py ============================================================================== --- pypy/build/benchmark/specific/pystone.py (original) +++ pypy/build/benchmark/specific/pystone.py Thu Sep 10 18:56:58 2009 @@ -1,13 +1,3 @@ +from test import pystone -from benchmark.runner import ScriptRunner - -RUN_PYSTONE = 'from test import pystone; print pystone.pystones()' - -class PystoneRunner(ScriptRunner): - def __init__(self): - ScriptRunner.__init__(self, 'pystone', RUN_PYSTONE) - - def read_output(self, output): - output = output.strip('()\n') - time, pystones = output.split(", ") - return float(time) +print pystone.pystones() Added: pypy/build/benchmark/test/test_interpreters.py ============================================================================== --- (empty file) +++ pypy/build/benchmark/test/test_interpreters.py Thu Sep 10 18:56:58 2009 @@ -0,0 +1,54 @@ +import py, os +from benchmark.interpreters import BaseInterpreter, RUsage + +class FailingInterpreter(BaseInterpreter): + executable = '/bin/false' + +class SuccessfulInterperter(BaseInterpreter): + executable = '/bin/true' + +class EchoInterpreter(BaseInterpreter): + executable = '/bin/echo' + +class FakeScript(object): + def __init__(self, args = []): + self.runargs = args + self.stdout = [] + self.stderr = [] + + def do_stdout(self, data): + self.stdout.append(data) + + def do_stderr(self, data): + self.stderr.append(data) + +class TestInterpreter(object): + + def test_success(self): + s = FakeScript() + bi = SuccessfulInterperter(s) + bi.run() + assert os.WIFEXITED(bi.status) + assert os.WEXITSTATUS(bi.status) == 0 + assert not bi.failed() + + def test_fail(self): + s = FakeScript() + bi = FailingInterpreter(s) + bi.run() + assert os.WIFEXITED(bi.status) + assert os.WEXITSTATUS(bi.status) != 0 + assert bi.failed() + + def test_echo(self): + s = FakeScript(['fake']) + bi = EchoInterpreter(s) + bi.run() + assert s.stdout == ['fake\n', ''] + +class TestRUsage(object): + def test_basic(self): + ru = RUsage(range(16)) + + for k in RUsage._keys: + assert getattr(ru, k) in range(16) Modified: pypy/build/benchmark/test/test_runner.py ============================================================================== --- pypy/build/benchmark/test/test_runner.py (original) +++ pypy/build/benchmark/test/test_runner.py Thu Sep 10 18:56:58 2009 @@ -1,28 +1,38 @@ import py -from benchmark.runner import ScriptRunner, ErrorExecuting, ProgramRunner +from benchmark.runner import BenchmarkIterator, BenchmarkRunner, BaseBenchmark from pypy.tool.udir import udir -class TestRunner(object): - def test_script_runner(self): - runner = ScriptRunner("test1", "print 'time: 0'") - t = runner.run(5) - assert t == [0, 0, 0, 0, 0] - - def test_scipt_runner_float(self): - runner = ScriptRunner("test2", "print 'time: 0.3'") - t = runner.run(5) - assert t == [0.3, 0.3, 0.3, 0.3, 0.3] - - def test_script_runner_fail(self): - runner = ScriptRunner("test3", "import sys; sys.exit(1)") - py.test.raises(ErrorExecuting, runner.run) - - def test_program_runner(self): - tmpdir = udir.join("benchmark_testdir") - tmpdir.ensure(dir=True) - f = tmpdir.join("xxx.py") - f.write("print 'time: 0'") - runner = ProgramRunner("test4", str(f)) - t = runner.run(3) - assert t == [0, 0, 0] +class TestBenchmarkIterator(object): + def setup_class(self): + self.tmpdir = udir.join("iterator_testdir") + self.tmpdir.ensure(dir=True) + for fn in ("a.py", "b.py", "c.py"): + f = self.tmpdir.join(fn) + f.write("print '%s'" % fn) + + def test_iterate(self): + bi = BenchmarkIterator(self.tmpdir, str) + expected = [str(self.tmpdir.join(fn)) + for fn in ("a.py", "b.py", "c.py")] + assert set(bi) == set(expected) + + +class FakeInterpreter(object): + executable = 'Fake' + def __init__(self, script): + self.script = script + + def run(self): + class RUsage(object): + ru_stime = 4.2 + ru_utime = 2.3 + + self.rusage = RUsage() + +class TestBenchmarkRunner(object): + def test_simple(self): + br = BenchmarkRunner('.') + br.benchmarks = [ BaseBenchmark('foo') ] + br.interpreters = [ FakeInterpreter ] + br.run() From cfbolz at codespeak.net Thu Sep 10 19:18:44 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 19:18:44 +0200 (CEST) Subject: [pypy-svn] r67628 - in pypy/branch/spine-of-frames/pypy/jit/metainterp: . test Message-ID: <20090910171844.5D6E0168021@codespeak.net> Author: cfbolz Date: Thu Sep 10 19:18:43 2009 New Revision: 67628 Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/pyjitpl.py pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_recursive.py Log: do things in the other order, to make it possible to call stuff in the leave hook Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/pyjitpl.py Thu Sep 10 19:18:43 2009 @@ -1089,13 +1089,13 @@ def generate_bytecode(self, policy): self._codewriter = codewriter.CodeWriter(self, policy) - self.portal_code = self._codewriter.make_portal_bytecode( - self.portal_graph) self.leave_code = None if self.leave_graph: self.leave_code = self._codewriter.make_one_bytecode( (self.leave_graph, None), False) + self.portal_code = self._codewriter.make_portal_bytecode( + self.portal_graph) self._class_sizes = self._codewriter.class_sizes # ---------- construction-time interface ---------- Modified: pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_recursive.py Thu Sep 10 19:18:43 2009 @@ -384,9 +384,13 @@ def c(code, pc): return "L" not in hlstr(code) - def leave(code, pc, frame): + def really_leave(frame): frame.hookcalled = True + def leave(code, pc, frame): + # use an indirection, because that case was buggy before + really_leave(frame) + class ExpectedHook(Exception): pass class UnexpectedHook(Exception): From afa at codespeak.net Thu Sep 10 19:23:08 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Thu, 10 Sep 2009 19:23:08 +0200 (CEST) Subject: [pypy-svn] r67629 - pypy/branch/windowserror Message-ID: <20090910172308.DFCD6168023@codespeak.net> Author: afa Date: Thu Sep 10 19:23:04 2009 New Revision: 67629 Removed: pypy/branch/windowserror/ Log: Kill merged branch From cfbolz at codespeak.net Thu Sep 10 19:44:24 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 19:44:24 +0200 (CEST) Subject: [pypy-svn] r67630 - pypy/branch/spine-of-frames/pypy/module/pypyjit Message-ID: <20090910174424.5D53E16801E@codespeak.net> Author: cfbolz Date: Thu Sep 10 19:44:23 2009 New Revision: 67630 Modified: pypy/branch/spine-of-frames/pypy/module/pypyjit/interp_jit.py Log: actually add a leave hook in the Python interpreter's JIT driver. Modified: pypy/branch/spine-of-frames/pypy/module/pypyjit/interp_jit.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/pypyjit/interp_jit.py (original) +++ pypy/branch/spine-of-frames/pypy/module/pypyjit/interp_jit.py Thu Sep 10 19:44:23 2009 @@ -51,6 +51,10 @@ name = opcode_method_names[ord(bytecode.co_code[next_instr])] return '%s #%d %s' % (bytecode.get_repr(), next_instr, name) +def leave(next_instr, pycode, frame, ec): + from pypy.interpreter.executioncontext import ExecutionContext + ExecutionContext._jit_rechain_frame(ec, frame) + class PyPyJitDriver(JitDriver): reds = ['frame', 'ec'] greens = ['next_instr', 'pycode'] @@ -65,7 +69,8 @@ ## return (valuestackdepth, blockstack) pypyjitdriver = PyPyJitDriver(can_inline = can_inline, - get_printable_location = get_printable_location) + get_printable_location = get_printable_location, + leave = leave) class __extend__(PyFrame): From cfbolz at codespeak.net Thu Sep 10 19:53:15 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 19:53:15 +0200 (CEST) Subject: [pypy-svn] r67631 - pypy/branch/spine-of-frames/pypy/module/pypyjit Message-ID: <20090910175315.72C7F16801E@codespeak.net> Author: cfbolz Date: Thu Sep 10 19:53:15 2009 New Revision: 67631 Modified: pypy/branch/spine-of-frames/pypy/module/pypyjit/interp_jit.py Log: add comment Modified: pypy/branch/spine-of-frames/pypy/module/pypyjit/interp_jit.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/pypyjit/interp_jit.py (original) +++ pypy/branch/spine-of-frames/pypy/module/pypyjit/interp_jit.py Thu Sep 10 19:53:15 2009 @@ -53,6 +53,8 @@ def leave(next_instr, pycode, frame, ec): from pypy.interpreter.executioncontext import ExecutionContext + # can't use a method here, since this function is seen later than the main + # annotation ExecutionContext._jit_rechain_frame(ec, frame) class PyPyJitDriver(JitDriver): From cfbolz at codespeak.net Thu Sep 10 19:53:59 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 19:53:59 +0200 (CEST) Subject: [pypy-svn] r67632 - pypy/branch/spine-of-frames/pypy/jit/tl Message-ID: <20090910175359.35AA116801E@codespeak.net> Author: cfbolz Date: Thu Sep 10 19:53:58 2009 New Revision: 67632 Modified: pypy/branch/spine-of-frames/pypy/jit/tl/pypyjit_child.py Log: nice feeling of realism Modified: pypy/branch/spine-of-frames/pypy/jit/tl/pypyjit_child.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/tl/pypyjit_child.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/tl/pypyjit_child.py Thu Sep 10 19:53:58 2009 @@ -43,7 +43,7 @@ option.view = True warmspot.jittify_and_run(interp, graph, [], policy=policy, listops=True, CPUClass=LLtypeCPU, - backendopt=True, + backendopt=True, inline=True, optimizer=optimize) From fijal at codespeak.net Thu Sep 10 20:02:03 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 10 Sep 2009 20:02:03 +0200 (CEST) Subject: [pypy-svn] r67633 - pypy/branch/spine-of-frames/pypy/jit/backend Message-ID: <20090910180203.88D8E16801E@codespeak.net> Author: fijal Date: Thu Sep 10 20:02:03 2009 New Revision: 67633 Added: pypy/branch/spine-of-frames/pypy/jit/backend/showstats.py (contents, props changed) Log: A useful script that I happen to have around. Show statistics from log.ops file. Added: pypy/branch/spine-of-frames/pypy/jit/backend/showstats.py ============================================================================== --- (empty file) +++ pypy/branch/spine-of-frames/pypy/jit/backend/showstats.py Thu Sep 10 20:02:03 2009 @@ -0,0 +1,19 @@ +#!/usr/bin/env python +import sys, py +from pypy.jit.metainterp.test.oparser import parse +from pypy.rpython.lltypesystem import lltype, llmemory + +class AllDict(dict): + def __getitem__(self, item): + return lltype.nullptr(llmemory.GCREF.TO) + +alldict = AllDict() + +def main(argv): + lst = py.path.local(argv[0]).read().split("[") + lst = ['[' + i for i in lst if i] + for oplist in lst: + print len(parse(oplist, namespace=alldict).operations) + +if __name__ == '__main__': + main(sys.argv[1:]) From fijal at codespeak.net Thu Sep 10 20:07:03 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 10 Sep 2009 20:07:03 +0200 (CEST) Subject: [pypy-svn] r67634 - pypy/branch/spine-of-frames/pypy/jit/backend Message-ID: <20090910180703.0012C16801E@codespeak.net> Author: fijal Date: Thu Sep 10 20:07:03 2009 New Revision: 67634 Modified: pypy/branch/spine-of-frames/pypy/jit/backend/showstats.py Log: improve a bit Modified: pypy/branch/spine-of-frames/pypy/jit/backend/showstats.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/jit/backend/showstats.py (original) +++ pypy/branch/spine-of-frames/pypy/jit/backend/showstats.py Thu Sep 10 20:07:03 2009 @@ -1,6 +1,7 @@ #!/usr/bin/env python import sys, py from pypy.jit.metainterp.test.oparser import parse +from pypy.jit.metainterp.resoperation import rop from pypy.rpython.lltypesystem import lltype, llmemory class AllDict(dict): @@ -13,7 +14,18 @@ lst = py.path.local(argv[0]).read().split("[") lst = ['[' + i for i in lst if i] for oplist in lst: - print len(parse(oplist, namespace=alldict).operations) + loop = parse(oplist, namespace=alldict) + num_ops = 0 + num_dmp = 0 + num_guards = 0 + for op in loop.operations: + if op.opnum == rop.DEBUG_MERGE_POINT: + num_dmp += 1 + else: + num_ops += 1 + if op.is_guard(): + num_guards += 1 + print "Loop, length: %d, opcodes: %d, guards: %d" % (num_ops, num_dmp, num_guards) if __name__ == '__main__': main(sys.argv[1:]) From cfbolz at codespeak.net Thu Sep 10 20:22:22 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 10 Sep 2009 20:22:22 +0200 (CEST) Subject: [pypy-svn] r67636 - pypy/trunk/pypy/translator/c Message-ID: <20090910182222.6299B16801E@codespeak.net> Author: cfbolz Date: Thu Sep 10 20:22:18 2009 New Revision: 67636 Modified: pypy/trunk/pypy/translator/c/genc.py Log: (fijal): -pg and -fomit-frame-pointer are incompatible, force it to -fno-omit-frame-pointer in case of make profile Modified: pypy/trunk/pypy/translator/c/genc.py ============================================================================== --- pypy/trunk/pypy/translator/c/genc.py (original) +++ pypy/trunk/pypy/translator/c/genc.py Thu Sep 10 20:22:18 2009 @@ -472,7 +472,7 @@ ('linuxmemchk', '', '$(MAKE) CFLAGS="-g -O1 -DRPY_ASSERT -DLINUXMEMCHK" $(TARGET)'), ('llsafer', '', '$(MAKE) CFLAGS="-O2 -DRPY_LL_ASSERT" $(TARGET)'), ('lldebug', '', '$(MAKE) CFLAGS="-g -DRPY_ASSERT -DRPY_LL_ASSERT" $(TARGET)'), - ('profile', '', '$(MAKE) CFLAGS="-g -O1 -pg $(CFLAGS)" LDFLAGS="-pg $(LDFLAGS)" $(TARGET)'), + ('profile', '', '$(MAKE) CFLAGS="-g -O1 -pg $(CFLAGS) -fno-omit-frame-pointer" LDFLAGS="-pg $(LDFLAGS)" $(TARGET)'), ] if self.has_profopt(): rules.append( From antocuni at codespeak.net Thu Sep 10 20:45:24 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 10 Sep 2009 20:45:24 +0200 (CEST) Subject: [pypy-svn] r67637 - pypy/trunk/pypy/jit/backend Message-ID: <20090910184524.EBF5F168029@codespeak.net> Author: antocuni Date: Thu Sep 10 20:45:23 2009 New Revision: 67637 Added: pypy/trunk/pypy/jit/backend/showstats.py - copied unchanged from r67636, pypy/branch/spine-of-frames/pypy/jit/backend/showstats.py Log: copy this script from the spine-of-frames branch From antocuni at codespeak.net Thu Sep 10 21:46:46 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 10 Sep 2009 21:46:46 +0200 (CEST) Subject: [pypy-svn] r67640 - in pypy/trunk/pypy/rpython: . lltypesystem ootypesystem test Message-ID: <20090910194646.9917316801E@codespeak.net> Author: antocuni Date: Thu Sep 10 21:46:45 2009 New Revision: 67640 Modified: pypy/trunk/pypy/rpython/lltypesystem/rclass.py pypy/trunk/pypy/rpython/ootypesystem/rclass.py pypy/trunk/pypy/rpython/rclass.py pypy/trunk/pypy/rpython/test/test_rclass.py Log: xmove the code to handle _immutable_ and _immutable_fields into AbstractInstanceRepr, so that it can be used by both lltype and ootype. Move the tests in the base class too, although one is still failing for ootype. Modified: pypy/trunk/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/rclass.py Thu Sep 10 21:46:45 2009 @@ -8,8 +8,7 @@ AbstractInstanceRepr,\ MissingRTypeAttribute,\ getclassrepr, getinstancerepr,\ - get_type_repr, rtype_new_instance, \ - FieldListAccessor + get_type_repr, rtype_new_instance from pypy.rpython.lltypesystem.lltype import \ Ptr, Struct, GcStruct, malloc, \ cast_pointer, cast_ptr_to_int, castable, nullptr, \ @@ -348,14 +347,7 @@ adtmeths = {} if hints is None: hints = {} - if '_immutable_' in self.classdef.classdesc.classdict: - hints = hints.copy() - hints['immutable'] = True - if '_immutable_fields_' in self.classdef.classdesc.classdict: - hints = hints.copy() - self.immutable_field_list = self.classdef.classdesc.classdict['_immutable_fields_'].value - accessor = FieldListAccessor() - hints['immutable_fields'] = accessor + hints = self._check_for_immutable_hints(hints) if ('_hash_cache_' in fields or '_hash_cache_' in self.rbase.allinstancefields): adtmeths = adtmeths.copy() @@ -374,10 +366,7 @@ attachRuntimeTypeInfo(self.object_type) def _setup_repr_final(self): - hints = self.object_type._hints - if "immutable_fields" in hints: - accessor = hints["immutable_fields"] - self._parse_field_list(self.immutable_field_list, accessor) + AbstractInstanceRepr._setup_repr_final(self) if self.gcflavor == 'gc': if (self.classdef is not None and self.classdef.classdesc.lookup('__del__') is not None): Modified: pypy/trunk/pypy/rpython/ootypesystem/rclass.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/rclass.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/rclass.py Thu Sep 10 21:46:45 2009 @@ -182,9 +182,7 @@ hints = classdef.classdesc.pyobj._rpython_hints else: hints = {} - if '_immutable_' in self.classdef.classdesc.classdict: - hints = hints.copy() - hints['immutable'] = True + hints = self._check_for_immutable_hints(hints) self.lowleveltype = ootype.Instance(classdef.name, b, {}, {}, _hints = hints) self.prebuiltinstances = {} # { id(x): (x, _ptr) } self.object_type = self.lowleveltype @@ -318,7 +316,8 @@ def _setup_repr_final(self): if self.classdef is None: return - + AbstractInstanceRepr._setup_repr_final(self) + # we attach methods here and not in _setup(), because we want # to be sure that all the reprs of the input arguments of all # our methods have been computed at this point Modified: pypy/trunk/pypy/rpython/rclass.py ============================================================================== --- pypy/trunk/pypy/rpython/rclass.py (original) +++ pypy/trunk/pypy/rpython/rclass.py Thu Sep 10 21:46:45 2009 @@ -149,6 +149,17 @@ def _setup_repr(self): pass + def _check_for_immutable_hints(self, hints): + if '_immutable_' in self.classdef.classdesc.classdict: + hints = hints.copy() + hints['immutable'] = True + if '_immutable_fields_' in self.classdef.classdesc.classdict: + hints = hints.copy() + self.immutable_field_list = self.classdef.classdesc.classdict['_immutable_fields_'].value + accessor = FieldListAccessor() + hints['immutable_fields'] = accessor + return hints + def __repr__(self): if self.classdef is None: clsname = 'object' @@ -164,7 +175,10 @@ return 'InstanceR %s' % (clsname,) def _setup_repr_final(self): - pass + hints = self.object_type._hints + if "immutable_fields" in hints: + accessor = hints["immutable_fields"] + self._parse_field_list(self.immutable_field_list, accessor) def _parse_field_list(self, fields, accessor): with_suffix = {} Modified: pypy/trunk/pypy/rpython/test/test_rclass.py ============================================================================== --- pypy/trunk/pypy/rpython/test/test_rclass.py (original) +++ pypy/trunk/pypy/rpython/test/test_rclass.py Thu Sep 10 21:46:45 2009 @@ -700,6 +700,60 @@ assert res == 0 + def test_immutable(self): + class I(object): + _immutable_ = True + + def __init__(self, v): + self.v = v + + i = I(3) + def f(): + return i.v + + t, typer, graph = self.gengraph(f, [], backendopt=True) + assert summary(graph) == {} + + def test_immutable_fields(self): + from pypy.jit.metainterp.typesystem import deref + class A(object): + _immutable_fields_ = ["x", "y[*]"] + + def __init__(self, x, y): + self.x = x + self.y = y + + def f(): + return A(3, []) + t, typer, graph = self.gengraph(f, []) + A_TYPE = deref(graph.getreturnvar().concretetype) + accessor = A_TYPE._hints["immutable_fields"] + assert accessor.fields == {"inst_x" : "", "inst_y" : "[*]"} or \ + accessor.fields == {"ox" : "", "oy" : "[*]"} # for ootype + + def test_immutable_inheritance(self): + if self.type_system == 'ootype': + py.test.skip('fixme!') + class I(object): + def __init__(self, v): + self.v = v + + class J(I): + _immutable_ = True + def __init__(self, v, w): + self.w = w + I.__init__(self, v) + + j = J(3, 4) + def f(): + j.v = j.v * 1 # make the annotator think it is mutated + j.w = j.w * 1 # make the annotator think it is mutated + return j.v + j.w + + t, typer, graph = self.gengraph(f, [], backendopt=True) + assert summary(graph) == {"setfield": 2} + + class TestLltype(BaseTestRclass, LLRtypeMixin): def test__del__(self): @@ -765,55 +819,6 @@ assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] assert destrptra is not None assert destrptrb is not None - - def test_immutable(self): - class I(object): - _immutable_ = True - - def __init__(self, v): - self.v = v - - i = I(3) - def f(): - return i.v - - t, typer, graph = self.gengraph(f, [], backendopt=True) - assert summary(graph) == {} - - def test_immutable_fields(self): - class A(object): - _immutable_fields_ = ["x", "y[*]"] - - def __init__(self, x, y): - self.x = x - self.y = y - - def f(): - return A(3, []) - t, typer, graph = self.gengraph(f, []) - A_TYPE = graph.getreturnvar().concretetype - accessor = A_TYPE.TO._hints["immutable_fields"] - assert accessor.fields == {"inst_x" : "", "inst_y" : "[*]"} - - def test_immutable_inheritance(self): - class I(object): - def __init__(self, v): - self.v = v - - class J(I): - _immutable_ = True - def __init__(self, v, w): - self.w = w - I.__init__(self, v) - - j = J(3, 4) - def f(): - j.v = j.v * 1 # make the annotator think it is mutated - j.w = j.w * 1 # make the annotator think it is mutated - return j.v + j.w - - t, typer, graph = self.gengraph(f, [], backendopt=True) - assert summary(graph) == {"setfield": 2} def test_instance_repr(self): from pypy.rlib.objectmodel import current_object_addr_as_int From antocuni at codespeak.net Thu Sep 10 22:25:15 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 10 Sep 2009 22:25:15 +0200 (CEST) Subject: [pypy-svn] r67641 - in pypy/trunk/pypy/rpython: lltypesystem ootypesystem test Message-ID: <20090910202515.1E466168025@codespeak.net> Author: antocuni Date: Thu Sep 10 22:25:12 2009 New Revision: 67641 Modified: pypy/trunk/pypy/rpython/lltypesystem/lloperation.py pypy/trunk/pypy/rpython/ootypesystem/ooopimpl.py pypy/trunk/pypy/rpython/test/test_rclass.py Log: make it possible to constant-fold an oogetfield on an immutable instance. This makes test_immutable_inheritance passing Modified: pypy/trunk/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/lloperation.py Thu Sep 10 22:25:12 2009 @@ -482,7 +482,7 @@ 'oonewcustomdict': LLOp(oo=True, canraise=(MemoryError,)), 'oonewarray': LLOp(oo=True, canraise=(MemoryError,)), 'oosetfield': LLOp(oo=True), - 'oogetfield': LLOp(oo=True, sideeffects=False), + 'oogetfield': LLOp(oo=True, sideeffects=False, canrun=True), 'oosend': LLOp(oo=True, canraise=(Exception,)), 'ooupcast': LLOp(oo=True, canfold=True), 'oodowncast': LLOp(oo=True, canfold=True), Modified: pypy/trunk/pypy/rpython/ootypesystem/ooopimpl.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/ooopimpl.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/ooopimpl.py Thu Sep 10 22:25:12 2009 @@ -51,6 +51,11 @@ def op_subclassof(class1, class2): return ootype.subclassof(class1, class2) +def op_oogetfield(inst, name): + checkinst(inst) + if not ootype.typeOf(inst)._hints.get('immutable'): + raise TypeError("cannot fold oogetfield on mutable instance") + return getattr(inst, name) def is_inst(inst): T = ootype.typeOf(inst) Modified: pypy/trunk/pypy/rpython/test/test_rclass.py ============================================================================== --- pypy/trunk/pypy/rpython/test/test_rclass.py (original) +++ pypy/trunk/pypy/rpython/test/test_rclass.py Thu Sep 10 22:25:12 2009 @@ -732,8 +732,6 @@ accessor.fields == {"ox" : "", "oy" : "[*]"} # for ootype def test_immutable_inheritance(self): - if self.type_system == 'ootype': - py.test.skip('fixme!') class I(object): def __init__(self, v): self.v = v @@ -751,7 +749,9 @@ return j.v + j.w t, typer, graph = self.gengraph(f, [], backendopt=True) - assert summary(graph) == {"setfield": 2} + f_summary = summary(graph) + assert f_summary == {"setfield": 2} or \ + f_summary == {"oosetfield": 2} # for ootype class TestLltype(BaseTestRclass, LLRtypeMixin): From antocuni at codespeak.net Thu Sep 10 22:26:24 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 10 Sep 2009 22:26:24 +0200 (CEST) Subject: [pypy-svn] r67642 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090910202624.40D76168023@codespeak.net> Author: antocuni Date: Thu Sep 10 22:26:23 2009 New Revision: 67642 Modified: pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py Log: thanks to r6764{0,1}, the immutable_fields tests pass also on ootype now Modified: pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py Thu Sep 10 22:26:23 2009 @@ -57,6 +57,5 @@ class TestLLtypeImmutableFieldsTests(ImmutableFieldsTests, LLJitMixin): pass -# XXX implement -# class TestOOtypeImmutableFieldsTests(ImmutableFieldsTests, OOJitMixin): -# pass +class TestOOtypeImmutableFieldsTests(ImmutableFieldsTests, OOJitMixin): + pass From antocuni at codespeak.net Fri Sep 11 10:46:08 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 11 Sep 2009 10:46:08 +0200 (CEST) Subject: [pypy-svn] r67646 - pypy/trunk/pypy/jit/backend/cli/test Message-ID: <20090911084608.D9DB4168024@codespeak.net> Author: antocuni Date: Fri Sep 11 10:46:06 2009 New Revision: 67646 Modified: pypy/trunk/pypy/jit/backend/cli/test/test_zrpy_basic.py Log: fix cli jit tests that were broken due to the optimizer change Modified: pypy/trunk/pypy/jit/backend/cli/test/test_zrpy_basic.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/test/test_zrpy_basic.py (original) +++ pypy/trunk/pypy/jit/backend/cli/test/test_zrpy_basic.py Fri Sep 11 10:46:06 2009 @@ -7,8 +7,8 @@ CPUClass = CliCPU def meta_interp(self, *args, **kwds): - from pypy.jit.metainterp import simple_optimize - kwds['optimizer'] = simple_optimize + from pypy.rlib.jit import OPTIMIZER_SIMPLE + kwds['optimizer'] = OPTIMIZER_SIMPLE return CliCompiledMixin.meta_interp(self, *args, **kwds) From pedronis at codespeak.net Fri Sep 11 10:59:37 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Sep 2009 10:59:37 +0200 (CEST) Subject: [pypy-svn] r67647 - pypy/trunk/pypy/jit/backend/test Message-ID: <20090911085937.3D64E168026@codespeak.net> Author: pedronis Date: Fri Sep 11 10:59:36 2009 New Revision: 67647 Modified: pypy/trunk/pypy/jit/backend/test/support.py Log: start fixing some agressive_inlining originated breakage Modified: pypy/trunk/pypy/jit/backend/test/support.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/support.py (original) +++ pypy/trunk/pypy/jit/backend/test/support.py Fri Sep 11 10:59:36 2009 @@ -1,4 +1,5 @@ import py +import sys from pypy.jit.metainterp.history import log from pypy.translator.translator import TranslationContext @@ -15,7 +16,7 @@ raise NotImplementedError # XXX backendopt is ignored - def meta_interp(self, function, args, repeat=1, backendopt=None, **kwds): # XXX ignored + def meta_interp(self, function, args, repeat=1, inline=False, trace_limit=sys.maxint, backendopt=None, **kwds): # XXX ignored from pypy.jit.metainterp.warmspot import WarmRunnerDesc from pypy.annotation.listdef import s_list_of_strings from pypy.annotation import model as annmodel @@ -52,6 +53,8 @@ **kwds) warmrunnerdesc.state.set_param_threshold(3) # for tests warmrunnerdesc.state.set_param_trace_eagerness(2) # for tests + warmrunnerdesc.state.set_param_trace_limit(trace_limit) + warmrunnerdesc.state.set_param_inlining(inline) mixlevelann = warmrunnerdesc.annhelper entry_point_graph = mixlevelann.getgraph(entry_point, [s_list_of_strings], annmodel.SomeInteger()) From afa at codespeak.net Fri Sep 11 11:00:27 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Fri, 11 Sep 2009 11:00:27 +0200 (CEST) Subject: [pypy-svn] r67648 - in pypy/trunk/pypy/lib: _ctypes app_test/ctypes_tests Message-ID: <20090911090027.4124D168026@codespeak.net> Author: afa Date: Fri Sep 11 11:00:26 2009 New Revision: 67648 Modified: pypy/trunk/pypy/lib/_ctypes/structure.py pypy/trunk/pypy/lib/app_test/ctypes_tests/test_structures.py Log: ctypes.Structure.__getattr__ calls hasattr which calls __getattr___... The recursion limit was hit every time a structure is created. Modified: pypy/trunk/pypy/lib/_ctypes/structure.py ============================================================================== --- pypy/trunk/pypy/lib/_ctypes/structure.py (original) +++ pypy/trunk/pypy/lib/_ctypes/structure.py Fri Sep 11 11:00:26 2009 @@ -79,8 +79,9 @@ tp._fficompositesize = tp._ffistruct.size def struct_getattr(self, name): - if hasattr(self, '_fieldtypes') and name in self._fieldtypes: - return self._fieldtypes[name] + if name not in ('_fields_', '_fieldtypes'): + if hasattr(self, '_fieldtypes') and name in self._fieldtypes: + return self._fieldtypes[name] return _CDataMeta.__getattribute__(self, name) def struct_setattr(self, name, value): Modified: pypy/trunk/pypy/lib/app_test/ctypes_tests/test_structures.py ============================================================================== --- pypy/trunk/pypy/lib/app_test/ctypes_tests/test_structures.py (original) +++ pypy/trunk/pypy/lib/app_test/ctypes_tests/test_structures.py Fri Sep 11 11:00:26 2009 @@ -392,6 +392,27 @@ x.other = 42 assert x.other == 42 + def test_getattr_recursion(self): + # Structure.__getattr__ used to call itself recursively + # and hit the recursion limit. + import sys + events = [] + + def tracefunc(frame, event, arg): + funcname = frame.f_code.co_name + if 'getattr' in funcname: + events.append(funcname) + + oldtrace = sys.settrace(tracefunc) + try: + class X(Structure): + _fields_ = [("a", c_int)] + + assert len(events) < 20 + finally: + sys.settrace(oldtrace) + events = None + class TestPointerMember(BaseCTypesTestChecker): def test_1(self): From pedronis at codespeak.net Fri Sep 11 11:19:04 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Sep 2009 11:19:04 +0200 (CEST) Subject: [pypy-svn] r67649 - in pypy/trunk/pypy/jit: backend/test metainterp/test Message-ID: <20090911091904.E0B80168024@codespeak.net> Author: pedronis Date: Fri Sep 11 11:19:04 2009 New Revision: 67649 Modified: pypy/trunk/pypy/jit/backend/test/support.py pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Log: fix more indirect breakage from the agressive_inlining merge (the z tests are evil) Modified: pypy/trunk/pypy/jit/backend/test/support.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/support.py (original) +++ pypy/trunk/pypy/jit/backend/test/support.py Fri Sep 11 11:19:04 2009 @@ -76,6 +76,12 @@ def check_enter_count_at_most(self, *args, **kwds): pass + def check_max_trace_length(self, *args, **kwds): + pass + + def check_aborted_count(self, *args, **kwds): + pass + def interp_operations(self, *args, **kwds): py.test.skip("interp_operations test skipped") Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Fri Sep 11 11:19:04 2009 @@ -343,6 +343,7 @@ if n < 50: n = recursive(n) n -= 1 + return n TRACE_LIMIT = 20 res = self.meta_interp(loop, [100], optimizer=OPTIMIZER_SIMPLE, inline=True, trace_limit=TRACE_LIMIT) self.check_max_trace_length(TRACE_LIMIT) From cfbolz at codespeak.net Fri Sep 11 11:41:41 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 11 Sep 2009 11:41:41 +0200 (CEST) Subject: [pypy-svn] r67650 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090911094141.E06B2168024@codespeak.net> Author: cfbolz Date: Fri Sep 11 11:41:40 2009 New Revision: 67650 Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py Log: Tiny optimization: when we read from a non-standard virtualizable and figure out that it really _is_ the standard one, remember this information. Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Fri Sep 11 11:41:40 2009 @@ -518,7 +518,10 @@ eqbox = self.metainterp.execute_and_record(rop.OOIS, [box, standard_box]) eqbox = self.implement_guard_value(pc, eqbox) - return not eqbox.getint() + result = not eqbox.getint() + if not result: + self.metainterp.replace_box(box, standard_box) + return result def _get_virtualizable_field_descr(self, index): vinfo = self.metainterp.staticdata.virtualizable_info Modified: pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py Fri Sep 11 11:41:40 2009 @@ -826,6 +826,40 @@ assert res == 55 self.check_loops(new_with_vtable=0) + def test_check_for_nonstandardness_only_once(self): + myjitdriver = JitDriver(greens = [], reds = ['frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['x', 'y', 'z'] + + def __init__(self, x, y, z=1): + self = hint(self, access_directly=True) + self.x = x + self.y = y + self.z = z + + class SomewhereElse: + pass + somewhere_else = SomewhereElse() + + def f(n): + frame = Frame(n, 0) + somewhere_else.top_frame = frame # escapes + frame = hint(frame, access_directly=True) + while frame.x > 0: + myjitdriver.can_enter_jit(frame=frame) + myjitdriver.jit_merge_point(frame=frame) + top_frame = somewhere_else.top_frame + child_frame = Frame(frame.x, top_frame.z, 17) + frame.y += child_frame.x + frame.x -= top_frame.z + return somewhere_else.top_frame.y + + res = self.meta_interp(f, [10]) + assert res == 55 + self.check_loops(new_with_vtable=0, oois=1) + def test_virtual_child_frame_with_arrays(self): myjitdriver = JitDriver(greens = [], reds = ['frame'], virtualizables = ['frame']) From cfbolz at codespeak.net Fri Sep 11 11:45:59 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 11 Sep 2009 11:45:59 +0200 (CEST) Subject: [pypy-svn] r67651 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090911094559.7F9BF168024@codespeak.net> Author: cfbolz Date: Fri Sep 11 11:45:59 2009 New Revision: 67651 Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: replace double-not Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Fri Sep 11 11:45:59 2009 @@ -518,10 +518,10 @@ eqbox = self.metainterp.execute_and_record(rop.OOIS, [box, standard_box]) eqbox = self.implement_guard_value(pc, eqbox) - result = not eqbox.getint() - if not result: + isstandard = eqbox.getint() + if isstandard: self.metainterp.replace_box(box, standard_box) - return result + return not isstandard def _get_virtualizable_field_descr(self, index): vinfo = self.metainterp.staticdata.virtualizable_info From cfbolz at codespeak.net Fri Sep 11 16:28:18 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 11 Sep 2009 16:28:18 +0200 (CEST) Subject: [pypy-svn] r67654 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090911142818.4D5D4168024@codespeak.net> Author: cfbolz Date: Fri Sep 11 16:28:16 2009 New Revision: 67654 Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Log: the Next Bug (TM): When blackholing in the presence of inlining, if an exception is raised by the portal, it has been ignored so far. Fix this. Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Fri Sep 11 16:28:16 2009 @@ -836,7 +836,13 @@ portal_code = self.metainterp.staticdata.portal_code # small hack: fish for the result box lenenv = len(self.env) - self.perform_call(portal_code, varargs) + raised = self.perform_call(portal_code, varargs) + # in general this cannot be assumed, but when blackholing, + # perform_call returns True only if an exception is called. In + # this case perform_call has called finishframe_exception + # already, so we need to return. + if raised: + return True if lenenv == len(self.env): res = None else: Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Fri Sep 11 16:28:16 2009 @@ -212,6 +212,50 @@ res = self.meta_interp(main, [100], optimizer=OPTIMIZER_SIMPLE, inline=True) assert res == 0 + def test_guard_failure_and_then_exception_in_inlined_function(self): + from pypy.rpython.annlowlevel import hlstr + def p(code, pc): + code = hlstr(code) + return "%s %d %s" % (code, pc, code[pc]) + def c(code, pc): + return "l" not in hlstr(code) + myjitdriver = JitDriver(greens=['code', 'pc'], reds=['n', 'flag'], + get_printable_location=p, can_inline=c) + def f(code, n): + pc = 0 + flag = False + while pc < len(code): + + myjitdriver.jit_merge_point(n=n, code=code, pc=pc, flag=flag) + op = code[pc] + if op == "-": + n -= 1 + elif op == "c": + try: + n = f("---ir---", n) + except Exception: + return n + elif op == "i": + if n < 200: + flag = True + elif op == "r": + if flag: + raise Exception + elif op == "l": + if n > 0: + myjitdriver.can_enter_jit(n=n, code=code, pc=0, flag=flag) + pc = 0 + continue + else: + assert 0 + pc += 1 + return n + def main(n): + return f("c-l", n) + print main(1000) + res = self.meta_interp(main, [1000], optimizer=OPTIMIZER_SIMPLE, inline=True) + assert res == main(1000) + def test_exception_in_inlined_function(self): from pypy.rpython.annlowlevel import hlstr def p(code, pc): From cfbolz at codespeak.net Fri Sep 11 19:09:10 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 11 Sep 2009 19:09:10 +0200 (CEST) Subject: [pypy-svn] r67655 - pypy/trunk/pypy/objspace/std Message-ID: <20090911170910.5E91C168021@codespeak.net> Author: cfbolz Date: Fri Sep 11 19:09:09 2009 New Revision: 67655 Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py Log: Make object creation a bit (but not much) more JIT-friendly. Still does not allow it to have virtual objects, because of the resizable list. Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/dictmultiobject.py (original) +++ pypy/trunk/pypy/objspace/std/dictmultiobject.py Fri Sep 11 19:09:09 2009 @@ -710,15 +710,27 @@ return new_structure def lookup_position(self, key): - # jit helper - self = hint(self, promote=True) - key = hint(key, promote=True) - return _lookup_position_shared(self, key) + # jit helper + self = hint(self, promote=True) + key = hint(key, promote=True) + return _lookup_position_shared(self, key) + + def get_next_structure(self, key): + # jit helper + self = hint(self, promote=True) + key = hint(key, promote=True) + return _get_next_structure_shared(self, key) @purefunction def _lookup_position_shared(self, key): return self.keys.get(key, -1) + at purefunction +def _get_next_structure_shared(self, key): + new_structure = self.other_structs.get(key) + if new_structure is None: + new_structure = self.new_structure(key) + return new_structure class State(object): def __init__(self, space): @@ -759,9 +771,7 @@ if i != -1: self.entries[i] = w_value return self - new_structure = self.structure.other_structs.get(key) - if new_structure is None: - new_structure = self.structure.new_structure(key) + new_structure = self.structure.get_next_structure(key) self.entries.append(w_value) assert self.structure.length + 1 == new_structure.length self.structure = new_structure From pedronis at codespeak.net Sat Sep 12 11:44:48 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 12 Sep 2009 11:44:48 +0200 (CEST) Subject: [pypy-svn] r67657 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090912094448.10C17168021@codespeak.net> Author: pedronis Date: Sat Sep 12 11:44:47 2009 New Revision: 67657 Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Log: this was debugging print and made the x86 zrpy variant unhappy Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Sat Sep 12 11:44:47 2009 @@ -322,7 +322,6 @@ n -= 1 elif op == "c": if n < 70 and n % 3 == 1: - print "F" n = f("--", n) elif op == "l": if n > 0: From arigo at codespeak.net Sat Sep 12 20:23:59 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 12 Sep 2009 20:23:59 +0200 (CEST) Subject: [pypy-svn] r67658 - in pypy/trunk/pypy/translator/c/gcc: . test Message-ID: <20090912182359.C3D7C16800E@codespeak.net> Author: arigo Date: Sat Sep 12 20:23:58 2009 New Revision: 67658 Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Log: Prevent the 'gcmap' symbols added after most CALLs to get in the way of debugging. This is done with an obscure hack described in the source. Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py Sat Sep 12 20:23:58 2009 @@ -8,6 +8,7 @@ from pypy.translator.c.gcc.trackgcroot import FunctionGcRootTracker from pypy.translator.c.gcc.trackgcroot import compress_callshape from pypy.translator.c.gcc.trackgcroot import decompress_callshape +from pypy.translator.c.gcc.trackgcroot import OFFSET_LABELS from StringIO import StringIO this_dir = py.path.local(__file__).dirpath() @@ -119,7 +120,7 @@ for format, _, path in tests: yield check_computegcmaptable, format, path -r_globallabel = re.compile(r"([\w]+)[:]") +r_globallabel = re.compile(r"([\w]+)=[.]+") r_expected = re.compile(r"\s*;;\s*expected\s+([{].+[}])") def check_computegcmaptable(format, path): @@ -148,7 +149,7 @@ assert format_callshape(got) == expected seen[label] = True expectedlines.insert(i-2, '\t.globl\t%s\n' % (label,)) - expectedlines.insert(i-1, '%s:\n' % (label,)) + expectedlines.insert(i-1, '%s=.+%d\n' % (label, OFFSET_LABELS)) prevline = line assert len(seen) == len(tabledict), ( "computed table contains unexpected entries:\n%r" % Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Sat Sep 12 20:23:58 2009 @@ -22,10 +22,13 @@ r_sectionstart = re.compile(r"\t\.("+'|'.join(OTHERSECTIONS)+").*$") r_functionstart_darwin = re.compile(r"_(\w+):\s*$") +OFFSET_LABELS = 2**30 + # inside functions LABEL = r'([.]?[\w$@]+)' r_label = re.compile(LABEL+"[:]\s*$") r_globl = re.compile(r"\t[.]globl\t(\w+)\s*$") +r_globllabel = re.compile(LABEL+r"=[.][+]%d\s*$"%OFFSET_LABELS) r_insn = re.compile(r"\t([a-z]\w*)\s") r_jump = re.compile(r"\tj\w+\s+"+LABEL+"\s*$") OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])' @@ -133,7 +136,7 @@ shapeofs += len(bytes) if is_range: n = ~ n - print >> output, '\t.long\t%s' % (label,) + print >> output, '\t.long\t%s-%d' % (label, OFFSET_LABELS) print >> output, '\t.long\t%d' % (n,) _globl('__gcmapend') _label('__gcmapend') @@ -487,7 +490,7 @@ match = r_globl.match(self.lines[call.lineno+1]) if match: label1 = match.group(1) - match = r_label.match(self.lines[call.lineno+2]) + match = r_globllabel.match(self.lines[call.lineno+2]) if match: label2 = match.group(1) if label1 == label2: @@ -500,7 +503,13 @@ break k += 1 self.labels[label] = None - self.lines.insert(call.lineno+1, '%s:\n' % (label,)) + # These global symbols are not directly labels pointing to the + # code location because such global labels in the middle of + # functions confuse gdb. Instead, we add to the global symbol's + # value a big constant, which is subtracted again when we need + # the original value for gcmaptable.s. That's a hack. + self.lines.insert(call.lineno+1, '%s=.+%d\n' % (label, + OFFSET_LABELS)) self.lines.insert(call.lineno+1, '\t.globl\t%s\n' % (label,)) call.global_label = label From arigo at codespeak.net Sat Sep 12 20:36:50 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 12 Sep 2009 20:36:50 +0200 (CEST) Subject: [pypy-svn] r67659 - pypy/trunk/pypy/translator/goal Message-ID: <20090912183650.AC06C168010@codespeak.net> Author: arigo Date: Sat Sep 12 20:36:49 2009 New Revision: 67659 Modified: pypy/trunk/pypy/translator/goal/translate.py Log: Add a hack: don't force --pyjitpl when we specify explicitly --annotate or --rtype together with the -Ojit optimization level. Modified: pypy/trunk/pypy/translator/goal/translate.py ============================================================================== --- pypy/trunk/pypy/translator/goal/translate.py (original) +++ pypy/trunk/pypy/translator/goal/translate.py Sat Sep 12 20:36:49 2009 @@ -261,7 +261,9 @@ if config.translation.jit: if 'jitpolicy' not in targetspec_dic: raise Exception('target has no jitpolicy defined.') - drv.set_extra_goals(['pyjitpl']) + if (translateconfig.goals != ['annotate'] and + translateconfig.goals != ['rtype']): + drv.set_extra_goals(['pyjitpl']) log_config(config.translation, "translation configuration") pdb_plus_show.expose({'drv': drv, 'prof': prof}) From arigo at codespeak.net Sat Sep 12 20:38:29 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 12 Sep 2009 20:38:29 +0200 (CEST) Subject: [pypy-svn] r67660 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090912183829.4FA3A16800E@codespeak.net> Author: arigo Date: Sat Sep 12 20:38:28 2009 New Revision: 67660 Modified: pypy/trunk/pypy/jit/backend/x86/runner.py Log: Kill old code. Modified: pypy/trunk/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/runner.py (original) +++ pypy/trunk/pypy/jit/backend/x86/runner.py Sat Sep 12 20:38:28 2009 @@ -25,7 +25,6 @@ self._bootstrap_cache = {} self._guard_list = [] self.setup() - self.caught_exception = None if rtyper is not None: # for tests self.lltype2vtable = rtyper.lltype_to_vtable_mapping() @@ -57,7 +56,6 @@ assert isinstance(verbose, bool) func = self.get_bootstrap_code(loop) guard_index = self.execute_call(loop, func, verbose) - self._guard_index = guard_index # for tests op = self._guard_list[guard_index] if verbose: print "Leaving at: %d" % self.assembler.fail_boxes_int[ @@ -90,31 +88,17 @@ LLInterpreter.current_interpreter = self.debug_ll_interpreter res = 0 try: - self.caught_exception = None if verbose: print "Entering: %d" % rffi.cast(lltype.Signed, func) #llop.debug_print(lltype.Void, ">>>> Entering", # rffi.cast(lltype.Signed, func)) res = func() #llop.debug_print(lltype.Void, "<<<< Back") - self.reraise_caught_exception() finally: if not self.translate_support_code: LLInterpreter.current_interpreter = prev_interpreter return res - def reraise_caught_exception(self): - # this helper is in its own function so that the call to it - # shows up in traceback -- useful to avoid confusing tracebacks, - # which are typical when using the 3-arguments raise. - if self.caught_exception is not None: - if not we_are_translated(): - exc, val, tb = self.caught_exception - raise exc, val, tb - else: - exc = self.caught_exception - raise exc - def make_guard_index(self, guard_op): index = len(self._guard_list) self._guard_list.append(guard_op) From benjamin at codespeak.net Sat Sep 12 20:39:12 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Sat, 12 Sep 2009 20:39:12 +0200 (CEST) Subject: [pypy-svn] r67661 - pypy/trunk/pypy/module/__builtin__ Message-ID: <20090912183912.78A6616800E@codespeak.net> Author: benjamin Date: Sat Sep 12 20:39:11 2009 New Revision: 67661 Modified: pypy/trunk/pypy/module/__builtin__/__init__.py Log: kill pickle support hook which isn't used Modified: pypy/trunk/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/__init__.py (original) +++ pypy/trunk/pypy/module/__builtin__/__init__.py Sat Sep 12 20:39:11 2009 @@ -141,14 +141,6 @@ self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) for i, name in enumerate(OPTIMIZED_BUILTINS): self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) - # call installations for pickle support - for name in self.loaders.keys(): - if name.startswith('_install_pickle_support_for_'): - w_install = self.get(name) - space.call_function(w_install) - # xxx hide the installer - space.delitem(self.w_dict, space.wrap(name)) - del self.loaders[name] # install the more general version of isinstance() & co. in the space from pypy.module.__builtin__ import abstractinst as ab space.abstract_isinstance_w = ab.abstract_isinstance_w.__get__(space) From benjamin at codespeak.net Sat Sep 12 20:40:34 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Sat, 12 Sep 2009 20:40:34 +0200 (CEST) Subject: [pypy-svn] r67662 - pypy/trunk/pypy/module/__builtin__/test Message-ID: <20090912184034.9D1F516800E@codespeak.net> Author: benjamin Date: Sat Sep 12 20:40:34 2009 New Revision: 67662 Modified: pypy/trunk/pypy/module/__builtin__/test/test_minmax.py Log: two tests that work Modified: pypy/trunk/pypy/module/__builtin__/test/test_minmax.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/test/test_minmax.py (original) +++ pypy/trunk/pypy/module/__builtin__/test/test_minmax.py Sat Sep 12 20:40:34 2009 @@ -21,10 +21,9 @@ def test_min_strings(self): assert min('aaa', 'bbb', 'c') == 'aaa' - # write an imaginary test when we have complex numbers - - # XXX we have no mixed comparison operator yet on StdObjSpace - def _test_min_mixed(self): + # write an imaginary test when we have complex numbers + + def test_min_mixed(self): assert min('1', 2, 3, 'aa') == 2 def test_min_noargs(self): @@ -55,9 +54,8 @@ assert max('aaa', 'bbb', 'c') == 'c' # write an imaginary test when we have complex numbers - - # XXX we have no mixed comparison operator yet on StdObjSpace - def _test_max_mixed(self): + + def test_max_mixed(self): assert max('1', 2, 3, 'aa') == 'aa' def test_max_noargs(self): From benjamin at codespeak.net Sat Sep 12 20:48:54 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Sat, 12 Sep 2009 20:48:54 +0200 (CEST) Subject: [pypy-svn] r67663 - pypy/trunk/pypy/module/__builtin__/test Message-ID: <20090912184854.6885316800E@codespeak.net> Author: benjamin Date: Sat Sep 12 20:48:54 2009 New Revision: 67663 Modified: pypy/trunk/pypy/module/__builtin__/test/test_minmax.py Log: remove very old XXXy comments Modified: pypy/trunk/pypy/module/__builtin__/test/test_minmax.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/test/test_minmax.py (original) +++ pypy/trunk/pypy/module/__builtin__/test/test_minmax.py Sat Sep 12 20:48:54 2009 @@ -11,18 +11,12 @@ def test_min_floats(self): assert min(0.1, 2.7, 14.7) == 0.1 - # write fixed point if that becomes a type. - def test_min_chars(self): assert min('a', 'b', 'c') == 'a' - # write a unicode test when unicode works. - def test_min_strings(self): assert min('aaa', 'bbb', 'c') == 'aaa' - # write an imaginary test when we have complex numbers - def test_min_mixed(self): assert min('1', 2, 3, 'aa') == 2 @@ -43,18 +37,12 @@ def test_max_floats(self): assert max(0.1, 2.7, 14.7) == 14.7 - # write fixed point if that becomes a type. - def test_max_chars(self): assert max('a', 'b', 'c') == 'c' - # write a unicode test when unicode works. - def test_max_strings(self): assert max('aaa', 'bbb', 'c') == 'c' - # write an imaginary test when we have complex numbers - def test_max_mixed(self): assert max('1', 2, 3, 'aa') == 'aa' From magcius at codespeak.net Sun Sep 13 01:17:37 2009 From: magcius at codespeak.net (magcius at codespeak.net) Date: Sun, 13 Sep 2009 01:17:37 +0200 (CEST) Subject: [pypy-svn] r67664 - in pypy/branch/avm/pypy/translator: avm1 avm2 Message-ID: <20090912231737.79E77168014@codespeak.net> Author: magcius Date: Sun Sep 13 01:17:35 2009 New Revision: 67664 Removed: pypy/branch/avm/pypy/translator/avm1/node.py Modified: pypy/branch/avm/pypy/translator/avm2/avm2gen.py pypy/branch/avm/pypy/translator/avm2/constants.py pypy/branch/avm/pypy/translator/avm2/instructions.py Log: New stuff Modified: pypy/branch/avm/pypy/translator/avm2/avm2gen.py ============================================================================== --- pypy/branch/avm/pypy/translator/avm2/avm2gen.py (original) +++ pypy/branch/avm/pypy/translator/avm2/avm2gen.py Sun Sep 13 01:17:35 2009 @@ -64,17 +64,29 @@ push_constant(self.db, v.concretetype, v.value, self) else: self.push_const(v) + + def call_oostring(self, OOTYPE): + str_qname = constants.QName("String") + self.I(instructions.findpropstrict(str_qname)) + self.I(instructions.swap()) + self.I(instructions.callproperty(str_qname, 1)) + + call_oounicode = call_oostring + + def oonewarray(self, TYPE, length=1): + arr_qname = constants.QName("Array") + self.I(instructions.findpropstrict(arr_qname)) + self.push_const(length) + self.I(instructions.callproperty(arr_qname, 1)) def push_this(self): self.I(instructions.getlocal(0)) - - def push_arg(self, v): - assert v.name in self.registers - self.push_local(v) def push_local(self, v): self.push_var(v.name) + push_arg = push_local + def push_var(self, v): assert v in self.registers self.I(instructions.getlocal(self.registers.find(v))) Modified: pypy/branch/avm/pypy/translator/avm2/constants.py ============================================================================== --- pypy/branch/avm/pypy/translator/avm2/constants.py (original) +++ pypy/branch/avm/pypy/translator/avm2/constants.py Sun Sep 13 01:17:35 2009 @@ -90,18 +90,19 @@ TYPE_NAMESPACE_SET_NamespaceSet = 0x15 # Multiname types -TYPE_MULTINAME_QName = 0x07 -TYPE_MULTINAME_QNameA = 0x0D -TYPE_MULTINAME_Multiname = 0x09 -TYPE_MULTINAME_MultinameA = 0x0E -TYPE_MULTINAME_RtqName = 0x0F -TYPE_MULTINAME_RtqNameA = 0x10 -TYPE_MULTINAME_RtqNameL = 0x11 -TYPE_MULTINAME_RtqNameLA = 0x12 -TYPE_MULTINAME_NameL = 0x13 -TYPE_MULTINAME_NameLA = 0x14 -TYPE_MULTINAME_MultinameL = 0x1B -TYPE_MULTINAME_MultinameLA = 0x1C +TYPE_MULTINAME_QName = 0x07 # o.ns::name - fully resolved at compile-time +TYPE_MULTINAME_QNameA = 0x0D # o. at ns::name +TYPE_MULTINAME_Multiname = 0x09 # o.name - uses an nsset to resolve at runtime +TYPE_MULTINAME_MultinameA = 0x0E # o. at name +TYPE_MULTINAME_RtqName = 0x0F # o.ns::name - namespace on stack +TYPE_MULTINAME_RtqNameA = 0x10 # o. at ns::name +TYPE_MULTINAME_RtqNameL = 0x11 # o.ns::[name] - namespace and name on stack +TYPE_MULTINAME_RtqNameLA = 0x12 # o. at ns::name +TYPE_MULTINAME_NameL = 0x13 # o.[name] - implied public namespace, name on stack +TYPE_MULTINAME_NameLA = 0x14 # o.@[name] +TYPE_MULTINAME_MultinameL = 0x1B # o.[name] - +TYPE_MULTINAME_MultinameLA = 0x1C # o.@[name] +TYPE_MULTINAME_TypeName = 0x16 # o.ns::name. - used to implement Vector def py_to_abc(value, pool): if value is True: @@ -166,7 +167,7 @@ return hash(tuple(self.namespaces)) def __eq__(self, other): - return len(self) == len(other) and all(n1 == n2 for n1, n2 in zip(self.namespaces, other.namespaces)) + return self.namespaces == other.namespaces def __ne__(self, other): return not self == other @@ -199,13 +200,13 @@ self._ns_set_index = None def __eq__(self, other): - return self.kind == other.kind and self.ns_set == other.ns_set + return self.KIND == other.KIND and self.ns_set == other.ns_set def __ne__(self, other): return not self == other def __hash__(self): - return hash((self.kind, self.ns_set)) + return hash((self.KIND, self.ns_set)) def write_to_pool(self, pool): self._ns_set_index = pool.nsset_pool.index_for(self.ns_set) @@ -226,13 +227,13 @@ self._name_index = None def __eq__(self, other): - return self.kind == other.kind and self.name == other.name + return self.KIND == other.KIND and self.name == other.name def __ne__(self, other): return not self == other def __hash__(self): - return hash((self.kind, self.name)) + return hash((self.KIND, self.name)) def write_to_pool(self, pool): super(Multiname, self).write_to_pool(pool) @@ -245,7 +246,7 @@ def serialize(self): assert self._name_index is not None, "Please call write_to_pool before serializing" assert self._ns_set_index is not None, "Please call write_to_pool before serializing" - return chr(self.kind) + u32(self._name_index) + u32(self._ns_set_index) + return chr(self.KIND) + u32(self._name_index) + u32(self._ns_set_index) class MultinameA(Multiname): KIND = TYPE_MULTINAME_MultinameA @@ -254,7 +255,7 @@ class QName(object): KIND = TYPE_MULTINAME_QName - def __init__(self, name, ns): + def __init__(self, name, ns=None): self.name = name self.ns = ns @@ -262,13 +263,13 @@ self._ns_index = None def __eq__(self, other): - return self.kind == other.kind and self.name == other.name and self.ns == other.ns + return self.KIND == other.KIND and self.name == other.name and self.ns == other.ns def __ne__(self, other): return not self == other def __hash__(self): - return hash((self.kind, self.name, self.ns)) + return hash((self.KIND, self.name, self.ns)) def write_to_pool(self, pool): assert self.name != "" @@ -281,7 +282,7 @@ def serialize(self): assert self._name_index is not None, "Please call write_to_pool before serializing" assert self._ns_index is not None, "Please call write_to_pool before serializing" - return chr(self.kind) + u32(self._ns_index) + u32(self._name_index) + return chr(self.KIND) + u32(self._ns_index) + u32(self._name_index) class QNameA(QName): KIND = TYPE_MULTINAME_QNameA @@ -290,16 +291,19 @@ KIND = TYPE_MULTINAME_RtqNameL def serialize(self): - return chr(self.kind) + return chr(self.KIND) def __eq__(self, other): - return self.kind == other.kind + return self.KIND == other.KIND def __ne__(self, other): return not self == other def __hash__(self): - return hash((self.kind)) + return hash((self.KIND)) + + def serialize(self): + return chr(self.KIND) class RtqNameLA(RtqNameL): KIND = TYPE_MULTINAME_RtqNameLA @@ -311,6 +315,15 @@ self.name = name self._name_index = None + def __eq__(self, other): + return self.KIND == other.KIND and self.name == other.name + + def __ne__(self): + return not self == other + + def __hash__(self): + return hash((self.KIND, self.name)) + def write_to_pool(self, pool): assert self.name != "" if self.name == "*": @@ -320,10 +333,39 @@ def serialize(self): assert self._name_index is not None, "Please call write_to_pool before serializing" + return chr(self.KIND) + u32(self._name_index) class RtqNameA(object): KIND = TYPE_MULTINAME_RtqNameA - + +class TypeName(object): + KIND = TYPE_MULTINAME_TypeName + + def __init__(self, name, *types): + self.name = name + self.types = list(types) + + self._name_index = None + self._types_indices = None + + def __eq__(self, other): + return self.KIND == other.KIND and self.name == other.name and self.types == other.types + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.KIND, self.name, tuple(self.types))) + + def write_to_pool(self, pool): + self._name_index = pool.mutliname_pool.index_for(self.name) + self._types_indices = [pool.multiname_pool.index_for(t) for t in self.types] + + def serialize(self): + assert self._name_index is not None, "Please call write_to_pool before serializing" + assert self._types_indices is not None, "Please call write_to_pool before serializing" + return ''.join([chr(self.KIND), u32(self._name_index), u32(self._types_indices)] + [u32(a) for a in self._types_indices]) + # ====================================== # Constant Pool # ====================================== @@ -339,7 +381,7 @@ return iter(self.pool) def index_for(self, value): - if value == self.default: + if value == self.default or value is None: return 0 if value in self.index_map: @@ -370,17 +412,17 @@ self.nsset_pool = ValuePool(NO_NAMESPACE_SET) self.multiname_pool = ValuePool() - def has_RTNS(self, index): - return self.multiname_pool[index].kind in (TYPE_MULTINAME_RtqName, - TYPE_MULTINAME_RtqNameA, - TYPE_MULTINAME_RtqNameL, - TYPE_MULTINAME_RtqNameLA) - - def has_RTName(self, index): - return self.multiname_pool[index].kind in (TYPE_MULTINAME_MultinameL, - TYPE_MULTINAME_MultinameLA, - TYPE_MULTINAME_RtqNameL, - TYPE_MULTINAME_RtqNameLA) + def has_RTNS(self, m): + return m.kind in (TYPE_MULTINAME_RtqName, + TYPE_MULTINAME_RtqNameA, + TYPE_MULTINAME_RtqNameL, + TYPE_MULTINAME_RtqNameLA) + + def has_RTName(self, m): + return m.kind in (TYPE_MULTINAME_MultinameL, + TYPE_MULTINAME_MultinameLA, + TYPE_MULTINAME_RtqNameL, + TYPE_MULTINAME_RtqNameLA) def serialize(self): Modified: pypy/branch/avm/pypy/translator/avm2/instructions.py ============================================================================== --- pypy/branch/avm/pypy/translator/avm2/instructions.py (original) +++ pypy/branch/avm/pypy/translator/avm2/instructions.py Sun Sep 13 01:17:35 2009 @@ -86,11 +86,15 @@ @needs_specialized def _set_assembler_props(self, asm): super(_Avm2NamespaceInstruction, self)._set_assembler_props(asm) - has_rtns = asm.constants.has_RTNS(self.argument) - has_rtname = asm.constants.has_RTName(self.argument) + has_rtns = asm.constants.has_RTNS(self.multiname) + has_rtname = asm.constants.has_RTName(self.multiname) + self.argument = asm.constants.multiname_pool.index_for(self.multiname) asm.stack_depth -= int(has_rtns) + int(has_rtname) + def __call__(self, multiname): + return self.specialize(multiname=multiname) + class _Avm2SetLocalInstruction(_Avm2U30Instruction): @needs_specialized def __call__(self, index): @@ -196,20 +200,26 @@ @needs_specialized def _set_assembler_props(self, asm): + self.index = asm.constants.multiname_pool.index_for(self.multiname) asm.stack_depth += 1 - (self.argument + 1) # push object/args; push result - def __call__(self, index, num_args): - return self.specialize(index=index, argument=num_args) + def __call__(self, multiname, num_args): + return self.specialize(multiname=multiname, argument=num_args) class _Avm2CallMN(_Avm2CallIDX): + is_void = False @needs_specialized def _set_assembler_props(self, asm): - has_rtns = asm.constants.has_rtns(self.index) - has_rtname = asm.constants.has_rtname(self.index) + has_rtns = asm.constants.has_RTNS(self.multiname) + has_rtname = asm.constants.has_RTName(self.multiname) asm.stack_depth += int(self.is_void) - (1 + int(has_rtns) + int(has_rtname) + self.argument) + + + def __call__(self, multiname, num_args): + return self.specialize(multiname=multiname, argument=num_args) - def __call__(self, index, num_args, is_void): - return self.specialize(index=index, argument=num_args, is_void=is_void) +class _Avm2CallMNVoid(_Avm2CallMN): + is_void = True class _Avm2NewArray(_Avm2U30Instruction): @needs_specialized @@ -316,8 +326,8 @@ callproperty = _Avm2CallMN(0x46, 'callproperty') constructprop = _Avm2CallMN(0x4A, 'constructprop') callproplex = _Avm2CallMN(0x4C, 'callproplex') -callsupervoid = _Avm2CallMN(0x4E, 'callsupervoid') -callpropvoid = _Avm2CallMN(0x4F, 'callpropvoid') +callsupervoid = _Avm2CallMNVoid(0x4E, 'callsupervoid') +callpropvoid = _Avm2CallMNVoid(0x4F, 'callpropvoid') #} #{ Instructions that do not chage the stack height stack and take one U30 argument. @@ -395,19 +405,19 @@ debug = _Avm2DebugInstruction(0xEF, 'debug') label_internal = _Avm2ShortInstruction(0x09, 'label') -label = _Avm2LabelInstruction(None, 'label'); +label = _Avm2LabelInstruction(None, 'label') lookupswitch = _Avm2LookupSwitchInstruction(0x1B, 'lookupswitch') -deleteproperty = _Avm2NamespaceInstruction(0x6A, 'deleteproperty', 1, 1) -getdescendants = _Avm2NamespaceInstruction(0x59, 'getdescendants', 1, 1) -getproperty = _Avm2NamespaceInstruction(0x66, 'getproperty', 1, 1) -getsuper = _Avm2NamespaceInstruction(0x04, 'getsuper', 1, 1) -findproperty = _Avm2NamespaceInstruction(0x5E, 'findproperty', 0, 1) -findpropstrict = _Avm2NamespaceInstruction(0x5D, 'findpropstrict', 0, 1) -initproperty = _Avm2NamespaceInstruction(0x68, 'initproperty', 2, 0) -setproperty = _Avm2NamespaceInstruction(0x61, 'setproperty', 2, 0) -setsuper = _Avm2NamespaceInstruction(0x05, 'setsuper', 2, 0) +deleteproperty = _Avm2NamespaceInstruction(0x6A, 'deleteproperty', 0) +getdescendants = _Avm2NamespaceInstruction(0x59, 'getdescendants', 0) +getproperty = _Avm2NamespaceInstruction(0x66, 'getproperty', 0) +getsuper = _Avm2NamespaceInstruction(0x04, 'getsuper', 0) +findproperty = _Avm2NamespaceInstruction(0x5E, 'findproperty', 1) +findpropstrict = _Avm2NamespaceInstruction(0x5D, 'findpropstrict', 1) +initproperty = _Avm2NamespaceInstruction(0x68, 'initproperty', -2) +setproperty = _Avm2NamespaceInstruction(0x61, 'setproperty', -2) +setsuper = _Avm2NamespaceInstruction(0x05, 'setsuper', -2) kill = _Avm2KillInstruction(0x08, 'kill') #} From cfbolz at codespeak.net Mon Sep 14 11:19:04 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 11:19:04 +0200 (CEST) Subject: [pypy-svn] r67666 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090914091904.C1839168009@codespeak.net> Author: cfbolz Date: Mon Sep 14 11:19:03 2009 New Revision: 67666 Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py Log: Instantiating a class dynamically produces an indirect_call that the JIT cannot look into at all. This is the reason why user-class instances in the Python interpreter can never be virtual. Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Mon Sep 14 11:19:03 2009 @@ -620,6 +620,30 @@ res = self.interp_operations(f, [13]) assert res == 72 + @py.test.mark.xfail + def test_instantiate_does_not_call(self): + mydriver = JitDriver(reds = ['n', 'x'], greens = []) + class Base: pass + class A(Base): foo = 72 + class B(Base): foo = 8 + + def f(n): + x = 0 + while n > 0: + mydriver.can_enter_jit(n=n, x=x) + mydriver.jit_merge_point(n=n, x=x) + if n % 2 == 0: + cls = A + else: + cls = B + inst = cls() + x += inst.foo + n -= 1 + return + res = self.meta_interp(f, [20]) + assert res == f(20) + self.check_loops(call=0) + def test_zerodivisionerror(self): # test the case of exception-raising operation that is not delegated # to the backend at all: ZeroDivisionError From cfbolz at codespeak.net Mon Sep 14 11:52:59 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 11:52:59 +0200 (CEST) Subject: [pypy-svn] r67667 - in pypy/branch/spine-of-frames/pypy/module/_stackless: . test Message-ID: <20090914095259.0D6D916800A@codespeak.net> Author: cfbolz Date: Mon Sep 14 11:52:58 2009 New Revision: 67667 Modified: pypy/branch/spine-of-frames/pypy/module/_stackless/interp_coroutine.py pypy/branch/spine-of-frames/pypy/module/_stackless/test/test_coroutine.py Log: Of course there are features in the stackless module that are completely untested, which then break translation: Add a test for the ._framestack attribute on coroutines. Modified: pypy/branch/spine-of-frames/pypy/module/_stackless/interp_coroutine.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/_stackless/interp_coroutine.py (original) +++ pypy/branch/spine-of-frames/pypy/module/_stackless/interp_coroutine.py Mon Sep 14 11:52:58 2009 @@ -271,12 +271,15 @@ def w_descr__framestack(space, self): assert isinstance(self, AppCoroutine) index = self.subctx.framestackdepth + if not index: + return space.newtuple([]) items = [None] * index f = self.subctx.topframe + f.force_f_back() while index > 0: index -= 1 items[index] = space.wrap(f) - f = f.f_back + f = f.f_back() assert f is None return space.newtuple(items) Modified: pypy/branch/spine-of-frames/pypy/module/_stackless/test/test_coroutine.py ============================================================================== --- pypy/branch/spine-of-frames/pypy/module/_stackless/test/test_coroutine.py (original) +++ pypy/branch/spine-of-frames/pypy/module/_stackless/test/test_coroutine.py Mon Sep 14 11:52:58 2009 @@ -116,6 +116,35 @@ co.bind(f) raises(ValueError, co.bind, f) + def test__framestack(self): + import _stackless as stackless + main = stackless.coroutine.getmain() + co = stackless.coroutine() + def g(): + return co._framestack + def f(): + return g() + + co.bind(f) + stack = co.switch() + assert stack == () # running corountine, _framestack is empty + + co = stackless.coroutine() + def g(): + return main.switch() + def f(): + return g() + + co.bind(f) + co.switch() + stack = co._framestack + assert len(stack) == 2 + assert stack[0].f_code is f.func_code + assert stack[1].f_code is g.func_code + + co = stackless.coroutine() + + class AppTestDirect: def setup_class(cls): From cfbolz at codespeak.net Mon Sep 14 11:57:16 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 11:57:16 +0200 (CEST) Subject: [pypy-svn] r67668 - pypy/extradoc/planning Message-ID: <20090914095716.2A90F16800B@codespeak.net> Author: cfbolz Date: Mon Sep 14 11:57:16 2009 New Revision: 67668 Modified: pypy/extradoc/planning/jit.txt Log: A few things that we have done now, and a few new problems that I found during the weekend. Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Mon Sep 14 11:57:16 2009 @@ -15,6 +15,12 @@ pypy-jit behaviour that explicitely check whether the loops make sense +- objectmodel.instantiate is currently not seen by the JIT. This makes all + instance allocation in the Python interpreter escape + +- store sinking also for get/setarrayitem +- lose less information across residual calls + - the tragedy of the skipped tests - keep test coverage in check @@ -30,23 +36,19 @@ Python interpreter: - make shared dicts support shadowtracking -- make shared dicts revert to string dicts less often - don't look for the global-lookup-cache when a function contains no LOAD_GLOBAL +- it's a bit silly that it's possible to change the code objects of builtin + functions +- the lookup annotation optimization interferes with the JIT inlining discussion -------------------- -- need to trace aggressively -- give up when trace becomes too long - need to remember when we gave up -- need to reset counters - tracing aggressively will put pressure on the speed of tracing - what should we do about recursive calls? - connecting compiled loops accross a call? -- problem: when we inline one function, and then hit something non-inlinable, - how do we make the inlined function's frame not escape via the - non-inlinable's f_back? things we know are missing --------------------------- From cfbolz at codespeak.net Mon Sep 14 12:01:33 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 12:01:33 +0200 (CEST) Subject: [pypy-svn] r67669 - in pypy/trunk/pypy/objspace/std: . test Message-ID: <20090914100133.137F2168003@codespeak.net> Author: cfbolz Date: Mon Sep 14 12:01:33 2009 New Revision: 67669 Added: pypy/trunk/pypy/objspace/std/sharingdict.py (contents, props changed) pypy/trunk/pypy/objspace/std/test/test_sharingdict.py (contents, props changed) Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py Log: Do a bit of counting to predict the final size of an sharing dictionary. This makes it possible to use a non-resizable list in its implementation, which reduces the number of indirections and also should make instance creation a bit more JIT-friendly. Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/dictmultiobject.py (original) +++ pypy/trunk/pypy/objspace/std/dictmultiobject.py Mon Sep 14 12:01:33 2009 @@ -4,8 +4,6 @@ from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.rlib.jit import purefunction -from pypy.rlib.rweakref import RWeakValueDictionary def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -686,190 +684,6 @@ return None -class SharedStructure(object): - def __init__(self, keys=None, length=0, - last_key=None, - back_struct=None): - if keys is None: - keys = {} - self.keys = keys - self.length = length - self.back_struct = back_struct - other_structs = RWeakValueDictionary(SharedStructure) - self.other_structs = other_structs - self.last_key = last_key - if last_key is not None: - assert back_struct is not None - - def new_structure(self, added_key): - keys = self.keys.copy() - keys[added_key] = len(self.keys) - new_structure = SharedStructure(keys, self.length + 1, - added_key, self) - self.other_structs.set(added_key, new_structure) - return new_structure - - def lookup_position(self, key): - # jit helper - self = hint(self, promote=True) - key = hint(key, promote=True) - return _lookup_position_shared(self, key) - - def get_next_structure(self, key): - # jit helper - self = hint(self, promote=True) - key = hint(key, promote=True) - return _get_next_structure_shared(self, key) - - at purefunction -def _lookup_position_shared(self, key): - return self.keys.get(key, -1) - - at purefunction -def _get_next_structure_shared(self, key): - new_structure = self.other_structs.get(key) - if new_structure is None: - new_structure = self.new_structure(key) - return new_structure - -class State(object): - def __init__(self, space): - self.empty_structure = SharedStructure() - - -class SharedDictImplementation(DictImplementation): - - def __init__(self, space): - self.space = space - self.structure = space.fromcache(State).empty_structure - self.entries = [] - - def get(self, w_lookup): - space = self.space - w_lookup_type = space.type(w_lookup) - if space.is_w(w_lookup_type, space.w_str): - lookup = space.str_w(w_lookup) - i = self.structure.lookup_position(lookup) - if i == -1: - return None - return self.entries[i] - elif _is_sane_hash(space, w_lookup_type): - return None - else: - return self._as_rdict().get(w_lookup) - - def setitem(self, w_key, w_value): - space = self.space - if space.is_w(space.type(w_key), space.w_str): - return self.setitem_str(w_key, w_value) - else: - return self._as_rdict().setitem(w_key, w_value) - - def setitem_str(self, w_key, w_value, shadows_type=True): - key = self.space.str_w(w_key) - i = self.structure.lookup_position(key) - if i != -1: - self.entries[i] = w_value - return self - new_structure = self.structure.get_next_structure(key) - self.entries.append(w_value) - assert self.structure.length + 1 == new_structure.length - self.structure = new_structure - assert self.structure.keys[key] >= 0 - return self - - def delitem(self, w_key): - space = self.space - w_key_type = space.type(w_key) - if space.is_w(w_key_type, space.w_str): - key = space.str_w(w_key) - if (self.structure.last_key is not None and - key == self.structure.last_key): - self.entries.pop() - self.structure = self.structure.back_struct - return self - return self._as_rdict().delitem(w_key) - elif _is_sane_hash(space, w_key_type): - raise KeyError - else: - return self._as_rdict().delitem(w_key) - - def length(self): - return self.structure.length - - def iteritems(self): - return SharedItemIteratorImplementation(self.space, self) - - def iterkeys(self): - return SharedKeyIteratorImplementation(self.space, self) - - def itervalues(self): - return SharedValueIteratorImplementation(self.space, self) - - def keys(self): - space = self.space - return [space.wrap(key) - for (key, item) in self.structure.keys.iteritems() - if item >= 0] - - def values(self): - return self.entries[:] - - def items(self): - space = self.space - return [space.newtuple([space.wrap(key), self.entries[item]]) - for (key, item) in self.structure.keys.iteritems() - if item >= 0] - - def _as_rdict(self, as_strdict=False): - if as_strdict: - newimpl = StrDictImplementation(self.space) - else: - newimpl = self.space.DefaultDictImpl(self.space) - for k, i in self.structure.keys.items(): - if i >= 0: - newimpl.setitem_str(self.space.wrap(k), self.entries[i]) - return newimpl - - -class SharedValueIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.values = dictimplementation.entries - - def next(self): - if self.pos < self.len: - return self.values[self.pos] - else: - self.values = None - return None - -class SharedItemIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.structure.keys.iteritems() - - def next_entry(self): - implementation = self.dictimplementation - assert isinstance(implementation, SharedDictImplementation) - for key, index in self.iterator: - w_value = implementation.entries[index] - return self.space.newtuple([self.space.wrap(key), w_value]) - else: - return None - -class SharedKeyIteratorImplementation(IteratorImplementation): - def __init__(self, space, dictimplementation): - IteratorImplementation.__init__(self, space, dictimplementation) - self.iterator = dictimplementation.structure.keys.iteritems() - - def next_entry(self): - implementation = self.dictimplementation - assert isinstance(implementation, SharedDictImplementation) - for key, index in self.iterator: - return self.space.wrap(key) - else: - return None import time, py @@ -1052,6 +866,7 @@ elif space.config.objspace.std.withdictmeasurement: w_self.implementation = MeasuringDictImplementation(space) elif space.config.objspace.std.withsharingdict and sharing: + from pypy.objspace.std.sharingdict import SharedDictImplementation w_self.implementation = SharedDictImplementation(space) else: w_self.implementation = space.emptydictimpl Added: pypy/trunk/pypy/objspace/std/sharingdict.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/objspace/std/sharingdict.py Mon Sep 14 12:01:33 2009 @@ -0,0 +1,216 @@ +from pypy.objspace.std.dictmultiobject import DictImplementation, StrDictImplementation +from pypy.objspace.std.dictmultiobject import IteratorImplementation +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash +from pypy.rlib.jit import purefunction, hint, we_are_jitted +from pypy.rlib.rweakref import RWeakValueDictionary + +NUM_DIGITS = 4 + +class SharedStructure(object): + _immutable_fields_ = ["keys", "length", "back_struct", "other_structs", + "last_key"] + + def __init__(self, keys=None, length=0, + last_key=None, + back_struct=None): + if keys is None: + keys = {} + self.keys = keys + self.length = length + self.back_struct = back_struct + other_structs = RWeakValueDictionary(SharedStructure) + self.other_structs = other_structs + self.last_key = last_key + self._size_estimate = length << NUM_DIGITS + if last_key is not None: + assert back_struct is not None + + def new_structure(self, added_key): + keys = self.keys.copy() + keys[added_key] = len(self.keys) + new_structure = SharedStructure(keys, self.length + 1, + added_key, self) + self.other_structs.set(added_key, new_structure) + return new_structure + + def lookup_position(self, key): + # jit helper + self = hint(self, promote=True) + key = hint(key, promote=True) + return _lookup_position_shared(self, key) + + def get_next_structure(self, key): + # jit helper + self = hint(self, promote=True) + key = hint(key, promote=True) + newstruct = _get_next_structure_shared(self, key) + if not we_are_jitted(): + self._size_estimate -= self.size_estimate() + self._size_estimate += newstruct.size_estimate() + return newstruct + + def size_estimate(self): + self = hint(self, promote=True) + return _size_estimate(self) + + at purefunction +def _lookup_position_shared(self, key): + return self.keys.get(key, -1) + + at purefunction +def _get_next_structure_shared(self, key): + new_structure = self.other_structs.get(key) + if new_structure is None: + new_structure = self.new_structure(key) + return new_structure + + at purefunction +def _size_estimate(self): + return self._size_estimate >> NUM_DIGITS + + +class State(object): + def __init__(self, space): + self.empty_structure = SharedStructure() + self.emptylist = [] + + +class SharedDictImplementation(DictImplementation): + + def __init__(self, space): + self.space = space + self.structure = space.fromcache(State).empty_structure + self.entries = space.fromcache(State).emptylist + + def get(self, w_lookup): + space = self.space + w_lookup_type = space.type(w_lookup) + if space.is_w(w_lookup_type, space.w_str): + lookup = space.str_w(w_lookup) + i = self.structure.lookup_position(lookup) + if i == -1: + return None + return self.entries[i] + elif _is_sane_hash(space, w_lookup_type): + return None + else: + return self._as_rdict().get(w_lookup) + + def setitem(self, w_key, w_value): + space = self.space + if space.is_w(space.type(w_key), space.w_str): + return self.setitem_str(w_key, w_value) + else: + return self._as_rdict().setitem(w_key, w_value) + + def setitem_str(self, w_key, w_value, shadows_type=True): + key = self.space.str_w(w_key) + i = self.structure.lookup_position(key) + if i != -1: + self.entries[i] = w_value + return self + new_structure = self.structure.get_next_structure(key) + if new_structure.length > len(self.entries): + new_entries = [None] * new_structure.size_estimate() + for i in range(len(self.entries)): + new_entries[i] = self.entries[i] + self.entries = new_entries + + self.entries[new_structure.length - 1] = w_value + assert self.structure.length + 1 == new_structure.length + self.structure = new_structure + assert self.structure.keys[key] >= 0 + return self + + def delitem(self, w_key): + space = self.space + w_key_type = space.type(w_key) + if space.is_w(w_key_type, space.w_str): + key = space.str_w(w_key) + if (self.structure.last_key is not None and + key == self.structure.last_key): + self.entries[self.structure.length - 1] = None + self.structure = self.structure.back_struct + return self + return self._as_rdict().delitem(w_key) + elif _is_sane_hash(space, w_key_type): + raise KeyError + else: + return self._as_rdict().delitem(w_key) + + def length(self): + return self.structure.length + + def iteritems(self): + return SharedItemIteratorImplementation(self.space, self) + + def iterkeys(self): + return SharedKeyIteratorImplementation(self.space, self) + + def itervalues(self): + return SharedValueIteratorImplementation(self.space, self) + + def keys(self): + space = self.space + return [space.wrap(key) + for (key, item) in self.structure.keys.iteritems() + if item >= 0] + + def values(self): + return self.entries[:self.structure.length] + + def items(self): + space = self.space + return [space.newtuple([space.wrap(key), self.entries[item]]) + for (key, item) in self.structure.keys.iteritems() + if item >= 0] + + def _as_rdict(self, as_strdict=False): + if as_strdict: + newimpl = StrDictImplementation(self.space) + else: + newimpl = self.space.DefaultDictImpl(self.space) + for k, i in self.structure.keys.items(): + if i >= 0: + newimpl.setitem_str(self.space.wrap(k), self.entries[i]) + return newimpl + + +class SharedValueIteratorImplementation(IteratorImplementation): + def __init__(self, space, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.values = dictimplementation.entries + + def next(self): + if self.pos < self.len: + return self.values[self.pos] + else: + self.values = None + return None + +class SharedItemIteratorImplementation(IteratorImplementation): + def __init__(self, space, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = dictimplementation.structure.keys.iteritems() + + def next_entry(self): + implementation = self.dictimplementation + assert isinstance(implementation, SharedDictImplementation) + for key, index in self.iterator: + w_value = implementation.entries[index] + return self.space.newtuple([self.space.wrap(key), w_value]) + else: + return None + +class SharedKeyIteratorImplementation(IteratorImplementation): + def __init__(self, space, dictimplementation): + IteratorImplementation.__init__(self, space, dictimplementation) + self.iterator = dictimplementation.structure.keys.iteritems() + + def next_entry(self): + implementation = self.dictimplementation + assert isinstance(implementation, SharedDictImplementation) + for key, index in self.iterator: + return self.space.wrap(key) + else: + return None Added: pypy/trunk/pypy/objspace/std/test/test_sharingdict.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/objspace/std/test/test_sharingdict.py Mon Sep 14 12:01:33 2009 @@ -0,0 +1,29 @@ +from pypy.conftest import gettestobjspace +from pypy.objspace.std.sharingdict import SharedStructure, NUM_DIGITS +from pypy.interpreter import gateway + +def instance_with_keys(structure, *keys): + for key in keys: + structure = structure.get_next_structure(key) + return structure + +def test_size_estimate(): + empty_structure = SharedStructure() + instances = [] + for i in range(100): + instances.append(instance_with_keys(empty_structure, "a", "b", "c", "d", "e", "f")) + instances.append(instance_with_keys(empty_structure, "x", "y")) + assert empty_structure.size_estimate() == 4 + assert empty_structure.other_structs.get("a").size_estimate() == 6 + assert empty_structure.other_structs.get("x").size_estimate() == 2 + +def test_size_estimate2(): + empty_structure = SharedStructure() + instances = [] + for i in range(100): + instances.append(instance_with_keys(empty_structure, "a", "b", "c", "d", "e", "f")) + instances.append(instance_with_keys(empty_structure, "x", "y")) + instances.append(instance_with_keys(empty_structure, "x", "y")) + assert empty_structure.size_estimate() == 3 + assert empty_structure.other_structs.get("a").size_estimate() == 6 + assert empty_structure.other_structs.get("x").size_estimate() == 2 From cfbolz at codespeak.net Mon Sep 14 14:57:04 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 14:57:04 +0200 (CEST) Subject: [pypy-svn] r67670 - pypy/extradoc/sprintinfo/ddorf2009 Message-ID: <20090914125704.9FCEC168009@codespeak.net> Author: cfbolz Date: Mon Sep 14 14:57:02 2009 New Revision: 67670 Added: pypy/extradoc/sprintinfo/ddorf2009/ pypy/extradoc/sprintinfo/ddorf2009/announce.txt pypy/extradoc/sprintinfo/ddorf2009/people.txt Log: (pedronis, cfbolz, arigo) draft the sprint announcement Added: pypy/extradoc/sprintinfo/ddorf2009/announce.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/ddorf2009/announce.txt Mon Sep 14 14:57:02 2009 @@ -0,0 +1,56 @@ +D??sseldorf PyPy sprint November 6 - November 13 2009 +===================================================== + +The next PyPy sprint will be held in the Computer Science department of +Heinrich-Heine Universit?a ?tD??sseldorf from the 6th to the 13th of +November 2009. This is a fully public sprint, everyone is welcome to join us. + +Topics and goals +---------------- + +At the sprint we intend to work on the JIT generator in PyPy and on applying +it to PyPy Python interpreter. + +The precise work that will be done is not fixed, as we don't know in which +state the JIT will be in November. However, possible areas of work might +include: + +- tweaking the interpreter/objspace to be more JIT-friendly, e.g. + instance implementation code, call code +- if there is interest starting non x86-32 JIT backends +- trying out existing software to find features where the optimizations of the + JIT could be improved +- improving our benchmarking infrastructure + +We will give special priority to topics that "non-core" people find +interesting (as long as they are somehow JIT-related). + +For an introduction of how our JIT-generation process works, please refer to +our blog: + +http://morepypy.blogspot.com/2009/03/jit-bit-of-look-inside.html + +There is also a more dense academic paper about the subject: + +http://codespeak.net/svn/pypy/extradoc/talk/icooolps2009/bolz-tracing-jit-final.pdf + +Location +-------- + +The sprint will take place in a seminar room of the computer science +department. It is in the building 25.12 of the university campus. For travel +instructions see + + http://stups.cs.uni-duesseldorf.de/anreise/esbahn.php + +Registration +------------ + +If you'd like to come, please subscribe to the `pypy-sprint mailing list`_ +and drop a note about your interests and post any questions. More +organisational information will be send to that list. We'll keep +a list of `people`_ which we'll update (which you can do so yourself +if you have codespeak commit rights). + +.. _`pypy-sprint mailing list`: http://codespeak.net/mailman/listinfo/pypy-sprint +.. _`people`: http://codespeak.net/pypy/extradoc/sprintinfo/ddorf2009/people.txt Added: pypy/extradoc/sprintinfo/ddorf2009/people.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/ddorf2009/people.txt Mon Sep 14 14:57:02 2009 @@ -0,0 +1,50 @@ +People coming to the Duesseldorf sprint November 2009 +==================================================== + +People who have a ``?`` in their arrive/depart or accomodation +column are known to be coming but there are no details +available yet from them. + +==================== ============== ===================== + Name Arrive/Depart Accomodation +==================== ============== ===================== +Carl Friedrich Bolz always there private +==================== ============== ===================== +==================== ============== ===================== + + + +==================== ============== ===================== + Name Arrive/Depart Accomodation +==================== ============== ===================== +Armin Rigo +Michael Hudson +Antonio Cuni +Samuele Pedroni +Anders Chrigstroem +Maciej Fijalkowski +Andrew Thompson +Stephan Diehl +Eric van Riet paap +Niko Matsakis +Leonardo Santagada +Richard Emslie +Christian Tismer +Alexander Schremmer +Jacob Hallen ? ? +Aurelien Campeas ? ? +Alexandre Fayolle ? ? +Lene Wagner ? ? +Amaury Forgeot d'Arc ? ? +Valentino Volonghi ? ? +Boris Feigin ? ? +Bert Freudenberg ? ? +Laura Creighton ? ? +Beatrice Duering ? ? +Johan Hahn ? ? +Holger Krekel ? ? +Anders Chrigstroem ? ? +Samuele Pedroni ? ? +Anders Lehmann ? ? +Niklaus Haldimann ? ? +==================== ============== ===================== From cfbolz at codespeak.net Mon Sep 14 14:57:58 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 14:57:58 +0200 (CEST) Subject: [pypy-svn] r67671 - pypy/extradoc/sprintinfo/ddorf2009 Message-ID: <20090914125758.E5DAD168008@codespeak.net> Author: cfbolz Date: Mon Sep 14 14:57:58 2009 New Revision: 67671 Modified: pypy/extradoc/sprintinfo/ddorf2009/announce.txt Log: fix umlauts Modified: pypy/extradoc/sprintinfo/ddorf2009/announce.txt ============================================================================== --- pypy/extradoc/sprintinfo/ddorf2009/announce.txt (original) +++ pypy/extradoc/sprintinfo/ddorf2009/announce.txt Mon Sep 14 14:57:58 2009 @@ -2,7 +2,7 @@ ===================================================== The next PyPy sprint will be held in the Computer Science department of -Heinrich-Heine Universit?a ?tD??sseldorf from the 6th to the 13th of +Heinrich-Heine Universit?t D?sseldorf from the 6th to the 13th of November 2009. This is a fully public sprint, everyone is welcome to join us. Topics and goals From cfbolz at codespeak.net Mon Sep 14 15:04:38 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 15:04:38 +0200 (CEST) Subject: [pypy-svn] r67672 - pypy/trunk/pypy/objspace/std Message-ID: <20090914130438.1D4FB16800B@codespeak.net> Author: cfbolz Date: Mon Sep 14 15:04:37 2009 New Revision: 67672 Modified: pypy/trunk/pypy/objspace/std/typeobject.py Log: - let the JIT constant-fold issubtype calls between builtin types - lookups on builtin types don't need to promote the version_tag Modified: pypy/trunk/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/pypy/objspace/std/typeobject.py Mon Sep 14 15:04:37 2009 @@ -7,7 +7,7 @@ from pypy.objspace.std.dictproxyobject import W_DictProxyObject from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.objectmodel import current_object_addr_as_int -from pypy.rlib.jit import hint, purefunction +from pypy.rlib.jit import hint, purefunction, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import intmask, r_uint from copy_reg import _HEAPTYPE @@ -53,7 +53,8 @@ _immutable_fields_ = ["__flags__", 'needsdel', 'weakrefable', - 'hasdict'] + 'hasdict', + 'nslots'] # for config.objspace.std.getattributeshortcut # (False is a conservative default, fixed during real usage) @@ -176,6 +177,7 @@ return None + @dont_look_inside def _lookup(w_self, key): space = w_self.space for w_class in w_self.mro_w: @@ -184,6 +186,7 @@ return w_value return None + @dont_look_inside def _lookup_where(w_self, key): # like lookup() but also returns the parent class in which the # attribute was found @@ -194,15 +197,25 @@ return w_class, w_value return None, None + @purefunction + def _pure_lookup_where_builtin_type(w_self, name): + assert not w_self.is_heaptype() + return w_self._lookup_where(name) + def lookup_where_with_method_cache(w_self, name): space = w_self.space + w_self = hint(w_self, promote=True) assert space.config.objspace.std.withmethodcache + if (space.config.objspace.std.immutable_builtintypes and + we_are_jitted() and not w_self.is_heaptype()): + w_self = hint(w_self, promote=True) + name = hint(name, promote=True) + return w_self._pure_lookup_where_builtin_type(name) version_tag = w_self.version_tag version_tag = hint(version_tag, promote=True) if version_tag is None: tup = w_self._lookup_where(name) return tup - w_self = hint(w_self, promote=True) name = hint(name, promote=True) return w_self._pure_lookup_where_with_method_cache(name, version_tag) @@ -606,8 +619,36 @@ space.wrap("__init__() should return None")) return w_newobject +def _issubtype(w_type1, w_type2): + return w_type2 in w_type1.mro_w + + at purefunction +def _pure_issubtype_builtin(w_type1, w_type2): + return _issubtype(w_type1, w_type2) + + at purefunction +def _pure_issubtype(w_type1, w_type2, version_tag1, version_tag2): + return _issubtype(w_type1, w_type2) + def issubtype__Type_Type(space, w_type1, w_type2): - return space.newbool(w_type2 in w_type1.mro_w) + w_type1 = hint(w_type1, promote=True) + w_type2 = hint(w_type2, promote=True) + if space.config.objspace.std.withtypeversion and we_are_jitted(): + if (space.config.objspace.std.immutable_builtintypes and + not w_type1.is_heaptype() and + not w_type2.is_heaptype()): + res = _pure_issubtype_builtin(w_type1, w_type2) + return space.newbool(res) + else: + version_tag1 = w_type1.version_tag + version_tag2 = w_type2.version_tag + if version_tag1 is not None and version_tag2 is not None: + version_tag1 = hint(version_tag1, promote=True) + version_tag2 = hint(version_tag2, promote=True) + res = _pure_issubtype(w_type1, w_type2, version_tag1, version_tag2) + return space.newbool(res) + res = _issubtype(w_type1, w_type2) + return space.newbool(res) def repr__Type(space, w_obj): w_mod = w_obj.get_module() From cfbolz at codespeak.net Mon Sep 14 15:07:10 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 15:07:10 +0200 (CEST) Subject: [pypy-svn] r67673 - pypy/trunk/pypy/jit/tl Message-ID: <20090914130710.BDB5C16800A@codespeak.net> Author: cfbolz Date: Mon Sep 14 15:07:09 2009 New Revision: 67673 Modified: pypy/trunk/pypy/jit/tl/pypyjit_demo.py Log: a loop with a long loop counter Modified: pypy/trunk/pypy/jit/tl/pypyjit_demo.py ============================================================================== --- pypy/trunk/pypy/jit/tl/pypyjit_demo.py (original) +++ pypy/trunk/pypy/jit/tl/pypyjit_demo.py Mon Sep 14 15:07:09 2009 @@ -37,18 +37,14 @@ a = A(1) print a print a - i = 0 - N = 1000 - #N = 10000000 + i = 0L + N = 1000L + N = 10000000L step = 3 start = time.clock() odd = 0 while i < N: - i = i + a.f() - if i % 2: - i += 2 - odd += 1 - print a.count, i, odd + i = i + 1 end = time.clock() print i print end-start, 'seconds' From pedronis at codespeak.net Mon Sep 14 15:39:24 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 14 Sep 2009 15:39:24 +0200 (CEST) Subject: [pypy-svn] r67674 - pypy/trunk/pypy/translator/goal Message-ID: <20090914133924.7168A168008@codespeak.net> Author: pedronis Date: Mon Sep 14 15:39:23 2009 New Revision: 67674 Modified: pypy/trunk/pypy/translator/goal/ann_override.py Log: mark the 'cached*' fields as immutable in the process Modified: pypy/trunk/pypy/translator/goal/ann_override.py ============================================================================== --- pypy/trunk/pypy/translator/goal/ann_override.py (original) +++ pypy/trunk/pypy/translator/goal/ann_override.py Mon Sep 14 15:39:23 2009 @@ -69,10 +69,17 @@ srcmodule='') return funcdesc.cachedgraph((typ, x), builder=builder) return funcdesc.cachedgraph(typ) + + def _remember_immutable(pol, t, cached): + # for jit benefit + if cached not in t._immutable_fields_: # accessed this way just + # for convenience + t._immutable_fields_.append(cached) def attach_lookup(pol, t, attr): cached = "cached_%s" % attr if not t.is_heaptype(): + pol._remember_immutable(t, cached) setattr(t, cached, t._lookup(attr)) return True return False @@ -80,6 +87,7 @@ def attach_lookup_in_type_where(pol, t, attr): cached = "cached_where_%s" % attr if not t.is_heaptype(): + pol._remember_immutable(t, cached) setattr(t, cached, t._lookup_where(attr)) return True return False From cfbolz at codespeak.net Mon Sep 14 16:50:06 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 16:50:06 +0200 (CEST) Subject: [pypy-svn] r67675 - pypy/trunk/pypy/rlib Message-ID: <20090914145006.0FF6016800C@codespeak.net> Author: cfbolz Date: Mon Sep 14 16:50:05 2009 New Revision: 67675 Added: pypy/trunk/pypy/rlib/jit.py.merge.tmp - copied unchanged from r67674, pypy/trunk/pypy/rlib/jit.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/spine-of-frames/pypy/rlib/jit.py revisions 67428 to 67674: ------------------------------------------------------------------------ r67624 | cfbolz | 2009-09-10 16:45:13 +0200 (Thu, 10 Sep 2009) | 2 lines merge in changes from revisions r67429 through r67623 of trunk. ------------------------------------------------------------------------ r67429 | cfbolz | 2009-09-02 15:32:28 +0200 (Wed, 02 Sep 2009) | 2 lines a branch where to try to link frames together differently ------------------------------------------------------------------------ From cfbolz at codespeak.net Mon Sep 14 16:50:10 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 16:50:10 +0200 (CEST) Subject: [pypy-svn] r67676 - pypy/trunk/pypy/objspace/std Message-ID: <20090914145010.4096E16800C@codespeak.net> Author: cfbolz Date: Mon Sep 14 16:50:08 2009 New Revision: 67676 Added: pypy/trunk/pypy/objspace/std/typeobject.py.merge.tmp - copied unchanged from r67674, pypy/trunk/pypy/objspace/std/typeobject.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/spine-of-frames/pypy/objspace/std/typeobject.py revisions 67428 to 67674: ------------------------------------------------------------------------ r67624 | cfbolz | 2009-09-10 16:45:13 +0200 (Thu, 10 Sep 2009) | 2 lines merge in changes from revisions r67429 through r67623 of trunk. ------------------------------------------------------------------------ r67429 | cfbolz | 2009-09-02 15:32:28 +0200 (Wed, 02 Sep 2009) | 2 lines a branch where to try to link frames together differently ------------------------------------------------------------------------ From cfbolz at codespeak.net Mon Sep 14 16:50:13 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 16:50:13 +0200 (CEST) Subject: [pypy-svn] r67677 - pypy/trunk/pypy/objspace/std Message-ID: <20090914145013.0D49D168010@codespeak.net> Author: cfbolz Date: Mon Sep 14 16:50:13 2009 New Revision: 67677 Added: pypy/trunk/pypy/objspace/std/dictmultiobject.py.merge.tmp - copied unchanged from r67674, pypy/trunk/pypy/objspace/std/dictmultiobject.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/spine-of-frames/pypy/objspace/std/dictmultiobject.py revisions 67428 to 67674: ------------------------------------------------------------------------ r67624 | cfbolz | 2009-09-10 16:45:13 +0200 (Thu, 10 Sep 2009) | 2 lines merge in changes from revisions r67429 through r67623 of trunk. ------------------------------------------------------------------------ r67429 | cfbolz | 2009-09-02 15:32:28 +0200 (Wed, 02 Sep 2009) | 2 lines a branch where to try to link frames together differently ------------------------------------------------------------------------ From cfbolz at codespeak.net Mon Sep 14 16:50:18 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 16:50:18 +0200 (CEST) Subject: [pypy-svn] r67678 - pypy/trunk/pypy/jit/tl Message-ID: <20090914145018.DBFA7168014@codespeak.net> Author: cfbolz Date: Mon Sep 14 16:50:17 2009 New Revision: 67678 Added: pypy/trunk/pypy/jit/tl/pypyjit_child.py.merge.tmp - copied, changed from r67674, pypy/trunk/pypy/jit/tl/pypyjit_child.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/spine-of-frames/pypy/jit/tl/pypyjit_child.py revisions 67428 to 67674: ------------------------------------------------------------------------ r67632 | cfbolz | 2009-09-10 19:53:58 +0200 (Thu, 10 Sep 2009) | 2 lines nice feeling of realism ------------------------------------------------------------------------ r67624 | cfbolz | 2009-09-10 16:45:13 +0200 (Thu, 10 Sep 2009) | 2 lines merge in changes from revisions r67429 through r67623 of trunk. ------------------------------------------------------------------------ r67429 | cfbolz | 2009-09-02 15:32:28 +0200 (Wed, 02 Sep 2009) | 2 lines a branch where to try to link frames together differently ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/tl/pypyjit_child.py.merge.tmp (from r67674, pypy/trunk/pypy/jit/tl/pypyjit_child.py) ============================================================================== --- pypy/trunk/pypy/jit/tl/pypyjit_child.py (original) +++ pypy/trunk/pypy/jit/tl/pypyjit_child.py.merge.tmp Mon Sep 14 16:50:17 2009 @@ -40,7 +40,8 @@ option.view = True warmspot.jittify_and_run(interp, graph, [], policy=policy, listops=True, CPUClass=LLtypeCPU, - backendopt=True) + backendopt=True, inline=True, + optimizer=optimize) def run_child_ootype(glob, loc): From cfbolz at codespeak.net Mon Sep 14 16:50:21 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 16:50:21 +0200 (CEST) Subject: [pypy-svn] r67679 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090914145021.EEA12168016@codespeak.net> Author: cfbolz Date: Mon Sep 14 16:50:21 2009 New Revision: 67679 Added: pypy/trunk/pypy/jit/metainterp/warmspot.py.merge.tmp - copied unchanged from r67674, pypy/trunk/pypy/jit/metainterp/warmspot.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/spine-of-frames/pypy/jit/metainterp/warmspot.py revisions 67428 to 67674: ------------------------------------------------------------------------ r67624 | cfbolz | 2009-09-10 16:45:13 +0200 (Thu, 10 Sep 2009) | 2 lines merge in changes from revisions r67429 through r67623 of trunk. ------------------------------------------------------------------------ r67429 | cfbolz | 2009-09-02 15:32:28 +0200 (Wed, 02 Sep 2009) | 2 lines a branch where to try to link frames together differently ------------------------------------------------------------------------ From cfbolz at codespeak.net Mon Sep 14 16:50:25 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 16:50:25 +0200 (CEST) Subject: [pypy-svn] r67680 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090914145025.6EE1916800C@codespeak.net> Author: cfbolz Date: Mon Sep 14 16:50:24 2009 New Revision: 67680 Added: pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp - copied, changed from r67674, pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/spine-of-frames/pypy/jit/metainterp/pyjitpl.py revisions 67428 to 67674: ------------------------------------------------------------------------ r67628 | cfbolz | 2009-09-10 19:18:43 +0200 (Thu, 10 Sep 2009) | 3 lines do things in the other order, to make it possible to call stuff in the leave hook ------------------------------------------------------------------------ r67624 | cfbolz | 2009-09-10 16:45:13 +0200 (Thu, 10 Sep 2009) | 2 lines merge in changes from revisions r67429 through r67623 of trunk. ------------------------------------------------------------------------ r67429 | cfbolz | 2009-09-02 15:32:28 +0200 (Wed, 02 Sep 2009) | 2 lines a branch where to try to link frames together differently ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp (from r67674, pypy/trunk/pypy/jit/metainterp/pyjitpl.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp Mon Sep 14 16:50:24 2009 @@ -1092,13 +1092,13 @@ def generate_bytecode(self, policy): self._codewriter = codewriter.CodeWriter(self, policy) - self.portal_code = self._codewriter.make_portal_bytecode( - self.portal_graph) self.leave_code = None if self.leave_graph: self.leave_code = self._codewriter.make_one_bytecode( (self.leave_graph, None), False) + self.portal_code = self._codewriter.make_portal_bytecode( + self.portal_graph) self._class_sizes = self._codewriter.class_sizes # ---------- construction-time interface ---------- From cfbolz at codespeak.net Mon Sep 14 16:50:29 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 16:50:29 +0200 (CEST) Subject: [pypy-svn] r67681 - pypy/trunk/pypy/interpreter/test Message-ID: <20090914145029.C919F168016@codespeak.net> Author: cfbolz Date: Mon Sep 14 16:50:28 2009 New Revision: 67681 Added: pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py.merge.tmp - copied, changed from r67674, pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/spine-of-frames/pypy/interpreter/test/test_zzpickle_and_slow.py revisions 67428 to 67674: ------------------------------------------------------------------------ r67624 | cfbolz | 2009-09-10 16:45:13 +0200 (Thu, 10 Sep 2009) | 2 lines merge in changes from revisions r67429 through r67623 of trunk. ------------------------------------------------------------------------ r67433 | cfbolz | 2009-09-02 17:53:35 +0200 (Wed, 02 Sep 2009) | 2 lines try to have frames not escape via the f_backs of the next "real" frame. ------------------------------------------------------------------------ r67429 | cfbolz | 2009-09-02 15:32:28 +0200 (Wed, 02 Sep 2009) | 2 lines a branch where to try to link frames together differently ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py.merge.tmp (from r67674, pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py) ============================================================================== --- pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py (original) +++ pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py.merge.tmp Mon Sep 14 16:50:28 2009 @@ -30,18 +30,23 @@ from pypy.interpreter import pytraceback def hide_top_frame(space, w_frame): w_last = None - while w_frame.f_back: + while w_frame.f_back(): + # should have been forced by traceback capturing + assert w_frame.f_back_forced w_last = w_frame - w_frame = w_frame.f_back + w_frame = w_frame.f_back() assert w_last - w_saved = w_last.f_back - w_last.f_back = None + w_saved = w_last.f_back() + w_last.f_back_some = None + w_saved.f_forward = None return w_saved def restore_top_frame(space, w_frame, w_saved): - while w_frame.f_back: - w_frame = w_frame.f_back - w_frame.f_back = w_saved + while w_frame.f_back(): + assert w_frame.f_back_forced + w_frame = w_frame.f_back() + w_frame.f_back_some = w_saved + w_saved.f_forward = w_frame def read_exc_type(space, w_frame): if w_frame.last_exception is None: From cfbolz at codespeak.net Mon Sep 14 16:50:38 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 16:50:38 +0200 (CEST) Subject: [pypy-svn] r67682 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090914145038.D569D168027@codespeak.net> Author: cfbolz Date: Mon Sep 14 16:50:38 2009 New Revision: 67682 Added: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py.merge.tmp - copied, changed from r67674, pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_recursive.py revisions 67428 to 67674: ------------------------------------------------------------------------ r67628 | cfbolz | 2009-09-10 19:18:43 +0200 (Thu, 10 Sep 2009) | 3 lines do things in the other order, to make it possible to call stuff in the leave hook ------------------------------------------------------------------------ r67624 | cfbolz | 2009-09-10 16:45:13 +0200 (Thu, 10 Sep 2009) | 2 lines merge in changes from revisions r67429 through r67623 of trunk. ------------------------------------------------------------------------ r67429 | cfbolz | 2009-09-02 15:32:28 +0200 (Wed, 02 Sep 2009) | 2 lines a branch where to try to link frames together differently ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py.merge.tmp (from r67674, pypy/trunk/pypy/jit/metainterp/test/test_recursive.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py.merge.tmp Mon Sep 14 16:50:38 2009 @@ -427,9 +427,12 @@ def c(code, pc): return "L" not in hlstr(code) - def leave(code, pc, frame): + def really_leave(frame): frame.hookcalled = True + def leave(code, pc, frame): + really_leave(frame) + class ExpectedHook(Exception): pass class UnexpectedHook(Exception): From cfbolz at codespeak.net Mon Sep 14 16:50:41 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 16:50:41 +0200 (CEST) Subject: [pypy-svn] r67683 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090914145041.8CB20168027@codespeak.net> Author: cfbolz Date: Mon Sep 14 16:50:40 2009 New Revision: 67683 Added: pypy/trunk/pypy/jit/metainterp/test/test_basic.py.merge.tmp - copied unchanged from r67674, pypy/trunk/pypy/jit/metainterp/test/test_basic.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/spine-of-frames/pypy/jit/metainterp/test/test_basic.py revisions 67428 to 67674: ------------------------------------------------------------------------ r67624 | cfbolz | 2009-09-10 16:45:13 +0200 (Thu, 10 Sep 2009) | 2 lines merge in changes from revisions r67429 through r67623 of trunk. ------------------------------------------------------------------------ r67429 | cfbolz | 2009-09-02 15:32:28 +0200 (Wed, 02 Sep 2009) | 2 lines a branch where to try to link frames together differently ------------------------------------------------------------------------ From cfbolz at codespeak.net Mon Sep 14 16:51:41 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 16:51:41 +0200 (CEST) Subject: [pypy-svn] r67684 - in pypy/trunk/pypy: interpreter interpreter/test jit/metainterp jit/metainterp/test jit/tl module/_stackless module/pypyjit module/sys objspace/std rlib Message-ID: <20090914145141.3AF1616800C@codespeak.net> Author: cfbolz Date: Mon Sep 14 16:51:40 2009 New Revision: 67684 Added: pypy/trunk/pypy/interpreter/executioncontext.py - copied unchanged from r67683, pypy/branch/spine-of-frames/pypy/interpreter/executioncontext.py pypy/trunk/pypy/interpreter/generator.py - copied unchanged from r67683, pypy/branch/spine-of-frames/pypy/interpreter/generator.py pypy/trunk/pypy/interpreter/pyframe.py - copied unchanged from r67683, pypy/branch/spine-of-frames/pypy/interpreter/pyframe.py pypy/trunk/pypy/interpreter/pytraceback.py - copied unchanged from r67683, pypy/branch/spine-of-frames/pypy/interpreter/pytraceback.py pypy/trunk/pypy/interpreter/test/test_executioncontext.py - copied unchanged from r67683, pypy/branch/spine-of-frames/pypy/interpreter/test/test_executioncontext.py pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py - copied unchanged from r67683, pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py.merge.tmp pypy/trunk/pypy/jit/metainterp/pyjitpl.py - copied unchanged from r67683, pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_basic.py - copied unchanged from r67683, pypy/trunk/pypy/jit/metainterp/test/test_basic.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_recursive.py - copied unchanged from r67683, pypy/trunk/pypy/jit/metainterp/test/test_recursive.py.merge.tmp pypy/trunk/pypy/jit/metainterp/warmspot.py - copied unchanged from r67683, pypy/trunk/pypy/jit/metainterp/warmspot.py.merge.tmp pypy/trunk/pypy/jit/tl/pypyjit_child.py - copied unchanged from r67683, pypy/trunk/pypy/jit/tl/pypyjit_child.py.merge.tmp pypy/trunk/pypy/module/_stackless/ - copied from r67683, pypy/branch/spine-of-frames/pypy/module/_stackless/ pypy/trunk/pypy/module/pypyjit/interp_jit.py - copied unchanged from r67683, pypy/branch/spine-of-frames/pypy/module/pypyjit/interp_jit.py pypy/trunk/pypy/module/sys/ - copied from r67683, pypy/branch/spine-of-frames/pypy/module/sys/ pypy/trunk/pypy/objspace/std/dictmultiobject.py - copied unchanged from r67683, pypy/trunk/pypy/objspace/std/dictmultiobject.py.merge.tmp pypy/trunk/pypy/objspace/std/typeobject.py - copied unchanged from r67683, pypy/trunk/pypy/objspace/std/typeobject.py.merge.tmp pypy/trunk/pypy/rlib/jit.py - copied unchanged from r67683, pypy/trunk/pypy/rlib/jit.py.merge.tmp Removed: pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py.merge.tmp pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_basic.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_recursive.py.merge.tmp pypy/trunk/pypy/jit/metainterp/warmspot.py.merge.tmp pypy/trunk/pypy/jit/tl/pypyjit_child.py.merge.tmp pypy/trunk/pypy/objspace/std/dictmultiobject.py.merge.tmp pypy/trunk/pypy/objspace/std/typeobject.py.merge.tmp pypy/trunk/pypy/rlib/jit.py.merge.tmp Log: (pedronis, arigo, cfbolz): merge the spine-of-frames branch From benjamin at codespeak.net Mon Sep 14 17:17:01 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Mon, 14 Sep 2009 17:17:01 +0200 (CEST) Subject: [pypy-svn] r67685 - pypy/trunk/pypy/interpreter Message-ID: <20090914151701.AC875168007@codespeak.net> Author: benjamin Date: Mon Sep 14 17:17:01 2009 New Revision: 67685 Modified: pypy/trunk/pypy/interpreter/generator.py Log: avoid raising and catching pointless exceptions Modified: pypy/trunk/pypy/interpreter/generator.py ============================================================================== --- pypy/trunk/pypy/interpreter/generator.py (original) +++ pypy/trunk/pypy/interpreter/generator.py Mon Sep 14 17:17:01 2009 @@ -129,6 +129,7 @@ for block in self.frame.blockstack: if not isinstance(block, LoopBlock): self.descr_close() + return def __del__(self): self._enqueue_for_destruction(self.space) From pedronis at codespeak.net Mon Sep 14 18:25:59 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 14 Sep 2009 18:25:59 +0200 (CEST) Subject: [pypy-svn] r67686 - pypy/trunk/pypy/interpreter/test Message-ID: <20090914162559.D2874168006@codespeak.net> Author: pedronis Date: Mon Sep 14 18:25:57 2009 New Revision: 67686 Modified: pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py Log: leave f_forward alone, it is not maintained in the non-jit case, fixes the test Modified: pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py ============================================================================== --- pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py (original) +++ pypy/trunk/pypy/interpreter/test/test_zzpickle_and_slow.py Mon Sep 14 18:25:57 2009 @@ -38,7 +38,6 @@ assert w_last w_saved = w_last.f_back() w_last.f_back_some = None - w_saved.f_forward = None return w_saved def restore_top_frame(space, w_frame, w_saved): @@ -46,7 +45,6 @@ assert w_frame.f_back_forced w_frame = w_frame.f_back() w_frame.f_back_some = w_saved - w_saved.f_forward = w_frame def read_exc_type(space, w_frame): if w_frame.last_exception is None: @@ -193,7 +191,7 @@ def test_pickle_frame_with_exc(self): #import sys # avoid creating a closure for now - del self + self = None def f(): try: raise ValueError From cfbolz at codespeak.net Mon Sep 14 18:52:11 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 14 Sep 2009 18:52:11 +0200 (CEST) Subject: [pypy-svn] r67687 - pypy/trunk/pypy/jit/tl Message-ID: <20090914165211.606BE16800B@codespeak.net> Author: cfbolz Date: Mon Sep 14 18:52:10 2009 New Revision: 67687 Modified: pypy/trunk/pypy/jit/tl/pypyjit_child.py Log: this was broken by the merge somehow Modified: pypy/trunk/pypy/jit/tl/pypyjit_child.py ============================================================================== --- pypy/trunk/pypy/jit/tl/pypyjit_child.py (original) +++ pypy/trunk/pypy/jit/tl/pypyjit_child.py Mon Sep 14 18:52:10 2009 @@ -2,6 +2,7 @@ from pypy.rpython.lltypesystem import lltype from pypy.jit.metainterp import warmspot from pypy.module.pypyjit.policy import PyPyJitPolicy +from pypy.rlib.jit import OPTIMIZER_FULL # Current output: http://paste.pocoo.org/show/106540/ # @@ -41,7 +42,7 @@ warmspot.jittify_and_run(interp, graph, [], policy=policy, listops=True, CPUClass=LLtypeCPU, backendopt=True, inline=True, - optimizer=optimize) + optimizer=OPTIMIZER_FULL) def run_child_ootype(glob, loc): From cfbolz at codespeak.net Tue Sep 15 10:28:04 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 15 Sep 2009 10:28:04 +0200 (CEST) Subject: [pypy-svn] r67688 - pypy/branch/spine-of-frames Message-ID: <20090915082804.42187168009@codespeak.net> Author: cfbolz Date: Tue Sep 15 10:28:02 2009 New Revision: 67688 Removed: pypy/branch/spine-of-frames/ Log: remove merged branch From cfbolz at codespeak.net Tue Sep 15 10:31:36 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 15 Sep 2009 10:31:36 +0200 (CEST) Subject: [pypy-svn] r67689 - pypy/trunk/pypy/module/__builtin__/test Message-ID: <20090915083136.66512168007@codespeak.net> Author: cfbolz Date: Tue Sep 15 10:31:35 2009 New Revision: 67689 Modified: pypy/trunk/pypy/module/__builtin__/test/test_classobj.py Log: fix imports in oldstyle classes tests Modified: pypy/trunk/pypy/module/__builtin__/test/test_classobj.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/test/test_classobj.py (original) +++ pypy/trunk/pypy/module/__builtin__/test/test_classobj.py Tue Sep 15 10:31:35 2009 @@ -770,7 +770,7 @@ def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withsharingdict": True}) def is_sharing(space, w_inst): - from pypy.objspace.std.dictmultiobject import SharedDictImplementation, W_DictMultiObject + from pypy.objspace.std.sharingdict import SharedDictImplementation, W_DictMultiObject w_d = w_inst.getdict() return space.wrap(isinstance(w_d, W_DictMultiObject) and isinstance(w_d.implementation, SharedDictImplementation)) From antocuni at codespeak.net Tue Sep 15 14:11:50 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 15 Sep 2009 14:11:50 +0200 (CEST) Subject: [pypy-svn] r67690 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090915121150.59B4416801D@codespeak.net> Author: antocuni Date: Tue Sep 15 14:11:48 2009 New Revision: 67690 Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py Log: fix this test. Btw, it seems that returning None is not really supported by ootype tests, causing all subsequent tests to fail. Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Tue Sep 15 14:11:48 2009 @@ -639,7 +639,7 @@ inst = cls() x += inst.foo n -= 1 - return + return x res = self.meta_interp(f, [20]) assert res == f(20) self.check_loops(call=0) From arigo at codespeak.net Tue Sep 15 15:24:49 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 15:24:49 +0200 (CEST) Subject: [pypy-svn] r67691 - pypy/trunk/pypy/rpython/lltypesystem Message-ID: <20090915132449.02771168008@codespeak.net> Author: arigo Date: Tue Sep 15 15:24:46 2009 New Revision: 67691 Modified: pypy/trunk/pypy/rpython/lltypesystem/rlist.py Log: Add an ll_assert. This should be always true if translator/simplify.py did its job properly. Modified: pypy/trunk/pypy/rpython/lltypesystem/rlist.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/rlist.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/rlist.py Tue Sep 15 15:24:46 2009 @@ -390,6 +390,7 @@ ll_list2fixed.oopspec = 'list.list2fixed(l)' def ll_list2fixed_exact(l): + ll_assert(l.length == len(l.items), "ll_list2fixed_exact: bad length") return l.items # ____________________________________________________________ From arigo at codespeak.net Tue Sep 15 15:38:23 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 15:38:23 +0200 (CEST) Subject: [pypy-svn] r67692 - pypy/branch/asmgcroot-callback Message-ID: <20090915133823.16CE8168008@codespeak.net> Author: arigo Date: Tue Sep 15 15:38:22 2009 New Revision: 67692 Added: pypy/branch/asmgcroot-callback/ - copied from r67691, pypy/trunk/ Log: A branch in which to try to implement callback support in --gcrootfinder=asmgcc. From arigo at codespeak.net Tue Sep 15 15:41:18 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 15:41:18 +0200 (CEST) Subject: [pypy-svn] r67693 - in pypy/branch/asmgcroot-callback/pypy: rpython rpython/lltypesystem rpython/lltypesystem/test rpython/memory/gctransform translator/c/src Message-ID: <20090915134118.30A6F168008@codespeak.net> Author: arigo Date: Tue Sep 15 15:41:17 2009 New Revision: 67693 Modified: pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/test/test_lloperation.py pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Log: Change the operations "gc_llvm_*" into a single better-named operation. Modified: pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py Tue Sep 15 15:41:17 2009 @@ -875,6 +875,9 @@ def op_gc_set_max_heap_size(self, maxsize): raise NotImplementedError("gc_set_max_heap_size") + def op_gc_asmgcroot_static(self, index): + raise NotImplementedError("gc_asmgcroot_static") + def op_do_malloc_fixedsize_clear(self): raise NotImplementedError("do_malloc_fixedsize_clear") Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py Tue Sep 15 15:41:17 2009 @@ -415,13 +415,11 @@ canunwindgc=True), 'gc_x_size_header': LLOp(), - # for llvm.gcroot() support. can change at any time - 'llvm_frameaddress': LLOp(sideeffects=False), - 'llvm_gcmapstart': LLOp(sideeffects=False), - 'llvm_gcmapend': LLOp(sideeffects=False), - 'llvm_gccallshapes': LLOp(sideeffects=False), - 'llvm_store_gcroot': LLOp(), - 'llvm_load_gcroot': LLOp(), + # for asmgcroot support to get the address of various static structures + # 0: gcmapstart + # 1: gcmapend + # 2: gccallshapes + 'gc_asmgcroot_static': LLOp(sideeffects=False), # NOTE NOTE NOTE! don't forget *** canunwindgc=True *** for anything that # can go through a stack unwind, in particular anything that mallocs! Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/test/test_lloperation.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/test/test_lloperation.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/test/test_lloperation.py Tue Sep 15 15:41:17 2009 @@ -50,6 +50,6 @@ for opname, llop in LL_OPERATIONS.items(): if llop.canfold: continue - if opname.startswith('gc_x_') or opname.startswith('llvm_'): + if opname.startswith('gc_x_'): continue # ignore experimental stuff assert opname in LL_INTERP_OPERATIONS Modified: pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py Tue Sep 15 15:41:17 2009 @@ -169,8 +169,8 @@ return caller.frame_address != llmemory.NULL def locate_caller_based_on_retaddr(self, retaddr): - gcmapstart = llop.llvm_gcmapstart(llmemory.Address) - gcmapend = llop.llvm_gcmapend(llmemory.Address) + gcmapstart = llop.gc_asmgcroot_static(llmemory.Address, 0) + gcmapend = llop.gc_asmgcroot_static(llmemory.Address, 1) item = search_in_gcmap(gcmapstart, gcmapend, retaddr) if item: self._shape_decompressor.setpos(item.signed[1]) @@ -297,7 +297,7 @@ def setpos(self, pos): if pos < 0: pos = ~ pos # can ignore this "range" marker here - gccallshapes = llop.llvm_gccallshapes(llmemory.Address) + gccallshapes = llop.gc_asmgcroot_static(llmemory.Address, 2) self.addr = gccallshapes + pos def setaddr(self, addr): Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Tue Sep 15 15:41:17 2009 @@ -43,10 +43,11 @@ "0" (p), "m" (__gcnoreorderhack)); \ _r; }) -#define OP_LLVM_GCMAPSTART(r) r = &__gcmapstart -#define OP_LLVM_GCMAPEND(r) r = &__gcmapend -#define OP_LLVM_GCCALLSHAPES(r) r = &__gccallshapes - +#define OP_GC_ASMGCROOT_STATIC(i, r) r = \ + i == 0 ? &__gcmapstart : \ + i == 1 ? &__gcmapend : \ + i == 2 ? &__gccallshapes : \ + NULL #define RAW_MALLOC_ZERO_FILLED 0 From arigo at codespeak.net Tue Sep 15 16:35:08 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 16:35:08 +0200 (CEST) Subject: [pypy-svn] r67694 - in pypy/branch/asmgcroot-callback/pypy: rpython/memory/gctransform translator/c/gcc translator/c/src Message-ID: <20090915143508.6BD4516800D@codespeak.net> Author: arigo Date: Tue Sep 15 16:35:06 2009 New Revision: 67694 Modified: pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Log: Change pypy_asm_stackwalk to store the current stack top in a linked list instead of passing it as an argument to its callback. This lets the callback handle multiple stacks by walking this list. The list is doubly-linked and circular, to make it easy to remove the added item. Modified: pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py Tue Sep 15 16:35:06 2009 @@ -42,8 +42,8 @@ def __init__(self, gctransformer): BaseRootWalker.__init__(self, gctransformer) - def _asm_callback(initialframedata): - self.walk_stack_from(initialframedata) + def _asm_callback(): + self.walk_stack_from() self._asm_callback = _asm_callback self._shape_decompressor = ShapeDecompressor() if hasattr(gctransformer.translator, '_jit2gc'): @@ -60,20 +60,31 @@ gcdata._gc_collect_stack_root = collect_stack_root pypy_asm_stackwalk(llhelper(ASM_CALLBACK_PTR, self._asm_callback)) - def walk_stack_from(self, initialframedata): + def walk_stack_from(self): curframe = lltype.malloc(WALKFRAME, flavor='raw') otherframe = lltype.malloc(WALKFRAME, flavor='raw') - self.fill_initial_frame(curframe, initialframedata) - # Loop over all the frames in the stack - while self.walk_to_parent_frame(curframe, otherframe): - swap = curframe - curframe = otherframe # caller becomes callee - otherframe = swap + + # Walk over all the pieces of stack. They are in a circular linked + # list of structures of 7 words, the 2 first words being prev/next. + # The anchor of this linked list is: + anchor = llop.gc_asmgcroot_static(llmemory.Address, 3) + initialframedata = anchor.address[1] + while initialframedata != anchor: # while we have not looped back + self.fill_initial_frame(curframe, initialframedata) + # Loop over all the frames in the stack + while self.walk_to_parent_frame(curframe, otherframe): + swap = curframe + curframe = otherframe # caller becomes callee + otherframe = swap + # Then proceed to the next piece of stack + initialframedata = initialframedata.address[1] + # lltype.free(otherframe, flavor='raw') lltype.free(curframe, flavor='raw') def fill_initial_frame(self, curframe, initialframedata): # Read the information provided by initialframedata + initialframedata += 2*sizeofaddr #skip the prev/next words at the start reg = 0 while reg < CALLEE_SAVED_REGS: # NB. 'initialframedata' stores the actual values of the @@ -339,8 +350,7 @@ INDEX_OF_EBP = 3 FRAME_PTR = CALLEE_SAVED_REGS # the frame is at index 4 in the array -ASM_CALLBACK_PTR = lltype.Ptr(lltype.FuncType([llmemory.Address], - lltype.Void)) +ASM_CALLBACK_PTR = lltype.Ptr(lltype.FuncType([], lltype.Void)) # used internally by walk_stack_from() WALKFRAME = lltype.Struct('WALKFRAME', Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py Tue Sep 15 16:35:06 2009 @@ -100,21 +100,34 @@ /* See description in asmgcroot.py */ movl 4(%esp), %edx /* my argument, which is the callback */ movl %esp, %eax /* my frame top address */ - pushl %eax /* ASM_FRAMEDATA[4] */ - pushl %ebp /* ASM_FRAMEDATA[3] */ - pushl %edi /* ASM_FRAMEDATA[2] */ - pushl %esi /* ASM_FRAMEDATA[1] */ - pushl %ebx /* ASM_FRAMEDATA[0] */ - movl %esp, %eax /* address of ASM_FRAMEDATA */ - pushl %eax /* respect Mac OS X 16 bytes aligment */ - pushl %eax /* the one argument to the callback */ - call *%edx /* invoke the callback */ - addl $8, %esp - popl %ebx /* restore from ASM_FRAMEDATA[0] */ - popl %esi /* restore from ASM_FRAMEDATA[1] */ - popl %edi /* restore from ASM_FRAMEDATA[2] */ - popl %ebp /* restore from ASM_FRAMEDATA[3] */ - popl %eax + pushl %eax /* ASM_FRAMEDATA[6] */ + pushl %ebp /* ASM_FRAMEDATA[5] */ + pushl %edi /* ASM_FRAMEDATA[4] */ + pushl %esi /* ASM_FRAMEDATA[3] */ + pushl %ebx /* ASM_FRAMEDATA[2] */ + + /* Add this ASM_FRAMEDATA to the front of the circular linked */ + /* list. Let's call it 'self'. */ + movl __gcrootanchor+4, %eax /* next = gcrootanchor->next */ + pushl %eax /* self->next = next */ + pushl $__gcrootanchor /* self->prev = gcrootanchor */ + movl %esp, __gcrootanchor+4 /* gcrootanchor->next = self */ + movl %esp, (%eax) /* next->prev = self */ + + /* note: the Mac OS X 16 bytes aligment must be respected */ + call *%edx /* invoke the callback */ + + /* Detach this ASM_FRAMEDATA from the circular linked list */ + popl %ecx /* prev = self->prev */ + popl %edx /* next = self->next */ + movl %edx, 4(%ecx) /* prev->next = next */ + movl %ecx, (%edx) /* next->prev = prev */ + + popl %ebx /* restore from ASM_FRAMEDATA[2] */ + popl %esi /* restore from ASM_FRAMEDATA[3] */ + popl %edi /* restore from ASM_FRAMEDATA[4] */ + popl %ebp /* restore from ASM_FRAMEDATA[5] */ + popl %edx /* ignored ASM_FRAMEDATA[6] */ ret """ _variant(elf='.size pypy_asm_stackwalk, .-pypy_asm_stackwalk', @@ -122,6 +135,12 @@ mingw32='') print >> output, '\t.data' print >> output, '\t.align\t4' + _globl('__gcrootanchor') + _label('__gcrootanchor') + print >> output, '\t/* A circular doubly-linked list of all */' + print >> output, '\t/* the ASM_FRAMEDATAs currently alive */' + print >> output, '\t.long\t__gcrootanchor /* prev */' + print >> output, '\t.long\t__gcrootanchor /* next */' _globl('__gcmapstart') _label('__gcmapstart') for label, state, is_range in self.gcmaptable: Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Tue Sep 15 16:35:06 2009 @@ -20,6 +20,7 @@ extern char __gcmapstart; extern char __gcmapend; extern char __gccallshapes; +extern void *__gcrootanchor; #define __gcnoreorderhack __gcmapend /* The following pseudo-instruction is used by --gcrootfinder=asmgcc @@ -47,6 +48,7 @@ i == 0 ? &__gcmapstart : \ i == 1 ? &__gcmapend : \ i == 2 ? &__gccallshapes : \ + i == 3 ? &__gcrootanchor : \ NULL #define RAW_MALLOC_ZERO_FILLED 0 From antocuni at codespeak.net Tue Sep 15 16:40:45 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 15 Sep 2009 16:40:45 +0200 (CEST) Subject: [pypy-svn] r67695 - in pypy/trunk/pypy: annotation config doc/discussion rpython rpython/lltypesystem rpython/ootypesystem translator/test Message-ID: <20090915144045.083CA16800F@codespeak.net> Author: antocuni Date: Tue Sep 15 16:40:44 2009 New Revision: 67695 Removed: pypy/trunk/pypy/doc/discussion/list_comprehension_ootype.txt Modified: pypy/trunk/pypy/annotation/unaryop.py pypy/trunk/pypy/config/translationoption.py pypy/trunk/pypy/rpython/lltypesystem/rlist.py pypy/trunk/pypy/rpython/ootypesystem/rlist.py pypy/trunk/pypy/rpython/rlist.py pypy/trunk/pypy/translator/test/test_simplify.py Log: enable list comprehension optimization for ootype. This is slightly more convoluted than in lltype because there is no simple way to convert from an ootype.List to an ootype.Array apart copying item by item. Thus, to optimize the common case instead of a List we use a temporary record holding an array and the length. For the other cases, items are just copied one by one Modified: pypy/trunk/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/pypy/annotation/unaryop.py (original) +++ pypy/trunk/pypy/annotation/unaryop.py Tue Sep 15 16:40:44 2009 @@ -342,6 +342,8 @@ # not over an iterator object (because it has no known length) s_iterable = args_s[0] if isinstance(s_iterable, (SomeList, SomeDict)): + lst = SomeList(lst.listdef) # create a fresh copy + lst.known_maxlength = True lst.listdef.resize() lst.listdef.listitem.hint_maxlength = True elif 'fence' in hints: Modified: pypy/trunk/pypy/config/translationoption.py ============================================================================== --- pypy/trunk/pypy/config/translationoption.py (original) +++ pypy/trunk/pypy/config/translationoption.py Tue Sep 15 16:40:44 2009 @@ -29,7 +29,6 @@ ("translation.backendopt.constfold", False), ("translation.backendopt.heap2stack", False), ("translation.backendopt.clever_malloc_removal", False), - ("translation.list_comprehension_operations", False), ("translation.gc", "boehm"), # it's not really used, but some jit code expects a value here ] }), Modified: pypy/trunk/pypy/rpython/lltypesystem/rlist.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/rlist.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/rlist.py Tue Sep 15 16:40:44 2009 @@ -41,7 +41,8 @@ class BaseListRepr(AbstractBaseListRepr): rstr_ll = rstr.LLHelpers - def __init__(self, rtyper, item_repr, listitem=None): + # known_maxlength is ignored by lltype but used by ootype + def __init__(self, rtyper, item_repr, listitem=None, known_maxlength=False): self.rtyper = rtyper self.LIST = GcForwardReference() self.lowleveltype = Ptr(self.LIST) @@ -136,15 +137,8 @@ hints = hop.args_s[-1].const if 'maxlength' in hints: if optimized: - v_iterable = hop.args_v[1] - s_iterable = hop.args_s[1] - r_iterable = hop.args_r[1] v_list = hop.inputarg(self, arg=0) - hop2 = hop.copy() - while hop2.nb_args > 0: - hop2.r_s_popfirstarg() - hop2.v_s_insertfirstarg(v_iterable, s_iterable) - v_maxlength = r_iterable.rtype_len(hop2) + v_maxlength = self._get_v_maxlength(hop) hop.llops.gendirectcall(ll_set_maxlength, v_list, v_maxlength) return v_list if 'fence' in hints: Modified: pypy/trunk/pypy/rpython/ootypesystem/rlist.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/rlist.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/rlist.py Tue Sep 15 16:40:44 2009 @@ -11,7 +11,7 @@ class BaseListRepr(AbstractBaseListRepr): rstr_ll = rstr.LLHelpers - def __init__(self, rtyper, item_repr, listitem=None): + def __init__(self, rtyper, item_repr, listitem=None, known_maxlength=False): self.rtyper = rtyper if not isinstance(item_repr, Repr): assert callable(item_repr) @@ -19,6 +19,7 @@ else: self.external_item_repr, self.item_repr = \ externalvsinternal(rtyper, item_repr) + self.known_maxlength = known_maxlength self.LIST = self._make_empty_type() self.lowleveltype = self.LIST self.listitem = listitem @@ -29,8 +30,14 @@ if 'item_repr' not in self.__dict__: self.external_item_repr, self.item_repr = \ self._externalvsinternal(self.rtyper, self._item_repr_computer()) - if not ootype.hasItemType(self.lowleveltype): - ootype.setItemType(self.lowleveltype, self.item_repr.lowleveltype) + if not self._hasItemType(self.lowleveltype): + self._setItemType(self.lowleveltype, self.item_repr.lowleveltype) + + def _hasItemType(self, LIST): + return ootype.hasItemType(LIST) + + def _setItemType(self, LIST, ITEM): + ootype.setItemType(LIST, ITEM) def _externalvsinternal(self, rtyper, item_repr): return item_repr, item_repr @@ -49,15 +56,57 @@ def rtype_hint(self, hop): hints = hop.args_s[-1].const - if 'maxlength' in hints or 'fence' in hints: - # see doc/discussion/list_comprehension_ootype.txt - assert False, 'TODO' + optimized = getattr(self.listitem, 'hint_maxlength', False) + if optimized and 'maxlength' in hints: + return self.rtype_hint_maxlength(hop) + elif 'fence' in hints: + return self.rtype_hint_fence(hop) return AbstractBaseListRepr.rtype_hint(self, hop) + def rtype_hint_maxlength(self, hop): + v_maxlength = self._get_v_maxlength(hop) + RESLIST = hop.r_result.LIST + _, ARRAY = RESLIST._lookup_field('items') + cRESLIST = hop.inputconst(Void, hop.r_result.LIST) + cARRAY = hop.inputconst(Void, ARRAY) + return hop.llops.gendirectcall(ll_newlist_maxlength, cRESLIST, cARRAY, v_maxlength) + + def rtype_hint_fence(self, hop): + hints = hop.args_s[-1].const + v_list = hop.inputarg(self, arg=0) + RESLIST = hop.r_result.LIST + cRESLIST = hop.inputconst(Void, hop.r_result.LIST) + if self.known_maxlength: + if isinstance(hop.r_result, FixedSizeListRepr): + if 'exactlength' in hints: + llfn = ll_known_maxlength2fixed_exact + else: + llfn = ll_known_maxlength2fixed + else: + llfn = ll_known_maxlength2list + else: + llfn = ll_list2fixed + return hop.llops.gendirectcall(llfn, cRESLIST, v_list) + class ListRepr(AbstractListRepr, BaseListRepr): + + def _hasItemType(self, LIST): + if self.known_maxlength: + _, ARRAY = LIST._lookup_field('items') + return ootype.hasItemType(ARRAY) + else: + return ootype.hasItemType(LIST) + + def _setItemType(self, LIST, ITEM): + if self.known_maxlength: + _, ARRAY = LIST._lookup_field('items') + ootype.setItemType(ARRAY, ITEM) + else: + ootype.setItemType(LIST, ITEM) + def null_const(self): - return self.LIST._null + return ootype.null(self.LIST) def prepare_const(self, n): result = self.LIST.ll_newlist(n) @@ -67,7 +116,10 @@ return ListIteratorRepr(self) def _make_empty_type(self): - return ootype.List() + if self.known_maxlength: + return ootype.Record({"items": ootype.Array(), "length": ootype.Signed}) + else: + return ootype.List() def _generate_newlist(self, llops, items_v): c_list = inputconst(ootype.Void, self.lowleveltype) @@ -77,6 +129,15 @@ llops.genop("oosend", [c_resize, v_result, c_length], resulttype=ootype.Void) return v_result + def rtype_method_append(self, hop): + if self.known_maxlength: + v_lst, v_value = hop.inputargs(self, self.item_repr) + hop.exception_cannot_occur() + hop.gendirectcall(ll_append_maxlength, v_lst, v_value) + else: + return AbstractListRepr.rtype_method_append(self, hop) + + class __extend__(pairtype(BaseListRepr, BaseListRepr)): def rtype_is_((r_lst1, r_lst2), hop): @@ -100,6 +161,50 @@ lst._ll_resize(length) return lst +# lists with known_maxlength +def ll_newlist_maxlength(LIST, ARRAY, length): + lst = ootype.new(LIST) + lst.items = ootype.oonewarray(ARRAY, length) + lst.length = 0 + return lst + +def ll_append_maxlength(l, newitem): + l.items.ll_setitem_fast(l.length, newitem) + l.length += 1 + +def ll_known_maxlength2fixed(ARRAY, l): + n = l.length + olditems = l.items + if n == olditems.ll_length(): + return olditems + else: + newitems = ootype.oonewarray(ARRAY, n) + for i in range(n): + item = olditems.ll_getitem_fast(i) + newitems.ll_setitem_fast(i, item) + return newitems +ll_known_maxlength2fixed.oopspec = 'list.list2fixed(l)' + +def ll_known_maxlength2fixed_exact(ARRAY, l): + return l.items + +def ll_known_maxlength2list(RESLIST, l): + res = ootype.new(RESLIST) + length = l.length + res._ll_resize_ge(length) + for i in range(length): + item = l.items.ll_getitem_fast(i) + res.ll_setitem_fast(i, item) + return res + +def ll_list2fixed(RESLIST, l): + length = l.ll_length() + res = ootype.oonewarray(RESLIST, length) + for i in range(length): + item = l.ll_getitem_fast(i) + res.ll_setitem_fast(i, item) + return res + # Fixed-size list class FixedSizeListRepr(AbstractFixedSizeListRepr, BaseListRepr): def compact_repr(self): Modified: pypy/trunk/pypy/rpython/rlist.py ============================================================================== --- pypy/trunk/pypy/rpython/rlist.py (original) +++ pypy/trunk/pypy/rpython/rlist.py Tue Sep 15 16:40:44 2009 @@ -42,16 +42,17 @@ # cannot do the rtyper.getrepr() call immediately, for the case # of recursive structures -- i.e. if the listdef contains itself rlist = rtyper.type_system.rlist + item_repr = lambda: rtyper.getrepr(listitem.s_value) + known_maxlength = getattr(self, 'known_maxlength', False) if self.listdef.listitem.resized: - return rlist.ListRepr(rtyper, - lambda: rtyper.getrepr(listitem.s_value), listitem) + return rlist.ListRepr(rtyper, item_repr, listitem, known_maxlength) else: - return rlist.FixedSizeListRepr(rtyper, - lambda: rtyper.getrepr(listitem.s_value), listitem) + return rlist.FixedSizeListRepr(rtyper, item_repr, listitem) def rtyper_makekey(self): self.listdef.listitem.dont_change_any_more = True - return self.__class__, self.listdef.listitem + known_maxlength = getattr(self, 'known_maxlength', False) + return self.__class__, self.listdef.listitem, known_maxlength class AbstractBaseListRepr(Repr): @@ -160,6 +161,17 @@ item_eq_func = self.item_repr.get_ll_eq_function() return list_eq + def _get_v_maxlength(self, hop): + v_iterable = hop.args_v[1] + s_iterable = hop.args_s[1] + r_iterable = hop.args_r[1] + hop2 = hop.copy() + while hop2.nb_args > 0: + hop2.r_s_popfirstarg() + hop2.v_s_insertfirstarg(v_iterable, s_iterable) + v_maxlength = r_iterable.rtype_len(hop2) + return v_maxlength + class AbstractListRepr(AbstractBaseListRepr): Modified: pypy/trunk/pypy/translator/test/test_simplify.py ============================================================================== --- pypy/trunk/pypy/translator/test/test_simplify.py (original) +++ pypy/trunk/pypy/translator/test/test_simplify.py Tue Sep 15 16:40:44 2009 @@ -348,8 +348,7 @@ if conftest.option.view: t.view() t.buildrtyper(self.typesystem).specialize() - if self.typesystem == 'lltype': - backend_optimizations(t) + backend_optimizations(t) if conftest.option.view: t.view() graph = graphof(t, func) @@ -364,6 +363,14 @@ res = interp.eval_graph(graph, [10]) assert res == 5 * 17 + def test_simple_non_exact(self): + def main(n): + lst = [x*17 for x in range(n) if x < 5] + return len(lst) + interp, graph = self.specialize(main, [int]) + res = interp.eval_graph(graph, [10]) + assert res == 5 + def test_mutated_after_listcomp(self): def main(n): lst = [x*17 for x in range(n)] @@ -424,7 +431,6 @@ res = interp.eval_graph(graph, [10]) assert res == 5 * 17 -## TODO: maxlength and fence hints are not supported by ootype -## see doc/discussion/list_comprehension_ootype.txt -##class TestOOSpecializeListComprehension(TestLLSpecializeListComprehension): -## typesystem = 'ootype' + +class TestOOSpecializeListComprehension(TestLLSpecializeListComprehension): + typesystem = 'ootype' From iko at codespeak.net Tue Sep 15 16:40:51 2009 From: iko at codespeak.net (iko at codespeak.net) Date: Tue, 15 Sep 2009 16:40:51 +0200 (CEST) Subject: [pypy-svn] r67696 - in pypy/build/benchmark: . test Message-ID: <20090915144051.A6C2A168014@codespeak.net> Author: iko Date: Tue Sep 15 16:40:51 2009 New Revision: 67696 Modified: pypy/build/benchmark/interpreters.py pypy/build/benchmark/runner.py pypy/build/benchmark/test/test_interpreters.py Log: clean up a bit add elapse time default statistic Modified: pypy/build/benchmark/interpreters.py ============================================================================== --- pypy/build/benchmark/interpreters.py (original) +++ pypy/build/benchmark/interpreters.py Tue Sep 15 16:40:51 2009 @@ -1,4 +1,4 @@ -import os, fcntl, gc, select, fcntl, signal, errno +import os, fcntl, gc, select, fcntl, signal, errno, time BUFSIZ = 8192 @@ -11,27 +11,31 @@ def __getattr__(self, key): if key in self._keys: return self[self._keys.index(key)] - return tuple.__getattr__(self, key) + raise AttributeError("'RUsage' object has no attribute %r" % (key,)) class BaseInterpreter(object): rusage = None status = None cpid = None pid = None + starttime = None def __init__(self, script): self.script = script + self.statistics = {} def sighandler(self, sig, frame): + signal.signal(signal.SIGCHLD, self.sighandler) cpid, status, rusage = os.wait4(self.pid, os.WNOHANG) if cpid == self.pid: self.cpid = cpid self.rusage = RUsage(rusage) self.status = status + self.statistics['ru_elapsed'] = time.time() - self.starttime + def run(self): - # Set signal handler to get select to return on exit signal.signal(signal.SIGCHLD, self.sighandler) stdout_r, stdout_w = os.pipe() @@ -41,6 +45,7 @@ gc_was_enabled = gc.isenabled() gc.disable() + self.starttime = time.time() try: self.pid = os.fork() except: @@ -65,6 +70,8 @@ if gc_was_enabled: gc.enable() + self.script.do_start(self) + fdset = set([stdout_r, stderr_r]) timeout = None @@ -95,12 +102,19 @@ fdset.remove(stderr_r) self.do_stderr(data) + self._set_statistics() + self.script.do_finish(self) + + def _set_statistics(self): + """ set statistics from rusage """ + for stat in ('ru_utime', 'ru_stime', 'ru_maxrss'): + self.statistics[stat] = getattr(self.rusage, stat) def do_stdout(self, data): - self.script.do_stdout(data) + self.script.do_stdout(self, data) def do_stderr(self, data): - self.script.do_stderr(data) + self.script.do_stderr(self, data) def failed(self): if self.status is None: @@ -114,3 +128,5 @@ class PyPyInterpreter(BaseInterpreter): executable = "pypy-c" + +interpreters = [PythonInterpreter, PyPyInterpreter] Modified: pypy/build/benchmark/runner.py ============================================================================== --- pypy/build/benchmark/runner.py (original) +++ pypy/build/benchmark/runner.py Tue Sep 15 16:40:51 2009 @@ -8,10 +8,20 @@ def __init__(self, path): self.runargs = [str(path)] - def do_stdout(self, data): + def do_start(self, interp): + """ Interpreter has been started """ + pass + + def do_finish(self, interp): + """ Interpreter has exited """ + pass + + def do_stdout(self, interp, data): + """ stdout data received from interpreter """ sys.stdout.write(data) - def do_stderr(self, data): + def do_stderr(self, interp, data): + """ stderr data received from interpreter """ sys.stderr.write(data) class BenchmarkIterator(object): @@ -27,22 +37,12 @@ continue yield self.factory(f) -# XXX move to interpreters -class InterpreterIterator(list): - """ an iterable of the interpreters to run """ - def __init__(self): - # Introspect interpreters - bi = interpreters.BaseInterpreter - for name in dir(interpreters): - i = getattr(interpreters, name) - if i is not bi and type(i) is type(bi) and issubclass(i, bi): - self.append(i) - class BenchmarkRunner(object): """ Run the benchmarks using the defined interpreters """ + interpreters = interpreters.interpreters + def __init__(self, benchmarkdir): self.benchmarks = BenchmarkIterator(benchmarkdir, BaseBenchmark) - self.interpreters = InterpreterIterator() def run(self): for bm in self.benchmarks: @@ -51,7 +51,7 @@ print interp.executable i = interp(bm) i.run() - print 'Time: ', (i.rusage.ru_stime + i.rusage.ru_utime) + print 'Time: %(ru_elapsed).4f %(ru_stime).4f %(ru_utime).4f ' % i.statistics if __name__ == '__main__': if len(sys.argv) >= 2: Modified: pypy/build/benchmark/test/test_interpreters.py ============================================================================== --- pypy/build/benchmark/test/test_interpreters.py (original) +++ pypy/build/benchmark/test/test_interpreters.py Tue Sep 15 16:40:51 2009 @@ -15,11 +15,19 @@ self.runargs = args self.stdout = [] self.stderr = [] + self.interp = None + self.finish = None - def do_stdout(self, data): + def do_start(self, interp): + self.interp = interp + + def do_finish(self, interp): + self.finish = interp + + def do_stdout(self, interp, data): self.stdout.append(data) - def do_stderr(self, data): + def do_stderr(self, interp, data): self.stderr.append(data) class TestInterpreter(object): @@ -31,6 +39,13 @@ assert os.WIFEXITED(bi.status) assert os.WEXITSTATUS(bi.status) == 0 assert not bi.failed() + assert s.interp is bi + assert s.finish is bi + assert bi.statistics['ru_elapsed'] >= 0 + assert bi.statistics['ru_stime'] >= 0 + assert bi.statistics['ru_utime'] >= 0 + assert bi.statistics['ru_elapsed'] >= (bi.statistics['ru_stime'] + + bi.statistics['ru_utime']) def test_fail(self): s = FakeScript() @@ -45,7 +60,7 @@ bi = EchoInterpreter(s) bi.run() assert s.stdout == ['fake\n', ''] - + class TestRUsage(object): def test_basic(self): ru = RUsage(range(16)) From arigo at codespeak.net Tue Sep 15 17:15:02 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 17:15:02 +0200 (CEST) Subject: [pypy-svn] r67697 - in pypy/branch/asmgcroot-callback/pypy: rpython rpython/lltypesystem translator/c/gcc translator/c/src Message-ID: <20090915151502.5F2BE16800B@codespeak.net> Author: arigo Date: Tue Sep 15 17:15:00 2009 New Revision: 67697 Modified: pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Log: In-progress. Add an operation that turns into a marker in the assembler source, used to know which functions are callbacks from C. Modified: pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py Tue Sep 15 17:15:00 2009 @@ -878,6 +878,9 @@ def op_gc_asmgcroot_static(self, index): raise NotImplementedError("gc_asmgcroot_static") + def op_gc_stack_bottom(): + pass # marker for trackgcroot.py + def op_do_malloc_fixedsize_clear(self): raise NotImplementedError("do_malloc_fixedsize_clear") Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py Tue Sep 15 17:15:00 2009 @@ -420,6 +420,7 @@ # 1: gcmapend # 2: gccallshapes 'gc_asmgcroot_static': LLOp(sideeffects=False), + 'gc_stack_bottom': LLOp(sideeffects=False, canrun=True), # NOTE NOTE NOTE! don't forget *** canunwindgc=True *** for anything that # can go through a stack unwind, in particular anything that mallocs! Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py Tue Sep 15 17:15:00 2009 @@ -382,6 +382,9 @@ print arg, print +def op_gc_stack_bottom(): + pass # marker for trackgcroot.py + def op_promote_virtualizable(object, fieldname, flags): pass # XXX should do something Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py Tue Sep 15 17:15:00 2009 @@ -205,6 +205,8 @@ """ Function creating wrappers for callbacks. Note that this is cheating as we assume constant callbacks and we just memoize wrappers """ + from pypy.rpython.lltypesystem import lltype + from pypy.rpython.lltypesystem.lloperation import llop if hasattr(callable, '_errorcode_'): errorcode = callable._errorcode_ else: @@ -213,6 +215,7 @@ args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))]) source = py.code.Source(r""" def wrapper(%s): # no *args - no GIL for mallocing the tuple + llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py if aroundstate is not None: before = aroundstate.before after = aroundstate.after Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py Tue Sep 15 17:15:00 2009 @@ -41,6 +41,7 @@ LOCALVAR = r"%eax|%edx|%ecx|%ebx|%esi|%edi|%ebp|\d*[(]%esp[)]" LOCALVARFP = LOCALVAR + r"|-?\d*[(]%ebp[)]" r_gcroot_marker = re.compile(r"\t/[*] GCROOT ("+LOCALVARFP+") [*]/") +r_bottom_marker = re.compile(r"\t/[*] GC_STACK_BOTTOM [*]/") r_localvarnofp = re.compile(LOCALVAR) r_localvarfp = re.compile(LOCALVARFP) r_localvar_esp = re.compile(r"(\d*)[(]%esp[)]") @@ -229,7 +230,8 @@ def process_function(self, lines, entrypoint, filename): tracker = FunctionGcRootTracker(lines, filetag=getidentifier(filename), format=self.format) - tracker.is_main = tracker.funcname == entrypoint + is_main = tracker.funcname == entrypoint + tracker.is_stack_bottom = is_main if self.verbose == 1: sys.stderr.write('.') elif self.verbose > 1: @@ -244,7 +246,7 @@ self.gcmaptable[:0] = table else: self.gcmaptable.extend(table) - self.seen_main |= tracker.is_main + self.seen_main |= is_main return tracker.lines @@ -271,7 +273,8 @@ self.uses_frame_pointer = False self.r_localvar = r_localvarnofp self.filetag = filetag - self.is_main = False + # a "stack bottom" function is either main() or a callback from C code + self.is_stack_bottom = False def computegcmaptable(self, verbose=0): self.findlabels() @@ -297,7 +300,7 @@ for insn in self.list_call_insns(): if not hasattr(insn, 'framesize'): continue # calls that never end up reaching a RET - if self.is_main: + if self.is_stack_bottom: retaddr = LOC_NOWHERE # end marker for asmgcroot.py elif self.uses_frame_pointer: retaddr = frameloc(LOC_EBP_BASED, 4) @@ -323,7 +326,7 @@ else: regindex = CALLEE_SAVE_REGISTERS.index(tag) shape[1 + regindex] = loc - if LOC_NOWHERE in shape and not self.is_main: + if LOC_NOWHERE in shape and not self.is_stack_bottom: reg = CALLEE_SAVE_REGISTERS[shape.index(LOC_NOWHERE) - 1] raise AssertionError("cannot track where register %s is saved" % (reg,)) @@ -358,6 +361,8 @@ insn = meth(line) elif r_gcroot_marker.match(line): insn = self._visit_gcroot_marker(line) + elif r_bottom_marker.match(line): + self.is_stack_bottom = True elif line == '\t/* ignore_in_trackgcroot */\n': ignore_insns = True elif line == '\t/* end_ignore_in_trackgcroot */\n': @@ -469,7 +474,7 @@ yield source for insn in self.insns: - for loc, tag in insn.requestgcroots().items(): + for loc, tag in insn.requestgcroots(self).items(): self.walk_instructions_backwards(walker, insn, loc) def dump(self): @@ -702,7 +707,7 @@ return self._visit_epilogue() + self._visit_pop('%ebp') def visit_ret(self, line): - return InsnRet(self.is_main) + return InsnRet() def visit_jmp(self, line): match = r_jmp_switch.match(line) @@ -724,7 +729,7 @@ if r_unaryinsn_star.match(line): # that looks like an indirect tail-call. # tail-calls are equivalent to RET for us - return InsnRet(self.is_main) + return InsnRet() try: self.conditional_jump(line) except KeyError: @@ -733,7 +738,7 @@ target = match.group(1) assert not target.startswith('.') # tail-calls are equivalent to RET for us - return InsnRet(self.is_main) + return InsnRet() return InsnStop() def register_jump_to(self, label): @@ -837,7 +842,7 @@ return '%s(%s)' % (self.__class__.__name__, ', '.join([str(getattr(self, name)) for name in self._args_])) - def requestgcroots(self): + def requestgcroots(self, tracker): return {} def source_of(self, localvar, tag): @@ -910,11 +915,12 @@ class InsnRet(InsnStop): framesize = 0 - def __init__(self, is_main): - self.is_main = is_main - def requestgcroots(self): - if self.is_main: # no need to track the value of these registers in - return {} # the caller function if we are the main() + def requestgcroots(self, tracker): + # no need to track the value of these registers in the caller + # function if we are the main(), or if we are flagged as a + # "bottom" function (a callback from C code) + if tracker.is_stack_bottom: + return {} else: return dict(zip(CALLEE_SAVE_REGISTERS, CALLEE_SAVE_REGISTERS)) @@ -957,7 +963,7 @@ _locals_ = ['loc'] def __init__(self, loc): self.loc = loc - def requestgcroots(self): + def requestgcroots(self, tracker): return {self.loc: None} class InsnPrologue(Insn): Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Tue Sep 15 17:15:00 2009 @@ -44,6 +44,9 @@ "0" (p), "m" (__gcnoreorderhack)); \ _r; }) +/* marker for trackgcroot.py */ +#define OP_GC_STACK_BOTTOM(r) asm volatile ("/* GC_STACK_BOTTOM */" : : ) + #define OP_GC_ASMGCROOT_STATIC(i, r) r = \ i == 0 ? &__gcmapstart : \ i == 1 ? &__gcmapend : \ From arigo at codespeak.net Tue Sep 15 17:29:02 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 17:29:02 +0200 (CEST) Subject: [pypy-svn] r67698 - in pypy/branch/asmgcroot-callback/pypy: rpython rpython/lltypesystem rpython/memory/gctransform translator/c/gcc translator/c/src Message-ID: <20090915152902.DB3F9168009@codespeak.net> Author: arigo Date: Tue Sep 15 17:29:01 2009 New Revision: 67698 Modified: pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Log: Improve debugging by crashing with a "clear" error message if the number of stack pieces seen during collection differs from the number of live stack pieces. Modified: pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py Tue Sep 15 17:29:01 2009 @@ -878,7 +878,7 @@ def op_gc_asmgcroot_static(self, index): raise NotImplementedError("gc_asmgcroot_static") - def op_gc_stack_bottom(): + def op_gc_stack_bottom(self, n): pass # marker for trackgcroot.py def op_do_malloc_fixedsize_clear(self): Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py Tue Sep 15 17:29:01 2009 @@ -382,7 +382,7 @@ print arg, print -def op_gc_stack_bottom(): +def op_gc_stack_bottom(n): pass # marker for trackgcroot.py def op_promote_virtualizable(object, fieldname, flags): Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py Tue Sep 15 17:29:01 2009 @@ -215,7 +215,7 @@ args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))]) source = py.code.Source(r""" def wrapper(%s): # no *args - no GIL for mallocing the tuple - llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py + llop.gc_stack_bottom(lltype.Void, +1) # marker for trackgcroot.py if aroundstate is not None: before = aroundstate.before after = aroundstate.after @@ -244,6 +244,7 @@ # here we don't hold the GIL any more. As in the wrapper() produced # by llexternal, it is essential that no exception checking occurs # after the call to before(). + llop.gc_stack_bottom(lltype.Void, -1) # marker for trackgcroot.py return result """ % (args, args)) miniglobals = locals().copy() Modified: pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py Tue Sep 15 17:29:01 2009 @@ -69,6 +69,7 @@ # The anchor of this linked list is: anchor = llop.gc_asmgcroot_static(llmemory.Address, 3) initialframedata = anchor.address[1] + stackscount = 0 while initialframedata != anchor: # while we have not looped back self.fill_initial_frame(curframe, initialframedata) # Loop over all the frames in the stack @@ -78,7 +79,13 @@ otherframe = swap # Then proceed to the next piece of stack initialframedata = initialframedata.address[1] + stackscount += 1 # + expected = llop.gc_asmgcroot_static(llmemory.Address, 4) + ll_assert(not (stackscount < expected.signed[0]), + "non-closed stacks around") + ll_assert(stackscount == expected.signed[0], + "stacks counter corruption?") lltype.free(otherframe, flavor='raw') lltype.free(curframe, flavor='raw') Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py Tue Sep 15 17:29:01 2009 @@ -142,6 +142,9 @@ print >> output, '\t/* the ASM_FRAMEDATAs currently alive */' print >> output, '\t.long\t__gcrootanchor /* prev */' print >> output, '\t.long\t__gcrootanchor /* next */' + _globl('__gcstackscount') + _label('__gcstackscount') + print >> output, '\t.long\t1' _globl('__gcmapstart') _label('__gcmapstart') for label, state, is_range in self.gcmaptable: Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Tue Sep 15 17:29:01 2009 @@ -21,6 +21,7 @@ extern char __gcmapend; extern char __gccallshapes; extern void *__gcrootanchor; +extern long __gcstackscount; /* for debugging */ #define __gcnoreorderhack __gcmapend /* The following pseudo-instruction is used by --gcrootfinder=asmgcc @@ -45,13 +46,16 @@ _r; }) /* marker for trackgcroot.py */ -#define OP_GC_STACK_BOTTOM(r) asm volatile ("/* GC_STACK_BOTTOM */" : : ) +#define OP_GC_STACK_BOTTOM(n, r) \ + asm volatile ("/* GC_STACK_BOTTOM */" : : ); \ + __gcstackscount += n #define OP_GC_ASMGCROOT_STATIC(i, r) r = \ i == 0 ? &__gcmapstart : \ i == 1 ? &__gcmapend : \ i == 2 ? &__gccallshapes : \ i == 3 ? &__gcrootanchor : \ + i == 4 ? &__gcstackscount : \ NULL #define RAW_MALLOC_ZERO_FILLED 0 From arigo at codespeak.net Tue Sep 15 18:40:12 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 18:40:12 +0200 (CEST) Subject: [pypy-svn] r67699 - in pypy/branch/asmgcroot-callback/pypy: rpython/lltypesystem rpython/memory/gctransform translator/c/gcc translator/c/gcc/test translator/c/src Message-ID: <20090915164012.252F116800A@codespeak.net> Author: arigo Date: Tue Sep 15 18:40:09 2009 New Revision: 67699 Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Log: test_callback_with_collect passes... but only when compiled without -O2. The hack of specifying extra arguments does not support being compiled with optimizations -- I guess it's because the extra, apparently-unused arguments give a space in which the function is allowed to write any temporary garbage. Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py Tue Sep 15 18:40:09 2009 @@ -136,6 +136,7 @@ call_external_function = miniglobals['call_external_function'] call_external_function._dont_inline_ = True call_external_function._annspecialcase_ = 'specialize:ll' + call_external_function._gctransformer_hint_close_stack_ = True call_external_function = func_with_new_name(call_external_function, 'ccall_' + name) # don't inline, as a hack to guarantee that no GC pointer is alive Modified: pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py Tue Sep 15 18:40:09 2009 @@ -4,7 +4,8 @@ from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.rbuiltin import gen_cast from pypy.rpython.annlowlevel import llhelper -from pypy.objspace.flow.model import Constant +from pypy.objspace.flow.model import Constant, Variable, Block, Link, copygraph +from pypy.translator.unsimplify import copyvar from pypy.rlib.debug import ll_assert @@ -36,6 +37,54 @@ def build_root_walker(self): return AsmStackRootWalker(self) + def gct_direct_call(self, hop): + fnptr = hop.spaceop.args[0].value + try: + close_stack = fnptr._obj._callable._gctransformer_hint_close_stack_ + except AttributeError: + close_stack = False + if close_stack: + # obscure hack to continue passing the arguments of the call + # across the call to the pypy_asm_stackwalk helper: change the + # callee to expect 9 extra arguments in front (!). This works + # because 8 words is the frame size of the intermediate helper + # and there is one extra argument passed to the helper... + graph = copygraph(fnptr._obj.graph) + block2 = graph.startblock + block2.isstartblock = False + inputvars = [copyvar(None, v) for v in block2.inputargs] + dummyvars = [] + for i in range(9): + v = Variable('dummy') + v.concretetype = lltype.Signed + dummyvars.append(v) + block1 = Block(dummyvars + inputvars) + block1.closeblock(Link(inputvars, block2)) + block1.isstartblock = True + graph.startblock = block1 + FUNC1 = lltype.typeOf(fnptr).TO + FUNC2 = lltype.FuncType(tuple([lltype.Signed] * len(dummyvars)) + + FUNC1.ARGS, + FUNC1.RESULT) + fnptr2 = lltype.functionptr(FUNC2, + fnptr._obj._name + '_dummies', + graph=graph) + c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2)) + HELPERFUNC = lltype.FuncType((lltype.Ptr(FUNC2),) + FUNC1.ARGS, + FUNC1.RESULT) + # + livevars = self.push_roots(hop) + v_asm_stackwalk = hop.genop("cast_pointer", [c_asm_stackwalk], + resulttype=lltype.Ptr(HELPERFUNC)) + hop.genop("indirect_call", + [v_asm_stackwalk, c_fnptr2] + + hop.spaceop.args[1:] + + [Constant(None, lltype.Void)], + resultvar=hop.spaceop.result) + self.pop_roots(hop, livevars) + else: + FrameworkGCTransformer.gct_direct_call(self, hop) + class AsmStackRootWalker(BaseRootWalker): @@ -84,7 +133,7 @@ expected = llop.gc_asmgcroot_static(llmemory.Address, 4) ll_assert(not (stackscount < expected.signed[0]), "non-closed stacks around") - ll_assert(stackscount == expected.signed[0], + ll_assert(not (stackscount > expected.signed[0]), "stacks counter corruption?") lltype.free(otherframe, flavor='raw') lltype.free(curframe, flavor='raw') @@ -369,9 +418,11 @@ pypy_asm_stackwalk = rffi.llexternal('pypy_asm_stackwalk', [ASM_CALLBACK_PTR], - lltype.Void, + lltype.Signed, sandboxsafe=True, _nowrapper=True) +c_asm_stackwalk = Constant(pypy_asm_stackwalk, + lltype.typeOf(pypy_asm_stackwalk)) pypy_asm_gcroot = rffi.llexternal('pypy_asm_gcroot', [llmemory.Address], Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py Tue Sep 15 18:40:09 2009 @@ -95,5 +95,5 @@ # for the individual tests see # ====> ../../test/test_newgc.py - def test_callback_with_collect(self): - py.test.skip("in-progress") + #def test_callback_with_collect(self): + # py.test.skip("in-progress") Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py Tue Sep 15 18:40:09 2009 @@ -115,20 +115,24 @@ movl %esp, __gcrootanchor+4 /* gcrootanchor->next = self */ movl %esp, (%eax) /* next->prev = self */ - /* note: the Mac OS X 16 bytes aligment must be respected */ + /* note: the Mac OS X 16 bytes aligment must be respected. */ + /* Pushed a total of 8 words including my return address; */ + /* please keep this number 8 in sync with asmgcroot.py! */ call *%edx /* invoke the callback */ /* Detach this ASM_FRAMEDATA from the circular linked list */ - popl %ecx /* prev = self->prev */ - popl %edx /* next = self->next */ - movl %edx, 4(%ecx) /* prev->next = next */ - movl %ecx, (%edx) /* next->prev = prev */ + popl %esi /* prev = self->prev */ + popl %edi /* next = self->next */ + movl %edi, 4(%esi) /* prev->next = next */ + movl %esi, (%edi) /* next->prev = prev */ popl %ebx /* restore from ASM_FRAMEDATA[2] */ popl %esi /* restore from ASM_FRAMEDATA[3] */ popl %edi /* restore from ASM_FRAMEDATA[4] */ popl %ebp /* restore from ASM_FRAMEDATA[5] */ - popl %edx /* ignored ASM_FRAMEDATA[6] */ + popl %ecx /* ignored ASM_FRAMEDATA[6] */ + /* the return value is the one of the 'call' above, */ + /* because %eax (and possibly %edx) are unmodified */ ret """ _variant(elf='.size pypy_asm_stackwalk, .-pypy_asm_stackwalk', Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Tue Sep 15 18:40:09 2009 @@ -22,6 +22,7 @@ extern char __gccallshapes; extern void *__gcrootanchor; extern long __gcstackscount; /* for debugging */ +extern long pypy_asm_stackwalk(void*); #define __gcnoreorderhack __gcmapend /* The following pseudo-instruction is used by --gcrootfinder=asmgcc @@ -51,11 +52,11 @@ __gcstackscount += n #define OP_GC_ASMGCROOT_STATIC(i, r) r = \ - i == 0 ? &__gcmapstart : \ - i == 1 ? &__gcmapend : \ - i == 2 ? &__gccallshapes : \ - i == 3 ? &__gcrootanchor : \ - i == 4 ? &__gcstackscount : \ + i == 0 ? (void*)&__gcmapstart : \ + i == 1 ? (void*)&__gcmapend : \ + i == 2 ? (void*)&__gccallshapes : \ + i == 3 ? (void*)&__gcrootanchor : \ + i == 4 ? (void*)&__gcstackscount : \ NULL #define RAW_MALLOC_ZERO_FILLED 0 From arigo at codespeak.net Tue Sep 15 19:48:49 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 19:48:49 +0200 (CEST) Subject: [pypy-svn] r67700 - in pypy/trunk/pypy/rlib: . test Message-ID: <20090915174849.8173B168009@codespeak.net> Author: arigo Date: Tue Sep 15 19:48:47 2009 New Revision: 67700 Modified: pypy/trunk/pypy/rlib/libffi.py pypy/trunk/pypy/rlib/test/test_libffi.py Log: Pass the CDLL instance to the FuncPtr and RawFuncPtr class, as a keepalive, to prevent dlclose() from being called too early. Modified: pypy/trunk/pypy/rlib/libffi.py ============================================================================== --- pypy/trunk/pypy/rlib/libffi.py (original) +++ pypy/trunk/pypy/rlib/libffi.py Tue Sep 15 19:48:47 2009 @@ -506,8 +506,10 @@ class RawFuncPtr(AbstractFuncPtr): - def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL): + def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL, + keepalive=None): AbstractFuncPtr.__init__(self, name, argtypes, restype, flags) + self.keepalive = keepalive self.funcsym = funcsym def call(self, args_ll, ll_result): @@ -527,9 +529,11 @@ ll_args = lltype.nullptr(rffi.VOIDPP.TO) ll_result = lltype.nullptr(rffi.VOIDP.TO) - def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL): + def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL, + keepalive=None): # initialize each one of pointers with null AbstractFuncPtr.__init__(self, name, argtypes, restype, flags) + self.keepalive = keepalive self.funcsym = funcsym self.argnum = len(self.argtypes) self.pushed_args = 0 @@ -609,7 +613,9 @@ lltype.free(ll_libname, flavor='raw') def __del__(self): + print 'in __del__' if self.lib and self.unload_on_finalization: + print 'calling dlclose()' dlclose(self.lib) self.lib = lltype.nullptr(rffi.CCHARP.TO) @@ -617,20 +623,21 @@ # these arguments are already casted to proper ffi # structures! return FuncPtr(name, argtypes, restype, dlsym(self.lib, name), - flags=flags) + flags=flags, keepalive=self) def getrawpointer(self, name, argtypes, restype, flags=FUNCFLAG_CDECL): # these arguments are already casted to proper ffi # structures! return RawFuncPtr(name, argtypes, restype, dlsym(self.lib, name), - flags=flags) + flags=flags, keepalive=self) def getrawpointer_byordinal(self, ordinal, argtypes, restype, flags=FUNCFLAG_CDECL): # these arguments are already casted to proper ffi # structures! return RawFuncPtr(name, argtypes, restype, - dlsym_byordinal(self.lib, ordinal), flags=flags) + dlsym_byordinal(self.lib, ordinal), flags=flags, + keepalive=self) def getaddressindll(self, name): return dlsym(self.lib, name) Modified: pypy/trunk/pypy/rlib/test/test_libffi.py ============================================================================== --- pypy/trunk/pypy/rlib/test/test_libffi.py (original) +++ pypy/trunk/pypy/rlib/test/test_libffi.py Tue Sep 15 19:48:47 2009 @@ -377,6 +377,37 @@ assert not ALLOCATED + def test_cdll_life_time(self): + from pypy.translator.tool.cbuild import ExternalCompilationInfo + from pypy.translator.platform import platform + from pypy.tool.udir import udir + + c_file = udir.ensure("test_libffi", dir=1).join("xlib.c") + c_file.write(py.code.Source(''' + long fun(long i) { + return i + 42; + } + ''')) + eci = ExternalCompilationInfo(export_symbols=['fun']) + lib_name = str(platform.compile([c_file], eci, 'x', standalone=False)) + + lib = CDLL(lib_name) + slong = cast_type_to_ffitype(rffi.LONG) + fun = lib.getrawpointer('fun', [slong], slong) + del lib # already delete here + + buffer = lltype.malloc(rffi.LONGP.TO, 2, flavor='raw') + buffer[0] = 200 + buffer[1] = -1 + fun.call([rffi.cast(rffi.VOIDP, buffer)], + rffi.cast(rffi.VOIDP, rffi.ptradd(buffer, 1))) + assert buffer[1] == 242 + + lltype.free(buffer, flavor='raw') + del fun + + assert not ALLOCATED + class TestWin32Handles: def setup_class(cls): if sys.platform != 'win32': From arigo at codespeak.net Tue Sep 15 19:50:13 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 19:50:13 +0200 (CEST) Subject: [pypy-svn] r67701 - in pypy/branch/asmgcroot-callback/pypy/rlib: . test Message-ID: <20090915175013.A3B9A16800A@codespeak.net> Author: arigo Date: Tue Sep 15 19:50:13 2009 New Revision: 67701 Modified: pypy/branch/asmgcroot-callback/pypy/rlib/libffi.py pypy/branch/asmgcroot-callback/pypy/rlib/test/test_libffi.py Log: Merge r67700 from the trunk. Modified: pypy/branch/asmgcroot-callback/pypy/rlib/libffi.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rlib/libffi.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rlib/libffi.py Tue Sep 15 19:50:13 2009 @@ -506,8 +506,10 @@ class RawFuncPtr(AbstractFuncPtr): - def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL): + def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL, + keepalive=None): AbstractFuncPtr.__init__(self, name, argtypes, restype, flags) + self.keepalive = keepalive self.funcsym = funcsym def call(self, args_ll, ll_result): @@ -527,9 +529,11 @@ ll_args = lltype.nullptr(rffi.VOIDPP.TO) ll_result = lltype.nullptr(rffi.VOIDP.TO) - def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL): + def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL, + keepalive=None): # initialize each one of pointers with null AbstractFuncPtr.__init__(self, name, argtypes, restype, flags) + self.keepalive = keepalive self.funcsym = funcsym self.argnum = len(self.argtypes) self.pushed_args = 0 @@ -609,7 +613,9 @@ lltype.free(ll_libname, flavor='raw') def __del__(self): + print 'in __del__' if self.lib and self.unload_on_finalization: + print 'calling dlclose()' dlclose(self.lib) self.lib = lltype.nullptr(rffi.CCHARP.TO) @@ -617,20 +623,21 @@ # these arguments are already casted to proper ffi # structures! return FuncPtr(name, argtypes, restype, dlsym(self.lib, name), - flags=flags) + flags=flags, keepalive=self) def getrawpointer(self, name, argtypes, restype, flags=FUNCFLAG_CDECL): # these arguments are already casted to proper ffi # structures! return RawFuncPtr(name, argtypes, restype, dlsym(self.lib, name), - flags=flags) + flags=flags, keepalive=self) def getrawpointer_byordinal(self, ordinal, argtypes, restype, flags=FUNCFLAG_CDECL): # these arguments are already casted to proper ffi # structures! return RawFuncPtr(name, argtypes, restype, - dlsym_byordinal(self.lib, ordinal), flags=flags) + dlsym_byordinal(self.lib, ordinal), flags=flags, + keepalive=self) def getaddressindll(self, name): return dlsym(self.lib, name) Modified: pypy/branch/asmgcroot-callback/pypy/rlib/test/test_libffi.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rlib/test/test_libffi.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rlib/test/test_libffi.py Tue Sep 15 19:50:13 2009 @@ -377,6 +377,37 @@ assert not ALLOCATED + def test_cdll_life_time(self): + from pypy.translator.tool.cbuild import ExternalCompilationInfo + from pypy.translator.platform import platform + from pypy.tool.udir import udir + + c_file = udir.ensure("test_libffi", dir=1).join("xlib.c") + c_file.write(py.code.Source(''' + long fun(long i) { + return i + 42; + } + ''')) + eci = ExternalCompilationInfo(export_symbols=['fun']) + lib_name = str(platform.compile([c_file], eci, 'x', standalone=False)) + + lib = CDLL(lib_name) + slong = cast_type_to_ffitype(rffi.LONG) + fun = lib.getrawpointer('fun', [slong], slong) + del lib # already delete here + + buffer = lltype.malloc(rffi.LONGP.TO, 2, flavor='raw') + buffer[0] = 200 + buffer[1] = -1 + fun.call([rffi.cast(rffi.VOIDP, buffer)], + rffi.cast(rffi.VOIDP, rffi.ptradd(buffer, 1))) + assert buffer[1] == 242 + + lltype.free(buffer, flavor='raw') + del fun + + assert not ALLOCATED + class TestWin32Handles: def setup_class(cls): if sys.platform != 'win32': From arigo at codespeak.net Tue Sep 15 19:52:43 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 19:52:43 +0200 (CEST) Subject: [pypy-svn] r67702 - in pypy/branch/asmgcroot-callback/pypy: rpython/memory/gctransform translator/c/gcc Message-ID: <20090915175243.E4AE316800A@codespeak.net> Author: arigo Date: Tue Sep 15 19:52:43 2009 New Revision: 67702 Modified: pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py Log: Intermediate checkin. The tests explode but I need to look around revisions... Modified: pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py Tue Sep 15 19:52:43 2009 @@ -5,6 +5,7 @@ from pypy.rpython.rbuiltin import gen_cast from pypy.rpython.annlowlevel import llhelper from pypy.objspace.flow.model import Constant, Variable, Block, Link, copygraph +from pypy.objspace.flow.model import SpaceOperation from pypy.translator.unsimplify import copyvar from pypy.rlib.debug import ll_assert @@ -18,6 +19,7 @@ class AsmGcRootFrameworkGCTransformer(FrameworkGCTransformer): + _asmgcc_save_restore_arguments = None def push_roots(self, hop, keep_current_args=False): livevars = self.get_livevars_for_roots(hop, keep_current_args) @@ -44,42 +46,70 @@ except AttributeError: close_stack = False if close_stack: - # obscure hack to continue passing the arguments of the call - # across the call to the pypy_asm_stackwalk helper: change the - # callee to expect 9 extra arguments in front (!). This works - # because 8 words is the frame size of the intermediate helper - # and there is one extra argument passed to the helper... - graph = copygraph(fnptr._obj.graph) - block2 = graph.startblock + # We cannot easily pass variable amount of arguments of the call + # across the call to the pypy_asm_stackwalk helper. So we store + # them away and restore them. We need to make a new graph + # that starts with restoring the arguments. + if self._asmgcc_save_restore_arguments is None: + self._asmgcc_save_restore_arguments = {} + sradict = self._asmgcc_save_restore_arguments + sra = [] # list of pointers to raw-malloced containers for args + seen = {} + FUNC1 = lltype.typeOf(fnptr).TO + for TYPE in FUNC1.ARGS: + if isinstance(TYPE, lltype.Ptr): + TYPE = llmemory.Address + num = seen.get(TYPE, 0) + seen[TYPE] = num + 1 + key = (TYPE, num) + if key not in sradict: + CONTAINER = lltype.FixedSizeArray(TYPE, 1) + p = lltype.malloc(CONTAINER, flavor='raw', zero=True) + sradict[key] = Constant(p, lltype.Ptr(CONTAINER)) + sra.append(sradict[key]) + # + # store the value of the arguments + livevars = self.push_roots(hop) + c_item0 = Constant('item0', lltype.Void) + for v_arg, c_p in zip(hop.spaceop.args[1:], sra): + if isinstance(v_arg.concretetype, lltype.Ptr): + v_arg = hop.genop("cast_ptr_to_adr", [v_arg], + resulttype=llmemory.Address) + hop.genop("bare_setfield", [c_p, c_item0, v_arg]) + # + # make a copy of the graph that will reload the values + graph2 = copygraph(fnptr._obj.graph) + block2 = graph2.startblock block2.isstartblock = False - inputvars = [copyvar(None, v) for v in block2.inputargs] - dummyvars = [] - for i in range(9): - v = Variable('dummy') - v.concretetype = lltype.Signed - dummyvars.append(v) - block1 = Block(dummyvars + inputvars) - block1.closeblock(Link(inputvars, block2)) + block1 = Block([]) + reloadedvars = [] + for v, c_p in zip(block2.inputargs, sra): + v = copyvar(None, v) + if isinstance(v.concretetype, lltype.Ptr): + w = Variable('tmp') + w.concretetype = llmemory.Address + else: + w = v + block1.operations.append(SpaceOperation('getfield', + [c_p, c_item0], w)) + if w is not v: + block1.operations.append(SpaceOperation('cast_adr_to_ptr', + [w], v)) + reloadedvars.append(v) + block1.closeblock(Link(reloadedvars, block2)) block1.isstartblock = True - graph.startblock = block1 - FUNC1 = lltype.typeOf(fnptr).TO - FUNC2 = lltype.FuncType(tuple([lltype.Signed] * len(dummyvars)) - + FUNC1.ARGS, - FUNC1.RESULT) + graph2.startblock = block1 + FUNC2 = lltype.FuncType([], FUNC1.RESULT) fnptr2 = lltype.functionptr(FUNC2, - fnptr._obj._name + '_dummies', - graph=graph) + fnptr._obj._name + '_reload', + graph=graph2) c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2)) - HELPERFUNC = lltype.FuncType((lltype.Ptr(FUNC2),) + FUNC1.ARGS, - FUNC1.RESULT) + HELPERFUNC = lltype.FuncType([lltype.Ptr(FUNC2)], FUNC1.RESULT) # - livevars = self.push_roots(hop) v_asm_stackwalk = hop.genop("cast_pointer", [c_asm_stackwalk], resulttype=lltype.Ptr(HELPERFUNC)) hop.genop("indirect_call", - [v_asm_stackwalk, c_fnptr2] - + hop.spaceop.args[1:] - + [Constant(None, lltype.Void)], + [v_asm_stackwalk, c_fnptr2, Constant(None, lltype.Void)], resultvar=hop.spaceop.result) self.pop_roots(hop, livevars) else: Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py Tue Sep 15 19:52:43 2009 @@ -116,8 +116,6 @@ movl %esp, (%eax) /* next->prev = self */ /* note: the Mac OS X 16 bytes aligment must be respected. */ - /* Pushed a total of 8 words including my return address; */ - /* please keep this number 8 in sync with asmgcroot.py! */ call *%edx /* invoke the callback */ /* Detach this ASM_FRAMEDATA from the circular linked list */ From arigo at codespeak.net Tue Sep 15 20:02:09 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 20:02:09 +0200 (CEST) Subject: [pypy-svn] r67703 - in pypy/branch/asmgcroot-callback/pypy/translator/c: gcc src Message-ID: <20090915180209.B9D3B16800A@codespeak.net> Author: arigo Date: Tue Sep 15 20:02:09 2009 New Revision: 67703 Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Log: Fix. Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/trackgcroot.py Tue Sep 15 20:02:09 2009 @@ -144,9 +144,6 @@ print >> output, '\t/* the ASM_FRAMEDATAs currently alive */' print >> output, '\t.long\t__gcrootanchor /* prev */' print >> output, '\t.long\t__gcrootanchor /* next */' - _globl('__gcstackscount') - _label('__gcstackscount') - print >> output, '\t.long\t1' _globl('__gcmapstart') _label('__gcmapstart') for label, state, is_range in self.gcmaptable: Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Tue Sep 15 20:02:09 2009 @@ -25,6 +25,10 @@ extern long pypy_asm_stackwalk(void*); #define __gcnoreorderhack __gcmapend +#ifndef PYPY_NOT_MAIN_FILE +long __gcstackscount = 1; +#endif + /* The following pseudo-instruction is used by --gcrootfinder=asmgcc just after a call to tell gcc to put a GCROOT mark on each gc-pointer local variable. All such local variables need to go through a "v = From arigo at codespeak.net Tue Sep 15 20:27:05 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 20:27:05 +0200 (CEST) Subject: [pypy-svn] r67704 - pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test Message-ID: <20090915182705.5C1B8168009@codespeak.net> Author: arigo Date: Tue Sep 15 20:27:02 2009 New Revision: 67704 Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py Log: Add a test. Passing, annoyingly. Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py Tue Sep 15 20:27:02 2009 @@ -95,5 +95,37 @@ # for the individual tests see # ====> ../../test/test_newgc.py + def test_callback_simple(self): + import gc + from pypy.rpython.lltypesystem import lltype, rffi + from pypy.rpython.annlowlevel import llhelper + from pypy.translator.tool.cbuild import ExternalCompilationInfo + + c_source = py.code.Source(""" + int mystuff(int(*cb)(int, int)) + { + return cb(40, 2); + } + """) + eci = ExternalCompilationInfo(separate_module_sources=[c_source]) + S = lltype.GcStruct('S', ('x', lltype.Signed)) + CALLBACK = lltype.FuncType([lltype.Signed, lltype.Signed], + lltype.Signed) + z = rffi.llexternal('mystuff', [lltype.Ptr(CALLBACK)], lltype.Signed, + compilation_info=eci) + + def mycallback(a, b): + gc.collect() + return a + b + + def f(): + p = lltype.malloc(S) + p.x = 100 + result = z(mycallback) + return result * p.x + + c_fn = self.getcompiled(f) + assert c_fn() == 4200 + #def test_callback_with_collect(self): # py.test.skip("in-progress") From arigo at codespeak.net Tue Sep 15 21:33:30 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Sep 2009 21:33:30 +0200 (CEST) Subject: [pypy-svn] r67705 - in pypy/branch/asmgcroot-callback/pypy/translator/c: . gcc/test src Message-ID: <20090915193330.AAB8D168009@codespeak.net> Author: arigo Date: Tue Sep 15 21:33:29 2009 New Revision: 67705 Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/funcgen.py pypy/branch/asmgcroot-callback/pypy/translator/c/gc.py pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Log: The blame goes to the 'keepalive' operation that was explicitly used in the test. It did not have the correct semantic effect with gcrootfinder=asmgcc... Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/funcgen.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/funcgen.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/funcgen.py Tue Sep 15 21:33:29 2009 @@ -665,7 +665,15 @@ return '%s\t/* hint: %r */' % (self.OP_SAME_AS(op), hints) def OP_KEEPALIVE(self, op): # xxx what should be the sematics consequences of this - return "/* kept alive: %s */ ;" % self.expr(op.args[0], special_case_void=False) + v = op.args[0] + TYPE = self.lltypemap(v) + if TYPE is Void: + return "/* kept alive: void */" + if isinstance(TYPE, Ptr) and TYPE.TO._gckind == 'gc': + meth = getattr(self.gcpolicy, 'GC_KEEPALIVE', None) + if meth: + return meth(self, v) + return "/* kept alive: %s */" % self.expr(v) #address operations def OP_RAW_STORE(self, op): Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gc.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/gc.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gc.py Tue Sep 15 21:33:29 2009 @@ -319,6 +319,9 @@ class AsmGcRootFrameworkGcPolicy(FrameworkGcPolicy): transformerclass = asmgcroot.AsmGcRootFrameworkGCTransformer + def GC_KEEPALIVE(self, funcgen, v): + return 'pypy_asm_keepalive(%s);' % funcgen.expr(v) + name_to_gcpolicy = { 'boehm': BoehmGcPolicy, Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_asmgcroot.py Tue Sep 15 21:33:29 2009 @@ -104,7 +104,7 @@ c_source = py.code.Source(""" int mystuff(int(*cb)(int, int)) { - return cb(40, 2); + return cb(40, 2) + cb(3, 4); } """) eci = ExternalCompilationInfo(separate_module_sources=[c_source]) @@ -125,7 +125,4 @@ return result * p.x c_fn = self.getcompiled(f) - assert c_fn() == 4200 - - #def test_callback_with_collect(self): - # py.test.skip("in-progress") + assert c_fn() == 4900 Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Tue Sep 15 21:33:29 2009 @@ -50,6 +50,9 @@ "0" (p), "m" (__gcnoreorderhack)); \ _r; }) +#define pypy_asm_keepalive(v) asm volatile ("/* keepalive %0 */" : : \ + "g" (v)) + /* marker for trackgcroot.py */ #define OP_GC_STACK_BOTTOM(n, r) \ asm volatile ("/* GC_STACK_BOTTOM */" : : ); \ From arigo at codespeak.net Wed Sep 16 10:40:23 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 16 Sep 2009 10:40:23 +0200 (CEST) Subject: [pypy-svn] r67706 - pypy/trunk/pypy/rlib Message-ID: <20090916084023.591AE168005@codespeak.net> Author: arigo Date: Wed Sep 16 10:40:20 2009 New Revision: 67706 Modified: pypy/trunk/pypy/rlib/libffi.py Log: Oups, forgot to remove these debugging prints. Modified: pypy/trunk/pypy/rlib/libffi.py ============================================================================== --- pypy/trunk/pypy/rlib/libffi.py (original) +++ pypy/trunk/pypy/rlib/libffi.py Wed Sep 16 10:40:20 2009 @@ -613,9 +613,7 @@ lltype.free(ll_libname, flavor='raw') def __del__(self): - print 'in __del__' if self.lib and self.unload_on_finalization: - print 'calling dlclose()' dlclose(self.lib) self.lib = lltype.nullptr(rffi.CCHARP.TO) From arigo at codespeak.net Wed Sep 16 10:41:16 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 16 Sep 2009 10:41:16 +0200 (CEST) Subject: [pypy-svn] r67707 - pypy/branch/asmgcroot-callback/pypy/rlib Message-ID: <20090916084116.D2FCB168008@codespeak.net> Author: arigo Date: Wed Sep 16 10:41:16 2009 New Revision: 67707 Modified: pypy/branch/asmgcroot-callback/pypy/rlib/libffi.py Log: Merge r67706 from trunk. Modified: pypy/branch/asmgcroot-callback/pypy/rlib/libffi.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rlib/libffi.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rlib/libffi.py Wed Sep 16 10:41:16 2009 @@ -613,9 +613,7 @@ lltype.free(ll_libname, flavor='raw') def __del__(self): - print 'in __del__' if self.lib and self.unload_on_finalization: - print 'calling dlclose()' dlclose(self.lib) self.lib = lltype.nullptr(rffi.CCHARP.TO) From antocuni at codespeak.net Wed Sep 16 10:51:05 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 16 Sep 2009 10:51:05 +0200 (CEST) Subject: [pypy-svn] r67708 - pypy/extradoc/sprintinfo/ddorf2009 Message-ID: <20090916085105.38F08168002@codespeak.net> Author: antocuni Date: Wed Sep 16 10:51:04 2009 New Revision: 67708 Modified: pypy/extradoc/sprintinfo/ddorf2009/people.txt Log: my dates Modified: pypy/extradoc/sprintinfo/ddorf2009/people.txt ============================================================================== --- pypy/extradoc/sprintinfo/ddorf2009/people.txt (original) +++ pypy/extradoc/sprintinfo/ddorf2009/people.txt Wed Sep 16 10:51:04 2009 @@ -9,6 +9,7 @@ Name Arrive/Depart Accomodation ==================== ============== ===================== Carl Friedrich Bolz always there private +Antonio Cuni 6/11 - 13/11 ??? ==================== ============== ===================== ==================== ============== ===================== @@ -19,7 +20,6 @@ ==================== ============== ===================== Armin Rigo Michael Hudson -Antonio Cuni Samuele Pedroni Anders Chrigstroem Maciej Fijalkowski From arigo at codespeak.net Wed Sep 16 11:21:11 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 16 Sep 2009 11:21:11 +0200 (CEST) Subject: [pypy-svn] r67709 - in pypy/branch/asmgcroot-callback/pypy: config rlib rpython rpython/lltypesystem rpython/memory/gctransform translator/c translator/c/gcc/test translator/c/src translator/c/test Message-ID: <20090916092111.6D4AD168002@codespeak.net> Author: arigo Date: Wed Sep 16 11:21:10 2009 New Revision: 67709 Added: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_thread.py (contents, props changed) Modified: pypy/branch/asmgcroot-callback/pypy/config/translationoption.py pypy/branch/asmgcroot-callback/pypy/rlib/objectmodel.py pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/framework.py pypy/branch/asmgcroot-callback/pypy/translator/c/funcgen.py pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py Log: Small changes that seem to make threads work on top of asmgcc. Modified: pypy/branch/asmgcroot-callback/pypy/config/translationoption.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/config/translationoption.py (original) +++ pypy/branch/asmgcroot-callback/pypy/config/translationoption.py Wed Sep 16 11:21:10 2009 @@ -80,8 +80,7 @@ requires={ "shadowstack": [("translation.gctransformer", "framework")], "asmgcc": [("translation.gctransformer", "framework"), - ("translation.backend", "c"), - ("translation.thread", False)], + ("translation.backend", "c")], }), # other noticeable options Modified: pypy/branch/asmgcroot-callback/pypy/rlib/objectmodel.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rlib/objectmodel.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rlib/objectmodel.py Wed Sep 16 11:21:10 2009 @@ -223,7 +223,7 @@ def is_in_callback(): from pypy.rpython.lltypesystem import rffi - return rffi.aroundstate.callback_counter > 0 + return rffi.stackcounter.stacks_counter > 1 class UnboxedValue(object): Modified: pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py Wed Sep 16 11:21:10 2009 @@ -878,7 +878,7 @@ def op_gc_asmgcroot_static(self, index): raise NotImplementedError("gc_asmgcroot_static") - def op_gc_stack_bottom(self, n): + def op_gc_stack_bottom(self): pass # marker for trackgcroot.py def op_do_malloc_fixedsize_clear(self): Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py Wed Sep 16 11:21:10 2009 @@ -416,9 +416,7 @@ 'gc_x_size_header': LLOp(), # for asmgcroot support to get the address of various static structures - # 0: gcmapstart - # 1: gcmapend - # 2: gccallshapes + # see translator/c/src/mem.h for the valid indices 'gc_asmgcroot_static': LLOp(sideeffects=False), 'gc_stack_bottom': LLOp(sideeffects=False, canrun=True), Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py Wed Sep 16 11:21:10 2009 @@ -382,7 +382,7 @@ print arg, print -def op_gc_stack_bottom(n): +def op_gc_stack_bottom(): pass # marker for trackgcroot.py def op_promote_virtualizable(object, fieldname, flags): Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py Wed Sep 16 11:21:10 2009 @@ -216,7 +216,7 @@ args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))]) source = py.code.Source(r""" def wrapper(%s): # no *args - no GIL for mallocing the tuple - llop.gc_stack_bottom(lltype.Void, +1) # marker for trackgcroot.py + llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py if aroundstate is not None: before = aroundstate.before after = aroundstate.after @@ -226,8 +226,7 @@ if after: after() # from now on we hold the GIL - if aroundstate is not None: - aroundstate.callback_counter += 1 + stackcounter.stacks_counter += 1 try: result = callable(%s) except Exception, e: @@ -238,20 +237,19 @@ import traceback traceback.print_exc() result = errorcode - if aroundstate is not None: - aroundstate.callback_counter -= 1 + stackcounter.stacks_counter -= 1 if before: before() # here we don't hold the GIL any more. As in the wrapper() produced # by llexternal, it is essential that no exception checking occurs # after the call to before(). - llop.gc_stack_bottom(lltype.Void, -1) # marker for trackgcroot.py return result """ % (args, args)) miniglobals = locals().copy() miniglobals['Exception'] = Exception miniglobals['os'] = os miniglobals['we_are_translated'] = we_are_translated + miniglobals['stackcounter'] = stackcounter exec source.compile() in miniglobals return miniglobals['wrapper'] _make_wrapper_for._annspecialcase_ = 'specialize:memo' @@ -261,11 +259,17 @@ def _freeze_(self): self.before = None # or a regular RPython function self.after = None # or a regular RPython function - self.callback_counter = 0 return False aroundstate = AroundState() aroundstate._freeze_() +class StackCounter: + def _freeze_(self): + self.stacks_counter = 1 # number of "stack pieces": callbacks + return False # and threads increase it by one +stackcounter = StackCounter() +stackcounter._freeze_() + # ____________________________________________________________ # Few helpers for keeping callback arguments alive # this makes passing opaque objects possible (they don't even pass Modified: pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py Wed Sep 16 11:21:10 2009 @@ -46,75 +46,79 @@ except AttributeError: close_stack = False if close_stack: - # We cannot easily pass variable amount of arguments of the call - # across the call to the pypy_asm_stackwalk helper. So we store - # them away and restore them. We need to make a new graph - # that starts with restoring the arguments. - if self._asmgcc_save_restore_arguments is None: - self._asmgcc_save_restore_arguments = {} - sradict = self._asmgcc_save_restore_arguments - sra = [] # list of pointers to raw-malloced containers for args - seen = {} - FUNC1 = lltype.typeOf(fnptr).TO - for TYPE in FUNC1.ARGS: - if isinstance(TYPE, lltype.Ptr): - TYPE = llmemory.Address - num = seen.get(TYPE, 0) - seen[TYPE] = num + 1 - key = (TYPE, num) - if key not in sradict: - CONTAINER = lltype.FixedSizeArray(TYPE, 1) - p = lltype.malloc(CONTAINER, flavor='raw', zero=True) - sradict[key] = Constant(p, lltype.Ptr(CONTAINER)) - sra.append(sradict[key]) - # - # store the value of the arguments - livevars = self.push_roots(hop) - c_item0 = Constant('item0', lltype.Void) - for v_arg, c_p in zip(hop.spaceop.args[1:], sra): - if isinstance(v_arg.concretetype, lltype.Ptr): - v_arg = hop.genop("cast_ptr_to_adr", [v_arg], - resulttype=llmemory.Address) - hop.genop("bare_setfield", [c_p, c_item0, v_arg]) - # - # make a copy of the graph that will reload the values - graph2 = copygraph(fnptr._obj.graph) - block2 = graph2.startblock - block2.isstartblock = False - block1 = Block([]) - reloadedvars = [] - for v, c_p in zip(block2.inputargs, sra): - v = copyvar(None, v) - if isinstance(v.concretetype, lltype.Ptr): - w = Variable('tmp') - w.concretetype = llmemory.Address - else: - w = v - block1.operations.append(SpaceOperation('getfield', - [c_p, c_item0], w)) - if w is not v: - block1.operations.append(SpaceOperation('cast_adr_to_ptr', - [w], v)) - reloadedvars.append(v) - block1.closeblock(Link(reloadedvars, block2)) - block1.isstartblock = True - graph2.startblock = block1 - FUNC2 = lltype.FuncType([], FUNC1.RESULT) - fnptr2 = lltype.functionptr(FUNC2, - fnptr._obj._name + '_reload', - graph=graph2) - c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2)) - HELPERFUNC = lltype.FuncType([lltype.Ptr(FUNC2)], FUNC1.RESULT) - # - v_asm_stackwalk = hop.genop("cast_pointer", [c_asm_stackwalk], - resulttype=lltype.Ptr(HELPERFUNC)) - hop.genop("indirect_call", - [v_asm_stackwalk, c_fnptr2, Constant(None, lltype.Void)], - resultvar=hop.spaceop.result) - self.pop_roots(hop, livevars) + self.handle_call_with_close_stack(hop) else: FrameworkGCTransformer.gct_direct_call(self, hop) + def handle_call_with_close_stack(self, hop): + fnptr = hop.spaceop.args[0].value + # We cannot easily pass variable amount of arguments of the call + # across the call to the pypy_asm_stackwalk helper. So we store + # them away and restore them. We need to make a new graph + # that starts with restoring the arguments. + if self._asmgcc_save_restore_arguments is None: + self._asmgcc_save_restore_arguments = {} + sradict = self._asmgcc_save_restore_arguments + sra = [] # list of pointers to raw-malloced containers for args + seen = {} + FUNC1 = lltype.typeOf(fnptr).TO + for TYPE in FUNC1.ARGS: + if isinstance(TYPE, lltype.Ptr): + TYPE = llmemory.Address + num = seen.get(TYPE, 0) + seen[TYPE] = num + 1 + key = (TYPE, num) + if key not in sradict: + CONTAINER = lltype.FixedSizeArray(TYPE, 1) + p = lltype.malloc(CONTAINER, flavor='raw', zero=True) + sradict[key] = Constant(p, lltype.Ptr(CONTAINER)) + sra.append(sradict[key]) + # + # store the value of the arguments + livevars = self.push_roots(hop) + c_item0 = Constant('item0', lltype.Void) + for v_arg, c_p in zip(hop.spaceop.args[1:], sra): + if isinstance(v_arg.concretetype, lltype.Ptr): + v_arg = hop.genop("cast_ptr_to_adr", [v_arg], + resulttype=llmemory.Address) + hop.genop("bare_setfield", [c_p, c_item0, v_arg]) + # + # make a copy of the graph that will reload the values + graph2 = copygraph(fnptr._obj.graph) + block2 = graph2.startblock + block2.isstartblock = False + block1 = Block([]) + reloadedvars = [] + for v, c_p in zip(block2.inputargs, sra): + v = copyvar(None, v) + if isinstance(v.concretetype, lltype.Ptr): + w = Variable('tmp') + w.concretetype = llmemory.Address + else: + w = v + block1.operations.append(SpaceOperation('getfield', + [c_p, c_item0], w)) + if w is not v: + block1.operations.append(SpaceOperation('cast_adr_to_ptr', + [w], v)) + reloadedvars.append(v) + block1.closeblock(Link(reloadedvars, block2)) + block1.isstartblock = True + graph2.startblock = block1 + FUNC2 = lltype.FuncType([], FUNC1.RESULT) + fnptr2 = lltype.functionptr(FUNC2, + fnptr._obj._name + '_reload', + graph=graph2) + c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2)) + HELPERFUNC = lltype.FuncType([lltype.Ptr(FUNC2)], FUNC1.RESULT) + # + v_asm_stackwalk = hop.genop("cast_pointer", [c_asm_stackwalk], + resulttype=lltype.Ptr(HELPERFUNC)) + hop.genop("indirect_call", + [v_asm_stackwalk, c_fnptr2, Constant(None, lltype.Void)], + resultvar=hop.spaceop.result) + self.pop_roots(hop, livevars) + class AsmStackRootWalker(BaseRootWalker): @@ -134,6 +138,9 @@ self._extra_gcmapstart = returns_null self._extra_gcmapend = returns_null + def need_thread_support(self, gctransformer, getfn): + pass # threads supported "out of the box" by the rest of the code + def walk_stack_roots(self, collect_stack_root): gcdata = self.gcdata gcdata._gc_collect_stack_root = collect_stack_root @@ -160,11 +167,9 @@ initialframedata = initialframedata.address[1] stackscount += 1 # - expected = llop.gc_asmgcroot_static(llmemory.Address, 4) - ll_assert(not (stackscount < expected.signed[0]), - "non-closed stacks around") - ll_assert(not (stackscount > expected.signed[0]), - "stacks counter corruption?") + expected = rffi.stackcounter.stacks_counter + ll_assert(not (stackscount < expected), "non-closed stacks around") + ll_assert(not (stackscount > expected), "stacks counter corruption?") lltype.free(otherframe, flavor='raw') lltype.free(curframe, flavor='raw') Modified: pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/framework.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/framework.py Wed Sep 16 11:21:10 2009 @@ -151,6 +151,7 @@ gcdata.gc = GCClass(translator.config.translation, **GC_PARAMS) root_walker = self.build_root_walker() + self.root_walker = root_walker gcdata.set_query_functions(gcdata.gc) gcdata.gc.set_root_walker(root_walker) self.num_pushs = 0 @@ -370,17 +371,7 @@ # thread support if translator.config.translation.thread: - if not hasattr(root_walker, "need_thread_support"): - raise Exception("%s does not support threads" % ( - root_walker.__class__.__name__,)) - root_walker.need_thread_support() - self.thread_prepare_ptr = getfn(root_walker.thread_prepare, - [], annmodel.s_None) - self.thread_run_ptr = getfn(root_walker.thread_run, - [], annmodel.s_None, - inline=True) - self.thread_die_ptr = getfn(root_walker.thread_die, - [], annmodel.s_None) + root_walker.need_thread_support(self, getfn) self.layoutbuilder.encode_type_shapes_now() @@ -703,15 +694,18 @@ def gct_gc_thread_prepare(self, hop): assert self.translator.config.translation.thread - hop.genop("direct_call", [self.thread_prepare_ptr]) + if hasattr(self.root_walker, 'thread_prepare_ptr'): + hop.genop("direct_call", [self.root_walker.thread_prepare_ptr]) def gct_gc_thread_run(self, hop): assert self.translator.config.translation.thread - hop.genop("direct_call", [self.thread_run_ptr]) + if hasattr(self.root_walker, 'thread_run_ptr'): + hop.genop("direct_call", [self.root_walker.thread_run_ptr]) def gct_gc_thread_die(self, hop): assert self.translator.config.translation.thread - hop.genop("direct_call", [self.thread_die_ptr]) + if hasattr(self.root_walker, 'thread_die_ptr'): + hop.genop("direct_call", [self.root_walker.thread_die_ptr]) def gct_malloc_nonmovable_varsize(self, hop): TYPE = hop.spaceop.result.concretetype @@ -900,6 +894,10 @@ if collect_stack_root: self.walk_stack_roots(collect_stack_root) # abstract + def need_thread_support(self, gctransformer, getfn): + raise Exception("%s does not support threads" % ( + self.__class__.__name__,)) + class ShadowStackRootWalker(BaseRootWalker): need_root_stack = True @@ -958,7 +956,7 @@ if self.collect_stacks_from_other_threads is not None: self.collect_stacks_from_other_threads(collect_stack_root) - def need_thread_support(self): + def need_thread_support(self, gctransformer, getfn): from pypy.module.thread import ll_thread # xxx fish from pypy.rpython.memory.support import AddressDict from pypy.rpython.memory.support import copy_without_null_values @@ -1069,7 +1067,8 @@ gcdata.thread_stacks.foreach(collect_stack, callback) self.thread_setup = thread_setup - self.thread_prepare = thread_prepare - self.thread_run = thread_run - self.thread_die = thread_die + self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) + self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, + inline=True) + self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) self.collect_stacks_from_other_threads = collect_more_stacks Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/funcgen.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/funcgen.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/funcgen.py Wed Sep 16 11:21:10 2009 @@ -371,13 +371,13 @@ yield 'while (%s) {' % expr for op in self.gen_link(enterlink): yield '\t' + op - yield '\t block%d_back:' % self.blocknum[headblock] + # the semicolon after the colon is needed in case no operation + # produces any code after the label + yield '\t block%d_back: ;' % self.blocknum[headblock] if headblock.operations: for i, op in enumerate(headblock.operations): for line in self.gen_op(op): yield '\t' + line - else: - yield '\t;' yield '}' for op in self.gen_link(exitlink): yield op Added: pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_thread.py ============================================================================== --- (empty file) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/test/test_thread.py Wed Sep 16 11:21:10 2009 @@ -0,0 +1,4 @@ +from pypy.translator.c.test import test_standalone + +class TestThreadedAsmGcc(test_standalone.TestThread): + gcrootfinder = 'asmgcc' Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/src/mem.h Wed Sep 16 11:21:10 2009 @@ -21,14 +21,9 @@ extern char __gcmapend; extern char __gccallshapes; extern void *__gcrootanchor; -extern long __gcstackscount; /* for debugging */ extern long pypy_asm_stackwalk(void*); #define __gcnoreorderhack __gcmapend -#ifndef PYPY_NOT_MAIN_FILE -long __gcstackscount = 1; -#endif - /* The following pseudo-instruction is used by --gcrootfinder=asmgcc just after a call to tell gcc to put a GCROOT mark on each gc-pointer local variable. All such local variables need to go through a "v = @@ -54,16 +49,13 @@ "g" (v)) /* marker for trackgcroot.py */ -#define OP_GC_STACK_BOTTOM(n, r) \ - asm volatile ("/* GC_STACK_BOTTOM */" : : ); \ - __gcstackscount += n +#define OP_GC_STACK_BOTTOM(r) asm volatile ("/* GC_STACK_BOTTOM */" : : ) #define OP_GC_ASMGCROOT_STATIC(i, r) r = \ i == 0 ? (void*)&__gcmapstart : \ i == 1 ? (void*)&__gcmapend : \ i == 2 ? (void*)&__gccallshapes : \ i == 3 ? (void*)&__gcrootanchor : \ - i == 4 ? (void*)&__gcstackscount : \ NULL #define RAW_MALLOC_ZERO_FILLED 0 Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py Wed Sep 16 11:21:10 2009 @@ -286,9 +286,27 @@ class TestThread(object): + gcrootfinder = 'shadowstack' + + def compile(self, entry_point): + t = TranslationContext() + t.config.translation.gc = "semispace" + t.config.translation.gcrootfinder = self.gcrootfinder + t.config.translation.thread = True + t.buildannotator().build_types(entry_point, [s_list_of_strings]) + t.buildrtyper().specialize() + # + cbuilder = CStandaloneBuilder(t, entry_point, t.config) + cbuilder.generate_source() + cbuilder.compile() + # + return t, cbuilder + + def test_stack_size(self): import time from pypy.module.thread import ll_thread + from pypy.rpython.lltypesystem import lltype class State: pass @@ -337,13 +355,7 @@ os.write(1, "done\n") return 0 - t = TranslationContext() - t.buildannotator().build_types(entry_point, [s_list_of_strings]) - t.buildrtyper().specialize() - - cbuilder = CStandaloneBuilder(t, entry_point, t.config) - cbuilder.generate_source() - cbuilder.compile() + t, cbuilder = self.compile(entry_point) # recursing should crash with only 32 KB of stack, # and it should eventually work with more stack @@ -364,3 +376,70 @@ break # finish else: py.test.fail("none of the stack sizes worked") + + + def test_thread_and_gc(self): + import time, gc + from pypy.module.thread import ll_thread + from pypy.rpython.lltypesystem import lltype + + class State: + pass + state = State() + + class Cons: + def __init__(self, head, tail): + self.head = head + self.tail = tail + + def bootstrap(): + state.ll_lock.acquire(True) + state.xlist.append(Cons(123, Cons(456, None))) + gc.collect() + state.ll_lock.release() + + def entry_point(argv): + os.write(1, "hello world\n") + state.xlist = [] + x2 = Cons(51, Cons(62, Cons(74, None))) + # start 5 new threads + state.ll_lock = ll_thread.Lock(ll_thread.allocate_ll_lock()) + ident1 = ll_thread.start_new_thread(bootstrap, ()) + ident2 = ll_thread.start_new_thread(bootstrap, ()) + # + state.ll_lock.acquire(True) + gc.collect() + state.ll_lock.release() + # + ident3 = ll_thread.start_new_thread(bootstrap, ()) + ident4 = ll_thread.start_new_thread(bootstrap, ()) + ident5 = ll_thread.start_new_thread(bootstrap, ()) + # wait for the 5 threads to finish + while True: + state.ll_lock.acquire(True) + gc.collect() + if len(state.xlist) == 5: + break + state.ll_lock.release() + time.sleep(0.1) + # check that the malloced structures were not overwritten + assert x2.head == 51 + assert x2.tail.head == 62 + assert x2.tail.tail.head == 74 + assert x2.tail.tail.tail is None + # check the structures produced by the threads + for i in range(5): + assert state.xlist[i].head == 123 + assert state.xlist[i].tail.head == 456 + assert state.xlist[i].tail.tail is None + os.write(1, "%d ok\n" % (i+1)) + return 0 + + t, cbuilder = self.compile(entry_point) + data = cbuilder.cmdexec('') + assert data.splitlines() == ['hello world', + '1 ok', + '2 ok', + '3 ok', + '4 ok', + '5 ok'] From arigo at codespeak.net Wed Sep 16 11:42:25 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 16 Sep 2009 11:42:25 +0200 (CEST) Subject: [pypy-svn] r67710 - in pypy/branch/asmgcroot-callback/pypy: module/thread rpython/memory/gctransform Message-ID: <20090916094225.308F1168003@codespeak.net> Author: arigo Date: Wed Sep 16 11:42:23 2009 New Revision: 67710 Modified: pypy/branch/asmgcroot-callback/pypy/module/thread/os_thread.py pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py Log: Comments. Modified: pypy/branch/asmgcroot-callback/pypy/module/thread/os_thread.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/module/thread/os_thread.py (original) +++ pypy/branch/asmgcroot-callback/pypy/module/thread/os_thread.py Wed Sep 16 11:42:23 2009 @@ -18,8 +18,9 @@ # stored in the global bootstrapper object. # # * The GC is notified that a new thread is about to start; in the -# framework GC, this allocates a fresh new shadow stack (but doesn't -# use it yet). See gc_thread_prepare(). +# framework GC with shadow stacks, this allocates a fresh new shadow +# stack (but doesn't use it yet). See gc_thread_prepare(). This +# has no effect in asmgcc. # # * The new thread is launched at RPython level using an rffi call # to the C function RPyThreadStart() defined in @@ -35,6 +36,7 @@ # called from the rffi-generated wrapper). The gc_thread_run() # operation will automatically notice that the current thread id was # not seen before, and start using the freshly prepared shadow stack. +# Again, this has no effect in asmgcc. # # * Only then does bootstrap() really run. The first thing it does # is grab the start-up information (app-level callable and args) @@ -47,7 +49,7 @@ # thread. # # * Just before a thread finishes, gc_thread_die() is called to free -# its shadow stack. +# its shadow stack. This has no effect in asmgcc. class Bootstrapper(object): Modified: pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py Wed Sep 16 11:42:23 2009 @@ -139,7 +139,10 @@ self._extra_gcmapend = returns_null def need_thread_support(self, gctransformer, getfn): - pass # threads supported "out of the box" by the rest of the code + # Threads supported "out of the box" by the rest of the code. + # In particular, we can ignore the gc_thread_prepare, + # gc_thread_run and gc_thread_die operations. + pass def walk_stack_roots(self, collect_stack_root): gcdata = self.gcdata From antocuni at codespeak.net Wed Sep 16 11:42:33 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 16 Sep 2009 11:42:33 +0200 (CEST) Subject: [pypy-svn] r67711 - in pypy/trunk/pypy: rpython translator/test Message-ID: <20090916094233.F2121168009@codespeak.net> Author: antocuni Date: Wed Sep 16 11:42:33 2009 New Revision: 67711 Modified: pypy/trunk/pypy/rpython/rlist.py pypy/trunk/pypy/translator/test/test_simplify.py Log: test and fix: ootypesystem.rdict.*.rtype_len relies on hop.r_result to assign the resulttype but the one in hop2 is wrong because it has been copied from hop (which is a 'hint'): fix it. Modified: pypy/trunk/pypy/rpython/rlist.py ============================================================================== --- pypy/trunk/pypy/rpython/rlist.py (original) +++ pypy/trunk/pypy/rpython/rlist.py Wed Sep 16 11:42:33 2009 @@ -162,6 +162,7 @@ return list_eq def _get_v_maxlength(self, hop): + from pypy.rpython.rint import signed_repr v_iterable = hop.args_v[1] s_iterable = hop.args_s[1] r_iterable = hop.args_r[1] @@ -169,6 +170,7 @@ while hop2.nb_args > 0: hop2.r_s_popfirstarg() hop2.v_s_insertfirstarg(v_iterable, s_iterable) + hop2.r_result = signed_repr v_maxlength = r_iterable.rtype_len(hop2) return v_maxlength Modified: pypy/trunk/pypy/translator/test/test_simplify.py ============================================================================== --- pypy/trunk/pypy/translator/test/test_simplify.py (original) +++ pypy/trunk/pypy/translator/test/test_simplify.py Wed Sep 16 11:42:33 2009 @@ -400,6 +400,18 @@ res = interp.eval_graph(graph, [8, 3]) assert res == 28 - 3 + def test_dict(self): + def main(n, m): + d = {n: m, m: n} + lst = [i*17 for i in d] + return len(lst) + lst[0] + lst[-1] + interp, graph = self.specialize(main, [int, int]) + res = interp.eval_graph(graph, [8, 5]) + assert res == 2 + 8 * 17 + 5 * 17 + res = interp.eval_graph(graph, [4, 4]) + assert res == 1 + 4 * 17 + 4 * 17 + + def test_list_iterator(self): # for now, this is not optimized as a list comp def main(n): From arigo at codespeak.net Wed Sep 16 12:07:04 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 16 Sep 2009 12:07:04 +0200 (CEST) Subject: [pypy-svn] r67712 - pypy/branch/asmgcroot-callback/pypy/translator/c/test Message-ID: <20090916100704.7BA8716800D@codespeak.net> Author: arigo Date: Wed Sep 16 12:07:04 2009 New Revision: 67712 Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py Log: Fix the test. We need to use the official "around handlers" instead of our own because otherwise the "stacks_counter += 1" done by rffi is not protected by any lock. Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py Wed Sep 16 12:07:04 2009 @@ -307,26 +307,30 @@ import time from pypy.module.thread import ll_thread from pypy.rpython.lltypesystem import lltype + from pypy.rlib.objectmodel import invoke_around_extcall class State: pass state = State() + def before(): + ll_thread.release_NOAUTO(state.ll_lock) + def after(): + ll_thread.acquire_NOAUTO(state.ll_lock, True) + def recurse(n): if n > 0: return recurse(n-1)+1 else: - state.ll_lock.release() + before() time.sleep(0.2) - state.ll_lock.acquire(True) + after() return 0 def bootstrap(): # recurse a lot, like 2500 times - state.ll_lock.acquire(True) recurse(2500) state.count += 1 - state.ll_lock.release() def entry_point(argv): os.write(1, "hello world\n") @@ -336,17 +340,18 @@ s1 = State(); s2 = State(); s3 = State() s1.x = 0x11111111; s2.x = 0x22222222; s3.x = 0x33333333 # start 3 new threads - state.ll_lock = ll_thread.Lock(ll_thread.allocate_ll_lock()) + state.ll_lock = ll_thread.allocate_ll_lock() state.count = 0 + invoke_around_extcall(before, after) ident1 = ll_thread.start_new_thread(bootstrap, ()) ident2 = ll_thread.start_new_thread(bootstrap, ()) ident3 = ll_thread.start_new_thread(bootstrap, ()) # wait for the 3 threads to finish while True: - state.ll_lock.acquire(True) + after() if state.count == 3: break - state.ll_lock.release() + before() time.sleep(0.1) # check that the malloced structures were not overwritten assert s1.x == 0x11111111 @@ -382,45 +387,50 @@ import time, gc from pypy.module.thread import ll_thread from pypy.rpython.lltypesystem import lltype + from pypy.rlib.objectmodel import invoke_around_extcall class State: pass state = State() + def before(): + ll_thread.release_NOAUTO(state.ll_lock) + def after(): + ll_thread.acquire_NOAUTO(state.ll_lock, True) + class Cons: def __init__(self, head, tail): self.head = head self.tail = tail def bootstrap(): - state.ll_lock.acquire(True) state.xlist.append(Cons(123, Cons(456, None))) gc.collect() - state.ll_lock.release() def entry_point(argv): os.write(1, "hello world\n") state.xlist = [] x2 = Cons(51, Cons(62, Cons(74, None))) # start 5 new threads - state.ll_lock = ll_thread.Lock(ll_thread.allocate_ll_lock()) + state.ll_lock = ll_thread.allocate_ll_lock() + invoke_around_extcall(before, after) ident1 = ll_thread.start_new_thread(bootstrap, ()) ident2 = ll_thread.start_new_thread(bootstrap, ()) # - state.ll_lock.acquire(True) + after() gc.collect() - state.ll_lock.release() + before() # ident3 = ll_thread.start_new_thread(bootstrap, ()) ident4 = ll_thread.start_new_thread(bootstrap, ()) ident5 = ll_thread.start_new_thread(bootstrap, ()) # wait for the 5 threads to finish while True: - state.ll_lock.acquire(True) + after() gc.collect() if len(state.xlist) == 5: break - state.ll_lock.release() + before() time.sleep(0.1) # check that the malloced structures were not overwritten assert x2.head == 51 From arigo at codespeak.net Wed Sep 16 12:27:21 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 16 Sep 2009 12:27:21 +0200 (CEST) Subject: [pypy-svn] r67713 - pypy/branch/asmgcroot-callback/pypy/translator/c/test Message-ID: <20090916102721.A592216800B@codespeak.net> Author: arigo Date: Wed Sep 16 12:27:18 2009 New Revision: 67713 Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py Log: Really(?) fix the test. Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py Wed Sep 16 12:27:18 2009 @@ -2,6 +2,7 @@ import sys, os, re from pypy.rlib.rarithmetic import r_longlong +from pypy.rlib.debug import ll_assert, debug_print from pypy.translator.translator import TranslationContext from pypy.translator.backendopt import all from pypy.translator.c.genc import CStandaloneBuilder, ExternalCompilationInfo @@ -314,17 +315,21 @@ state = State() def before(): + debug_print("releasing...") + ll_assert(not ll_thread.acquire_NOAUTO(state.ll_lock, False), + "lock not held!") ll_thread.release_NOAUTO(state.ll_lock) + debug_print("released") def after(): + debug_print("waiting...") ll_thread.acquire_NOAUTO(state.ll_lock, True) + debug_print("acquired") def recurse(n): if n > 0: return recurse(n-1)+1 else: - before() - time.sleep(0.2) - after() + time.sleep(0.2) # invokes before/after return 0 def bootstrap(): @@ -341,6 +346,7 @@ s1.x = 0x11111111; s2.x = 0x22222222; s3.x = 0x33333333 # start 3 new threads state.ll_lock = ll_thread.allocate_ll_lock() + after() state.count = 0 invoke_around_extcall(before, after) ident1 = ll_thread.start_new_thread(bootstrap, ()) @@ -348,11 +354,9 @@ ident3 = ll_thread.start_new_thread(bootstrap, ()) # wait for the 3 threads to finish while True: - after() if state.count == 3: break - before() - time.sleep(0.1) + time.sleep(0.1) # invokes before/after # check that the malloced structures were not overwritten assert s1.x == 0x11111111 assert s2.x == 0x22222222 @@ -394,6 +398,8 @@ state = State() def before(): + ll_assert(not ll_thread.acquire_NOAUTO(state.ll_lock, False), + "lock not held!") ll_thread.release_NOAUTO(state.ll_lock) def after(): ll_thread.acquire_NOAUTO(state.ll_lock, True) @@ -413,25 +419,22 @@ x2 = Cons(51, Cons(62, Cons(74, None))) # start 5 new threads state.ll_lock = ll_thread.allocate_ll_lock() + after() invoke_around_extcall(before, after) ident1 = ll_thread.start_new_thread(bootstrap, ()) ident2 = ll_thread.start_new_thread(bootstrap, ()) # - after() gc.collect() - before() # ident3 = ll_thread.start_new_thread(bootstrap, ()) ident4 = ll_thread.start_new_thread(bootstrap, ()) ident5 = ll_thread.start_new_thread(bootstrap, ()) # wait for the 5 threads to finish while True: - after() gc.collect() if len(state.xlist) == 5: break - before() - time.sleep(0.1) + time.sleep(0.1) # invokes before/after # check that the malloced structures were not overwritten assert x2.head == 51 assert x2.tail.head == 62 From arigo at codespeak.net Wed Sep 16 12:46:03 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 16 Sep 2009 12:46:03 +0200 (CEST) Subject: [pypy-svn] r67714 - pypy/branch/asmgcroot-callback/pypy/translator/c/test Message-ID: <20090916104603.3494216800B@codespeak.net> Author: arigo Date: Wed Sep 16 12:46:02 2009 New Revision: 67714 Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py Log: Increase the level of recursion, as an attempt to fight off modern gcc's which are able to optimize the recursion by doing only one recursive call in assembler for every 10 recursive calls in C... Modified: pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py (original) +++ pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py Wed Sep 16 12:46:02 2009 @@ -333,8 +333,8 @@ return 0 def bootstrap(): - # recurse a lot, like 2500 times - recurse(2500) + # recurse a lot, like 19500 times + recurse(19500) state.count += 1 def entry_point(argv): @@ -368,7 +368,8 @@ # recursing should crash with only 32 KB of stack, # and it should eventually work with more stack - for test_kb in [32, 128, 512, 1024, 2048, 4096, 8192, 16384]: + for test_kb in [32, 128, 512, 1024, 2048, 4096, 8192, 16384, + 32768, 65536]: print >> sys.stderr, 'Trying with %d KB of stack...' % (test_kb,), try: data = cbuilder.cmdexec(str(test_kb * 1024)) From pedronis at codespeak.net Wed Sep 16 15:38:19 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 16 Sep 2009 15:38:19 +0200 (CEST) Subject: [pypy-svn] r67715 - in pypy/trunk/pypy: rlib rlib/test rpython rpython/memory rpython/memory/gc rpython/memory/gc/test rpython/memory/gctransform rpython/memory/test Message-ID: <20090916133819.4694E16800A@codespeak.net> Author: pedronis Date: Wed Sep 16 15:38:17 2009 New Revision: 67715 Modified: pypy/trunk/pypy/rlib/rgc.py pypy/trunk/pypy/rlib/test/test_rgc.py pypy/trunk/pypy/rpython/llinterp.py pypy/trunk/pypy/rpython/memory/gc/generation.py pypy/trunk/pypy/rpython/memory/gc/hybrid.py pypy/trunk/pypy/rpython/memory/gc/markcompact.py pypy/trunk/pypy/rpython/memory/gc/marksweep.py pypy/trunk/pypy/rpython/memory/gc/semispace.py pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py pypy/trunk/pypy/rpython/memory/gctransform/framework.py pypy/trunk/pypy/rpython/memory/gcwrapper.py pypy/trunk/pypy/rpython/memory/test/test_gc.py pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py Log: (arigo, pedronis) support passing a generation to collect to rgc.collect, 0 means the youngest which is at least useful for some tests Modified: pypy/trunk/pypy/rlib/rgc.py ============================================================================== --- pypy/trunk/pypy/rlib/rgc.py (original) +++ pypy/trunk/pypy/rlib/rgc.py Wed Sep 16 15:38:17 2009 @@ -143,13 +143,17 @@ class CollectEntry(ExtRegistryEntry): _about_ = gc.collect - def compute_result_annotation(self): + def compute_result_annotation(self, s_gen=None): from pypy.annotation import model as annmodel return annmodel.s_None def specialize_call(self, hop): + from pypy.rpython.lltypesystem import lltype hop.exception_cannot_occur() - return hop.genop('gc__collect', [], resulttype=hop.r_result) + args_v = [] + if len(hop.args_s) == 1: + args_v = hop.inputargs(lltype.Signed) + return hop.genop('gc__collect', args_v, resulttype=hop.r_result) class SetMaxHeapSizeEntry(ExtRegistryEntry): _about_ = set_max_heap_size Modified: pypy/trunk/pypy/rlib/test/test_rgc.py ============================================================================== --- pypy/trunk/pypy/rlib/test/test_rgc.py (original) +++ pypy/trunk/pypy/rlib/test/test_rgc.py Wed Sep 16 15:38:17 2009 @@ -13,11 +13,27 @@ assert len(ops) == 1 op = ops[0][1] assert op.opname == 'gc__collect' - + assert len(op.args) == 0 res = interpret(f, []) assert res is None + +def test_collect_0(): + def f(): + return gc.collect(0) + + t, typer, graph = gengraph(f, []) + ops = list(graph.iterblockops()) + assert len(ops) == 1 + op = ops[0][1] + assert op.opname == 'gc__collect' + assert len(op.args) == 1 + assert op.args[0].value == 0 + + res = interpret(f, []) + + assert res is None def test_can_move(): T0 = lltype.GcStruct('T') Modified: pypy/trunk/pypy/rpython/llinterp.py ============================================================================== --- pypy/trunk/pypy/rpython/llinterp.py (original) +++ pypy/trunk/pypy/rpython/llinterp.py Wed Sep 16 15:38:17 2009 @@ -818,8 +818,8 @@ return llmemory.cast_weakrefptr_to_ptr(PTRTYPE, obj) op_cast_weakrefptr_to_ptr.need_result_type = True - def op_gc__collect(self): - self.heap.collect() + def op_gc__collect(self, *gen): + self.heap.collect(*gen) def op_gc_can_move(self, ptr): addr = llmemory.cast_ptr_to_adr(ptr) Modified: pypy/trunk/pypy/rpython/memory/gc/generation.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gc/generation.py (original) +++ pypy/trunk/pypy/rpython/memory/gc/generation.py Wed Sep 16 15:38:17 2009 @@ -223,6 +223,12 @@ # ____________________________________________________________ # Support code for full collections + def collect(self, gen=1): + if gen == 0: + self.collect_nursery() + else: + SemiSpaceGC.collect(self) + def semispace_collect(self, size_changing=False): self.reset_young_gcflags() # we are doing a full collection anyway self.weakrefs_grow_older() Modified: pypy/trunk/pypy/rpython/memory/gc/hybrid.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gc/hybrid.py (original) +++ pypy/trunk/pypy/rpython/memory/gc/hybrid.py Wed Sep 16 15:38:17 2009 @@ -314,9 +314,10 @@ # the semispaces and not always doing the mark-n-sweep pass over the # external objects of 3rd generation. - def collect(self): - self.count_semispaceonly_collects = self.generation3_collect_threshold - GenerationGC.collect(self) + def collect(self, gen=2): + if gen > 1: + self.count_semispaceonly_collects = self.generation3_collect_threshold + GenerationGC.collect(self, gen) def is_collecting_gen3(self): count = self.count_semispaceonly_collects Modified: pypy/trunk/pypy/rpython/memory/gc/markcompact.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gc/markcompact.py (original) +++ pypy/trunk/pypy/rpython/memory/gc/markcompact.py Wed Sep 16 15:38:17 2009 @@ -193,7 +193,7 @@ self.totalsize_of_objs = totalsize return num - def collect(self): + def collect(self, gen=0): self.markcompactcollect() def markcompactcollect(self, needed=0): Modified: pypy/trunk/pypy/rpython/memory/gc/marksweep.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gc/marksweep.py (original) +++ pypy/trunk/pypy/rpython/memory/gc/marksweep.py Wed Sep 16 15:38:17 2009 @@ -215,7 +215,7 @@ return llmemory.cast_adr_to_ptr(result, llmemory.GCREF) malloc_varsize_clear._dont_inline_ = True - def collect(self): + def collect(self, gen=0): # 1. mark from the roots, and also the objects that objects-with-del # point to (using the list of malloced_objects_with_finalizer) # 2. walk the list of objects-without-del and free the ones not marked @@ -708,6 +708,6 @@ def write_free_statistics(self, typeid, result): llop.debug_print(lltype.Void, "free", typeid, " ", result) - def collect(self): + def collect(self, gen=0): self.count_mallocs = 0 - MarkSweepGC.collect(self) + MarkSweepGC.collect(self, gen) Modified: pypy/trunk/pypy/rpython/memory/gc/semispace.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gc/semispace.py (original) +++ pypy/trunk/pypy/rpython/memory/gc/semispace.py Wed Sep 16 15:38:17 2009 @@ -188,7 +188,7 @@ while self.max_space_size > size: self.max_space_size >>= 1 - def collect(self): + def collect(self, gen=0): self.debug_check_consistency() self.semispace_collect() # the indirection is required by the fact that collect() is referred Modified: pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py (original) +++ pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py Wed Sep 16 15:38:17 2009 @@ -271,6 +271,37 @@ class TestGenerationGC(TestSemiSpaceGC): from pypy.rpython.memory.gc.generation import GenerationGC as GCClass + def test_collect_gen(self): + gc = self.gc + old_semispace_collect = gc.semispace_collect + old_collect_nursery = gc.collect_nursery + calls = [] + def semispace_collect(): + calls.append('semispace_collect') + return old_semispace_collect() + def collect_nursery(): + calls.append('collect_nursery') + return old_collect_nursery() + gc.collect_nursery = collect_nursery + gc.semispace_collect = semispace_collect + + gc.collect() + assert calls == ['semispace_collect'] + calls = [] + + gc.collect(0) + assert calls == ['collect_nursery'] + calls = [] + + gc.collect(1) + assert calls == ['semispace_collect'] + calls = [] + + gc.collect(9) + assert calls == ['semispace_collect'] + calls = [] + + class TestHybridGC(TestGenerationGC): from pypy.rpython.memory.gc.hybrid import HybridGC as GCClass @@ -282,6 +313,42 @@ 'generation3_collect_threshold': 5, } + def test_collect_gen(self): + gc = self.gc + old_semispace_collect = gc.semispace_collect + old_collect_nursery = gc.collect_nursery + calls = [] + def semispace_collect(): + gen3 = gc.is_collecting_gen3() + calls.append(('semispace_collect', gen3)) + return old_semispace_collect() + def collect_nursery(): + calls.append('collect_nursery') + return old_collect_nursery() + gc.collect_nursery = collect_nursery + gc.semispace_collect = semispace_collect + + gc.collect() + assert calls == [('semispace_collect', True)] + calls = [] + + gc.collect(0) + assert calls == ['collect_nursery'] + calls = [] + + gc.collect(1) + assert calls == [('semispace_collect', False)] + calls = [] + + gc.collect(2) + assert calls == [('semispace_collect', True)] + calls = [] + + gc.collect(9) + assert calls == [('semispace_collect', True)] + calls = [] + + class TestMarkCompactGC(DirectGCTest): from pypy.rpython.memory.gc.markcompact import MarkCompactGC as GCClass Modified: pypy/trunk/pypy/rpython/memory/gctransform/framework.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/trunk/pypy/rpython/memory/gctransform/framework.py Wed Sep 16 15:38:17 2009 @@ -237,7 +237,7 @@ [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)] + [annmodel.SomeBool()], s_gcref) self.collect_ptr = getfn(GCClass.collect.im_func, - [s_gc], annmodel.s_None) + [s_gc, annmodel.SomeInteger()], annmodel.s_None) self.can_move_ptr = getfn(GCClass.can_move.im_func, [s_gc, annmodel.SomeAddress()], annmodel.SomeBool()) @@ -557,8 +557,13 @@ def gct_gc__collect(self, hop): op = hop.spaceop + if len(op.args) == 1: + v_gen = op.args[0] + else: + # pick a number larger than expected different gc gens :-) + v_gen = rmodel.inputconst(lltype.Signed, 9) livevars = self.push_roots(hop) - hop.genop("direct_call", [self.collect_ptr, self.c_const_gc], + hop.genop("direct_call", [self.collect_ptr, self.c_const_gc, v_gen], resultvar=op.result) self.pop_roots(hop, livevars) Modified: pypy/trunk/pypy/rpython/memory/gcwrapper.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gcwrapper.py (original) +++ pypy/trunk/pypy/rpython/memory/gcwrapper.py Wed Sep 16 15:38:17 2009 @@ -101,8 +101,8 @@ llmemory.cast_ptr_to_adr(toplevelcontainer)) llheap.setinterior(toplevelcontainer, inneraddr, INNERTYPE, newvalue) - def collect(self): - self.gc.collect() + def collect(self, *gen): + self.gc.collect(*gen) def can_move(self, addr): return self.gc.can_move(addr) Modified: pypy/trunk/pypy/rpython/memory/test/test_gc.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/test/test_gc.py (original) +++ pypy/trunk/pypy/rpython/memory/test/test_gc.py Wed Sep 16 15:38:17 2009 @@ -114,6 +114,21 @@ assert res == concat(100) #assert simulator.current_size - curr < 16000 * INT_SIZE / 4 + def test_collect_0(self): + #curr = simulator.current_size + def concat(j): + lst = [] + for i in range(j): + lst.append(str(i)) + result = len("".join(lst)) + if we_are_translated(): + # can't call llop.gc__collect directly + llop.gc__collect(lltype.Void, 0) + return result + res = self.interpret(concat, [100]) + assert res == concat(100) + #assert simulator.current_size - curr < 16000 * INT_SIZE / 4 + def test_finalizer(self): class B(object): pass Modified: pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py (original) +++ pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py Wed Sep 16 15:38:17 2009 @@ -7,7 +7,7 @@ from pypy.rpython.memory.gctransform import framework from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.memory.gc.marksweep import X_CLONE, X_POOL, X_POOL_PTR -from pypy.rlib.objectmodel import compute_unique_id +from pypy.rlib.objectmodel import compute_unique_id, we_are_translated from pypy.rlib.debug import ll_assert from pypy import conftest from pypy.rlib.rstring import StringBuilder @@ -376,6 +376,19 @@ res = run([4, 42]) #XXX pure lazyness here too assert res == 12 + def test_collect_0(self): + def concat(j, dummy): + lst = [] + for i in range(j): + lst.append(str(i)) + result = len("".join(lst)) + if we_are_translated(): + llop.gc__collect(lltype.Void, 0) + return result + run = self.runner(concat, nbargs=2) + res = run([100, 0]) + assert res == concat(100, 0) + def test_interior_ptrs(self): from pypy.rpython.lltypesystem.lltype import Struct, GcStruct, GcArray from pypy.rpython.lltypesystem.lltype import Array, Signed, malloc From cfbolz at codespeak.net Wed Sep 16 16:25:57 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 16 Sep 2009 16:25:57 +0200 (CEST) Subject: [pypy-svn] r67716 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090916142557.722C2168009@codespeak.net> Author: cfbolz Date: Wed Sep 16 16:25:55 2009 New Revision: 67716 Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py Log: failing test that shows the problem leading to the assertion error when running pypy-c-jit on test_mailbox.py Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py Wed Sep 16 16:25:55 2009 @@ -892,6 +892,19 @@ i16=0, i25=0, i39=0, i52=0, i55=0, i59=0, i43=1, i45=1, i48=1, i40=1) + def test_bug_2(self): + py.test.skip("fix me") + ops = """ + [p1] + i1 = ooisnull(p1) + guard_true(i1) + fail() + # + p2 = new_with_vtable(ConstClass(node_vtable)) + jump(p2) + """ + self.find_nodes(ops, 'Not', + i1=1) # ------------------------------ # Bridge tests From cfbolz at codespeak.net Wed Sep 16 17:00:23 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 16 Sep 2009 17:00:23 +0200 (CEST) Subject: [pypy-svn] r67717 - pypy/extradoc/planning Message-ID: <20090916150023.D360F16800A@codespeak.net> Author: cfbolz Date: Wed Sep 16 17:00:23 2009 New Revision: 67717 Modified: pypy/extradoc/planning/jit.txt Log: one thing was done, add a new thing Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Wed Sep 16 17:00:23 2009 @@ -40,7 +40,7 @@ LOAD_GLOBAL - it's a bit silly that it's possible to change the code objects of builtin functions -- the lookup annotation optimization interferes with the JIT +- raising an exception tends to escape frames, due to the traceback capturing inlining discussion -------------------- From arigo at codespeak.net Wed Sep 16 17:25:30 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 16 Sep 2009 17:25:30 +0200 (CEST) Subject: [pypy-svn] r67718 - in pypy/trunk/pypy/interpreter: . test Message-ID: <20090916152530.1B738168009@codespeak.net> Author: arigo Date: Wed Sep 16 17:25:27 2009 New Revision: 67718 Modified: pypy/trunk/pypy/interpreter/executioncontext.py pypy/trunk/pypy/interpreter/test/test_executioncontext.py Log: Make _jit_rechain_frame a static method, i.e. a global function from the translator's point of view, to minimize interaction with its already-translated class. Modified: pypy/trunk/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/trunk/pypy/interpreter/executioncontext.py (original) +++ pypy/trunk/pypy/interpreter/executioncontext.py Wed Sep 16 17:25:27 2009 @@ -146,14 +146,15 @@ self.framestackdepth -= 1 - def _jit_rechain_frame(self, frame): + @staticmethod + def _jit_rechain_frame(ec, frame): # this method is called after the jit has seen enter (and thus _chain) # of a frame, but then does not actually inline it. This method thus # needs to make sure that the state is as if the _chain method had been # executed outside of the jit. Note that this makes it important that # _unchain does not call we_are_jitted frame.f_back().f_forward = None - self.some_frame = frame + ec.some_frame = frame @staticmethod def _extract_back_from_frame(frame): Modified: pypy/trunk/pypy/interpreter/test/test_executioncontext.py ============================================================================== --- pypy/trunk/pypy/interpreter/test/test_executioncontext.py (original) +++ pypy/trunk/pypy/interpreter/test/test_executioncontext.py Wed Sep 16 17:25:27 2009 @@ -671,7 +671,7 @@ # recursive enter/leave seen by the jit frame3 = self.Frame(ec, frame) ec._chain(frame3) - ec._jit_rechain_frame(frame3) + ExecutionContext._jit_rechain_frame(ec, frame3) ec.jitted = False frame3.look_at() assert not frame2.escaped @@ -691,7 +691,7 @@ # recursive enter/leave seen by the jit frame3 = self.Frame(ec, frame) ec._chain(frame3) - ec._jit_rechain_frame(frame3) + ExecutionContext._jit_rechain_frame(ec, frame3) ec.jitted = False assert frame3.escaped @@ -720,7 +720,7 @@ ec._chain(frame3) # frame3 is not inlined, but contains a loop itself, for which code has # been generated - ec._jit_rechain_frame(frame3) + ExecutionContext._jit_rechain_frame(ec, frame3) ec.virtualizable = frame3 frame3.look_at() From arigo at codespeak.net Wed Sep 16 17:27:04 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 16 Sep 2009 17:27:04 +0200 (CEST) Subject: [pypy-svn] r67719 - pypy/branch/optimize-novaluedep Message-ID: <20090916152704.458E8168009@codespeak.net> Author: arigo Date: Wed Sep 16 17:27:03 2009 New Revision: 67719 Added: pypy/branch/optimize-novaluedep/ - copied from r67718, pypy/trunk/ Log: A branch in which to refactor jit/metainterp/optimize*.py to no longer query the value of the boxes it handles. From antocuni at codespeak.net Wed Sep 16 17:32:15 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 16 Sep 2009 17:32:15 +0200 (CEST) Subject: [pypy-svn] r67720 - in pypy/trunk/pypy/rlib: . test Message-ID: <20090916153215.15546168009@codespeak.net> Author: antocuni Date: Wed Sep 16 17:32:15 2009 New Revision: 67720 Modified: pypy/trunk/pypy/rlib/jit.py pypy/trunk/pypy/rlib/test/test_jit.py Log: make sure that hooks attached to the jitdriver are annotated at the right time. So far they were annotated only when the codewriter tried to get them, i.e. when the main annotation/rtyping phase was already over. On lltype it worked by chance, and on ootype it caused problems. Modified: pypy/trunk/pypy/rlib/jit.py ============================================================================== --- pypy/trunk/pypy/rlib/jit.py (original) +++ pypy/trunk/pypy/rlib/jit.py Wed Sep 16 17:32:15 2009 @@ -203,8 +203,28 @@ for name in driver.greens: s_green_key = kwds_s['s_' + name] s_green_key.hash() # force the hash cache to appear + + self.annotate_hooks(**kwds_s) return annmodel.s_None + def annotate_hooks(self, **kwds_s): + driver = self.instance.im_self + self.annotate_hook(driver.can_inline, driver.greens, **kwds_s) + self.annotate_hook(driver.get_printable_location, driver.greens, **kwds_s) + self.annotate_hook(driver.leave, driver.greens + driver.reds, **kwds_s) + + def annotate_hook(self, func, variables, **kwds_s): + if func is None: + return + bk = self.bookkeeper + s_func = bk.immutablevalue(func) + uniquekey = 'jitdriver.%s' % func.func_name + args_s = [] + for name in variables: + s_arg = kwds_s['s_' + name] + args_s.append(s_arg) + bk.emulate_pbc_call(uniquekey, s_func, args_s) + def specialize_call(self, hop, **kwds_i): # XXX to be complete, this could also check that the concretetype # of the variables are the same for each of the calls. Modified: pypy/trunk/pypy/rlib/test/test_jit.py ============================================================================== --- pypy/trunk/pypy/rlib/test/test_jit.py (original) +++ pypy/trunk/pypy/rlib/test/test_jit.py Wed Sep 16 17:32:15 2009 @@ -1,9 +1,10 @@ import py -from pypy.rlib.jit import hint, we_are_jitted +from pypy.rlib.jit import hint, we_are_jitted, JitDriver from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin +from pypy.rpython.lltypesystem import lltype -class TestJIT(BaseRtypingTest, LLRtypeMixin): +class BaseTestJIT(BaseRtypingTest): def test_hint(self): def f(): x = hint(5, hello="world") @@ -22,3 +23,43 @@ res = self.interpret(f, [4]) assert res == 5 + + def test_annotate_hooks(self): + + def can_inline(m): pass + def get_printable_location(m): pass + def leave(m, n): pass + + myjitdriver = JitDriver(greens=['m'], reds=['n'], + can_inline=can_inline, + get_printable_location=get_printable_location, + leave=leave) + def fn(n): + m = 42.5 + while n > 0: + myjitdriver.can_enter_jit(m=m, n=n) + myjitdriver.jit_merge_point(m=m, n=n) + n -= 1 + return n + + t, rtyper, fngraph = self.gengraph(fn, [int]) + + def getargs(func): + for graph in t.graphs: + if getattr(graph, 'func', None) is func: + return [v.concretetype for v in graph.getargs()] + raise Exception, 'function %r has not been annotated' % func + + leave_args = getargs(leave) + assert leave_args == [lltype.Float, lltype.Signed] + + can_inline_args = getargs(can_inline) + get_printable_location_args = getargs(get_printable_location) + assert can_inline_args == get_printable_location_args == [lltype.Float] + + +class TestJITLLtype(BaseTestJIT, LLRtypeMixin): + pass + +class TestJITOOtype(BaseTestJIT, OORtypeMixin): + pass From pedronis at codespeak.net Wed Sep 16 21:38:24 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 16 Sep 2009 21:38:24 +0200 (CEST) Subject: [pypy-svn] r67721 - in pypy/trunk/pypy: jit/metainterp rlib Message-ID: <20090916193824.988FB168008@codespeak.net> Author: pedronis Date: Wed Sep 16 21:38:22 2009 New Revision: 67721 Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py pypy/trunk/pypy/rlib/jit.py Log: this is at least enough to fix test_*recursive.py Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Wed Sep 16 21:38:22 2009 @@ -180,6 +180,10 @@ graphs = self.translator.graphs self.jit_merge_point_pos = find_jit_merge_point(graphs) graph, block, pos = self.jit_merge_point_pos + op = block.operations[pos] + args = op.args[2:] + s_binding = self.translator.annotator.binding + self.portal_args_s = [s_binding(v) for v in args] graph = copygraph(graph) graph.startblock.isstartblock = False graph.startblock = support.split_before_jit_merge_point( @@ -272,11 +276,7 @@ def make_leave_jit_graph(self): self.leave_graph = None if self.jitdriver.leave: - graph, block, index = self.jit_merge_point_pos - op = block.operations[index] - args = op.args[2:] - s_binding = self.translator.annotator.binding - args_s = [s_binding(v) for v in args] + args_s = self.portal_args_s from pypy.annotation import model as annmodel annhelper = MixLevelHelperAnnotator(self.translator.rtyper) s_result = annmodel.s_None @@ -298,7 +298,7 @@ s_result = annotationoftype(rettype) RETTYPE = annhelper.rtyper.getrepr(s_result).lowleveltype FUNC, PTR = self.cpu.ts.get_FuncType(self.green_args_spec, RETTYPE) - args_s = [annmodel.lltype_to_annotation(ARG) for ARG in FUNC.ARGS] + args_s = self.portal_args_s[:len(self.green_args_spec)] graph = annhelper.getgraph(func, args_s, s_result) funcptr = annhelper.graph2delayed(graph, FUNC) annhelper.finish() Modified: pypy/trunk/pypy/rlib/jit.py ============================================================================== --- pypy/trunk/pypy/rlib/jit.py (original) +++ pypy/trunk/pypy/rlib/jit.py Wed Sep 16 21:38:22 2009 @@ -200,11 +200,13 @@ raise JitHintError("%s expects the following keyword " "arguments: %s" % (self.instance, expected)) - for name in driver.greens: - s_green_key = kwds_s['s_' + name] - s_green_key.hash() # force the hash cache to appear + if self.instance.__name__ == 'jit_merge_point': + for name in driver.greens: + s_green_key = kwds_s['s_' + name] + s_green_key.hash() # force the hash cache to appear + + self.annotate_hooks(**kwds_s) - self.annotate_hooks(**kwds_s) return annmodel.s_None def annotate_hooks(self, **kwds_s): From antocuni at codespeak.net Wed Sep 16 22:49:44 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 16 Sep 2009 22:49:44 +0200 (CEST) Subject: [pypy-svn] r67722 - pypy/trunk/pypy/rlib Message-ID: <20090916204944.24A30168005@codespeak.net> Author: antocuni Date: Wed Sep 16 22:49:42 2009 New Revision: 67722 Modified: pypy/trunk/pypy/rlib/jit.py Log: annotate the hooks only after we annotate jit_merge_point, as the annotation of the arguments passed to can_enter_jit could be slightly different Modified: pypy/trunk/pypy/rlib/jit.py ============================================================================== --- pypy/trunk/pypy/rlib/jit.py (original) +++ pypy/trunk/pypy/rlib/jit.py Wed Sep 16 22:49:42 2009 @@ -210,10 +210,11 @@ return annmodel.s_None def annotate_hooks(self, **kwds_s): - driver = self.instance.im_self - self.annotate_hook(driver.can_inline, driver.greens, **kwds_s) - self.annotate_hook(driver.get_printable_location, driver.greens, **kwds_s) - self.annotate_hook(driver.leave, driver.greens + driver.reds, **kwds_s) + if self.instance.im_func is JitDriver.jit_merge_point.im_func: + driver = self.instance.im_self + self.annotate_hook(driver.can_inline, driver.greens, **kwds_s) + self.annotate_hook(driver.get_printable_location, driver.greens, **kwds_s) + self.annotate_hook(driver.leave, driver.greens + driver.reds, **kwds_s) def annotate_hook(self, func, variables, **kwds_s): if func is None: From antocuni at codespeak.net Wed Sep 16 22:59:44 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 16 Sep 2009 22:59:44 +0200 (CEST) Subject: [pypy-svn] r67723 - pypy/trunk/pypy/rlib Message-ID: <20090916205944.7019D168005@codespeak.net> Author: antocuni Date: Wed Sep 16 22:59:43 2009 New Revision: 67723 Modified: pypy/trunk/pypy/rlib/jit.py Log: revert 67722, as the check was already done by 67721. Moreover, move the for loop that computes s_green_key.hash() one level up, because it was put inside the if by 67721 by mistake Modified: pypy/trunk/pypy/rlib/jit.py ============================================================================== --- pypy/trunk/pypy/rlib/jit.py (original) +++ pypy/trunk/pypy/rlib/jit.py Wed Sep 16 22:59:43 2009 @@ -200,21 +200,20 @@ raise JitHintError("%s expects the following keyword " "arguments: %s" % (self.instance, expected)) - if self.instance.__name__ == 'jit_merge_point': - for name in driver.greens: - s_green_key = kwds_s['s_' + name] - s_green_key.hash() # force the hash cache to appear - - self.annotate_hooks(**kwds_s) + for name in driver.greens: + s_green_key = kwds_s['s_' + name] + s_green_key.hash() # force the hash cache to appear + if self.instance.__name__ == 'jit_merge_point': + self.annotate_hooks(**kwds_s) + return annmodel.s_None def annotate_hooks(self, **kwds_s): - if self.instance.im_func is JitDriver.jit_merge_point.im_func: - driver = self.instance.im_self - self.annotate_hook(driver.can_inline, driver.greens, **kwds_s) - self.annotate_hook(driver.get_printable_location, driver.greens, **kwds_s) - self.annotate_hook(driver.leave, driver.greens + driver.reds, **kwds_s) + driver = self.instance.im_self + self.annotate_hook(driver.can_inline, driver.greens, **kwds_s) + self.annotate_hook(driver.get_printable_location, driver.greens, **kwds_s) + self.annotate_hook(driver.leave, driver.greens + driver.reds, **kwds_s) def annotate_hook(self, func, variables, **kwds_s): if func is None: From arigo at codespeak.net Thu Sep 17 11:10:14 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 11:10:14 +0200 (CEST) Subject: [pypy-svn] r67726 - pypy/trunk/pypy/rlib/test Message-ID: <20090917091014.971A216800D@codespeak.net> Author: arigo Date: Thu Sep 17 11:10:13 2009 New Revision: 67726 Modified: pypy/trunk/pypy/rlib/test/test_rgc.py Log: Skip this test on Python < 2.5. Modified: pypy/trunk/pypy/rlib/test/test_rgc.py ============================================================================== --- pypy/trunk/pypy/rlib/test/test_rgc.py (original) +++ pypy/trunk/pypy/rlib/test/test_rgc.py Thu Sep 17 11:10:13 2009 @@ -2,7 +2,7 @@ from pypy.rpython.lltypesystem import lltype from pypy.rlib import rgc # Force registration of gc.collect import gc -import py +import py, sys def test_collect(): def f(): @@ -20,6 +20,9 @@ assert res is None def test_collect_0(): + if sys.version_info < (2, 5): + py.test.skip("requires Python 2.5 to call gc.collect() with an arg") + def f(): return gc.collect(0) From arigo at codespeak.net Thu Sep 17 11:13:20 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 11:13:20 +0200 (CEST) Subject: [pypy-svn] r67727 - pypy/branch/optimize-novaluedep/pypy/jit/metainterp Message-ID: <20090917091320.B205016800D@codespeak.net> Author: arigo Date: Thu Sep 17 11:13:19 2009 New Revision: 67727 Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/history.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/specnode.py Log: Goal-oriented programming! Kill the method nonnull() on Boxes and rename the overloaded method equals() to same_constant(), supposed to work only between Consts. Now the idea is to make optimize*.py still work... Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/history.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/history.py Thu Sep 17 11:13:19 2009 @@ -95,9 +95,6 @@ def _get_hash_(self): raise NotImplementedError - def nonnull(self): - raise NotImplementedError - def clonebox(self): raise NotImplementedError @@ -110,9 +107,6 @@ def getaddr(self, cpu): raise NotImplementedError - def equals(self, other): - raise NotImplementedError - def sort_key(self): raise NotImplementedError @@ -171,6 +165,9 @@ def constbox(self): return self + def same_constant(self, other): + raise NotImplementedError + def __repr__(self): return 'Const(%s)' % self._getrepr_() @@ -223,13 +220,11 @@ def _get_hash_(self): return self.value - def nonnull(self): - return self.value != 0 - def set_future_value(self, cpu, j): cpu.set_future_value_int(j, self.value) - def equals(self, other): + def same_constant(self, other): + assert isinstance(other, Const) return self.value == other.getint() def _getrepr_(self): @@ -269,13 +264,11 @@ def _get_hash_(self): return llmemory.cast_adr_to_int(self.value) - def nonnull(self): - return self.value != llmemory.NULL - def set_future_value(self, cpu, j): cpu.set_future_value_int(j, self.getint()) - def equals(self, other): + def same_constant(self, other): + assert isinstance(other, Const) return self.value == other.getaddr(self.cpu) def _getrepr_(self): @@ -307,8 +300,9 @@ def set_future_value(self, cpu, j): cpu.set_future_value_float(j, self.getfloat()) - def equals(self, other): - return self.value == other.getfloat() + def same_constant(self, other): + assert isinstance(other, ConstFloat) + return self.value == other.value def _getrepr_(self): return self.value @@ -343,14 +337,12 @@ def getaddr(self, cpu): return llmemory.cast_ptr_to_adr(self.value) - def nonnull(self): - return bool(self.value) - def set_future_value(self, cpu, j): cpu.set_future_value_ref(j, self.value) - def equals(self, other): - return self.value == other.getref_base() + def same_constant(self, other): + assert isinstance(other, ConstPtr) + return self.value == other.value _getrepr_ = repr_pointer @@ -389,9 +381,6 @@ else: return 0 - def nonnull(self): - return bool(self.value) - def set_future_value(self, cpu, j): cpu.set_future_value_ref(j, self.value) @@ -401,8 +390,9 @@ ## # real addr, but just a key for the dictionary ## return self.value - def equals(self, other): - return self.value == other.getref_base() + def same_constant(self, other): + assert isinstance(other, ConstObj) + return self.value == other.value _getrepr_ = repr_object @@ -435,9 +425,6 @@ else: raise NotImplementedError(kind) - def equals(self, other): - return self is other - def nonconstbox(self): return self @@ -493,9 +480,6 @@ def _get_hash_(self): return self.value - def nonnull(self): - return self.value != 0 - def set_future_value(self, cpu, j): cpu.set_future_value_int(j, self.value) @@ -571,9 +555,6 @@ def _get_hash_(self): return lltype.cast_ptr_to_int(self.value) - def nonnull(self): - return bool(self.value) - def set_future_value(self, cpu, j): cpu.set_future_value_ref(j, self.value) @@ -616,9 +597,6 @@ else: return 0 - def nonnull(self): - return bool(self.value) - def set_future_value(self, cpu, j): cpu.set_future_value_ref(j, self.value) Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py Thu Sep 17 11:13:19 2009 @@ -304,7 +304,7 @@ box = self.implement_guard_value(pc, valuebox) for i in range(len(constargs)): casebox = constargs[i] - if box.equals(casebox): + if box.same_constant(casebox): self.pc = jumptargets[i] break @@ -996,13 +996,13 @@ return guard_op def implement_guard_value(self, pc, box): - if isinstance(box, Box): + if isinstance(box, Const): + return box # no promotion needed, already a Const + else: promoted_box = box.constbox() self.generate_guard(pc, rop.GUARD_VALUE, box, [promoted_box]) self.metainterp.replace_box(box, promoted_box) return promoted_box - else: - return box # no promotion needed, already a Const def cls_of_box(self, box): return self.metainterp.cpu.ts.cls_of_box(self.metainterp.cpu, box) @@ -1418,7 +1418,8 @@ for i in range(self.staticdata.num_green_args): box1 = original_boxes[i] box2 = live_arg_boxes[i] - if not box1.equals(box2): + assert isinstance(box1, Constant) + if not box1.same_constant(box2): break else: # Found! Compile it as a loop. Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/specnode.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/specnode.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/specnode.py Thu Sep 17 11:13:19 2009 @@ -27,12 +27,12 @@ class ConstantSpecNode(SpecNode): def __init__(self, constbox): - assert constbox is not None + assert isinstance(constbox, Const) self.constbox = constbox def equals(self, other): return isinstance(other, ConstantSpecNode) and \ - self.constbox.equals(other.constbox) + self.constbox.same_constant(other.constbox) def extract_runtime_data(self, cpu, valuebox, resultlist): pass @@ -64,11 +64,12 @@ class VirtualInstanceSpecNode(AbstractVirtualStructSpecNode): def __init__(self, known_class, fields): AbstractVirtualStructSpecNode.__init__(self, fields) + assert isinstance(known_class, Const) self.known_class = known_class def equals(self, other): if not (isinstance(other, VirtualInstanceSpecNode) and - self.known_class.equals(other.known_class)): + self.known_class.same_constant(other.known_class)): return False return self.equal_fields(other) From arigo at codespeak.net Thu Sep 17 11:50:09 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 11:50:09 +0200 (CEST) Subject: [pypy-svn] r67728 - in pypy/branch/optimize-novaluedep/pypy/jit/metainterp: . test Message-ID: <20090917095009.5B078168005@codespeak.net> Author: arigo Date: Thu Sep 17 11:50:07 2009 New Revision: 67728 Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizefindnode.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/specnode.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py Log: (cfbolz, arigo) Fix optimizefindnode.py to no longer rely on the .value of Boxes. Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizefindnode.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizefindnode.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizefindnode.py Thu Sep 17 11:50:07 2009 @@ -6,6 +6,7 @@ from pypy.jit.metainterp.specnode import VirtualStructSpecNode from pypy.jit.metainterp.history import AbstractValue, ConstInt, Const from pypy.jit.metainterp.resoperation import rop +from pypy.jit.metainterp.executor import _execute_nonspec from pypy.jit.metainterp.optimizeutil import av_newdict, _findall, sort_descrs # ____________________________________________________________ @@ -30,7 +31,7 @@ origfields = None # optimization; equivalent to an empty dict curfields = None # optimization; equivalent to an empty dict - knownvaluebox = None # Used to store value of this box if constant + knownvaluebox = None # a Const with the value of this box, if constant # fields used to store the shape of the potential VirtualList arraydescr = None # set only on freshly-allocated or fromstart arrays @@ -112,30 +113,32 @@ node_escaped.unique = UNIQUE_NO node_escaped.escaped = True - def __init__(self): + def __init__(self, cpu): + self.cpu = cpu self.nodes = {} # Box -> InstanceNode def getnode(self, box): if isinstance(box, Const): - return self.set_constant_node(box) + return self.set_constant_node(box, box) return self.nodes.get(box, self.node_escaped) - def set_constant_node(self, box): + def set_constant_node(self, box, constbox): + assert isinstance(constbox, Const) node = InstanceNode() node.unique = UNIQUE_NO - node.knownvaluebox = box + node.knownvaluebox = constbox self.nodes[box] = node return node - def is_constant_box(self, box): + def get_constant_box(self, box): if isinstance(box, Const): - return True + return box try: node = self.nodes[box] except KeyError: - return False + return None else: - return node.is_constant() + return node.knownvaluebox def find_nodes(self, operations): for op in operations: @@ -150,11 +153,13 @@ def find_nodes_default(self, op): if op.is_always_pure(): for arg in op.args: - node = self.getnode(arg) - if not node.is_constant(): + if self.get_constant_box(arg) is None: break else: - self.set_constant_node(op.result) + # all constant arguments: we can constant-fold + argboxes = [self.get_constant_box(arg) for arg in op.args] + resbox = _execute_nonspec(self.cpu, op.opnum, argboxes, op.descr) + self.set_constant_node(op.result, resbox.constbox()) # default case: mark the arguments as escaping for box in op.args: self.getnode(box).mark_escaped() @@ -170,7 +175,9 @@ def find_nodes_NEW_WITH_VTABLE(self, op): instnode = InstanceNode() - instnode.knownclsbox = op.args[0] + box = op.args[0] + assert isinstance(box, Const) + instnode.knownclsbox = box self.nodes[op.result] = instnode def find_nodes_NEW(self, op): @@ -180,7 +187,8 @@ def find_nodes_NEW_ARRAY(self, op): lengthbox = op.args[0] - if not self.is_constant_box(lengthbox): + lengthbox = self.get_constant_box(lengthbox) + if lengthbox is None: return # var-sized arrays are not virtual arraynode = InstanceNode() arraynode.arraysize = lengthbox.getint() @@ -190,18 +198,22 @@ def find_nodes_ARRAYLEN_GC(self, op): arraynode = self.getnode(op.args[0]) if arraynode.arraydescr is not None: - assert op.result.getint() == arraynode.arraysize - self.set_constant_node(op.result) + resbox = ConstInt(arraynode.arraysize) + self.set_constant_node(op.result, resbox) def find_nodes_GUARD_CLASS(self, op): instnode = self.getnode(op.args[0]) if instnode.fromstart: # only useful (and safe) in this case - instnode.knownclsbox = op.args[1] + box = op.args[1] + assert isinstance(box, Const) + instnode.knownclsbox = box def find_nodes_GUARD_VALUE(self, op): instnode = self.getnode(op.args[0]) if instnode.fromstart: # only useful (and safe) in this case - instnode.knownvaluebox = op.args[1] + box = op.args[1] + assert isinstance(box, Const) + instnode.knownvaluebox = box def find_nodes_SETFIELD_GC(self, op): instnode = self.getnode(op.args[0]) @@ -240,7 +252,8 @@ def find_nodes_SETARRAYITEM_GC(self, op): indexbox = op.args[1] - if not self.is_constant_box(indexbox): + indexbox = self.get_constant_box(indexbox) + if indexbox is None: self.find_nodes_default(op) # not a Const index return arraynode = self.getnode(op.args[0]) @@ -255,7 +268,8 @@ def find_nodes_GETARRAYITEM_GC(self, op): indexbox = op.args[1] - if not self.is_constant_box(indexbox): + indexbox = self.get_constant_box(indexbox) + if indexbox is None: self.find_nodes_default(op) # not a Const index return arraynode = self.getnode(op.args[0]) @@ -328,7 +342,7 @@ assert inputnode.fromstart if inputnode.is_constant() and \ exitnode.is_constant() and \ - inputnode.knownvaluebox.equals(exitnode.knownvaluebox): + inputnode.knownvaluebox.same_constant(exitnode.knownvaluebox): return ConstantSpecNode(inputnode.knownvaluebox) if inputnode.escaped: return prebuiltNotSpecNode @@ -371,7 +385,7 @@ def intersect_instance(self, inputnode, exitnode): if (inputnode.knownclsbox is not None and - not inputnode.knownclsbox.equals(exitnode.knownclsbox)): + not inputnode.knownclsbox.same_constant(exitnode.knownclsbox)): # unique match, but the class is known to be a mismatch return prebuiltNotSpecNode # @@ -424,7 +438,7 @@ def matches_instance_node(self, exitnode): if exitnode.knownvaluebox is None: return False - return self.constbox.equals(exitnode.knownvaluebox) + return self.constbox.same_constant(exitnode.knownvaluebox) class __extend__(VirtualInstanceSpecNode): def make_instance_node(self): @@ -440,7 +454,7 @@ return False # assert exitnode.unique == UNIQUE_INST - if not self.known_class.equals(exitnode.knownclsbox): + if not self.known_class.same_constant(exitnode.knownclsbox): # unique match, but the class is known to be a mismatch return False # Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/specnode.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/specnode.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/specnode.py Thu Sep 17 11:50:07 2009 @@ -1,4 +1,5 @@ from pypy.tool.pairtype import extendabletype +from pypy.jit.metainterp.history import Const class SpecNode(object): Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py Thu Sep 17 11:50:07 2009 @@ -217,11 +217,10 @@ class BaseTestOptimizeFindNode(BaseTest): - def find_nodes(self, ops, spectext, boxkinds=None, **values): + def find_nodes(self, ops, spectext, boxkinds=None): assert boxkinds is None or isinstance(boxkinds, dict) loop = self.parse(ops, boxkinds=boxkinds) - loop.setvalues(**values) - perfect_specialization_finder = PerfectSpecializationFinder() + perfect_specialization_finder = PerfectSpecializationFinder(self.cpu) perfect_specialization_finder.find_nodes_loop(loop) self.check_specnodes(loop.specnodes, spectext) return (loop.getboxes(), perfect_specialization_finder.getnode) @@ -740,7 +739,7 @@ p2 = same_as(ConstPtr(myptr)) jump(p2) """ - self.find_nodes(ops, 'Constant(myptr)', p2=self.myptr) + self.find_nodes(ops, 'Constant(myptr)') def test_find_nodes_store_into_loop_constant_1(self): ops = """ @@ -781,7 +780,7 @@ setarrayitem_gc(p2, 0, i3, descr=arraydescr) jump(p2) """ - self.find_nodes(ops, 'VArray(arraydescr, Not)', i2=1) + self.find_nodes(ops, 'VArray(arraydescr, Not)') def test_find_nodes_arithmetic_propagation_bug_1(self): ops = """ @@ -793,7 +792,7 @@ setarrayitem_gc(p2, 0, 5) jump(p2) """ - self.find_nodes(ops, 'VArray(arraydescr, Not)', i2=1) + self.find_nodes(ops, 'VArray(arraydescr, Not)') def test_find_nodes_arithmetic_propagation_bug_2(self): ops = """ @@ -807,7 +806,7 @@ setarrayitem_gc(p2, i0, i3, descr=arraydescr) jump(p2) """ - self.find_nodes(ops, 'VArray(arraydescr, Not)', i2=1, i0=0) + self.find_nodes(ops, 'VArray(arraydescr, Not)') def test_find_nodes_arithmetic_propagation_bug_3(self): ops = """ @@ -821,7 +820,7 @@ setarrayitem_gc(p2, 0, i3, descr=arraydescr) jump(p2) """ - self.find_nodes(ops, 'VArray(arraydescr, Not)', i2=1) + self.find_nodes(ops, 'VArray(arraydescr, Not)') def test_find_nodes_bug_1(self): ops = """ @@ -888,9 +887,7 @@ fail() jump(p58) """ - self.find_nodes(ops, 'Virtual(node_vtable, valuedescr=Not)', - i16=0, i25=0, i39=0, i52=0, i55=0, i59=0, - i43=1, i45=1, i48=1, i40=1) + self.find_nodes(ops, 'Virtual(node_vtable, valuedescr=Not)') def test_bug_2(self): py.test.skip("fix me") @@ -909,13 +906,12 @@ # Bridge tests def find_bridge(self, ops, inputspectext, outputspectext, boxkinds=None, - mismatch=False, **values): + mismatch=False): assert boxkinds is None or isinstance(boxkinds, dict) inputspecnodes = self.unpack_specnodes(inputspectext) outputspecnodes = self.unpack_specnodes(outputspectext) bridge = self.parse(ops, boxkinds=boxkinds) - bridge.setvalues(**values) - bridge_specialization_finder = BridgeSpecializationFinder() + bridge_specialization_finder = BridgeSpecializationFinder(self.cpu) bridge_specialization_finder.find_nodes_bridge(bridge, inputspecnodes) matches = bridge_specialization_finder.bridge_matches(outputspecnodes) if mismatch: From antocuni at codespeak.net Thu Sep 17 12:00:00 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 17 Sep 2009 12:00:00 +0200 (CEST) Subject: [pypy-svn] r67729 - pypy/trunk/pypy/translator/jvm/src/pypy Message-ID: <20090917100000.D15D3168005@codespeak.net> Author: antocuni Date: Thu Sep 17 12:00:00 2009 New Revision: 67729 Modified: pypy/trunk/pypy/translator/jvm/src/pypy/PyPy.java pypy/trunk/pypy/translator/jvm/src/pypy/ll_os.java Log: (yoli, antocuni) this has been waiting forever in my wc. Fix ll_os on windows for the jvm backend Modified: pypy/trunk/pypy/translator/jvm/src/pypy/PyPy.java ============================================================================== --- pypy/trunk/pypy/translator/jvm/src/pypy/PyPy.java (original) +++ pypy/trunk/pypy/translator/jvm/src/pypy/PyPy.java Thu Sep 17 12:00:00 2009 @@ -924,7 +924,7 @@ public String ll_join(String a, String b) { - return a + "/" + b; // XXX + return a + File.separator + b; } public String ll_strtod_formatd(String format, double d) Modified: pypy/trunk/pypy/translator/jvm/src/pypy/ll_os.java ============================================================================== --- pypy/trunk/pypy/translator/jvm/src/pypy/ll_os.java (original) +++ pypy/trunk/pypy/translator/jvm/src/pypy/ll_os.java Thu Sep 17 12:00:00 2009 @@ -10,6 +10,7 @@ import com.sun.jna.Library; import com.sun.jna.Native; +import com.sun.jna.Platform; abstract class FileWrapper { @@ -172,15 +173,29 @@ public int symlink(String path1, String path2); public int access(String path, int mode); } + + static public interface Msvcrt extends Library { + public int _access(String path, int mode); + } + static final Libc libc; + static final Msvcrt msvcrt; static { - Libc res; + Libc res = null; + Msvcrt vcrt = null; try { - res = (Libc) Native.loadLibrary("c", Libc.class); + if ((Platform.isWindows())) { + vcrt = (Msvcrt) Native.loadLibrary("msvcrt", Msvcrt.class); + } + else { + res = (Libc) Native.loadLibrary("c", Libc.class); + } } catch (Throwable t) { res = null; + vcrt = null; } libc = res; + msvcrt = vcrt; } // NB: these values are those used by Windows and they differs @@ -298,6 +313,10 @@ //if ((mode & X_OK) != 0 && !file.canExecute()) // return false; + if (msvcrt != null) { + return msvcrt._access(path, mode) == 0; + } + return libc.access(path, mode) == 0; // note that 0==success } @@ -532,7 +551,7 @@ public void checkLibc() { if (libc == null) - throwOSError(EPERM, "jna.jar required"); + throwOSError(EPERM, "jna.jar and an Unix are required"); } public int ll_os_getpid() @@ -548,4 +567,9 @@ if (res != 0) throwOSError(res, ""); } + + public String posix__getfullpathname(String name) + { + return new File(name).getAbsolutePath(); + } } From antocuni at codespeak.net Thu Sep 17 12:41:57 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 17 Sep 2009 12:41:57 +0200 (CEST) Subject: [pypy-svn] r67730 - in pypy/trunk/pypy: jit/metainterp jit/metainterp/test rpython/ootypesystem Message-ID: <20090917104157.CAE56168005@codespeak.net> Author: antocuni Date: Thu Sep 17 12:41:54 2009 New Revision: 67730 Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py pypy/trunk/pypy/jit/metainterp/warmspot.py pypy/trunk/pypy/rpython/ootypesystem/rlist.py Log: remove the oopspec from ll_known_maxlength2fixed. This makes test_listcomp passing on ootype, although the produced loop looks inefficient both on lltype and ootype Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Thu Sep 17 12:41:54 2009 @@ -859,6 +859,21 @@ res = self.interp_operations(f, [3, 5]) assert res == 8 self.check_history_(int_add=0, call=1) + + def test_listcomp(self): + myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'lst']) + def f(x, y): + lst = [0, 0, 0] + while y > 0: + myjitdriver.can_enter_jit(x=x, y=y, lst=lst) + myjitdriver.jit_merge_point(x=x, y=y, lst=lst) + lst = [i+x for i in lst if i >=0] + y -= 1 + return lst[0] + res = self.meta_interp(f, [6, 7], listcomp=True, backendopt=True, listops=True) + # XXX: the loop looks inefficient + assert res == 42 + class TestOOtype(BasicTests, OOJitMixin): Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Thu Sep 17 12:41:54 2009 @@ -47,10 +47,15 @@ translator.warmrunnerdesc = warmrunnerdesc # for later debugging def ll_meta_interp(function, args, backendopt=False, type_system='lltype', - **kwds): + listcomp=False, **kwds): + if listcomp: + extraconfigopts = {'translation.list_comprehension_operations': True} + else: + extraconfigopts = {} interp, graph = get_interpreter(function, args, backendopt=False, # will be done below - type_system=type_system) + type_system=type_system, + **extraconfigopts) clear_tcache() return jittify_and_run(interp, graph, args, backendopt=backendopt, **kwds) Modified: pypy/trunk/pypy/rpython/ootypesystem/rlist.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/rlist.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/rlist.py Thu Sep 17 12:41:54 2009 @@ -183,7 +183,6 @@ item = olditems.ll_getitem_fast(i) newitems.ll_setitem_fast(i, item) return newitems -ll_known_maxlength2fixed.oopspec = 'list.list2fixed(l)' def ll_known_maxlength2fixed_exact(ARRAY, l): return l.items From pedronis at codespeak.net Thu Sep 17 13:54:43 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 17 Sep 2009 13:54:43 +0200 (CEST) Subject: [pypy-svn] r67731 - in pypy/trunk/pypy: jit/backend/llsupport jit/backend/x86 jit/backend/x86/test rpython rpython/lltypesystem rpython/lltypesystem/test rpython/memory/gc rpython/memory/gc/test rpython/memory/gctransform rpython/memory/test translator/c translator/c/test Message-ID: <20090917115443.26A26168005@codespeak.net> Author: pedronis Date: Thu Sep 17 13:54:41 2009 New Revision: 67731 Modified: pypy/trunk/pypy/jit/backend/llsupport/llmodel.py pypy/trunk/pypy/jit/backend/x86/assembler.py pypy/trunk/pypy/jit/backend/x86/runner.py pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py pypy/trunk/pypy/rpython/llinterp.py pypy/trunk/pypy/rpython/lltypesystem/lloperation.py pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py pypy/trunk/pypy/rpython/memory/gc/generation.py pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py pypy/trunk/pypy/rpython/memory/gctransform/framework.py pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py pypy/trunk/pypy/translator/c/gc.py pypy/trunk/pypy/translator/c/test/test_boehm.py Log: (micke, pedronis, armin around a bit yesterday) fix the issue that the failure code produced by the x86 backend was not marking the array it uses for failure pointer values which is old as pointing potentially to young objects. this was solved by inventing a new gc operation gc_assume_young_pointers implemented by at least the generation and hybrid gc, and by having the x86 backend produce a call to something that will end up invoking the operation at the end of the failure write backs Modified: pypy/trunk/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/trunk/pypy/jit/backend/llsupport/llmodel.py Thu Sep 17 13:54:41 2009 @@ -44,6 +44,14 @@ else: self._setup_exception_handling_untranslated() self.clear_exception() + self.setup() + if translate_support_code: + self._setup_on_leave_jitted_translated() + else: + self._setup_on_leave_jitted_untranslated() + + def setup(self): + pass def set_class_sizes(self, class_sizes): self.class_sizes = class_sizes @@ -131,10 +139,35 @@ self.pos_exc_value = pos_exc_value self.save_exception = save_exception - _SAVE_EXCEPTION_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) + def _setup_on_leave_jitted_untranslated(self): + # assume we don't need a backend leave in this case + self.on_leave_jitted_save_exc = self.save_exception + self.on_leave_jitted_noexc = lambda : None + + def _setup_on_leave_jitted_translated(self): + on_leave_jitted_hook = self.get_on_leave_jitted_hook() + save_exception = self.save_exception + + def on_leave_jitted_noexc(): + on_leave_jitted_hook() + + def on_leave_jitted_save_exc(): + on_leave_jitted_hook() + save_exception() - def get_save_exception_int(self): - f = llhelper(self._SAVE_EXCEPTION_FUNC, self.save_exception) + self.on_leave_jitted_noexc = on_leave_jitted_noexc + self.on_leave_jitted_save_exc = on_leave_jitted_save_exc + + def get_on_leave_jitted_hook(self): + return lambda : None + + _ON_JIT_LEAVE_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) + + def get_on_leave_jitted_int(self, save_exception): + if save_exception: + f = llhelper(self._ON_JIT_LEAVE_FUNC, self.on_leave_jitted_save_exc) + else: + f = llhelper(self._ON_JIT_LEAVE_FUNC, self.on_leave_jitted_noexc) return rffi.cast(lltype.Signed, f) def get_exception(self): Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py Thu Sep 17 13:54:41 2009 @@ -83,6 +83,11 @@ self.fail_boxes_ptr = lltype.malloc(lltype.GcArray(llmemory.GCREF), MAX_FAIL_BOXES, zero=True) + def leave_jitted_hook(self): + fail_boxes_ptr = self.fail_boxes_ptr + llop.gc_assume_young_pointers(lltype.Void, + llmemory.cast_ptr_to_adr(fail_boxes_ptr)) + def make_sure_mc_exists(self): if self.mc is None: rffi.cast(lltype.Signed, self.fail_boxes_int) # workaround @@ -653,10 +658,15 @@ mc.MOV(addr_add(imm(self.fail_box_int_addr), imm(len(locs) * WORD)), eax) - if exc: - # note that we don't have to save and restore eax, ecx and edx here - addr = self.cpu.get_save_exception_int() - mc.CALL(rel32(addr)) + + # we call a provided function that will + # - call our on_leave_jitted_hook which will mark + # the fail_boxes_ptr array as pointing to young objects to + # avoid unwarranted freeing + # - optionally save exception depending on the flag + addr = self.cpu.get_on_leave_jitted_int(save_exception=exc) + mc.CALL(rel32(addr)) + # don't break the following code sequence! mc = mc._mc mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD)) Modified: pypy/trunk/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/runner.py (original) +++ pypy/trunk/pypy/jit/backend/x86/runner.py Thu Sep 17 13:54:41 2009 @@ -21,16 +21,17 @@ gcdescr=None): AbstractLLCPU.__init__(self, rtyper, stats, translate_support_code, gcdescr) - TP = lltype.GcArray(llmemory.GCREF) self._bootstrap_cache = {} self._guard_list = [] - self.setup() if rtyper is not None: # for tests self.lltype2vtable = rtyper.lltype_to_vtable_mapping() def setup(self): self.assembler = Assembler386(self, self.translate_support_code) + def get_on_leave_jitted_hook(self): + return self.assembler.leave_jitted_hook + def setup_once(self): pass Modified: pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py Thu Sep 17 13:54:41 2009 @@ -54,7 +54,7 @@ return entrypoint -def compile_and_run(f, gc, **kwds): +def compile_and_run(f, gc, CPUClass=CPU386, **kwds): from pypy.annotation.listdef import s_list_of_strings from pypy.translator.translator import TranslationContext from pypy.jit.metainterp.warmspot import apply_jit @@ -68,7 +68,7 @@ t.buildannotator().build_types(f, [s_list_of_strings]) t.buildrtyper().specialize() if kwds['jit']: - apply_jit(t, CPUClass=CPU386, optimizer=OPTIMIZER_SIMPLE) + apply_jit(t, CPUClass=CPUClass, optimizer=OPTIMIZER_SIMPLE) cbuilder = genc.CStandaloneBuilder(t, f, t.config) cbuilder.generate_source() cbuilder.compile() @@ -326,6 +326,14 @@ check(l[13].x == 122) check(l[14].x == 132) check(l[15].x == 142) + + class CPU386CollectOnLeave(CPU386): + + def execute_operations(self, loop, verbose=False): + op = CPU386.execute_operations(self, loop, verbose) + rgc.collect(0) + return op + res = compile_and_run(get_test(main), "hybrid", gcrootfinder="asmgcc", - jit=True) + CPUClass=CPU386CollectOnLeave, jit=True) assert int(res) == 20 Modified: pypy/trunk/pypy/rpython/llinterp.py ============================================================================== --- pypy/trunk/pypy/rpython/llinterp.py (original) +++ pypy/trunk/pypy/rpython/llinterp.py Thu Sep 17 13:54:41 2009 @@ -821,6 +821,9 @@ def op_gc__collect(self, *gen): self.heap.collect(*gen) + def op_gc_assume_young_pointers(self, addr): + raise NotImplementedError + def op_gc_can_move(self, ptr): addr = llmemory.cast_ptr_to_adr(ptr) return self.heap.can_move(addr) Modified: pypy/trunk/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/lloperation.py Thu Sep 17 13:54:41 2009 @@ -100,6 +100,28 @@ return True llop = _LLOP() +class VoidMarker(object): + # marker wrapper for void arguments to llops + def __init__(self, value): + self.value = value + def _freeze_(self): + return True + +def void(value): + return VoidMarker(value) + +class Entry(ExtRegistryEntry): + _about_ = void + + def compute_result_annotation(self, s_value): + assert s_value.is_constant() + from pypy.annotation.bookkeeper import getbookkeeper + bk = getbookkeeper() + return bk.immutablevalue(VoidMarker(s_value.const)) + + def specialize_call(self, hop): + from pypy.rpython.lltypesystem import lltype + return hop.inputconst(lltype.Void, None) def enum_ops_without_sideeffects(raising_is_ok=False): """Enumerate operations that have no side-effects @@ -127,8 +149,16 @@ return lltype_to_annotation(RESULTTYPE.const) def specialize_call(self, hop): + from pypy.rpython.lltypesystem import lltype op = self.instance # the LLOp object that was called - args_v = [hop.inputarg(r, i+1) for i, r in enumerate(hop.args_r[1:])] + args_v = [] + for i, s_arg in enumerate(hop.args_s[1:]): + if s_arg.is_constant() and isinstance(s_arg.const, VoidMarker): + v_arg = hop.inputconst(lltype.Void, s_arg.const.value) + else: + v_arg = hop.inputarg(hop.args_r[i+1], i+1) + args_v.append(v_arg) + if op.canraise: hop.exception_is_here() else: @@ -408,6 +438,7 @@ 'gc_thread_prepare' : LLOp(canraise=(MemoryError,)), 'gc_thread_run' : LLOp(), 'gc_thread_die' : LLOp(), + 'gc_assume_young_pointers': LLOp(), # experimental operations in support of thread cloning, only # implemented by the Mark&Sweep GC 'gc_x_swap_pool': LLOp(canraise=(MemoryError,), canunwindgc=True), Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py Thu Sep 17 13:54:41 2009 @@ -1,5 +1,5 @@ import py -from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS, llop +from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS, llop, void from pypy.rpython.lltypesystem import lltype, opimpl from pypy.rpython.ootypesystem import ootype, ooopimpl from pypy.rpython.llinterp import LLFrame @@ -39,6 +39,19 @@ res = interpret(llf, [5, 7], policy=LowLevelAnnotatorPolicy()) assert res == 12 +def test_llop_with_voids_interp(): + from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy + S = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed)) + name_y = void('y') + def llf(): + s = lltype.malloc(S) + llop.bare_setfield(lltype.Void, s, void('x'), 3) + llop.bare_setfield(lltype.Void, s, name_y, 2) + return s.x + s.y + res = interpret(llf, [], policy=LowLevelAnnotatorPolicy()) + assert res == 5 + + # ___________________________________________________________________________ # This tests that the LLInterpreter and the LL_OPERATIONS tables are in sync. Modified: pypy/trunk/pypy/rpython/memory/gc/generation.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gc/generation.py (original) +++ pypy/trunk/pypy/rpython/memory/gc/generation.py Thu Sep 17 13:54:41 2009 @@ -448,6 +448,15 @@ remember_young_pointer._dont_inline_ = True self.remember_young_pointer = remember_young_pointer + def assume_young_pointers(self, addr_struct): + objhdr = self.header(addr_struct) + if objhdr.tid & GCFLAG_NO_YOUNG_PTRS: + self.old_objects_pointing_to_young.append(addr_struct) + objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS + if objhdr.tid & GCFLAG_NO_HEAP_PTRS: + objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS + self.last_generation_root_objects.append(addr_struct) + def write_into_last_generation_obj(self, addr_struct, addr): objhdr = self.header(addr_struct) if objhdr.tid & GCFLAG_NO_HEAP_PTRS: Modified: pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py (original) +++ pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py Thu Sep 17 13:54:41 2009 @@ -299,7 +299,19 @@ gc.collect(9) assert calls == ['semispace_collect'] - calls = [] + calls = [] + + def test_assume_young_pointers(self): + s0 = lltype.malloc(S, immortal=True) + self.consider_constant(s0) + s = self.malloc(S) + s.x = 1 + s0.next = s + self.gc.assume_young_pointers(llmemory.cast_ptr_to_adr(s0)) + + self.gc.collect(0) + + assert s0.next.x == 1 class TestHybridGC(TestGenerationGC): Modified: pypy/trunk/pypy/rpython/memory/gctransform/framework.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/trunk/pypy/rpython/memory/gctransform/framework.py Thu Sep 17 13:54:41 2009 @@ -242,6 +242,13 @@ [s_gc, annmodel.SomeAddress()], annmodel.SomeBool()) + if hasattr(GCClass, 'assume_young_pointers'): + # xxx should really be a noop for gcs without generations + self.assume_young_pointers_ptr = getfn( + GCClass.assume_young_pointers.im_func, + [s_gc, annmodel.SomeAddress()], + annmodel.s_None) + # in some GCs we can inline the common case of # malloc_fixedsize(typeid, size, True, False, False) if getattr(GCClass, 'inline_simple_malloc', False): @@ -574,6 +581,12 @@ hop.genop("direct_call", [self.can_move_ptr, self.c_const_gc, v_addr], resultvar=op.result) + def gct_gc_assume_young_pointers(self, hop): + op = hop.spaceop + v_addr = op.args[0] + hop.genop("direct_call", [self.assume_young_pointers_ptr, + self.c_const_gc, v_addr]) + def _can_realloc(self): return self.gcdata.gc.can_realloc Modified: pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py (original) +++ pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py Thu Sep 17 13:54:41 2009 @@ -5,7 +5,7 @@ from pypy.annotation import model as annmodel from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.memory.gctransform import framework -from pypy.rpython.lltypesystem.lloperation import llop +from pypy.rpython.lltypesystem.lloperation import llop, void from pypy.rpython.memory.gc.marksweep import X_CLONE, X_POOL, X_POOL_PTR from pypy.rlib.objectmodel import compute_unique_id, we_are_translated from pypy.rlib.debug import ll_assert @@ -1110,5 +1110,26 @@ res = run([100, 100]) assert res == 200 + def test_assume_young_pointers(self): + from pypy.rlib import rgc + S = lltype.GcForwardReference() + S.become(lltype.GcStruct('S', + ('x', lltype.Signed), + ('prev', lltype.Ptr(S)), + ('next', lltype.Ptr(S)))) + s0 = lltype.malloc(S, immortal=True) + def f(): + s = lltype.malloc(S) + s.x = 42 + llop.bare_setfield(lltype.Void, s0, void('next'), s) + llop.gc_assume_young_pointers(lltype.Void, + llmemory.cast_ptr_to_adr(s0)) + rgc.collect(0) + return s0.next.x + + run = self.runner(f, nbargs=0) + res = run([]) + assert res == 42 + def test_malloc_nonmovable_fixsize(self): py.test.skip("not supported") Modified: pypy/trunk/pypy/translator/c/gc.py ============================================================================== --- pypy/trunk/pypy/translator/c/gc.py (original) +++ pypy/trunk/pypy/translator/c/gc.py Thu Sep 17 13:54:41 2009 @@ -83,6 +83,9 @@ def OP_GC_THREAD_DIE(self, funcgen, op): return '' + def OP_GC_ASSUME_YOUNG_POINTERS(self, funcgen, op): + return '' + class RefcountingInfo: static_deallocator = None Modified: pypy/trunk/pypy/translator/c/test/test_boehm.py ============================================================================== --- pypy/trunk/pypy/translator/c/test/test_boehm.py (original) +++ pypy/trunk/pypy/translator/c/test/test_boehm.py Thu Sep 17 13:54:41 2009 @@ -1,6 +1,7 @@ import py from pypy.translator.translator import TranslationContext -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.memory.test import snippet from pypy.rpython.tool.rffi_platform import check_boehm from pypy.translator.c.genc import CExtModuleBuilder @@ -411,6 +412,17 @@ run = self.getcompiled(f) assert run() == True + def test_assume_young_pointers_nop(self): + S = lltype.GcStruct('S', ('x', lltype.Signed)) + s = lltype.malloc(S) + s.x = 0 + def f(): + llop.gc_assume_young_pointers(lltype.Void, + llmemory.cast_ptr_to_adr(s)) + return True + run = self.getcompiled(f) + assert run() == True + # reusing some tests from pypy.rpython.memory.test.snippet large_tests_ok = True From antocuni at codespeak.net Thu Sep 17 14:12:07 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 17 Sep 2009 14:12:07 +0200 (CEST) Subject: [pypy-svn] r67732 - in pypy/trunk/pypy: rpython/ootypesystem translator/test Message-ID: <20090917121207.1E6C6168005@codespeak.net> Author: antocuni Date: Thu Sep 17 14:12:05 2009 New Revision: 67732 Modified: pypy/trunk/pypy/rpython/ootypesystem/rlist.py pypy/trunk/pypy/translator/test/test_simplify.py Log: test&fix for yet another case in ootype list comprehension Modified: pypy/trunk/pypy/rpython/ootypesystem/rlist.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/rlist.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/rlist.py Thu Sep 17 14:12:05 2009 @@ -85,7 +85,10 @@ else: llfn = ll_known_maxlength2list else: - llfn = ll_list2fixed + if isinstance(hop.r_result, FixedSizeListRepr): + llfn = ll_list2fixed + else: + return v_list return hop.llops.gendirectcall(llfn, cRESLIST, v_list) Modified: pypy/trunk/pypy/translator/test/test_simplify.py ============================================================================== --- pypy/trunk/pypy/translator/test/test_simplify.py (original) +++ pypy/trunk/pypy/translator/test/test_simplify.py Thu Sep 17 14:12:05 2009 @@ -422,6 +422,18 @@ res = interp.eval_graph(graph, [8]) assert res == 5 * 17 + def test_list_iterator_mutated_after_listcomp(self): + # for now, this is not optimized as a list comp + def main(n): + r = range(n) + lst = [i*17 for i in iter(r)] + lst.append(42) + return lst[5] + interp, graph = self.specialize(main, [int]) + res = interp.eval_graph(graph, [8]) + assert res == 5 * 17 + + def test_dict_iterator(self): # for now, this is not optimized as a list comp def main(n, m): From pedronis at codespeak.net Thu Sep 17 15:53:43 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 17 Sep 2009 15:53:43 +0200 (CEST) Subject: [pypy-svn] r67733 - in pypy/trunk/pypy: jit/metainterp module/pypyjit Message-ID: <20090917135343.0A2CD168008@codespeak.net> Author: pedronis Date: Thu Sep 17 15:53:41 2009 New Revision: 67733 Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py pypy/trunk/pypy/module/pypyjit/interp_jit.py Log: removal of casts that are not needed anymore Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Thu Sep 17 15:53:41 2009 @@ -943,7 +943,7 @@ fn = support.maybe_on_top_of_llinterp(rtyper, get_printable_location_ptr) res = fn(*args) - if we_are_translated() or not isinstance(res, str): + if not we_are_translated() and not isinstance(res, str): res = hlstr(res) return res Modified: pypy/trunk/pypy/module/pypyjit/interp_jit.py ============================================================================== --- pypy/trunk/pypy/module/pypyjit/interp_jit.py (original) +++ pypy/trunk/pypy/module/pypyjit/interp_jit.py Thu Sep 17 15:53:41 2009 @@ -28,8 +28,6 @@ JUMP_ABSOLUTE = opmap['JUMP_ABSOLUTE'] def can_inline(next_instr, bytecode): - if we_are_translated(): - bytecode = cast_base_ptr_to_instance(PyCode, bytecode) co_code = bytecode.co_code next_instr = 0 while next_instr < len(co_code): @@ -46,8 +44,6 @@ def get_printable_location(next_instr, bytecode): from pypy.tool.stdlib_opcode import opcode_method_names - if we_are_translated(): - bytecode = cast_base_ptr_to_instance(PyCode, bytecode) name = opcode_method_names[ord(bytecode.co_code[next_instr])] return '%s #%d %s' % (bytecode.get_repr(), next_instr, name) From antocuni at codespeak.net Thu Sep 17 15:53:49 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 17 Sep 2009 15:53:49 +0200 (CEST) Subject: [pypy-svn] r67734 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090917135349.CF67D168008@codespeak.net> Author: antocuni Date: Thu Sep 17 15:53:49 2009 New Revision: 67734 Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py pypy/trunk/pypy/jit/metainterp/test/test_send.py Log: if an oosend can dispatch only to pure graphs, emit it as oosend_*_pure Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/codewriter.py Thu Sep 17 15:53:49 2009 @@ -1384,13 +1384,27 @@ self.minimize_variables() SELFTYPE, methname, meth = support.lookup_oosend_method(op) methdescr = self.codewriter.get_methdescr(SELFTYPE, methname, False) - self.emit('residual_oosend_canraise') + graphs = SELFTYPE._lookup_graphs(methname) + kind = self.get_kind_of_graphs(graphs) + self.emit('residual_oosend_%s' % kind) self.emit(self.get_position(methdescr)) non_void_args = [arg for arg in op.args[1:] if arg.concretetype is not ootype.Void] self.emit_varargs(non_void_args) self.register_var(op.result) + def get_kind_of_graphs(self, graphs): + pure = True + for graph in graphs: + if not hasattr(graph, 'func'): + pure = False + pure = pure and getattr(graph.func, '_pure_function_', False) + + if pure: + return 'pure' + else: + return 'canraise' + def serialize_op_debug_assert(self, op): log.WARNING("found debug_assert in %r; should have be removed" % (self.graph,)) Modified: pypy/trunk/pypy/jit/metainterp/test/test_send.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_send.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_send.py Thu Sep 17 15:53:49 2009 @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, hint, purefunction from pypy.jit.metainterp.policy import StopAtXPolicy from pypy.rpython.ootypesystem import ootype from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin @@ -533,6 +533,31 @@ else: self.check_loops(call=1) + def test_constfold_pure_oosend(self): + myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) + class A: + @purefunction + def foo(self): + return 42 + def fn(n, i): + res = 0 + obj = A() + while i > 0: + myjitdriver.can_enter_jit(i=i, obj=obj) + myjitdriver.jit_merge_point(i=i, obj=obj) + obj = hint(obj, promote=True) + res = obj.foo() + i-=1 + return res + policy = StopAtXPolicy(A.foo.im_func) + res = self.meta_interp(fn, [1, 20], policy=policy) + assert res == 42 + if self.type_system == 'ootype': + self.check_loops(oosend=0) + else: + self.check_loops(call=0) + + class TestOOtype(SendTests, OOJitMixin): pass From pedronis at codespeak.net Thu Sep 17 16:26:53 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 17 Sep 2009 16:26:53 +0200 (CEST) Subject: [pypy-svn] r67735 - in pypy/build/bot2/pypybuildbot: . test Message-ID: <20090917142653.E627B168005@codespeak.net> Author: pedronis Date: Thu Sep 17 16:26:50 2009 New Revision: 67735 Modified: pypy/build/bot2/pypybuildbot/summary.py pypy/build/bot2/pypybuildbot/test/test_summary.py Log: (micke, pedronis) teach summary about xfailed tests Modified: pypy/build/bot2/pypybuildbot/summary.py ============================================================================== --- pypy/build/bot2/pypybuildbot/summary.py (original) +++ pypy/build/bot2/pypybuildbot/summary.py Thu Sep 17 16:26:50 2009 @@ -31,6 +31,7 @@ self._outcomes = {} self.failed = set() self.skipped = set() + self._xfailed = 0 self.longreprs = {} self._run_info = run_info @@ -50,6 +51,8 @@ self.skipped.add(namekey) elif shortrepr == '.': pass + elif shortrepr == 'x': + self._xfailed += 1 else: self.failed.add(namekey) @@ -63,7 +66,12 @@ @property def numpassed(self): - return len(self._outcomes) - len(self.skipped) - len(self.failed) + return (len(self._outcomes) - len(self.skipped) - len(self.failed) + - self._xfailed) + + @property + def numxfailed(self): + return self._xfailed def populate(self, log): kind = None @@ -191,6 +199,7 @@ self._failed = None self._skipped = None self._numpassed = None + self._numxfailed = None self.revision = map.values()[0].revision @property @@ -220,6 +229,16 @@ self._numpassed = numpassed return self._numpassed + @property + def numxfailed(self): + if self._numxfailed is None: + numxfailed = 0 + for prefix, outcome in self.map.items(): + numxfailed += outcome.numxfailed + self._numxfailed = numxfailed + return self._numxfailed + + def get_outcome(self, namekey): which = namekey[0] if which not in self.map: @@ -299,11 +318,12 @@ maxend = day else: maxend = max(maxend, day) - text = "%s [%d, %d F, %d s%s]" % (builder, - run.numpassed, - len(run.failed), - len(run.skipped), - timing) + text = "%s [%d, %d F, %d s, %d x%s]" % (builder, + run.numpassed, + len(run.failed), + len(run.skipped), + run.numxfailed, + timing) anchors.append(html.a(text, href=host_agnostic(info['URL']))) if maxend is not None: mintxt = datetime.date(*minend).strftime("%d %b") @@ -388,8 +408,6 @@ def bars(): return ' |'*len(lines) for label, outcome_set in by_label: - count_failures = len(outcome_set.failed) - count_skipped = len(outcome_set.skipped) line = [bars(), ' '] + self._label_anchor(outcome_set, revsize) line.append((align-len(line[0]))*" ") line.append(self.make_run_anchors_for(outcome_set)) Modified: pypy/build/bot2/pypybuildbot/test/test_summary.py ============================================================================== --- pypy/build/bot2/pypybuildbot/test/test_summary.py (original) +++ pypy/build/bot2/pypybuildbot/test/test_summary.py Thu Sep 17 16:26:50 2009 @@ -115,6 +115,17 @@ ("a.c", '')]) assert rev_outcome_set.numpassed == 0 + + def test_populate_xfailed(self): + rev_outcome_set = summary.RevisionOutcomeSet(50000) + log = StringIO("""x a/b.py + EXC +""") + + rev_outcome_set.populate(log) + + assert rev_outcome_set.numxfailed == 1 + def test_absent_outcome(self): rev_outcome_set = summary.RevisionOutcomeSet(50000) @@ -165,6 +176,7 @@ traceback . a/b.py:test_two s a/b.py:test_three +x a/b.py:test_four """) rev_outcome_set_foo.populate(log) @@ -188,15 +200,12 @@ assert goutcome.revision == 50000 assert goutcome.failed == set([('foo', 'a.b', 'test_one')]) - assert goutcome.failed == set([('foo', 'a.b', 'test_one')]) assert goutcome.skipped == set([('foo', 'a.b', 'test_three'), ('bar', 'a.b', 'test_three'), ]) - assert goutcome.skipped == set([('foo', 'a.b', 'test_three'), - ('bar', 'a.b', 'test_three'), - ]) assert goutcome.numpassed == 3 + assert goutcome.numxfailed == 1 for prefix in ('foo', 'bar'): for mod, testname in (("a.b", "test_one"), ("a.b", "test_two"), @@ -218,6 +227,7 @@ assert goutcome_top.failed == set([('sub', 'foo', 'a.b', 'test_one')]) assert goutcome_top.numpassed == 3 + assert goutcome_top.numxfailed == 1 res = goutcome_top.get_outcome(('sub', 'foo', 'a.b', 'test_one')) assert res == 'F' From arigo at codespeak.net Thu Sep 17 16:27:09 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 16:27:09 +0200 (CEST) Subject: [pypy-svn] r67736 - in pypy/branch/optimize-novaluedep/pypy/jit: backend/llgraph metainterp metainterp/test Message-ID: <20090917142709.BD811168005@codespeak.net> Author: arigo Date: Thu Sep 17 16:27:08 2009 New Revision: 67736 Modified: pypy/branch/optimize-novaluedep/pypy/jit/backend/llgraph/llimpl.py pypy/branch/optimize-novaluedep/pypy/jit/backend/llgraph/runner.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/history.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py Log: (cfbolz, arigo): fix optimizeopt to no longer depend on the .value of boxes. Modified: pypy/branch/optimize-novaluedep/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/backend/llgraph/llimpl.py Thu Sep 17 16:27:08 2009 @@ -47,7 +47,9 @@ return LLSupport.from_rstr(s) # a list of argtypes of all operations - couldn't find any and it's -# very useful +# very useful. Note however that the table is half-broken here and +# there, in ways that are sometimes a bit hard to fix; that's why +# it is not "official". TYPES = { 'int_add' : (('int', 'int'), 'int'), 'int_sub' : (('int', 'int'), 'int'), Modified: pypy/branch/optimize-novaluedep/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/backend/llgraph/runner.py Thu Sep 17 16:27:08 2009 @@ -507,6 +507,12 @@ TYPE = A.ITEM return TypeDescr.new(TYPE) + @staticmethod + def typedescr2classbox(descr): + assert isinstance(descr, TypeDescr) + return history.ConstObj(ootype.cast_to_object( + ootype.runtimeClass(descr.TYPE))) + def get_exception(self): if llimpl._last_exception: e = llimpl._last_exception.args[0] Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/history.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/history.py Thu Sep 17 16:27:08 2009 @@ -168,6 +168,9 @@ def same_constant(self, other): raise NotImplementedError + def nonnull_constant(self): + raise NotImplementedError + def __repr__(self): return 'Const(%s)' % self._getrepr_() @@ -227,6 +230,9 @@ assert isinstance(other, Const) return self.value == other.getint() + def nonnull_constant(self): + return self.value != 0 + def _getrepr_(self): return self.value @@ -271,6 +277,9 @@ assert isinstance(other, Const) return self.value == other.getaddr(self.cpu) + def nonnull_constant(self): + return bool(self.value) + def _getrepr_(self): return self.value @@ -304,6 +313,9 @@ assert isinstance(other, ConstFloat) return self.value == other.value + def nonnull_constant(self): + return self.value != 0.0 + def _getrepr_(self): return self.value @@ -344,6 +356,9 @@ assert isinstance(other, ConstPtr) return self.value == other.value + def nonnull_constant(self): + return bool(self.value) + _getrepr_ = repr_pointer def repr_rpython(self): @@ -394,6 +409,9 @@ assert isinstance(other, ConstObj) return self.value == other.value + def nonnull_constant(self): + return bool(self.value) + _getrepr_ = repr_object def repr_rpython(self): Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py Thu Sep 17 16:27:08 2009 @@ -1,6 +1,7 @@ from pypy.jit.metainterp.history import Box, BoxInt from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstObj, REF from pypy.jit.metainterp.resoperation import rop, ResOperation +from pypy.jit.metainterp.executor import _execute_nonspec from pypy.jit.metainterp.specnode import SpecNode, NotSpecNode, ConstantSpecNode from pypy.jit.metainterp.specnode import AbstractVirtualStructSpecNode from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode @@ -38,15 +39,15 @@ class OptValue(object): - _attrs_ = ('box', 'level', 'missing', '_fields') + _attrs_ = ('box', 'known_class', 'level', '_fields') level = LEVEL_UNKNOWN - missing = False # is True if we don't know the value yet (for virtuals) _fields = None def __init__(self, box): self.box = box if isinstance(box, Const): self.level = LEVEL_CONSTANT + # invariant: box is a Const if and only if level == LEVEL_CONSTANT def force_box(self): return self.box @@ -57,30 +58,34 @@ def get_args_for_fail(self, modifier): pass - def initialize_if_missing(self, srcbox): - if self.missing: - dstbox = self.box - if dstbox is not None: - assert isinstance(dstbox, Box) - dstbox.changevalue_box(srcbox) - self.missing = False - def is_constant(self): return self.level == LEVEL_CONSTANT def is_null(self): - return self.is_constant() and not self.box.nonnull() - - def make_constant(self): - """Mark 'self' as actually representing a Const value.""" - self.box = self.force_box().constbox() + if self.is_constant(): + box = self.box + assert isinstance(box, Const) + return not box.nonnull_constant() + return False + + def make_constant(self, constbox): + """Replace 'self.box' with a Const box.""" + assert isinstance(constbox, Const) + self.box = constbox self.level = LEVEL_CONSTANT - def has_constant_class(self): - return self.level >= LEVEL_KNOWNCLASS + def get_constant_class(self, cpu): + level = self.level + if level == LEVEL_KNOWNCLASS: + return self.known_class + elif level == LEVEL_CONSTANT: + return cpu.ts.cls_of_box(cpu, self.box) + else: + return None - def make_constant_class(self): + def make_constant_class(self, classbox): if self.level < LEVEL_KNOWNCLASS: + self.known_class = classbox self.level = LEVEL_KNOWNCLASS def is_nonnull(self): @@ -88,7 +93,9 @@ if level == LEVEL_NONNULL or level == LEVEL_KNOWNCLASS: return True elif level == LEVEL_CONSTANT: - return self.box.nonnull() + box = self.box + assert isinstance(box, Const) + return box.nonnull_constant() else: return False @@ -97,6 +104,8 @@ self.level = LEVEL_NONNULL def make_null_or_nonnull(self): + # I think this needs to change: the Bool class can easily store + # whether to make it a null or a nonnull if self.box.nonnull(): self.make_nonnull() else: @@ -110,13 +119,21 @@ class BoolValue(OptValue): - def __init__(self, box, fromvalue): + def __init__(self, box, fromvalue, reversed): OptValue.__init__(self, box) + # If later 'box' is turned into a constant False + # (resp. True), then 'fromvalue' will be known to + # be null (resp. non-null). If 'reversed', then + # this logic is reversed. self.fromvalue = fromvalue + self.reversed = reversed - def make_constant(self): - OptValue.make_constant(self) - self.fromvalue.make_null_or_nonnull() + def make_constant(self, constbox): + OptValue.make_constant(self, constbox) + if constbox.nonnull_constant() ^ self.reversed: + self.fromvalue.make_nonnull() + else: + self.fromvalue.make_null() class ConstantValue(OptValue): level = LEVEL_CONSTANT @@ -124,7 +141,9 @@ def __init__(self, box): self.box = box -CVAL_ZERO = ConstantValue(ConstInt(0)) +CONST_0 = ConstInt(0) +CONST_1 = ConstInt(1) +CVAL_ZERO = ConstantValue(CONST_0) llhelper.CVAL_NULLREF = ConstantValue(ConstPtr(ConstPtr.value)) oohelper.CVAL_NULLREF = ConstantValue(ConstObj(ConstObj.value)) @@ -132,7 +151,7 @@ class AbstractVirtualValue(OptValue): _attrs_ = ('optimizer', 'keybox', 'source_op') box = None - level = LEVEL_KNOWNCLASS + level = LEVEL_NONNULL def __init__(self, optimizer, keybox, source_op=None): self.optimizer = optimizer @@ -195,9 +214,11 @@ class VirtualValue(AbstractVirtualStructValue): + level = LEVEL_KNOWNCLASS def __init__(self, optimizer, known_class, keybox, source_op=None): AbstractVirtualStructValue.__init__(self, optimizer, keybox, source_op) + assert isinstance(known_class, Const) self.known_class = known_class def _make_virtual(self, modifier, fielddescrs, fieldboxes): @@ -281,7 +302,7 @@ class __extend__(ConstantSpecNode): def setup_virtual_node(self, optimizer, box, newinputargs): - optimizer.make_constant(box) + optimizer.make_constant(box, self.constbox) def teardown_virtual_node(self, optimizer, value, newexitargs): pass @@ -345,10 +366,11 @@ self.interned_refs = {} def getinterned(self, box): - if not self.is_constant(box): + constbox = self.get_constant_box(box) + if constbox is None: return box - if box.type == REF: - value = box.getref_base() + if constbox.type == REF: + value = constbox.getref_base() if not value: return box key = self.cpu.ts.cast_ref_to_hashable(self.cpu, value) @@ -368,23 +390,28 @@ value = self.values[box] = OptValue(box) return value - def is_constant(self, box): + def get_constant_box(self, box): if isinstance(box, Const): - return True + return box try: - return self.values[box].is_constant() + value = self.values[box] except KeyError: - return False + return None + if value.is_constant(): + constbox = value.box + assert isinstance(constbox, Const) + return constbox + return None def make_equal_to(self, box, value): assert box not in self.values self.values[box] = value - def make_constant(self, box): - self.make_equal_to(box, ConstantValue(box.constbox())) + def make_constant(self, box, constbox): + self.make_equal_to(box, ConstantValue(constbox)) - def known_nonnull(self, box): - return self.getvalue(box).is_nonnull() + def make_constant_int(self, box, intvalue): + self.make_constant(box, ConstInt(intvalue)) def make_virtual(self, known_class, box, source_op=None): vvalue = VirtualValue(self, known_class, box, source_op) @@ -401,8 +428,8 @@ self.make_equal_to(box, vvalue) return vvalue - def make_bool(self, box, fromvalue): - value = BoolValue(box, fromvalue) + def make_bool(self, box, fromvalue, reversed): + value = BoolValue(box, fromvalue, reversed) self.make_equal_to(box, value) return value @@ -464,7 +491,7 @@ for i in range(len(op.args)): arg = op.args[i] if arg in self.values: - box = self.values[arg].force_box() + box = self.values[arg].force_box() # I think we definitely need box, at least for this but it's unclear I mean is it ok to replace box with Const(..) when we set level==CONSTANT?ah, in this direction. yes, I would expect that to be ok ah yes indeed I see it if box is not arg: if must_clone: op = op.clone() @@ -527,11 +554,13 @@ def optimize_default(self, op): if op.is_always_pure(): for arg in op.args: - if not self.is_constant(arg): + if self.get_constant_box(arg) is None: break else: # all constant arguments: constant-fold away - self.make_constant(op.result) + argboxes = [self.get_constant_box(arg) for arg in op.args] + resbox = _execute_nonspec(self.cpu, op.opnum, argboxes, op.descr) + self.make_constant(op.result, resbox.constbox()) return elif not op.has_no_side_effect() and not op.is_ovf(): self.clean_fields_of_values() @@ -551,34 +580,37 @@ op2.jump_target = op.jump_target self.emit_operation(op2, must_clone=False) - def optimize_guard(self, op): + def optimize_guard(self, op, constbox): value = self.getvalue(op.args[0]) if value.is_constant(): + box = value.box + assert isinstance(box, Const) + assert box.same_constant(constbox) return self.emit_operation(op) - value.make_constant() + value.make_constant(constbox) def optimize_GUARD_VALUE(self, op): - assert isinstance(op.args[1], Const) - if not we_are_translated(): - assert op.args[0].value == op.args[1].value - self.optimize_guard(op) + constbox = op.args[1] + assert isinstance(constbox, Const) + self.optimize_guard(op, constbox) def optimize_GUARD_TRUE(self, op): - assert op.args[0].getint() == 1 - self.optimize_guard(op) + self.optimize_guard(op, CONST_1) def optimize_GUARD_FALSE(self, op): - assert op.args[0].getint() == 0 - self.optimize_guard(op) + self.optimize_guard(op, CONST_0) def optimize_GUARD_CLASS(self, op): - # XXX should probably assert that the class is right value = self.getvalue(op.args[0]) - if value.has_constant_class(): + expectedclassbox = op.args[1] + assert isinstance(expectedclassbox, Const) + realclassbox = value.get_constant_class(self.cpu) + if realclassbox is not None: + assert realclassbox.same_constant(expectedclassbox) return self.emit_operation(op) - value.make_constant_class() + value.make_constant_class(expectedclassbox) def optimize_GUARD_NO_EXCEPTION(self, op): if not self.exception_might_have_happened: @@ -593,14 +625,13 @@ def _optimize_nullness(self, op, expect_nonnull): - if self.known_nonnull(op.args[0]): - assert op.result.getint() == expect_nonnull - self.make_constant(op.result) - elif self.is_constant(op.args[0]): # known to be null - assert op.result.getint() == (not expect_nonnull) - self.make_constant(op.result) + value = self.getvalue(op.args[0]) + if value.is_nonnull(): + self.make_constant_int(op.result, expect_nonnull) + elif value.is_null(): + self.make_constant_int(op.result, not expect_nonnull) else: - self.make_bool(op.result, self.getvalue(op.args[0])) + self.make_bool(op.result, value, not expect_nonnull) self.emit_operation(op) def optimize_OONONNULL(self, op): @@ -612,33 +643,31 @@ def optimize_INT_IS_TRUE(self, op): self._optimize_nullness(op, True) - def optimize_OOISNOT(self, op): + def _optimize_oois_ooisnot(self, op, expect_isnot, unary_opnum): value0 = self.getvalue(op.args[0]) value1 = self.getvalue(op.args[1]) - if value0.is_virtual() or value1.is_virtual(): - self.make_constant(op.result) + if value0.is_virtual(): + if value1.is_virtual(): + intres = (value0 is value1) ^ expect_isnot + self.make_constant_int(op.result, intres) + else: + self.make_constant_int(op.result, expect_isnot) + elif value1.is_virtual(): + self.make_constant_int(op.result, expect_isnot) elif value1.is_null(): - op = ResOperation(rop.OONONNULL, [op.args[0]], op.result) - self.optimize_OONONNULL(op) + op = ResOperation(unary_opnum, [op.args[0]], op.result) + self._optimize_nullness(op, expect_isnot) elif value0.is_null(): - op = ResOperation(rop.OONONNULL, [op.args[1]], op.result) - self.optimize_OONONNULL(op) + op = ResOperation(unary_opnum, [op.args[1]], op.result) + self._optimize_nullness(op, expect_isnot) else: self.optimize_default(op) + def optimize_OOISNOT(self, op): + self._optimize_oois_ooisnot(op, True, rop.OONONNULL) + def optimize_OOIS(self, op): - value0 = self.getvalue(op.args[0]) - value1 = self.getvalue(op.args[1]) - if value0.is_virtual() or value1.is_virtual(): - self.make_constant(op.result) - elif value1.is_null(): - op = ResOperation(rop.OOISNULL, [op.args[0]], op.result) - self.optimize_OOISNULL(op) - elif value0.is_null(): - op = ResOperation(rop.OOISNULL, [op.args[1]], op.result) - self.optimize_OOISNULL(op) - else: - self.optimize_default(op) + self._optimize_oois_ooisnot(op, False, rop.OOISNULL) def optimize_GETFIELD_GC(self, op): value = self.getvalue(op.args[0]) @@ -646,7 +675,6 @@ # optimizefindnode should ensure that fieldvalue is found fieldvalue = value.getfield(op.descr, None) assert fieldvalue is not None - fieldvalue.initialize_if_missing(op.result) self.make_equal_to(op.result, fieldvalue) else: # check if the field was read from another getfield_gc just before @@ -689,37 +717,37 @@ self.make_vstruct(op.descr, op.result, op) def optimize_NEW_ARRAY(self, op): - sizebox = op.args[0] - if self.is_constant(sizebox): - size = sizebox.getint() - if not isinstance(sizebox, ConstInt): - op = ResOperation(rop.NEW_ARRAY, [ConstInt(size)], op.result, + sizebox = self.get_constant_box(op.args[0]) + if sizebox is not None: + # if the original 'op' did not have a ConstInt as argument, + # build a new one with the ConstInt argument + if not isinstance(op.args[0], ConstInt): + op = ResOperation(rop.NEW_ARRAY, [sizebox], op.result, descr=op.descr) - self.make_varray(op.descr, size, op.result, op) + self.make_varray(op.descr, sizebox.getint(), op.result, op) else: self.optimize_default(op) def optimize_ARRAYLEN_GC(self, op): value = self.getvalue(op.args[0]) if value.is_virtual(): - assert op.result.getint() == value.getlength() - self.make_constant(op.result) + self.make_constant_int(op.result, value.getlength()) else: value.make_nonnull() self.optimize_default(op) def optimize_GETARRAYITEM_GC(self, op): value = self.getvalue(op.args[0]) - indexbox = op.args[1] - if value.is_virtual() and self.is_constant(indexbox): - # optimizefindnode should ensure that itemvalue is found - itemvalue = value.getitem(indexbox.getint(), None) - assert itemvalue is not None - itemvalue.initialize_if_missing(op.result) - self.make_equal_to(op.result, itemvalue) - else: - value.make_nonnull() - self.optimize_default(op) + if value.is_virtual(): + indexbox = self.get_constant_box(op.args[1]) + if indexbox is not None: + # optimizefindnode should ensure that itemvalue is found + itemvalue = value.getitem(indexbox.getint(), None) + assert itemvalue is not None + self.make_equal_to(op.result, itemvalue) + return + value.make_nonnull() + self.optimize_default(op) # note: the following line does not mean that the two operations are # completely equivalent, because GETARRAYITEM_GC_PURE is_always_pure(). @@ -727,19 +755,24 @@ def optimize_SETARRAYITEM_GC(self, op): value = self.getvalue(op.args[0]) - indexbox = op.args[1] - if value.is_virtual() and self.is_constant(indexbox): - value.setitem(indexbox.getint(), self.getvalue(op.args[2])) - else: - value.make_nonnull() - # don't use optimize_default, because otherwise unrelated struct - # fields will be cleared - self.emit_operation(op) + if value.is_virtual(): + indexbox = self.get_constant_box(op.args[1]) + if indexbox is not None: + value.setitem(indexbox.getint(), self.getvalue(op.args[2])) + return + value.make_nonnull() + # don't use optimize_default, because otherwise unrelated struct + # fields will be cleared + self.emit_operation(op) def optimize_INSTANCEOF(self, op): value = self.getvalue(op.args[0]) - if value.has_constant_class(): - self.make_constant(op.result) + realclassbox = value.get_constant_class(self.cpu) + if realclassbox is not None: + checkclassbox = self.cpu.typedescr2classbox(op.descr) + result = self.cpu.ts.subclassOf(self.cpu, realclassbox, + checkclassbox) + self.make_constant_int(op.result, result) return self.emit_operation(op) Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py Thu Sep 17 16:27:08 2009 @@ -96,15 +96,14 @@ expected.operations, remap) - def optimize_loop(self, ops, spectext, optops, checkspecnodes=True, - **values): + def optimize_loop(self, ops, spectext, optops, checkspecnodes=True): loop = self.parse(ops) - loop.setvalues(**values) # if checkspecnodes: # verify that 'spectext' is indeed what optimizefindnode would # compute for this loop - perfect_specialization_finder = PerfectSpecializationFinder() + cpu = self.cpu + perfect_specialization_finder = PerfectSpecializationFinder(cpu) perfect_specialization_finder.find_nodes_loop(loop) self.check_specnodes(loop.specnodes, spectext) else: @@ -128,7 +127,7 @@ fail(i0) jump(i) """ - self.optimize_loop(ops, 'Not', ops, i0=0) + self.optimize_loop(ops, 'Not', ops) def test_constant_propagate(self): ops = """ @@ -148,23 +147,40 @@ [] jump() """ - self.optimize_loop(ops, '', expected, i0=5, i1=1, i2=0) + self.optimize_loop(ops, '', expected) def test_constfold_all(self): - for op in range(rop.INT_ADD, rop.BOOL_NOT+1): + from pypy.jit.backend.llgraph.llimpl import TYPES # xxx fish + from pypy.jit.metainterp.executor import _execute_nonspec + from pypy.jit.metainterp.history import BoxInt + import random + for opnum in range(rop.INT_ADD, rop.BOOL_NOT+1): try: - op = opname[op] + op = opname[opnum] except KeyError: continue + if 'FLOAT' in op: + continue + argtypes, restype = TYPES[op.lower()] + args = [] + for argtype in argtypes: + assert argtype in ('int', 'bool') + args.append(random.randrange(1, 20)) + assert restype in ('int', 'bool') ops = """ [] - i1 = %s(3, 2) + i1 = %s(%s) + escape(i1) jump() - """ % op.lower() + """ % (op.lower(), ', '.join(map(str, args))) + argboxes = [BoxInt(a) for a in args] + expected_value = _execute_nonspec(self.cpu, opnum, + argboxes).getint() expected = """ [] + escape(%d) jump() - """ + """ % expected_value self.optimize_loop(ops, '', expected) # ---------- @@ -220,7 +236,7 @@ fail() jump(3) """ - self.optimize_loop(ops, 'Not', expected, i0=0, i1=1, i2=3) + self.optimize_loop(ops, 'Not', expected) def test_remove_guard_value_if_constant(self): ops = """ @@ -233,7 +249,7 @@ [] jump() """ - self.optimize_loop(ops, 'Constant(myptr)', expected, p1=self.nodebox.value) + self.optimize_loop(ops, 'Constant(myptr)', expected) def test_ooisnull_oononnull_1(self): ops = """ @@ -254,7 +270,7 @@ fail() jump(p0) """ - self.optimize_loop(ops, 'Not', expected, i0=1, i1=0) + self.optimize_loop(ops, 'Not', expected) def test_int_is_true_1(self): ops = """ @@ -274,7 +290,7 @@ fail() jump(i0) """ - self.optimize_loop(ops, 'Not', expected, i0=123, i1=1, i2=1) + self.optimize_loop(ops, 'Not', expected) def test_ooisnull_oononnull_2(self): ops = """ @@ -294,8 +310,7 @@ fail() jump(p0) """ - self.optimize_loop(ops, 'Not', expected, i0=1, i1=0, - p0=self.nodebox.value) + self.optimize_loop(ops, 'Not', expected) def test_ooisnull_oononnull_via_virtual(self): ops = """ @@ -318,8 +333,7 @@ fail() jump(p0) """ - self.optimize_loop(ops, 'Not', expected, i0=1, i1=0, - p0=self.nodebox.value) + self.optimize_loop(ops, 'Not', expected) def test_oois_1(self): ops = """ @@ -346,7 +360,7 @@ fail() jump(p0) """ - self.optimize_loop(ops, 'Not', expected, i0=1, i1=0, i2=1, i3=0) + self.optimize_loop(ops, 'Not', expected) def test_nonnull_1(self): ops = """ @@ -377,8 +391,7 @@ setfield_gc(p0, 5, descr=valuedescr) jump(p0) """ - self.optimize_loop(ops, 'Not', expected, - i0=1, i1=0, i2=1, i3=0, i4=1, i5=0) + self.optimize_loop(ops, 'Not', expected) def test_const_guard_value(self): ops = """ @@ -392,7 +405,7 @@ [] jump() """ - self.optimize_loop(ops, '', expected, i=8) + self.optimize_loop(ops, '', expected) def test_constptr_guard_value(self): ops = """ @@ -402,7 +415,7 @@ fail() jump() """ - self.optimize_loop(ops, '', ops, p1=self.nodebox.value) + self.optimize_loop(ops, '', ops) def test_p123_simple(self): @@ -562,9 +575,7 @@ self.optimize_loop(ops, '''Virtual(node_vtable), Virtual(node_vtable), Not''', - expected, checkspecnodes=False, - i1=1, i2=0, i3=1, i4=0, i5=1, i6=0, - i7=1, i8=0, i9=1, i10=0, i11=1, i12=0) + expected, checkspecnodes=False) # # to be complete, we also check the no-opt case where most comparisons # are not removed. The exact set of comparisons removed depends on @@ -615,7 +626,7 @@ # the 'expected' is sub-optimal, but it should be done by another later # optimization step. See test_find_nodes_default_field() for why. self.optimize_loop(ops, 'Virtual(node_vtable, valuedescr=Not)', - expected, i0=0) + expected) def test_virtual_3(self): ops = """ @@ -711,7 +722,7 @@ [i0] jump(0) """ - self.optimize_loop(ops, 'Not', expected, p2=self.nodebox.value, i1=0) + self.optimize_loop(ops, 'Not', expected) def test_nonvirtual_1(self): ops = """ @@ -794,7 +805,8 @@ [i] jump(5) """ - self.optimize_loop(ops, 'Not', expected, i1=5) + self.node.value = 5 + self.optimize_loop(ops, 'Not', expected) def test_getfield_gc_nonpure_2(self): ops = """ @@ -803,7 +815,7 @@ jump(i1) """ expected = ops - self.optimize_loop(ops, 'Not', expected, i1=5) + self.optimize_loop(ops, 'Not', expected) def test_varray_1(self): ops = """ @@ -821,7 +833,7 @@ [i1] jump(i1) """ - self.optimize_loop(ops, 'Not', expected, i3=3) + self.optimize_loop(ops, 'Not', expected) def test_array_non_optimized(self): ops = """ @@ -860,8 +872,7 @@ fail() jump(i0, 20, i0) """ - self.optimize_loop(ops, 'Not, VArray(arraydescr, Not, Not)', expected, - i3=15) + self.optimize_loop(ops, 'Not, VArray(arraydescr, Not, Not)', expected) def test_p123_array(self): ops = """ @@ -895,7 +906,7 @@ escape(i2) jump() """ - self.optimize_loop(ops, '', expected, i1=3, i2=3) + self.optimize_loop(ops, '', expected) def test_vstruct_1(self): ops = """ @@ -1088,7 +1099,7 @@ escape(i1) jump() """ - self.optimize_loop(ops, 'Constant(myptr)', expected, p1=self.nodebox.value) + self.optimize_loop(ops, 'Constant(myptr)', expected) def test_duplicate_getfield_sideeffects_1(self): ops = """ @@ -1138,11 +1149,7 @@ jump(i0, p3) """ self.optimize_loop(ops, 'Not, Virtual(node_vtable, nextdescr=Not)', - expected, i2=0, - p1=self.nodebox.value, - p2=self.nodebox.value, - p3=self.nodebox.value, - p4=self.nodebox.value) + expected) def test_bug_2(self): ops = """ @@ -1169,9 +1176,7 @@ jump(i0, p3) """ self.optimize_loop(ops, 'Not, VArray(arraydescr2, Not)', - expected, i2=0, - p3=self.sbox.value, - p4=self.sbox.value) + expected) # ---------- @@ -1298,7 +1303,7 @@ fail(i3, descr=fdescr) jump(1, i3) """ - self.optimize_loop(ops, 'Not, Not', expected, i1=1, i2=15) + self.optimize_loop(ops, 'Not, Not', expected) self.check_expanded_fail_descr('15, i3') def test_expand_fail_2(self): @@ -1318,7 +1323,7 @@ fail(i2, descr=fdescr) jump(1, i2) """ - self.optimize_loop(ops, 'Not, Not', expected, i1=1) + self.optimize_loop(ops, 'Not, Not', expected) self.check_expanded_fail_descr('''ptr where ptr is a node_vtable, valuedescr=i2 ''') @@ -1343,8 +1348,7 @@ fail(i3, i2, p3, descr=fdescr) jump(i2, 1, i3, p3) """ - self.optimize_loop(ops, 'Not, Not, Not, Not', expected, i1=1, - p3=self.nodebox.value) + self.optimize_loop(ops, 'Not, Not, Not, Not', expected) self.check_expanded_fail_descr('''p1, i3 where p1 is a node_vtable, valuedescr=1, nextdescr=p2 where p2 is a node_vtable, valuedescr=i2, nextdescr=p3 @@ -1374,7 +1378,7 @@ fail(i3, i2, descr=fdescr) jump(1, i2, i3) """ - self.optimize_loop(ops % arg, 'Not, Not, Not', expected, i1=1) + self.optimize_loop(ops % arg, 'Not, Not, Not', expected) self.check_expanded_fail_descr('''i3, %s, i3 where p1 is a node_vtable, valuedescr=i2, nextdescr=p2 where p2 is a node_vtable, valuedescr=i2''' % arg) @@ -1400,7 +1404,7 @@ fail(i3, i4, i2, descr=fdescr) jump(i2, 1, i3, i4) """ - self.optimize_loop(ops, 'Not, Not, Not, Not', expected, i1=1) + self.optimize_loop(ops, 'Not, Not, Not, Not', expected) self.check_expanded_fail_descr('''p1, i3, p2, i4 where p1 is a node_vtable, valuedescr=i4, nextdescr=p2 where p2 is a node_vtable, valuedescr=i2, nextdescr=p1 @@ -1423,7 +1427,7 @@ jump(i1, i1, i1) """ self.optimize_loop(ops, '''Virtual(node_vtable, valuedescr=Not), - Not, Not''', expected, i0=1) + Not, Not''', expected) self.check_expanded_fail_descr('''p0 where p0 is a node_vtable, valuedescr=i1b ''') @@ -1446,7 +1450,7 @@ fail(i1, descr=fdescr) jump(1) """ - self.optimize_loop(ops, 'Not', expected, i1=1) + self.optimize_loop(ops, 'Not', expected) self.check_expanded_fail_descr('''p1 where p1 is a varray arraydescr: 25, i1 ''') @@ -1470,7 +1474,7 @@ fail(i1, p1, descr=fdescr) jump(1, p1) """ - self.optimize_loop(ops, 'Not, Not', expected, i1=1) + self.optimize_loop(ops, 'Not, Not', expected) self.check_expanded_fail_descr('''p2 where p2 is a vstruct ssize, adescr=i1, bdescr=p1 ''') @@ -1510,7 +1514,7 @@ bdescr=Virtual(node_vtable, valuedescr=Not)), Not), - Not''', expected, i1=1) + Not''', expected) self.check_expanded_fail_descr('''p1a where p1a is a varray arraydescr2: p6s, p5s where p6s is a vstruct ssize, adescr=ia, bdescr=p7v @@ -1535,5 +1539,5 @@ [i0] jump(1) """ - self.optimize_loop(ops, 'Not', expected, i1=1) + self.optimize_loop(ops, 'Not', expected) From pedronis at codespeak.net Thu Sep 17 16:40:24 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 17 Sep 2009 16:40:24 +0200 (CEST) Subject: [pypy-svn] r67737 - pypy/trunk Message-ID: <20090917144024.BC406168005@codespeak.net> Author: pedronis Date: Thu Sep 17 16:40:24 2009 New Revision: 67737 Added: pypy/trunk/pytest_resultlog.py (contents, props changed) Log: (micke, pedronis) grab and tweak a copy of the resultlog plugin until we can use a newer official version from the py.lib directly with support for xfailed results Added: pypy/trunk/pytest_resultlog.py ============================================================================== --- (empty file) +++ pypy/trunk/pytest_resultlog.py Thu Sep 17 16:40:24 2009 @@ -0,0 +1,94 @@ +# xxx copied and tweaked from py.lib trunk until a new release comes around +"""resultlog plugin for machine-readable logging of test results. + Useful for buildbot integration code. +""" + +import py + +def pytest_addoption(parser): + group = parser.addgroup("resultlog", "resultlog plugin options") + group.addoption('--resultlog', action="store", dest="resultlog", metavar="path", default=None, + help="path for machine-readable result log.") + +def pytest_configure(config): + resultlog = config.option.resultlog + if resultlog: + logfile = open(resultlog, 'w', 1) # line buffered + config._resultlog = ResultLog(config, logfile) + config.pluginmanager.register(config._resultlog) + +def pytest_unconfigure(config): + resultlog = getattr(config, '_resultlog', None) + if resultlog: + resultlog.logfile.close() + del config._resultlog + config.pluginmanager.unregister(resultlog) + +def generic_path(item): + chain = item.listchain() + gpath = [chain[0].name] + fspath = chain[0].fspath + fspart = False + for node in chain[1:]: + newfspath = node.fspath + if newfspath == fspath: + if fspart: + gpath.append(':') + fspart = False + else: + gpath.append('.') + else: + gpath.append('/') + fspart = True + name = node.name + if name[0] in '([': + gpath.pop() + gpath.append(name) + fspath = newfspath + return ''.join(gpath) + +class ResultLog(object): + def __init__(self, config, logfile): + self.config = config + self.logfile = logfile # preferably line buffered + + def write_log_entry(self, testpath, shortrepr, longrepr): + print >>self.logfile, "%s %s" % (shortrepr, testpath) + for line in longrepr.splitlines(): + print >>self.logfile, " %s" % line + + def log_outcome(self, node, shortrepr, longrepr): + testpath = generic_path(node) + self.write_log_entry(testpath, shortrepr, longrepr) + + def pytest_runtest_logreport(self, report): + res = self.config.hook.pytest_report_teststatus(report=report) + if res is not None: + code = res[1] + else: + code = report.shortrepr + if code == 'x': + longrepr = str(report.longrepr) + elif code == 'P': + longrepr = '' + elif report.passed: + longrepr = "" + elif report.failed: + longrepr = str(report.longrepr) + elif report.skipped: + longrepr = str(report.longrepr.reprcrash.message) + self.log_outcome(report.item, code, longrepr) + + def pytest_collectreport(self, report): + if not report.passed: + if report.failed: + code = "F" + else: + assert report.skipped + code = "S" + longrepr = str(report.longrepr.reprcrash) + self.log_outcome(report.collector, code, longrepr) + + def pytest_internalerror(self, excrepr): + path = excrepr.reprcrash.path + self.write_log_entry(path, '!', str(excrepr)) From arigo at codespeak.net Thu Sep 17 16:52:56 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 16:52:56 +0200 (CEST) Subject: [pypy-svn] r67738 - in pypy/branch/optimize-novaluedep/pypy/jit/metainterp: . test Message-ID: <20090917145256.3C206168008@codespeak.net> Author: arigo Date: Thu Sep 17 16:52:55 2009 New Revision: 67738 Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimize.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py Log: (cfbolz, arigo): a case that was not covered by the tests. Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimize.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimize.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimize.py Thu Sep 17 16:52:55 2009 @@ -12,7 +12,7 @@ return None if options.logger_noopt is not None: options.logger_noopt.log_loop(loop) - finder = PerfectSpecializationFinder() + finder = PerfectSpecializationFinder(cpu) finder.find_nodes_loop(loop) for old_loop in old_loops: if equals_specnodes(old_loop.specnodes, loop.specnodes): @@ -30,7 +30,7 @@ return old_loops[0] if options.logger_noopt is not None: options.logger_noopt.log_loop(bridge) - finder = BridgeSpecializationFinder() + finder = BridgeSpecializationFinder(cpu) finder.find_nodes_bridge(bridge) for old_loop in old_loops: if finder.bridge_matches(old_loop.specnodes): Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py Thu Sep 17 16:52:55 2009 @@ -103,14 +103,6 @@ if self.level < LEVEL_NONNULL: self.level = LEVEL_NONNULL - def make_null_or_nonnull(self): - # I think this needs to change: the Bool class can easily store - # whether to make it a null or a nonnull - if self.box.nonnull(): - self.make_nonnull() - else: - self.make_constant() - def is_virtual(self): # Don't check this with 'isinstance(_, VirtualValue)'! # Even if it is a VirtualValue, the 'box' can be non-None, @@ -119,7 +111,7 @@ class BoolValue(OptValue): - def __init__(self, box, fromvalue, reversed): + def __init__(self, box, fromvalue, reversed, nullconstbox): OptValue.__init__(self, box) # If later 'box' is turned into a constant False # (resp. True), then 'fromvalue' will be known to @@ -127,13 +119,14 @@ # this logic is reversed. self.fromvalue = fromvalue self.reversed = reversed + self.nullconstbox = nullconstbox # of the correct type def make_constant(self, constbox): OptValue.make_constant(self, constbox) if constbox.nonnull_constant() ^ self.reversed: self.fromvalue.make_nonnull() else: - self.fromvalue.make_null() + self.fromvalue.make_constant(self.nullconstbox) class ConstantValue(OptValue): level = LEVEL_CONSTANT @@ -144,8 +137,10 @@ CONST_0 = ConstInt(0) CONST_1 = ConstInt(1) CVAL_ZERO = ConstantValue(CONST_0) -llhelper.CVAL_NULLREF = ConstantValue(ConstPtr(ConstPtr.value)) -oohelper.CVAL_NULLREF = ConstantValue(ConstObj(ConstObj.value)) +llhelper.CONST_NULL = ConstPtr(ConstPtr.value) +llhelper.CVAL_NULLREF = ConstantValue(llhelper.CONST_NULL) +oohelper.CONST_NULL = ConstObj(ConstObj.value) +oohelper.CVAL_NULLREF = ConstantValue(oohelper.CONST_NULL) class AbstractVirtualValue(OptValue): @@ -428,8 +423,8 @@ self.make_equal_to(box, vvalue) return vvalue - def make_bool(self, box, fromvalue, reversed): - value = BoolValue(box, fromvalue, reversed) + def make_bool(self, box, fromvalue, reversed, nullconstbox): + value = BoolValue(box, fromvalue, reversed, nullconstbox) self.make_equal_to(box, value) return value @@ -624,24 +619,24 @@ self.emit_operation(op) - def _optimize_nullness(self, op, expect_nonnull): + def _optimize_nullness(self, op, expect_nonnull, nullconstbox): value = self.getvalue(op.args[0]) if value.is_nonnull(): self.make_constant_int(op.result, expect_nonnull) elif value.is_null(): self.make_constant_int(op.result, not expect_nonnull) else: - self.make_bool(op.result, value, not expect_nonnull) + self.make_bool(op.result, value, not expect_nonnull, nullconstbox) self.emit_operation(op) def optimize_OONONNULL(self, op): - self._optimize_nullness(op, True) + self._optimize_nullness(op, True, self.cpu.ts.CONST_NULL) def optimize_OOISNULL(self, op): - self._optimize_nullness(op, False) + self._optimize_nullness(op, False, self.cpu.ts.CONST_NULL) def optimize_INT_IS_TRUE(self, op): - self._optimize_nullness(op, True) + self._optimize_nullness(op, True, CONST_0) def _optimize_oois_ooisnot(self, op, expect_isnot, unary_opnum): value0 = self.getvalue(op.args[0]) @@ -656,10 +651,10 @@ self.make_constant_int(op.result, expect_isnot) elif value1.is_null(): op = ResOperation(unary_opnum, [op.args[0]], op.result) - self._optimize_nullness(op, expect_isnot) + self._optimize_nullness(op, expect_isnot, self.cpu.ts.CONST_NULL) elif value0.is_null(): op = ResOperation(unary_opnum, [op.args[1]], op.result) - self._optimize_nullness(op, expect_isnot) + self._optimize_nullness(op, expect_isnot, self.cpu.ts.CONST_NULL) else: self.optimize_default(op) Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py Thu Sep 17 16:52:55 2009 @@ -1418,7 +1418,7 @@ for i in range(self.staticdata.num_green_args): box1 = original_boxes[i] box2 = live_arg_boxes[i] - assert isinstance(box1, Constant) + assert isinstance(box1, Const) if not box1.same_constant(box2): break else: Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py Thu Sep 17 16:52:55 2009 @@ -311,6 +311,66 @@ jump(p0) """ self.optimize_loop(ops, 'Not', expected) + ops = """ + [p0] + i1 = ooisnull(p0) + guard_false(i1) + fail() + i0 = oononnull(p0) # p0 != NULL + guard_true(i0) + fail() + jump(p0) + """ + expected = """ + [p0] + i1 = ooisnull(p0) + guard_false(i1) + fail() + jump(p0) + """ + self.optimize_loop(ops, 'Not', expected) + + def test_ooisnull_on_null_ptr_1(self): + ops = """ + [] + p0 = escape() + i0 = ooisnull(p0) + guard_true(i0) + fail() + i1 = oononnull(p0) + guard_false(i1) + fail() + jump() + """ + expected = """ + [] + p0 = escape() + i0 = ooisnull(p0) + guard_true(i0) + fail() + jump() + """ + self.optimize_loop(ops, '', expected) + ops = """ + [] + p0 = escape() + i0 = oononnull(p0) + guard_false(i0) + fail() + i1 = ooisnull(p0) + guard_true(i1) + fail() + jump() + """ + expected = """ + [] + p0 = escape() + i0 = oononnull(p0) + guard_false(i0) + fail() + jump() + """ + self.optimize_loop(ops, '', expected) def test_ooisnull_oononnull_via_virtual(self): ops = """ From antocuni at codespeak.net Thu Sep 17 16:53:41 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 17 Sep 2009 16:53:41 +0200 (CEST) Subject: [pypy-svn] r67739 - in pypy/trunk/pypy: jit/metainterp/test rpython/ootypesystem Message-ID: <20090917145341.26D6F168008@codespeak.net> Author: antocuni Date: Thu Sep 17 16:53:40 2009 New Revision: 67739 Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py pypy/trunk/pypy/rpython/ootypesystem/rtupletype.py Log: make sure that tuples are immutables also in ootype Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Thu Sep 17 16:53:40 2009 @@ -873,9 +873,17 @@ res = self.meta_interp(f, [6, 7], listcomp=True, backendopt=True, listops=True) # XXX: the loop looks inefficient assert res == 42 - - + def test_tuple_immutable(self): + def new(a, b): + return a, b + def f(a, b): + tup = new(a, b) + return tup[1] + res = self.interp_operations(f, [3, 5]) + assert res == 5 + self.check_history_(setfield_gc=2, getfield_gc_pure=1) + class TestOOtype(BasicTests, OOJitMixin): def test_oohash(self): Modified: pypy/trunk/pypy/rpython/ootypesystem/rtupletype.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/rtupletype.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/rtupletype.py Thu Sep 17 16:53:40 2009 @@ -10,4 +10,6 @@ return Void # empty tuple else: fields = [('item%d' % i, TYPE) for i, TYPE in enumerate(field_lltypes)] - return ootype.Record(dict(fields)) + hints = {'immutable': True, + 'noidentity': True} + return ootype.Record(dict(fields), _hints=hints) From iko at codespeak.net Thu Sep 17 17:15:19 2009 From: iko at codespeak.net (iko at codespeak.net) Date: Thu, 17 Sep 2009 17:15:19 +0200 (CEST) Subject: [pypy-svn] r67740 - in pypy/build/benchmark: . test Message-ID: <20090917151519.7F42C168005@codespeak.net> Author: iko Date: Thu Sep 17 17:15:19 2009 New Revision: 67740 Added: pypy/build/benchmark/statdb.py (contents, props changed) pypy/build/benchmark/test/test_statdb.py (contents, props changed) Log: Definitions for storing statistics in database Added: pypy/build/benchmark/statdb.py ============================================================================== --- (empty file) +++ pypy/build/benchmark/statdb.py Thu Sep 17 17:15:19 2009 @@ -0,0 +1,94 @@ + +import time, datetime + +import sqlalchemy +from sqlalchemy import Column, String, Integer, Float, DateTime +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker, relation + +Base = declarative_base() + +class Interpreter(Base): + __tablename__ = 'interpreters' + + id = Column(Integer, primary_key=True) + name = Column(String) + +class Benchmark(Base): + __tablename__ = 'benchmarks' + + id = Column(Integer, primary_key=True) + name = Column(String) + +class Run(Base): + __tablename__ = 'runs' + + id = Column(Integer, primary_key=True) + time = Column(DateTime) + + interp_id = Column(Integer, sqlalchemy.ForeignKey('interpreters.id')) + benchmark_id = Column(Integer, sqlalchemy.ForeignKey('benchmarks.id')) + + + interpreter = relation(Interpreter, backref='runs') + benchmark = relation(Benchmark, backref='benchmarks') + + +class Statistic(Base): + __tablename__ = 'statistics' + + id = Column(Integer, primary_key=True) + key = Column(String) + value = Column(Float) + + run_id = Column(Integer, sqlalchemy.ForeignKey('runs.id')) + + run = relation(Run, backref='statistics') + +class StatDB(object): + def __init__(self, dburi, time=time.time): + self.time = time + engine = sqlalchemy.create_engine(dburi) + Base.metadata.create_all(engine) + + self.session = sessionmaker(bind=engine)() + + def get_interp(self, interp, commit=True): + try: + interp_obj = self.session.query(Interpreter).filter_by( + name=interp).one() + except sqlalchemy.orm.exc.NoResultFound: + interp_obj = Interpreter(name=interp) + self.session.add(interp_obj) + if commit: + self.session.commit() + + return interp_obj + + def get_benchmark(self, benchmark, commit=True): + try: + benchmark_obj = self.session.query(Benchmark).filter_by( + name=benchmark).one() + except sqlalchemy.orm.exc.NoResultFound: + benchmark_obj = Benchmark(name=benchmark) + self.session.add(benchmark_obj) + if commit: + self.session.commit() + + return benchmark_obj + + def store_statistics(self, interp, benchmark, statdict): + interp = self.get_interp(interp, commit=False) + benchmark = self.get_benchmark(benchmark, commit=False) + + timestamp = datetime.datetime.utcfromtimestamp(self.time()) + run = Run(time = timestamp, + interpreter = interp, + benchmark = benchmark) + self.session.add(run) + + for key, value in statdict.iteritems(): + stat = Statistic(key = key, value = value, run = run) + self.session.add(stat) + + self.session.commit() Added: pypy/build/benchmark/test/test_statdb.py ============================================================================== --- (empty file) +++ pypy/build/benchmark/test/test_statdb.py Thu Sep 17 17:15:19 2009 @@ -0,0 +1,30 @@ + +import py +import time +from benchmark.statdb import StatDB, Interpreter, Benchmark + +class TestStatDB(object): + def _fake_time(self): + return 42 + + def setup_method(self, method): + self.statdb = StatDB('sqlite:///:memory:', time=self._fake_time) + + def test_get_interp(self): + interp = self.statdb.get_interp('foo') + assert isinstance(interp, Interpreter) + + interp2 = self.statdb.get_interp('foo') + assert interp2 is interp + + def test_get_benchmark(self): + benchmark = self.statdb.get_benchmark('foo') + assert isinstance(benchmark, Benchmark) + + benchmark2 = self.statdb.get_benchmark('foo') + assert benchmark2 is benchmark + + + def test_store(self): + self.statdb.store_statistics('interp_name', 'benchmark_name', + {'stat1' : 42.3, 'stat2' : 12345 }) From antocuni at codespeak.net Thu Sep 17 17:29:26 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 17 Sep 2009 17:29:26 +0200 (CEST) Subject: [pypy-svn] r67741 - pypy/trunk/pypy/rpython/ootypesystem Message-ID: <20090917152926.E85E3168008@codespeak.net> Author: antocuni Date: Thu Sep 17 17:29:23 2009 New Revision: 67741 Modified: pypy/trunk/pypy/rpython/ootypesystem/rtuple.py pypy/trunk/pypy/rpython/ootypesystem/rtupletype.py Log: really fix test_tuple_immutable. I was sure to have run the test before checking in, but evidently I didn't Modified: pypy/trunk/pypy/rpython/ootypesystem/rtuple.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/rtuple.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/rtuple.py Thu Sep 17 17:29:23 2009 @@ -2,14 +2,14 @@ from pypy.rpython.rtuple import AbstractTupleRepr, AbstractTupleIteratorRepr from pypy.rpython.ootypesystem import ootype from pypy.rpython.ootypesystem import rstr - +from pypy.rpython.ootypesystem.rtupletype import TUPLE_TYPE class TupleRepr(AbstractTupleRepr): rstr_ll = rstr.LLHelpers def __init__(self, rtyper, items_r): AbstractTupleRepr.__init__(self, rtyper, items_r) - self.lowleveltype = ootype.Record(dict(zip(self.fieldnames, self.lltypes))) + self.lowleveltype = TUPLE_TYPE(self.lltypes) def newtuple(cls, llops, r_tuple, items_v): # items_v should have the lowleveltype of the internal reprs Modified: pypy/trunk/pypy/rpython/ootypesystem/rtupletype.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/rtupletype.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/rtupletype.py Thu Sep 17 17:29:23 2009 @@ -7,7 +7,7 @@ def TUPLE_TYPE(field_lltypes): if len(field_lltypes) == 0: - return Void # empty tuple + return ootype.Void # empty tuple else: fields = [('item%d' % i, TYPE) for i, TYPE in enumerate(field_lltypes)] hints = {'immutable': True, From arigo at codespeak.net Thu Sep 17 17:54:28 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 17:54:28 +0200 (CEST) Subject: [pypy-svn] r67742 - in pypy/branch/optimize-novaluedep/pypy/jit: backend metainterp metainterp/test Message-ID: <20090917155428.E7D6A16800F@codespeak.net> Author: arigo Date: Thu Sep 17 17:54:28 2009 New Revision: 67742 Modified: pypy/branch/optimize-novaluedep/pypy/jit/backend/model.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/executor.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_specnode.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/typesystem.py Log: (cfbolz around, arigo) Fix translation issues. Modified: pypy/branch/optimize-novaluedep/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/backend/model.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/backend/model.py Thu Sep 17 17:54:28 2009 @@ -159,7 +159,7 @@ self.do_call(args[2:], calldescr) def do_cond_call_gc_malloc(self, args, calldescr): - xxx + raise NotImplementedError def do_cast_ptr_to_int(self, args, descr=None): raise NotImplementedError @@ -175,3 +175,7 @@ def do_instanceof(self, args, descr=None): raise NotImplementedError + + @staticmethod + def typedescr2classbox(descr): + raise NotImplementedError Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/executor.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/executor.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/executor.py Thu Sep 17 17:54:28 2009 @@ -146,17 +146,12 @@ def do_ooidentityhash(cpu, args, descr=None): obj = args[0].getref_base() - return ConstInt(ootype.ooidentityhash(obj)) + return ConstInt(cpu.ts.ooidentityhash(obj)) - -def do_subclassof(self, args, descr=None): +def do_subclassof(cpu, args, descr=None): assert len(args) == 2 box1, box2 = args - cls1 = box1.getref(ootype.Class) - cls2 = box2.getref(ootype.Class) - res = ootype.subclassof(cls1, cls2) - return BoxInt(res) - + return ConstInt(cpu.ts.subclassOf(cpu, box1, box2)) # ---------- # the following operations just delegate to the cpu: Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py Thu Sep 17 17:54:28 2009 @@ -308,7 +308,6 @@ subbox = optimizer.new_box(ofs) subspecnode.setup_virtual_node(optimizer, subbox, newinputargs) vvaluefield = optimizer.getvalue(subbox) - vvaluefield.missing = True vvalue.setfield(ofs, vvaluefield) def _setup_virtual_node_1(self, optimizer, box): raise NotImplementedError @@ -334,7 +333,6 @@ subspecnode = self.items[index] subspecnode.setup_virtual_node(optimizer, subbox, newinputargs) vvalueitem = optimizer.getvalue(subbox) - vvalueitem.missing = True vvalue.setitem(index, vvalueitem) def teardown_virtual_node(self, optimizer, value, newexitargs): assert value.is_virtual() Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_specnode.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_specnode.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_specnode.py Thu Sep 17 17:54:28 2009 @@ -1,5 +1,5 @@ from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.jit.metainterp.history import AbstractDescr, BoxPtr, ConstInt +from pypy.jit.metainterp.history import AbstractDescr, BoxPtr, ConstInt, ConstPtr from pypy.jit.metainterp.specnode import prebuiltNotSpecNode from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode from pypy.jit.metainterp.specnode import VirtualArraySpecNode @@ -25,7 +25,7 @@ def _get_cspecnode(s): from pypy.rpython.module.support import LLSupport llstr = lltype.cast_opaque_ptr(llmemory.GCREF, LLSupport.to_rstr(s)) - box = BoxPtr(llstr) + box = ConstPtr(llstr) return ConstantSpecNode(box) def test_equals_specnodes(): @@ -56,7 +56,7 @@ def test_extract_runtime_data_0(): res = [] - node = ConstantSpecNode('foo') + node = _get_cspecnode('foo') node.extract_runtime_data("cpu", "box1", res) assert res == [] Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/typesystem.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/typesystem.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/typesystem.py Thu Sep 17 17:54:28 2009 @@ -136,6 +136,9 @@ def getaddr_for_box(self, cpu, box): return box.getaddr(cpu) + def ooidentityhash(self, x): + raise NotImplementedError + class OOTypeHelper(TypeSystemHelper): name = 'ootype' @@ -231,6 +234,8 @@ def getaddr_for_box(self, cpu, box): return box.getref_base() + + ooidentityhash = staticmethod(ootype.ooidentityhash) llhelper = LLTypeHelper() oohelper = OOTypeHelper() From arigo at codespeak.net Thu Sep 17 19:01:28 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 19:01:28 +0200 (CEST) Subject: [pypy-svn] r67743 - in pypy/branch/optimize-novaluedep/pypy/jit/metainterp: . test Message-ID: <20090917170128.5B93016800E@codespeak.net> Author: arigo Date: Thu Sep 17 19:01:25 2009 New Revision: 67743 Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizefindnode.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeutil.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py Log: (arigo, cfbolz): start tracking again loops that are not efficient at all. Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizefindnode.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizefindnode.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizefindnode.py Thu Sep 17 19:01:25 2009 @@ -8,6 +8,7 @@ from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.executor import _execute_nonspec from pypy.jit.metainterp.optimizeutil import av_newdict, _findall, sort_descrs +from pypy.jit.metainterp.optimizeutil import InvalidLoop # ____________________________________________________________ @@ -341,9 +342,11 @@ def intersect(self, inputnode, exitnode): assert inputnode.fromstart if inputnode.is_constant() and \ - exitnode.is_constant() and \ - inputnode.knownvaluebox.same_constant(exitnode.knownvaluebox): - return ConstantSpecNode(inputnode.knownvaluebox) + exitnode.is_constant(): + if inputnode.knownvaluebox.same_constant(exitnode.knownvaluebox): + return ConstantSpecNode(inputnode.knownvaluebox) + else: + raise InvalidLoop if inputnode.escaped: return prebuiltNotSpecNode unique = exitnode.unique @@ -387,7 +390,7 @@ if (inputnode.knownclsbox is not None and not inputnode.knownclsbox.same_constant(exitnode.knownclsbox)): # unique match, but the class is known to be a mismatch - return prebuiltNotSpecNode + raise InvalidLoop # fields = self.compute_common_fields(inputnode.origfields, exitnode.curfields) Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py Thu Sep 17 19:01:25 2009 @@ -8,6 +8,7 @@ from pypy.jit.metainterp.specnode import VirtualArraySpecNode from pypy.jit.metainterp.specnode import VirtualStructSpecNode from pypy.jit.metainterp.optimizeutil import av_newdict2, _findall, sort_descrs +from pypy.jit.metainterp.optimizeutil import InvalidLoop from pypy.jit.metainterp import resume, compile from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.rlib.objectmodel import we_are_translated @@ -484,7 +485,7 @@ for i in range(len(op.args)): arg = op.args[i] if arg in self.values: - box = self.values[arg].force_box() # I think we definitely need box, at least for this but it's unclear I mean is it ok to replace box with Const(..) when we set level==CONSTANT?ah, in this direction. yes, I would expect that to be ok ah yes indeed I see it + box = self.values[arg].force_box() if box is not arg: if must_clone: op = op.clone() @@ -578,7 +579,8 @@ if value.is_constant(): box = value.box assert isinstance(box, Const) - assert box.same_constant(constbox) + if not box.same_constant(constbox): + raise InvalidLoop return self.emit_operation(op) value.make_constant(constbox) @@ -600,6 +602,9 @@ assert isinstance(expectedclassbox, Const) realclassbox = value.get_constant_class(self.cpu) if realclassbox is not None: + # the following assert should always be true for now, + # because invalid loops that would fail it are detected + # earlier, in optimizefindnode.py. assert realclassbox.same_constant(expectedclassbox) return self.emit_operation(op) Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeutil.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeutil.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeutil.py Thu Sep 17 19:01:25 2009 @@ -2,6 +2,11 @@ from pypy.rlib.unroll import unrolling_iterable from pypy.jit.metainterp import resoperation +class InvalidLoop(Exception): + """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).""" + # ____________________________________________________________ # Misc. utilities Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py Thu Sep 17 19:01:25 2009 @@ -10,7 +10,7 @@ ConstObj, AbstractDescr) from pypy.jit.metainterp.optimizefindnode import PerfectSpecializationFinder from pypy.jit.metainterp.optimizefindnode import BridgeSpecializationFinder -from pypy.jit.metainterp.optimizeutil import sort_descrs +from pypy.jit.metainterp.optimizeutil import sort_descrs, InvalidLoop from pypy.jit.metainterp.specnode import NotSpecNode, prebuiltNotSpecNode from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode from pypy.jit.metainterp.specnode import VirtualArraySpecNode @@ -417,9 +417,9 @@ p2 = new_with_vtable(ConstClass(node_vtable2)) jump(p2) """ - # this must give 'Not', not 'Virtual', because optimizeopt.py would - # remove the guard_class for a virtual. - self.find_nodes(ops, 'Not') + # this is not a valid loop at all, because of the mismatch + # between the produced and the consumed class. + py.test.raises(InvalidLoop, self.find_nodes, ops, None) def test_find_nodes_new_aliasing_mismatch(self): ops = """ @@ -431,6 +431,8 @@ p2 = new_with_vtable(ConstClass(node_vtable2)) jump(p2, p2) """ + # this is also not really a valid loop, but it's not detected + # because p2 is passed more than once in the jump(). self.find_nodes(ops, 'Not, Not') def test_find_nodes_new_escapes(self): @@ -517,14 +519,14 @@ ops = """ [p0] i0 = getfield_gc(p0, descr=valuedescr) - guard_value(i0, 0) + guard_value(i0, 5) fail() p1 = new_with_vtable(ConstClass(node_vtable)) # the field 'value' has its default value of 0 jump(p1) """ # The answer must contain the 'value' field, because otherwise - # we might get incorrect results: when tracing, maybe i0 was not 0. + # we might get incorrect results: when tracing, i0 was 5. self.find_nodes(ops, 'Virtual(node_vtable, valuedescr=Not)') def test_find_nodes_nonvirtual_guard_class(self): @@ -721,6 +723,15 @@ """ self.find_nodes(ops, 'Constant(myptr)') + def test_find_nodes_guard_value_constant_mismatch(self): + ops = """ + [p1] + guard_value(p1, ConstPtr(myptr2)) + fail() + jump(ConstPtr(myptr)) + """ + py.test.raises(InvalidLoop, self.find_nodes, ops, None) + def test_find_nodes_guard_value_escaping_constant(self): ops = """ [p1] @@ -889,19 +900,6 @@ """ self.find_nodes(ops, 'Virtual(node_vtable, valuedescr=Not)') - def test_bug_2(self): - py.test.skip("fix me") - ops = """ - [p1] - i1 = ooisnull(p1) - guard_true(i1) - fail() - # - p2 = new_with_vtable(ConstClass(node_vtable)) - jump(p2) - """ - self.find_nodes(ops, 'Not', - i1=1) # ------------------------------ # Bridge tests Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py Thu Sep 17 19:01:25 2009 @@ -7,6 +7,7 @@ BaseTest) from pypy.jit.metainterp.optimizefindnode import PerfectSpecializationFinder from pypy.jit.metainterp.optimizeopt import optimize_loop_1 +from pypy.jit.metainterp.optimizeutil import InvalidLoop from pypy.jit.metainterp.history import AbstractDescr, ConstInt from pypy.jit.metainterp import resume, executor, compile from pypy.jit.metainterp.resoperation import rop, opname @@ -221,22 +222,26 @@ def test_remove_consecutive_guard_value_constfold(self): ops = """ - [i0] + [] + i0 = escape() guard_value(i0, 0) fail() i1 = int_add(i0, 1) guard_value(i1, 1) fail() i2 = int_add(i1, 2) - jump(i2) + escape(i2) + jump() """ expected = """ - [i0] + [] + i0 = escape() guard_value(i0, 0) - fail() - jump(3) + fail() + escape(3) + jump() """ - self.optimize_loop(ops, 'Not', expected) + self.optimize_loop(ops, '', expected) def test_remove_guard_value_if_constant(self): ops = """ @@ -1238,6 +1243,33 @@ self.optimize_loop(ops, 'Not, VArray(arraydescr2, Not)', expected) + def test_invalid_loop_1(self): + ops = """ + [p1] + i1 = ooisnull(p1) + guard_true(i1) + fail() + # + p2 = new_with_vtable(ConstClass(node_vtable)) + jump(p2) + """ + py.test.raises(InvalidLoop, self.optimize_loop, + ops, 'Virtual(node_vtable)', None) + + def test_invalid_loop_2(self): + py.test.skip("this would fail if we had Fixed again in the specnodes") + ops = """ + [p1] + guard_class(p1, ConstClass(node_vtable2)) + fail() + # + p2 = new_with_vtable(ConstClass(node_vtable)) + escape(p2) # prevent it from staying Virtual + jump(p2) + """ + py.test.raises(InvalidLoop, self.optimize_loop, + ops, '...', None) + # ---------- def make_fail_descr(self): From arigo at codespeak.net Thu Sep 17 19:57:30 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 19:57:30 +0200 (CEST) Subject: [pypy-svn] r67744 - in pypy/branch/optimize-novaluedep/pypy/jit/metainterp: . test Message-ID: <20090917175730.2BEBB16800A@codespeak.net> Author: arigo Date: Thu Sep 17 19:57:27 2009 New Revision: 67744 Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/compile.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_send.py Log: (cfbolz, arigo) Catch the InvalidLoop exception. For now, forces unrolling, which makes again the two long-skipped tests of test_send pass :-) Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/compile.py Thu Sep 17 19:57:27 2009 @@ -11,6 +11,7 @@ from pypy.jit.metainterp import history from pypy.jit.metainterp.specnode import NotSpecNode from pypy.jit.metainterp.typesystem import llhelper, oohelper +from pypy.jit.metainterp.optimizeutil import InvalidLoop from pypy.rlib.debug import debug_print def compile_new_loop(metainterp, old_loops, greenkey, start=0): @@ -48,7 +49,8 @@ log.info("reusing loop at %r" % (loop,)) else: show_loop(metainterp, loop) - loop.check_consistency() + if loop is not None: + loop.check_consistency() return loop def _compile_new_bridge_1(metainterp, old_loops, resumekey): @@ -104,8 +106,12 @@ loop.operations = history.operations loop.operations[-1].jump_target = loop metainterp_sd = metainterp.staticdata - old_loop = metainterp_sd.state.optimize_loop(metainterp_sd.options, old_loops, - loop, metainterp.cpu) + try: + old_loop = metainterp_sd.state.optimize_loop(metainterp_sd.options, + old_loops, loop, + metainterp.cpu) + except InvalidLoop: + return None if old_loop is not None: if we_are_translated() and DEBUG > 0: debug_print("reusing old loop") @@ -374,9 +380,14 @@ new_loop = create_empty_loop(metainterp) new_loop.operations = metainterp.history.operations metainterp_sd = metainterp.staticdata - target_loop = metainterp_sd.state.optimize_bridge(metainterp_sd.options, - old_loops, new_loop, - metainterp.cpu) + options = metainterp_sd.options + try: + target_loop = metainterp_sd.state.optimize_bridge(options, + old_loops, new_loop, + metainterp.cpu) + except InvalidLoop: + assert 0, "InvalidLoop in optimize_bridge?" + return None # Did it work? If not, prepare_loop_from_bridge() will probably be used. if target_loop is not None: # Yes, we managed to create a bridge. Dispatch to resumekey to Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py Thu Sep 17 19:57:27 2009 @@ -1423,6 +1423,7 @@ break else: # Found! Compile it as a loop. + oldops = self.history.operations[:] if j > 0: # clean up, but without shifting the end of the list # (that would make 'history_guard_index' invalid) @@ -1442,7 +1443,15 @@ self.history.operations[i] = None compile.prepare_loop_from_bridge(self, self.resumekey) loop = self.compile(original_boxes, live_arg_boxes, start) - raise GenerateMergePoint(live_arg_boxes, loop) + if loop is not None: + raise GenerateMergePoint(live_arg_boxes, loop) + # creation of the loop was cancelled! Patch + # history.operations so that it contains again + # exactly its old list of operations... + # xxx maybe we could patch history.operations with + # Nones after calling self.compile() instead of + # before... + self.history.operations[:] = oldops # Otherwise, no loop found so far, so continue tracing. start = len(self.history.operations) @@ -1501,8 +1510,7 @@ old_loops = glob.compiled_merge_points.setdefault(greenargs, []) self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None) loop = compile.compile_new_loop(self, old_loops, greenkey, start) - assert loop is not None - if not we_are_translated(): + if not we_are_translated() and loop is not None: loop._call_history = self._debug_history return loop Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_send.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_send.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_send.py Thu Sep 17 19:57:27 2009 @@ -168,7 +168,6 @@ self.check_loop_count(3) def test_oosend_guard_failure(self): - py.test.skip("Unsupported yet") myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'w']) class Base: pass @@ -201,16 +200,16 @@ assert res == f(3, 28) res = self.meta_interp(f, [4, 28]) assert res == f(4, 28) - # The effect of the ClassGuard generated by the oosend to incr() - # should be to unroll the loop, giving two copies of the body in - # a single bigger loop with no failing guard except the final one. + # This checks that the loop was originally aborted due to an + # InvalidLoop condition, and was then unrolled, giving two copies + # of the body in a single bigger loop with no failing guard except + # the final one. self.check_loop_count(1) self.check_loops(guard_class=0, int_add=2, int_sub=2) self.check_jumps(14) def test_oosend_guard_failure_2(self): - py.test.skip("Unsupported yet") # same as above, but using prebuilt objects 'w1' and 'w2' myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'w']) class Base: @@ -237,6 +236,7 @@ else: w = w2 while y > 0: + myjitdriver.can_enter_jit(x=x, y=y, w=w) myjitdriver.jit_merge_point(x=x, y=y, w=w) w = w.incr() y -= 1 From arigo at codespeak.net Thu Sep 17 20:04:13 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 20:04:13 +0200 (CEST) Subject: [pypy-svn] r67745 - pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test Message-ID: <20090917180413.65B6016800A@codespeak.net> Author: arigo Date: Thu Sep 17 20:04:12 2009 New Revision: 67745 Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py Log: Add another passing test. Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py Thu Sep 17 20:04:12 2009 @@ -1270,6 +1270,23 @@ py.test.raises(InvalidLoop, self.optimize_loop, ops, '...', None) + def test_invalid_loop_3(self): + ops = """ + [p1] + p2 = getfield_gc(p1, descr=nextdescr) + i1 = ooisnull(p2) + guard_true(i1) + fail() + # + p3 = new_with_vtable(ConstClass(node_vtable)) + p4 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p3, p4, descr=nextdescr) + jump(p3) + """ + py.test.raises(InvalidLoop, self.optimize_loop, ops, + 'Virtual(node_vtable, nextdescr=Virtual(node_vtable))', + None) + # ---------- def make_fail_descr(self): From arigo at codespeak.net Thu Sep 17 20:06:25 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 20:06:25 +0200 (CEST) Subject: [pypy-svn] r67746 - pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test Message-ID: <20090917180625.0E71F16800A@codespeak.net> Author: arigo Date: Thu Sep 17 20:06:25 2009 New Revision: 67746 Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_loop_dummy.py Log: "Fix" test_loop_dummy. Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_loop_dummy.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_loop_dummy.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_loop_dummy.py Thu Sep 17 20:06:25 2009 @@ -17,6 +17,9 @@ def check_loop_count(self, count): pass + def check_jumps(self, maxcount): + pass + class TestLLtype(LoopDummyTest, LLJitMixin): pass From arigo at codespeak.net Thu Sep 17 20:26:00 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 20:26:00 +0200 (CEST) Subject: [pypy-svn] r67747 - pypy/branch/optimize-novaluedep/pypy/jit/metainterp Message-ID: <20090917182600.6FEBF16800C@codespeak.net> Author: arigo Date: Thu Sep 17 20:25:56 2009 New Revision: 67747 Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py Log: Fix for translation. Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py Thu Sep 17 20:25:56 2009 @@ -1451,7 +1451,8 @@ # xxx maybe we could patch history.operations with # Nones after calling self.compile() instead of # before... - self.history.operations[:] = oldops + del self.history.operations[:] + self.history.operations.extend(oldops) # Otherwise, no loop found so far, so continue tracing. start = len(self.history.operations) From arigo at codespeak.net Thu Sep 17 21:19:57 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 21:19:57 +0200 (CEST) Subject: [pypy-svn] r67748 - pypy/branch/optimize-novaluedep/pypy/jit/backend Message-ID: <20090917191957.4415816800A@codespeak.net> Author: arigo Date: Thu Sep 17 21:19:54 2009 New Revision: 67748 Modified: pypy/branch/optimize-novaluedep/pypy/jit/backend/model.py Log: Add these methods to the base model.py. You wouldn't belive it, but this is a fix for translating pypy-c-jit. Modified: pypy/branch/optimize-novaluedep/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/backend/model.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/backend/model.py Thu Sep 17 21:19:54 2009 @@ -23,6 +23,10 @@ """Set the value for the index'th argument for the loop to run.""" raise NotImplementedError + def set_future_value_float(self, index, floatvalue): + """Set the value for the index'th argument for the loop to run.""" + raise NotImplementedError + def set_future_value_ref(self, index, objvalue): """Set the value for the index'th argument for the loop to run.""" raise NotImplementedError @@ -32,6 +36,11 @@ lastest rop.FAIL. Returns an int.""" raise NotImplementedError + def get_latest_value_float(self, index): + """Returns the value for the index'th argument to the + lastest rop.FAIL. Returns a float.""" + raise NotImplementedError + def get_latest_value_ref(self, index): """Returns the value for the index'th argument to the lastest rop.FAIL. Returns a ptr or an obj.""" From arigo at codespeak.net Thu Sep 17 21:52:42 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 21:52:42 +0200 (CEST) Subject: [pypy-svn] r67749 - pypy/branch/optimize-novaluedep/pypy/jit/backend/cli Message-ID: <20090917195242.EEB6616800A@codespeak.net> Author: arigo Date: Thu Sep 17 21:52:39 2009 New Revision: 67749 Modified: pypy/branch/optimize-novaluedep/pypy/jit/backend/cli/runner.py Log: Trying to add the method to the CLI backend. Not really tested. Modified: pypy/branch/optimize-novaluedep/pypy/jit/backend/cli/runner.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/backend/cli/runner.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/backend/cli/runner.py Thu Sep 17 21:52:39 2009 @@ -86,6 +86,11 @@ T1, _ = T._lookup_field(fieldname) return FieldDescr.new(T1, fieldname) + @staticmethod + def typedescr2classbox(descr): + assert isinstance(descr, TypeDescr) + return ConstObj(ootype.cast_to_object(descr.ooclass)) + # ---------------------- def compile_operations(self, loop, bridge=None): From arigo at codespeak.net Thu Sep 17 21:54:22 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 21:54:22 +0200 (CEST) Subject: [pypy-svn] r67750 - pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test Message-ID: <20090917195422.0BC4F16800A@codespeak.net> Author: arigo Date: Thu Sep 17 21:54:21 2009 New Revision: 67750 Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py Log: Add a test for coverage. Checks optimizefindnode.py:477... Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py Thu Sep 17 21:54:21 2009 @@ -1135,6 +1135,22 @@ self.find_bridge(ops, 'Not', 'VArray(arraydescr, Not, Not, Not)', mismatch=True) + def test_bridge_nested_structs(self): + ops = """ + [] + p1 = new_with_vtable(ConstClass(node_vtable)) + p2 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p1, p2, descr=nextdescr) + jump(p1) + """ + self.find_bridge(ops, '', 'Not') + self.find_bridge(ops, '', 'Virtual(node_vtable, nextdescr=Not)') + self.find_bridge(ops, '', + 'Virtual(node_vtable, nextdescr=Virtual(node_vtable))') + self.find_bridge(ops, '', + 'Virtual(node_vtable, nextdescr=Virtual(node_vtable2))', + mismatch=True) + class TestLLtype(BaseTestOptimizeFindNode, LLtypeMixin): pass From arigo at codespeak.net Thu Sep 17 21:58:12 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Sep 2009 21:58:12 +0200 (CEST) Subject: [pypy-svn] r67751 - pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test Message-ID: <20090917195812.0728816800A@codespeak.net> Author: arigo Date: Thu Sep 17 21:58:12 2009 New Revision: 67751 Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py Log: Add a test for coverage of optimizeopt.py:83. Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py Thu Sep 17 21:58:12 2009 @@ -54,6 +54,7 @@ NODE2 = lltype.GcStruct('NODE2', ('parent', NODE), ('other', lltype.Ptr(NODE))) node = lltype.malloc(NODE) + node.parent.typeptr = node_vtable nodebox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, node)) myptr = nodebox.value myptr2 = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(NODE)) Modified: pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py Thu Sep 17 21:58:12 2009 @@ -220,6 +220,20 @@ """ self.optimize_loop(ops, 'Not', expected) + def test_remove_guard_class_constant(self): + ops = """ + [i0] + p0 = same_as(ConstPtr(myptr)) + guard_class(p0, ConstClass(node_vtable)) + fail() + jump(i0) + """ + expected = """ + [i0] + jump(i0) + """ + self.optimize_loop(ops, 'Not', expected) + def test_remove_consecutive_guard_value_constfold(self): ops = """ [] From antocuni at codespeak.net Fri Sep 18 11:48:57 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 18 Sep 2009 11:48:57 +0200 (CEST) Subject: [pypy-svn] r67752 - pypy/trunk/pypy/rpython/ootypesystem/module Message-ID: <20090918094857.82CDC168003@codespeak.net> Author: antocuni Date: Fri Sep 18 11:48:54 2009 New Revision: 67752 Modified: pypy/trunk/pypy/rpython/ootypesystem/module/ll_math.py Log: use the exact same type as tuples for return values of frexp and modf. This fixes test_rbuiltin.test_builtin_math_* for ootype. Modified: pypy/trunk/pypy/rpython/ootypesystem/module/ll_math.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/module/ll_math.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/module/ll_math.py Fri Sep 18 11:48:54 2009 @@ -1,8 +1,9 @@ import math from pypy.rpython.ootypesystem import ootype +from pypy.rpython.ootypesystem.rtupletype import TUPLE_TYPE -FREXP_RESULT = ootype.Record({"item0": ootype.Float, "item1": ootype.Signed}) -MODF_RESULT = ootype.Record({"item0": ootype.Float, "item1": ootype.Float}) +FREXP_RESULT = TUPLE_TYPE([ootype.Float, ootype.Signed]) +MODF_RESULT = TUPLE_TYPE([ootype.Float, ootype.Float]) def ll_frexp_result(mantissa, exponent): tup = ootype.new(FREXP_RESULT) From antocuni at codespeak.net Fri Sep 18 12:02:19 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 18 Sep 2009 12:02:19 +0200 (CEST) Subject: [pypy-svn] r67753 - in pypy/trunk/pypy: rpython/ootypesystem/module translator/cli Message-ID: <20090918100219.62D2C168005@codespeak.net> Author: antocuni Date: Fri Sep 18 12:02:13 2009 New Revision: 67753 Modified: pypy/trunk/pypy/rpython/ootypesystem/module/ll_os.py pypy/trunk/pypy/translator/cli/database.py Log: use the correct tuple types in the cli backend; test_builtin passes again Modified: pypy/trunk/pypy/rpython/ootypesystem/module/ll_os.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/module/ll_os.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/module/ll_os.py Fri Sep 18 12:02:13 2009 @@ -1,13 +1,7 @@ # mostly-deprecated module from pypy.rpython.ootypesystem import ootype - -def _make_tuple(FIELDS): - n = len(FIELDS) - fieldnames = ['item%d' % i for i in range(n)] - fields = dict(zip(fieldnames, FIELDS)) - return ootype.Record(fields) - +from pypy.rpython.ootypesystem.rtupletype import TUPLE_TYPE from pypy.rpython.module.ll_os_stat import PORTABLE_STAT_FIELDS -STAT_RESULT = _make_tuple([_TYPE for _name, _TYPE in PORTABLE_STAT_FIELDS]) +STAT_RESULT = TUPLE_TYPE([_TYPE for _name, _TYPE in PORTABLE_STAT_FIELDS]) Modified: pypy/trunk/pypy/translator/cli/database.py ============================================================================== --- pypy/trunk/pypy/translator/cli/database.py (original) +++ pypy/trunk/pypy/translator/cli/database.py Fri Sep 18 12:02:13 2009 @@ -9,7 +9,8 @@ from pypy.translator.cli.support import string_literal, Counter from pypy.translator.cli.cts import types from pypy.rpython.ootypesystem import ootype -from pypy.rpython.ootypesystem.module import ll_os +from pypy.rpython.ootypesystem.module import ll_os, ll_math +from pypy.rpython.ootypesystem.rtupletype import TUPLE_TYPE from pypy.translator.cli import dotnet from pypy.rlib.objectmodel import CDefinedIntSymbolic from pypy.translator.oosupport.database import Database as OODatabase @@ -20,18 +21,13 @@ from sets import Set as set BUILTIN_RECORDS = { - ootype.Record({"item0": ootype.Signed, "item1": ootype.Signed}): - '[pypylib]pypy.runtime.Record_Signed_Signed', - - ootype.Record({"item0": ootype.Float, "item1": ootype.Signed}): - '[pypylib]pypy.runtime.Record_Float_Signed', - - ootype.Record({"item0": ootype.Float, "item1": ootype.Float}): - '[pypylib]pypy.runtime.Record_Float_Float', - - ootype.Record({"item0": ootype.String, "item1": ootype.String}): - '[pypylib]pypy.runtime.Record_String_String', + TUPLE_TYPE([ootype.Signed, ootype.Signed]): + '[pypylib]pypy.runtime.Record_Signed_Signed', + TUPLE_TYPE([ootype.String, ootype.String]): + '[pypylib]pypy.runtime.Record_String_String', + ll_math.FREXP_RESULT: '[pypylib]pypy.runtime.Record_Float_Signed', + ll_math.MODF_RESULT: '[pypylib]pypy.runtime.Record_Float_Float', ll_os.STAT_RESULT: '[pypylib]pypy.runtime.Record_Stat_Result', } From antocuni at codespeak.net Fri Sep 18 12:12:41 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 18 Sep 2009 12:12:41 +0200 (CEST) Subject: [pypy-svn] r67754 - pypy/trunk/pypy/translator/cli/src Message-ID: <20090918101241.1D314168013@codespeak.net> Author: antocuni Date: Fri Sep 18 12:12:35 2009 New Revision: 67754 Modified: pypy/trunk/pypy/translator/cli/src/pypylib.cs Log: add a constructor of DictOfVoidKeys which takes an equality comparer; this is needed to instantiate a CustomDict with void keys, and fixes jit tests Modified: pypy/trunk/pypy/translator/cli/src/pypylib.cs ============================================================================== --- pypy/trunk/pypy/translator/cli/src/pypylib.cs (original) +++ pypy/trunk/pypy/translator/cli/src/pypylib.cs Fri Sep 18 12:12:35 2009 @@ -900,6 +900,7 @@ private TValue elem = default(TValue); public DictOfVoidKey() {} + public DictOfVoidKey(IEqualityComparer comparer) {} public int ll_length() { return this.length; } public TValue ll_get() { return this.elem; } From pedronis at codespeak.net Fri Sep 18 12:56:29 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 18 Sep 2009 12:56:29 +0200 (CEST) Subject: [pypy-svn] r67755 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090918105629.1FB07168010@codespeak.net> Author: pedronis Date: Fri Sep 18 12:56:27 2009 New Revision: 67755 Modified: pypy/trunk/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/jitprof.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py Log: operation execution and recording counting Modified: pypy/trunk/pypy/jit/metainterp/history.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py Fri Sep 18 12:56:27 2009 @@ -8,6 +8,7 @@ from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop +from pypy.jit.metainterp.jitprof import BLACKHOLED_OPS, RECORDED_OPS import py from pypy.tool.ansi_print import ansi_log @@ -769,6 +770,7 @@ raise NotImplementedError class History(RunningMatcher): + OPS_KIND = RECORDED_OPS extratext = '' def record(self, opnum, argboxes, resbox, descr=None): op = ResOperation(opnum, argboxes, resbox, descr) @@ -776,6 +778,7 @@ return op class BlackHole(RunningMatcher): + OPS_KIND = BLACKHOLED_OPS extratext = ' (BlackHole)' def record(self, opnum, argboxes, resbox, descr=None): return None Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/jitprof.py (original) +++ pypy/trunk/pypy/jit/metainterp/jitprof.py Fri Sep 18 12:56:27 2009 @@ -9,6 +9,10 @@ BACKEND = 1 RUNNING = 2 BLACKHOLE = 3 +OPS = 4 +RECORDED_OPS = 5 +BLACKHOLED_OPS = 6 +GUARDS = 7 class EmptyProfiler(object): initialized = True @@ -43,6 +47,10 @@ def end_blackhole(self): pass + def count_ops(self, opnum, kind=OPS): + pass + + class Profiler(object): initialized = False timer = time.time @@ -51,7 +59,8 @@ self.starttime = self.timer() self.t1 = self.starttime self.times = [0, 0, 0, 0] - self.counters = [0, 0, 0, 0] + self.counters = [0, 0, 0, 0, 0, 0, 0, 0] + self.calls = [[0, 0], [0, 0], [0, 0]] self.current = [] def finish(self): @@ -90,14 +99,34 @@ def start_blackhole(self): self._start(BLACKHOLE) def end_blackhole(self): self._end (BLACKHOLE) + def count_ops(self, opnum, kind=OPS): + from pypy.jit.metainterp.resoperation import rop + self.counters[kind] += 1 + if opnum == rop.CALL or opnum == rop.OOSEND: + self.calls[kind-OPS][0] += 1 + elif opnum == rop.CALL_PURE or opnum == rop.OOSEND_PURE: + self.calls[kind-OPS][1] += 1 + def print_stats(self): cnt = self.counters tim = self.times + calls = self.calls lines = ("Tracing: \t%d\t%f\n" % (cnt[TRACING], tim[TRACING]) + "Backend: \t%d\t%f\n" % (cnt[BACKEND], tim[BACKEND]) + "Running asm:\t%d\t%f\n" % (cnt[RUNNING], tim[RUNNING]) + "Blackhole: \t%d\t%f\n" % (cnt[BLACKHOLE], tim[BLACKHOLE]) + - "TOTAL: \t\t%f\n" % (self.tk - self.starttime)) + "TOTAL: \t\t%f\n" % (self.tk - self.starttime) + + "ops: \t%d\n" % cnt[OPS] + + " calls: \t%d\n" % calls[0][0] + + " pure calls: \t%d\n" % calls[0][1] + + "recorded ops: \t%d\n" % cnt[RECORDED_OPS] + + " calls: \t%d\n" % calls[1][0] + + " pure calls: \t%d\n" % calls[1][1] + + "guards: \t%d\n" % cnt[GUARDS] + + "blackholed ops:\t%d\n" % cnt[BLACKHOLED_OPS] + + " calls: \t%d\n" % calls[2][0] + + " pure calls: \t%d\n" % calls[2][1] + ) import os os.write(2, lines) Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Fri Sep 18 12:56:27 2009 @@ -10,6 +10,7 @@ from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import codewriter, executor from pypy.jit.backend.logger import Logger +from pypy.jit.metainterp.jitprof import EmptyProfiler, GUARDS from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize @@ -989,6 +990,7 @@ resumedescr = compile.ResumeGuardDescr( metainterp.history, len(metainterp.history.operations)-1) liveboxes = resumebuilder.finish(resumedescr) + self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count op = history.ResOperation(rop.FAIL, liveboxes, None, descr=resumedescr) guard_op.suboperations = [op] metainterp.attach_debug_info(guard_op) @@ -1045,7 +1047,6 @@ if profile is not None: self.profiler = profile() else: - from pypy.jit.metainterp.jitprof import EmptyProfiler self.profiler = EmptyProfiler() self.warmrunnerdesc = warmrunnerdesc @@ -1280,9 +1281,12 @@ resbox = resbox.nonconstbox() # ensure it is a Box else: assert resbox is None or isinstance(resbox, Box) + profiler = self.staticdata.profiler + profiler.count_ops(opnum) # record the operation if not constant-folded away if not canfold: op = self.history.record(opnum, argboxes, resbox, descr) + profiler.count_ops(opnum, self.history.OPS_KIND) self.attach_debug_info(op) if require_attention: self.after_generate_residual_call() Modified: pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py Fri Sep 18 12:56:27 2009 @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, dont_look_inside from pypy.jit.metainterp.test.test_basic import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -55,3 +55,26 @@ ] assert profiler.events == expected assert profiler.times == [2, 1, 1, 1] + assert profiler.counters == [1, 1, 1, 1, 4, 3, 1, 1] + + def test_simple_loop_with_call(self): + @dont_look_inside + def g(n): + pass + + myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res']) + def f(x, y): + res = 0 + while y > 0: + myjitdriver.can_enter_jit(x=x, y=y, res=res) + myjitdriver.jit_merge_point(x=x, y=y, res=res) + res += x + g(x) + y -= 1 + return res * 2 + res = self.meta_interp(f, [6, 7]) + assert res == 84 + profiler = pyjitpl._warmrunnerdesc.metainterp_sd.profiler + # calls = (executed, recorded, blackholed) x (inpure, pure) + assert profiler.calls == [[1, 0], [1, 0], [0, 0]] + From arigo at codespeak.net Fri Sep 18 13:58:20 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 13:58:20 +0200 (CEST) Subject: [pypy-svn] r67756 - pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem Message-ID: <20090918115820.7F96D168015@codespeak.net> Author: arigo Date: Fri Sep 18 13:58:19 2009 New Revision: 67756 Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py Log: Uh? Nonsense. Modified: pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py Fri Sep 18 13:58:19 2009 @@ -418,7 +418,7 @@ # for asmgcroot support to get the address of various static structures # see translator/c/src/mem.h for the valid indices 'gc_asmgcroot_static': LLOp(sideeffects=False), - 'gc_stack_bottom': LLOp(sideeffects=False, canrun=True), + 'gc_stack_bottom': LLOp(canrun=True), # NOTE NOTE NOTE! don't forget *** canunwindgc=True *** for anything that # can go through a stack unwind, in particular anything that mallocs! From pedronis at codespeak.net Fri Sep 18 14:16:20 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 18 Sep 2009 14:16:20 +0200 (CEST) Subject: [pypy-svn] r67757 - in pypy/trunk/pypy: . module/_minimal_curses/test rpython/module/test translator/c/test Message-ID: <20090918121620.674F316800D@codespeak.net> Author: pedronis Date: Fri Sep 18 14:16:19 2009 New Revision: 67757 Modified: pypy/trunk/pypy/conftest.py pypy/trunk/pypy/module/_minimal_curses/test/test_curses.py pypy/trunk/pypy/rpython/module/test/test_ll_termios.py pypy/trunk/pypy/translator/c/test/test_genc.py Log: amazing the stuff one finds living in the corners of pypy - fix these tests by making test_genc.py reading of option.view more robust - some import cleanups and comments in the tests - update some of the main conftest.py to the modern py.test idioms Modified: pypy/trunk/pypy/conftest.py ============================================================================== --- pypy/trunk/pypy/conftest.py (original) +++ pypy/trunk/pypy/conftest.py Fri Sep 18 14:16:19 2009 @@ -486,8 +486,8 @@ def spawn(self, argv): return self._spawn(sys.executable, argv) - def execute(self, target, *args): - assert not args + def runtest(self): + target = self.obj import pexpect source = py.code.Source(target)[1:].deindent() filename = self.safe_filename() Modified: pypy/trunk/pypy/module/_minimal_curses/test/test_curses.py ============================================================================== --- pypy/trunk/pypy/module/_minimal_curses/test/test_curses.py (original) +++ pypy/trunk/pypy/module/_minimal_curses/test/test_curses.py Fri Sep 18 14:16:19 2009 @@ -1,12 +1,9 @@ - -from pypy.translator.c.test.test_genc import compile -from pypy.module._minimal_curses import interp_curses -from pypy.module._minimal_curses import fficurses -from pypy.conftest import gettestobjspace from pypy.tool.autopath import pypydir from pypy.tool.udir import udir import py import sys +# tests here are run as snippets through a pexpected python subprocess + def setup_module(mod): try: @@ -73,7 +70,6 @@ child = self.spawn(['--withmod-_minimal_curses', str(f)]) child.expect('ok!') - class ExpectTestCCurses(object): """ Test compiled version """ Modified: pypy/trunk/pypy/rpython/module/test/test_ll_termios.py ============================================================================== --- pypy/trunk/pypy/rpython/module/test/test_ll_termios.py (original) +++ pypy/trunk/pypy/rpython/module/test/test_ll_termios.py Fri Sep 18 14:16:19 2009 @@ -1,11 +1,5 @@ - import py -import sys -import os - -from pypy.tool.autopath import pypydir -from pypy.translator.c.test.test_genc import compile -from pypy.tool.udir import udir +# tests here are run as snippets through a pexpected python subprocess def setup_module(mod): try: @@ -16,7 +10,6 @@ class ExpectTestLLTermios(object): def test_tcgetattr(self): - from pypy.translator.c.test.test_genc import compile import termios from pypy.rlib import rtermios Modified: pypy/trunk/pypy/translator/c/test/test_genc.py ============================================================================== --- pypy/trunk/pypy/translator/c/test/test_genc.py (original) +++ pypy/trunk/pypy/translator/c/test/test_genc.py Fri Sep 18 14:16:19 2009 @@ -23,7 +23,7 @@ # XXX fish t.driver.config.translation.countmallocs = True compiled_fn = t.compile_c() - if py.test.config.option.view: + if getattr(py.test.config.option, 'view', False): t.view() malloc_counters = t.driver.cbuilder.get_malloc_counters() def checking_fn(*args, **kwds): From arigo at codespeak.net Fri Sep 18 14:32:17 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 14:32:17 +0200 (CEST) Subject: [pypy-svn] r67758 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090918123217.35B4416801D@codespeak.net> Author: arigo Date: Fri Sep 18 14:32:16 2009 New Revision: 67758 Added: pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp - copied, changed from r67757, pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/optimize-novaluedep/pypy/jit/metainterp/pyjitpl.py revisions 67718 to 67757: ------------------------------------------------------------------------ r67747 | arigo | 2009-09-17 20:25:56 +0200 (Thu, 17 Sep 2009) | 2 lines Fix for translation. ------------------------------------------------------------------------ r67744 | arigo | 2009-09-17 19:57:27 +0200 (Thu, 17 Sep 2009) | 4 lines (cfbolz, arigo) Catch the InvalidLoop exception. For now, forces unrolling, which makes again the two long-skipped tests of test_send pass :-) ------------------------------------------------------------------------ r67738 | arigo | 2009-09-17 16:52:55 +0200 (Thu, 17 Sep 2009) | 2 lines (cfbolz, arigo): a case that was not covered by the tests. ------------------------------------------------------------------------ r67727 | arigo | 2009-09-17 11:13:19 +0200 (Thu, 17 Sep 2009) | 5 lines Goal-oriented programming! Kill the method nonnull() on Boxes and rename the overloaded method equals() to same_constant(), supposed to work only between Consts. Now the idea is to make optimize*.py still work... ------------------------------------------------------------------------ r67719 | arigo | 2009-09-16 17:27:03 +0200 (Wed, 16 Sep 2009) | 3 lines A branch in which to refactor jit/metainterp/optimize*.py to no longer query the value of the boxes it handles. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp (from r67757, pypy/trunk/pypy/jit/metainterp/pyjitpl.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp Fri Sep 18 14:32:16 2009 @@ -305,7 +305,7 @@ box = self.implement_guard_value(pc, valuebox) for i in range(len(constargs)): casebox = constargs[i] - if box.equals(casebox): + if box.same_constant(casebox): self.pc = jumptargets[i] break @@ -998,13 +998,13 @@ return guard_op def implement_guard_value(self, pc, box): - if isinstance(box, Box): + if isinstance(box, Const): + return box # no promotion needed, already a Const + else: promoted_box = box.constbox() self.generate_guard(pc, rop.GUARD_VALUE, box, [promoted_box]) self.metainterp.replace_box(box, promoted_box) return promoted_box - else: - return box # no promotion needed, already a Const def cls_of_box(self, box): return self.metainterp.cpu.ts.cls_of_box(self.metainterp.cpu, box) @@ -1422,10 +1422,12 @@ for i in range(self.staticdata.num_green_args): box1 = original_boxes[i] box2 = live_arg_boxes[i] - if not box1.equals(box2): + assert isinstance(box1, Const) + if not box1.same_constant(box2): break else: # Found! Compile it as a loop. + oldops = self.history.operations[:] if j > 0: # clean up, but without shifting the end of the list # (that would make 'history_guard_index' invalid) @@ -1445,7 +1447,16 @@ self.history.operations[i] = None compile.prepare_loop_from_bridge(self, self.resumekey) loop = self.compile(original_boxes, live_arg_boxes, start) - raise GenerateMergePoint(live_arg_boxes, loop) + if loop is not None: + raise GenerateMergePoint(live_arg_boxes, loop) + # creation of the loop was cancelled! Patch + # history.operations so that it contains again + # exactly its old list of operations... + # xxx maybe we could patch history.operations with + # Nones after calling self.compile() instead of + # before... + del self.history.operations[:] + self.history.operations.extend(oldops) # Otherwise, no loop found so far, so continue tracing. start = len(self.history.operations) @@ -1504,8 +1515,7 @@ old_loops = glob.compiled_merge_points.setdefault(greenargs, []) self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None) loop = compile.compile_new_loop(self, old_loops, greenkey, start) - assert loop is not None - if not we_are_translated(): + if not we_are_translated() and loop is not None: loop._call_history = self._debug_history return loop From arigo at codespeak.net Fri Sep 18 14:32:19 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 14:32:19 +0200 (CEST) Subject: [pypy-svn] r67759 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090918123219.E106F16801D@codespeak.net> Author: arigo Date: Fri Sep 18 14:32:18 2009 New Revision: 67759 Added: pypy/trunk/pypy/jit/metainterp/history.py.merge.tmp - copied, changed from r67757, pypy/trunk/pypy/jit/metainterp/history.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/optimize-novaluedep/pypy/jit/metainterp/history.py revisions 67718 to 67757: ------------------------------------------------------------------------ r67736 | arigo | 2009-09-17 16:27:08 +0200 (Thu, 17 Sep 2009) | 2 lines (cfbolz, arigo): fix optimizeopt to no longer depend on the .value of boxes. ------------------------------------------------------------------------ r67727 | arigo | 2009-09-17 11:13:19 +0200 (Thu, 17 Sep 2009) | 5 lines Goal-oriented programming! Kill the method nonnull() on Boxes and rename the overloaded method equals() to same_constant(), supposed to work only between Consts. Now the idea is to make optimize*.py still work... ------------------------------------------------------------------------ r67719 | arigo | 2009-09-16 17:27:03 +0200 (Wed, 16 Sep 2009) | 3 lines A branch in which to refactor jit/metainterp/optimize*.py to no longer query the value of the boxes it handles. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/history.py.merge.tmp (from r67757, pypy/trunk/pypy/jit/metainterp/history.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py.merge.tmp Fri Sep 18 14:32:18 2009 @@ -96,9 +96,6 @@ def _get_hash_(self): raise NotImplementedError - def nonnull(self): - raise NotImplementedError - def clonebox(self): raise NotImplementedError @@ -111,9 +108,6 @@ def getaddr(self, cpu): raise NotImplementedError - def equals(self, other): - raise NotImplementedError - def sort_key(self): raise NotImplementedError @@ -172,6 +166,12 @@ def constbox(self): return self + def same_constant(self, other): + raise NotImplementedError + + def nonnull_constant(self): + raise NotImplementedError + def __repr__(self): return 'Const(%s)' % self._getrepr_() @@ -224,15 +224,16 @@ def _get_hash_(self): return self.value - def nonnull(self): - return self.value != 0 - def set_future_value(self, cpu, j): cpu.set_future_value_int(j, self.value) - def equals(self, other): + def same_constant(self, other): + assert isinstance(other, Const) return self.value == other.getint() + def nonnull_constant(self): + return self.value != 0 + def _getrepr_(self): return self.value @@ -270,15 +271,16 @@ def _get_hash_(self): return llmemory.cast_adr_to_int(self.value) - def nonnull(self): - return self.value != llmemory.NULL - def set_future_value(self, cpu, j): cpu.set_future_value_int(j, self.getint()) - def equals(self, other): + def same_constant(self, other): + assert isinstance(other, Const) return self.value == other.getaddr(self.cpu) + def nonnull_constant(self): + return bool(self.value) + def _getrepr_(self): return self.value @@ -308,8 +310,12 @@ def set_future_value(self, cpu, j): cpu.set_future_value_float(j, self.getfloat()) - def equals(self, other): - return self.value == other.getfloat() + def same_constant(self, other): + assert isinstance(other, ConstFloat) + return self.value == other.value + + def nonnull_constant(self): + return self.value != 0.0 def _getrepr_(self): return self.value @@ -344,14 +350,15 @@ def getaddr(self, cpu): return llmemory.cast_ptr_to_adr(self.value) - def nonnull(self): - return bool(self.value) - def set_future_value(self, cpu, j): cpu.set_future_value_ref(j, self.value) - def equals(self, other): - return self.value == other.getref_base() + def same_constant(self, other): + assert isinstance(other, ConstPtr) + return self.value == other.value + + def nonnull_constant(self): + return bool(self.value) _getrepr_ = repr_pointer @@ -390,9 +397,6 @@ else: return 0 - def nonnull(self): - return bool(self.value) - def set_future_value(self, cpu, j): cpu.set_future_value_ref(j, self.value) @@ -402,8 +406,12 @@ ## # real addr, but just a key for the dictionary ## return self.value - def equals(self, other): - return self.value == other.getref_base() + def same_constant(self, other): + assert isinstance(other, ConstObj) + return self.value == other.value + + def nonnull_constant(self): + return bool(self.value) _getrepr_ = repr_object @@ -436,9 +444,6 @@ else: raise NotImplementedError(kind) - def equals(self, other): - return self is other - def nonconstbox(self): return self @@ -494,9 +499,6 @@ def _get_hash_(self): return self.value - def nonnull(self): - return self.value != 0 - def set_future_value(self, cpu, j): cpu.set_future_value_int(j, self.value) @@ -572,9 +574,6 @@ def _get_hash_(self): return lltype.cast_ptr_to_int(self.value) - def nonnull(self): - return bool(self.value) - def set_future_value(self, cpu, j): cpu.set_future_value_ref(j, self.value) @@ -617,9 +616,6 @@ else: return 0 - def nonnull(self): - return bool(self.value) - def set_future_value(self, cpu, j): cpu.set_future_value_ref(j, self.value) From arigo at codespeak.net Fri Sep 18 14:32:23 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 14:32:23 +0200 (CEST) Subject: [pypy-svn] r67760 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090918123223.28F4716801D@codespeak.net> Author: arigo Date: Fri Sep 18 14:32:22 2009 New Revision: 67760 Added: pypy/trunk/pypy/jit/metainterp/test/test_send.py.merge.tmp - copied, changed from r67757, pypy/trunk/pypy/jit/metainterp/test/test_send.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_send.py revisions 67718 to 67757: ------------------------------------------------------------------------ r67744 | arigo | 2009-09-17 19:57:27 +0200 (Thu, 17 Sep 2009) | 4 lines (cfbolz, arigo) Catch the InvalidLoop exception. For now, forces unrolling, which makes again the two long-skipped tests of test_send pass :-) ------------------------------------------------------------------------ r67719 | arigo | 2009-09-16 17:27:03 +0200 (Wed, 16 Sep 2009) | 3 lines A branch in which to refactor jit/metainterp/optimize*.py to no longer query the value of the boxes it handles. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/test/test_send.py.merge.tmp (from r67757, pypy/trunk/pypy/jit/metainterp/test/test_send.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_send.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_send.py.merge.tmp Fri Sep 18 14:32:22 2009 @@ -168,7 +168,6 @@ self.check_loop_count(3) def test_oosend_guard_failure(self): - py.test.skip("Unsupported yet") myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'w']) class Base: pass @@ -201,16 +200,16 @@ assert res == f(3, 28) res = self.meta_interp(f, [4, 28]) assert res == f(4, 28) - # The effect of the ClassGuard generated by the oosend to incr() - # should be to unroll the loop, giving two copies of the body in - # a single bigger loop with no failing guard except the final one. + # This checks that the loop was originally aborted due to an + # InvalidLoop condition, and was then unrolled, giving two copies + # of the body in a single bigger loop with no failing guard except + # the final one. self.check_loop_count(1) self.check_loops(guard_class=0, int_add=2, int_sub=2) self.check_jumps(14) def test_oosend_guard_failure_2(self): - py.test.skip("Unsupported yet") # same as above, but using prebuilt objects 'w1' and 'w2' myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'w']) class Base: @@ -237,6 +236,7 @@ else: w = w2 while y > 0: + myjitdriver.can_enter_jit(x=x, y=y, w=w) myjitdriver.jit_merge_point(x=x, y=y, w=w) w = w.incr() y -= 1 From arigo at codespeak.net Fri Sep 18 14:34:15 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 14:34:15 +0200 (CEST) Subject: [pypy-svn] r67761 - in pypy/trunk/pypy/jit: backend backend/cli backend/llgraph metainterp metainterp/test Message-ID: <20090918123415.8CF0D16801D@codespeak.net> Author: arigo Date: Fri Sep 18 14:34:15 2009 New Revision: 67761 Added: pypy/trunk/pypy/jit/backend/cli/ - copied from r67760, pypy/branch/optimize-novaluedep/pypy/jit/backend/cli/ pypy/trunk/pypy/jit/backend/llgraph/ - copied from r67760, pypy/branch/optimize-novaluedep/pypy/jit/backend/llgraph/ pypy/trunk/pypy/jit/backend/model.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/backend/model.py pypy/trunk/pypy/jit/metainterp/compile.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/executor.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/executor.py pypy/trunk/pypy/jit/metainterp/history.py - copied unchanged from r67760, pypy/trunk/pypy/jit/metainterp/history.py.merge.tmp pypy/trunk/pypy/jit/metainterp/optimize.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimize.py pypy/trunk/pypy/jit/metainterp/optimizefindnode.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizefindnode.py pypy/trunk/pypy/jit/metainterp/optimizeopt.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeopt.py pypy/trunk/pypy/jit/metainterp/optimizeutil.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/optimizeutil.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py - copied unchanged from r67760, pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp pypy/trunk/pypy/jit/metainterp/specnode.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/specnode.py pypy/trunk/pypy/jit/metainterp/test/test_loop_dummy.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_loop_dummy.py pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_optimizeopt.py pypy/trunk/pypy/jit/metainterp/test/test_send.py - copied unchanged from r67760, pypy/trunk/pypy/jit/metainterp/test/test_send.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_specnode.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/test/test_specnode.py pypy/trunk/pypy/jit/metainterp/typesystem.py - copied unchanged from r67760, pypy/branch/optimize-novaluedep/pypy/jit/metainterp/typesystem.py Removed: pypy/trunk/pypy/jit/metainterp/history.py.merge.tmp pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_send.py.merge.tmp Log: Merge the optimize-novaluedep branch: rewrite the optimize*.py files so that it no longer needs to read the .value stored in Boxes. Apart from cleaning up things, this allows a couple of rare bugs to be fixed. From arigo at codespeak.net Fri Sep 18 14:34:58 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 14:34:58 +0200 (CEST) Subject: [pypy-svn] r67762 - pypy/branch/optimize-novaluedep Message-ID: <20090918123458.0051D16801B@codespeak.net> Author: arigo Date: Fri Sep 18 14:34:58 2009 New Revision: 67762 Removed: pypy/branch/optimize-novaluedep/ Log: Remove merged branch. From arigo at codespeak.net Fri Sep 18 15:05:23 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 15:05:23 +0200 (CEST) Subject: [pypy-svn] r67763 - pypy/trunk/pypy/config Message-ID: <20090918130523.9204B168016@codespeak.net> Author: arigo Date: Fri Sep 18 15:05:22 2009 New Revision: 67763 Added: pypy/trunk/pypy/config/translationoption.py.merge.tmp - copied, changed from r67762, pypy/trunk/pypy/config/translationoption.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/asmgcroot-callback/pypy/config/translationoption.py revisions 67691 to 67762: ------------------------------------------------------------------------ r67709 | arigo | 2009-09-16 11:21:10 +0200 (Wed, 16 Sep 2009) | 2 lines Small changes that seem to make threads work on top of asmgcc. ------------------------------------------------------------------------ r67692 | arigo | 2009-09-15 15:38:22 +0200 (Tue, 15 Sep 2009) | 3 lines A branch in which to try to implement callback support in --gcrootfinder=asmgcc. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/config/translationoption.py.merge.tmp (from r67762, pypy/trunk/pypy/config/translationoption.py) ============================================================================== --- pypy/trunk/pypy/config/translationoption.py (original) +++ pypy/trunk/pypy/config/translationoption.py.merge.tmp Fri Sep 18 15:05:22 2009 @@ -79,8 +79,7 @@ requires={ "shadowstack": [("translation.gctransformer", "framework")], "asmgcc": [("translation.gctransformer", "framework"), - ("translation.backend", "c"), - ("translation.thread", False)], + ("translation.backend", "c")], }), # other noticeable options From arigo at codespeak.net Fri Sep 18 15:05:27 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 15:05:27 +0200 (CEST) Subject: [pypy-svn] r67764 - pypy/trunk/pypy/rpython Message-ID: <20090918130527.C55DF168016@codespeak.net> Author: arigo Date: Fri Sep 18 15:05:27 2009 New Revision: 67764 Added: pypy/trunk/pypy/rpython/llinterp.py.merge.tmp - copied, changed from r67762, pypy/trunk/pypy/rpython/llinterp.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/asmgcroot-callback/pypy/rpython/llinterp.py revisions 67691 to 67762: ------------------------------------------------------------------------ r67709 | arigo | 2009-09-16 11:21:10 +0200 (Wed, 16 Sep 2009) | 2 lines Small changes that seem to make threads work on top of asmgcc. ------------------------------------------------------------------------ r67698 | arigo | 2009-09-15 17:29:01 +0200 (Tue, 15 Sep 2009) | 4 lines Improve debugging by crashing with a "clear" error message if the number of stack pieces seen during collection differs from the number of live stack pieces. ------------------------------------------------------------------------ r67697 | arigo | 2009-09-15 17:15:00 +0200 (Tue, 15 Sep 2009) | 3 lines In-progress. Add an operation that turns into a marker in the assembler source, used to know which functions are callbacks from C. ------------------------------------------------------------------------ r67693 | arigo | 2009-09-15 15:41:17 +0200 (Tue, 15 Sep 2009) | 2 lines Change the operations "gc_llvm_*" into a single better-named operation. ------------------------------------------------------------------------ r67692 | arigo | 2009-09-15 15:38:22 +0200 (Tue, 15 Sep 2009) | 3 lines A branch in which to try to implement callback support in --gcrootfinder=asmgcc. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/rpython/llinterp.py.merge.tmp (from r67762, pypy/trunk/pypy/rpython/llinterp.py) ============================================================================== --- pypy/trunk/pypy/rpython/llinterp.py (original) +++ pypy/trunk/pypy/rpython/llinterp.py.merge.tmp Fri Sep 18 15:05:27 2009 @@ -878,6 +878,12 @@ def op_gc_set_max_heap_size(self, maxsize): raise NotImplementedError("gc_set_max_heap_size") + def op_gc_asmgcroot_static(self, index): + raise NotImplementedError("gc_asmgcroot_static") + + def op_gc_stack_bottom(self): + pass # marker for trackgcroot.py + def op_do_malloc_fixedsize_clear(self): raise NotImplementedError("do_malloc_fixedsize_clear") From arigo at codespeak.net Fri Sep 18 15:05:36 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 15:05:36 +0200 (CEST) Subject: [pypy-svn] r67765 - pypy/trunk/pypy/translator/c Message-ID: <20090918130536.E6D59168016@codespeak.net> Author: arigo Date: Fri Sep 18 15:05:35 2009 New Revision: 67765 Added: pypy/trunk/pypy/translator/c/gc.py.merge.tmp - copied, changed from r67762, pypy/trunk/pypy/translator/c/gc.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/asmgcroot-callback/pypy/translator/c/gc.py revisions 67691 to 67762: ------------------------------------------------------------------------ r67705 | arigo | 2009-09-15 21:33:29 +0200 (Tue, 15 Sep 2009) | 4 lines The blame goes to the 'keepalive' operation that was explicitly used in the test. It did not have the correct semantic effect with gcrootfinder=asmgcc... ------------------------------------------------------------------------ r67692 | arigo | 2009-09-15 15:38:22 +0200 (Tue, 15 Sep 2009) | 3 lines A branch in which to try to implement callback support in --gcrootfinder=asmgcc. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/translator/c/gc.py.merge.tmp (from r67762, pypy/trunk/pypy/translator/c/gc.py) ============================================================================== --- pypy/trunk/pypy/translator/c/gc.py (original) +++ pypy/trunk/pypy/translator/c/gc.py.merge.tmp Fri Sep 18 15:05:35 2009 @@ -322,6 +322,9 @@ class AsmGcRootFrameworkGcPolicy(FrameworkGcPolicy): transformerclass = asmgcroot.AsmGcRootFrameworkGCTransformer + def GC_KEEPALIVE(self, funcgen, v): + return 'pypy_asm_keepalive(%s);' % funcgen.expr(v) + name_to_gcpolicy = { 'boehm': BoehmGcPolicy, From arigo at codespeak.net Fri Sep 18 15:05:39 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 15:05:39 +0200 (CEST) Subject: [pypy-svn] r67766 - pypy/trunk/pypy/rpython/lltypesystem Message-ID: <20090918130539.1CF7D168016@codespeak.net> Author: arigo Date: Fri Sep 18 15:05:38 2009 New Revision: 67766 Added: pypy/trunk/pypy/rpython/lltypesystem/lloperation.py.merge.tmp - copied, changed from r67762, pypy/trunk/pypy/rpython/lltypesystem/lloperation.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/lloperation.py revisions 67691 to 67762: ------------------------------------------------------------------------ r67756 | arigo | 2009-09-18 13:58:19 +0200 (Fri, 18 Sep 2009) | 2 lines Uh? Nonsense. ------------------------------------------------------------------------ r67709 | arigo | 2009-09-16 11:21:10 +0200 (Wed, 16 Sep 2009) | 2 lines Small changes that seem to make threads work on top of asmgcc. ------------------------------------------------------------------------ r67697 | arigo | 2009-09-15 17:15:00 +0200 (Tue, 15 Sep 2009) | 3 lines In-progress. Add an operation that turns into a marker in the assembler source, used to know which functions are callbacks from C. ------------------------------------------------------------------------ r67693 | arigo | 2009-09-15 15:41:17 +0200 (Tue, 15 Sep 2009) | 2 lines Change the operations "gc_llvm_*" into a single better-named operation. ------------------------------------------------------------------------ r67692 | arigo | 2009-09-15 15:38:22 +0200 (Tue, 15 Sep 2009) | 3 lines A branch in which to try to implement callback support in --gcrootfinder=asmgcc. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/rpython/lltypesystem/lloperation.py.merge.tmp (from r67762, pypy/trunk/pypy/rpython/lltypesystem/lloperation.py) ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/lloperation.py.merge.tmp Fri Sep 18 15:05:38 2009 @@ -446,13 +446,10 @@ canunwindgc=True), 'gc_x_size_header': LLOp(), - # for llvm.gcroot() support. can change at any time - 'llvm_frameaddress': LLOp(sideeffects=False), - 'llvm_gcmapstart': LLOp(sideeffects=False), - 'llvm_gcmapend': LLOp(sideeffects=False), - 'llvm_gccallshapes': LLOp(sideeffects=False), - 'llvm_store_gcroot': LLOp(), - 'llvm_load_gcroot': LLOp(), + # for asmgcroot support to get the address of various static structures + # see translator/c/src/mem.h for the valid indices + 'gc_asmgcroot_static': LLOp(sideeffects=False), + 'gc_stack_bottom': LLOp(canrun=True), # NOTE NOTE NOTE! don't forget *** canunwindgc=True *** for anything that # can go through a stack unwind, in particular anything that mallocs! From arigo at codespeak.net Fri Sep 18 15:05:42 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 15:05:42 +0200 (CEST) Subject: [pypy-svn] r67767 - pypy/trunk/pypy/rpython/lltypesystem/test Message-ID: <20090918130542.05F99168016@codespeak.net> Author: arigo Date: Fri Sep 18 15:05:42 2009 New Revision: 67767 Added: pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py.merge.tmp - copied, changed from r67762, pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/test/test_lloperation.py revisions 67691 to 67762: ------------------------------------------------------------------------ r67693 | arigo | 2009-09-15 15:41:17 +0200 (Tue, 15 Sep 2009) | 2 lines Change the operations "gc_llvm_*" into a single better-named operation. ------------------------------------------------------------------------ r67692 | arigo | 2009-09-15 15:38:22 +0200 (Tue, 15 Sep 2009) | 3 lines A branch in which to try to implement callback support in --gcrootfinder=asmgcc. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py.merge.tmp (from r67762, pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py) ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py.merge.tmp Fri Sep 18 15:05:42 2009 @@ -63,6 +63,6 @@ for opname, llop in LL_OPERATIONS.items(): if llop.canfold: continue - if opname.startswith('gc_x_') or opname.startswith('llvm_'): + if opname.startswith('gc_x_'): continue # ignore experimental stuff assert opname in LL_INTERP_OPERATIONS From arigo at codespeak.net Fri Sep 18 15:05:47 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 15:05:47 +0200 (CEST) Subject: [pypy-svn] r67768 - pypy/trunk/pypy/rpython/memory/gctransform Message-ID: <20090918130547.0732D168016@codespeak.net> Author: arigo Date: Fri Sep 18 15:05:46 2009 New Revision: 67768 Added: pypy/trunk/pypy/rpython/memory/gctransform/framework.py.merge.tmp - copied, changed from r67762, pypy/trunk/pypy/rpython/memory/gctransform/framework.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/framework.py revisions 67691 to 67762: ------------------------------------------------------------------------ r67709 | arigo | 2009-09-16 11:21:10 +0200 (Wed, 16 Sep 2009) | 2 lines Small changes that seem to make threads work on top of asmgcc. ------------------------------------------------------------------------ r67692 | arigo | 2009-09-15 15:38:22 +0200 (Tue, 15 Sep 2009) | 3 lines A branch in which to try to implement callback support in --gcrootfinder=asmgcc. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/rpython/memory/gctransform/framework.py.merge.tmp (from r67762, pypy/trunk/pypy/rpython/memory/gctransform/framework.py) ============================================================================== --- pypy/trunk/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/trunk/pypy/rpython/memory/gctransform/framework.py.merge.tmp Fri Sep 18 15:05:46 2009 @@ -151,6 +151,7 @@ gcdata.gc = GCClass(translator.config.translation, **GC_PARAMS) root_walker = self.build_root_walker() + self.root_walker = root_walker gcdata.set_query_functions(gcdata.gc) gcdata.gc.set_root_walker(root_walker) self.num_pushs = 0 @@ -377,17 +378,7 @@ # thread support if translator.config.translation.thread: - if not hasattr(root_walker, "need_thread_support"): - raise Exception("%s does not support threads" % ( - root_walker.__class__.__name__,)) - root_walker.need_thread_support() - self.thread_prepare_ptr = getfn(root_walker.thread_prepare, - [], annmodel.s_None) - self.thread_run_ptr = getfn(root_walker.thread_run, - [], annmodel.s_None, - inline=True) - self.thread_die_ptr = getfn(root_walker.thread_die, - [], annmodel.s_None) + root_walker.need_thread_support(self, getfn) self.layoutbuilder.encode_type_shapes_now() @@ -721,15 +712,18 @@ def gct_gc_thread_prepare(self, hop): assert self.translator.config.translation.thread - hop.genop("direct_call", [self.thread_prepare_ptr]) + if hasattr(self.root_walker, 'thread_prepare_ptr'): + hop.genop("direct_call", [self.root_walker.thread_prepare_ptr]) def gct_gc_thread_run(self, hop): assert self.translator.config.translation.thread - hop.genop("direct_call", [self.thread_run_ptr]) + if hasattr(self.root_walker, 'thread_run_ptr'): + hop.genop("direct_call", [self.root_walker.thread_run_ptr]) def gct_gc_thread_die(self, hop): assert self.translator.config.translation.thread - hop.genop("direct_call", [self.thread_die_ptr]) + if hasattr(self.root_walker, 'thread_die_ptr'): + hop.genop("direct_call", [self.root_walker.thread_die_ptr]) def gct_malloc_nonmovable_varsize(self, hop): TYPE = hop.spaceop.result.concretetype @@ -918,6 +912,10 @@ if collect_stack_root: self.walk_stack_roots(collect_stack_root) # abstract + def need_thread_support(self, gctransformer, getfn): + raise Exception("%s does not support threads" % ( + self.__class__.__name__,)) + class ShadowStackRootWalker(BaseRootWalker): need_root_stack = True @@ -976,7 +974,7 @@ if self.collect_stacks_from_other_threads is not None: self.collect_stacks_from_other_threads(collect_stack_root) - def need_thread_support(self): + def need_thread_support(self, gctransformer, getfn): from pypy.module.thread import ll_thread # xxx fish from pypy.rpython.memory.support import AddressDict from pypy.rpython.memory.support import copy_without_null_values @@ -1087,7 +1085,8 @@ gcdata.thread_stacks.foreach(collect_stack, callback) self.thread_setup = thread_setup - self.thread_prepare = thread_prepare - self.thread_run = thread_run - self.thread_die = thread_die + self.thread_prepare_ptr = getfn(thread_prepare, [], annmodel.s_None) + self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None, + inline=True) + self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None) self.collect_stacks_from_other_threads = collect_more_stacks From arigo at codespeak.net Fri Sep 18 15:07:01 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 15:07:01 +0200 (CEST) Subject: [pypy-svn] r67769 - in pypy/trunk/pypy: config module/thread rlib rpython rpython/lltypesystem rpython/lltypesystem/test rpython/memory/gctransform translator/c translator/c/gcc translator/c/src translator/c/test Message-ID: <20090918130701.1050B168016@codespeak.net> Author: arigo Date: Fri Sep 18 15:07:00 2009 New Revision: 67769 Added: pypy/trunk/pypy/config/translationoption.py - copied unchanged from r67768, pypy/trunk/pypy/config/translationoption.py.merge.tmp pypy/trunk/pypy/module/thread/ - copied from r67768, pypy/branch/asmgcroot-callback/pypy/module/thread/ pypy/trunk/pypy/rlib/objectmodel.py - copied unchanged from r67768, pypy/branch/asmgcroot-callback/pypy/rlib/objectmodel.py pypy/trunk/pypy/rpython/llinterp.py - copied unchanged from r67768, pypy/trunk/pypy/rpython/llinterp.py.merge.tmp pypy/trunk/pypy/rpython/lltypesystem/lloperation.py - copied unchanged from r67768, pypy/trunk/pypy/rpython/lltypesystem/lloperation.py.merge.tmp pypy/trunk/pypy/rpython/lltypesystem/opimpl.py - copied unchanged from r67768, pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/opimpl.py pypy/trunk/pypy/rpython/lltypesystem/rffi.py - copied unchanged from r67768, pypy/branch/asmgcroot-callback/pypy/rpython/lltypesystem/rffi.py pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py - copied unchanged from r67768, pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py.merge.tmp pypy/trunk/pypy/rpython/memory/gctransform/asmgcroot.py - copied unchanged from r67768, pypy/branch/asmgcroot-callback/pypy/rpython/memory/gctransform/asmgcroot.py pypy/trunk/pypy/rpython/memory/gctransform/framework.py - copied unchanged from r67768, pypy/trunk/pypy/rpython/memory/gctransform/framework.py.merge.tmp pypy/trunk/pypy/translator/c/funcgen.py - copied unchanged from r67768, pypy/branch/asmgcroot-callback/pypy/translator/c/funcgen.py pypy/trunk/pypy/translator/c/gc.py - copied unchanged from r67768, pypy/trunk/pypy/translator/c/gc.py.merge.tmp pypy/trunk/pypy/translator/c/gcc/ - copied from r67768, pypy/branch/asmgcroot-callback/pypy/translator/c/gcc/ pypy/trunk/pypy/translator/c/src/ - copied from r67768, pypy/branch/asmgcroot-callback/pypy/translator/c/src/ pypy/trunk/pypy/translator/c/test/test_standalone.py - copied unchanged from r67768, pypy/branch/asmgcroot-callback/pypy/translator/c/test/test_standalone.py Removed: pypy/trunk/pypy/config/translationoption.py.merge.tmp pypy/trunk/pypy/rpython/llinterp.py.merge.tmp pypy/trunk/pypy/rpython/lltypesystem/lloperation.py.merge.tmp pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py.merge.tmp pypy/trunk/pypy/rpython/memory/gctransform/framework.py.merge.tmp pypy/trunk/pypy/translator/c/gc.py.merge.tmp Log: Merge 'asmgcroot-callback': This finishes the --gcrootfinder=asmgcc support on x86, by being safe against callbacks and threads. From arigo at codespeak.net Fri Sep 18 15:07:29 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 18 Sep 2009 15:07:29 +0200 (CEST) Subject: [pypy-svn] r67770 - pypy/branch/asmgcroot-callback Message-ID: <20090918130729.A0985168016@codespeak.net> Author: arigo Date: Fri Sep 18 15:07:29 2009 New Revision: 67770 Removed: pypy/branch/asmgcroot-callback/ Log: Remove merged branch. From cfbolz at codespeak.net Fri Sep 18 15:13:35 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 18 Sep 2009 15:13:35 +0200 (CEST) Subject: [pypy-svn] r67771 - in pypy/trunk/pypy/annotation: . test Message-ID: <20090918131335.AB5A2168010@codespeak.net> Author: cfbolz Date: Fri Sep 18 15:13:34 2009 New Revision: 67771 Modified: pypy/trunk/pypy/annotation/specialize.py pypy/trunk/pypy/annotation/test/test_annrpython.py Log: (pedronis, cfbolz): make it possible to use effectively annspecialcase together with *args. Modified: pypy/trunk/pypy/annotation/specialize.py ============================================================================== --- pypy/trunk/pypy/annotation/specialize.py (original) +++ pypy/trunk/pypy/annotation/specialize.py Fri Sep 18 15:13:34 2009 @@ -49,7 +49,7 @@ return graph key = nb_extra_args - name_suffix = '_star%d' % (nb_extra_args,) + name_suffix = '_star%d' % (nb_extra_args,) # xxx kill return flattened_s, key, name_suffix, builder else: @@ -442,6 +442,12 @@ return translator.buildflowgraph(miniglobals['constf']) return constgraphbuilder +def maybe_star_args(funcdesc, key, args_s): + args_s, key1, ignore, builder = flatten_star_args(funcdesc, args_s) + if key1 is not None: + key = key + (key1,) # xxx make sure key1 is already a tuple + return funcdesc.cachedgraph(key, builder=builder) + def specialize_argvalue(funcdesc, args_s, *argindices): from pypy.annotation.model import SomePBC key = [] @@ -456,11 +462,11 @@ raise Exception("specialize:arg(%d): argument not constant: %r" % (i, s)) key = tuple(key) - return funcdesc.cachedgraph(key) + return maybe_star_args(funcdesc, key, args_s) def specialize_argtype(funcdesc, args_s, *argindices): key = tuple([args_s[i].knowntype for i in argindices]) - return funcdesc.cachedgraph(key) + return maybe_star_args(funcdesc, key, args_s) def specialize_arglistitemtype(funcdesc, args_s, i): s = args_s[i] @@ -468,4 +474,4 @@ key = None else: key = s.listdef.listitem.s_value.knowntype - return funcdesc.cachedgraph(key) + return maybe_star_args(funcdesc, key, args_s) Modified: pypy/trunk/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/trunk/pypy/annotation/test/test_annrpython.py (original) +++ pypy/trunk/pypy/annotation/test/test_annrpython.py Fri Sep 18 15:13:34 2009 @@ -1120,6 +1120,30 @@ assert s.items[3].const == 7 assert s.items[4].const == 2 + def test_specialize_and_star_args(self): + class I(object): + def execute(self, op, *args): + if op == 0: + return args[0]+args[1] + if op == 1: + return args[0] * args[1] + args[2] + execute._annspecialcase_ = "specialize:arg(1)" + + def f(x, y): + i = I() + a = i.execute(0, x, y) + b = i.execute(1, y, y, 5) + return a+b + + a = self.RPythonAnnotator() + s = a.build_types(f, [int, int]) + + executedesc = a.bookkeeper.getdesc(I.execute.im_func) + assert len(executedesc._cache) == 2 + + assert len(executedesc._cache[(0, 2)].startblock.inputargs) == 4 + assert len(executedesc._cache[(1, 3)].startblock.inputargs) == 5 + def test_assert_list_doesnt_lose_info(self): class T(object): pass From cfbolz at codespeak.net Fri Sep 18 15:14:31 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 18 Sep 2009 15:14:31 +0200 (CEST) Subject: [pypy-svn] r67772 - pypy/trunk/pypy/annotation Message-ID: <20090918131431.6A2EB168010@codespeak.net> Author: cfbolz Date: Fri Sep 18 15:14:30 2009 New Revision: 67772 Modified: pypy/trunk/pypy/annotation/specialize.py Log: (pedronis, cfbolz): kill commented out old stuff Modified: pypy/trunk/pypy/annotation/specialize.py ============================================================================== --- pypy/trunk/pypy/annotation/specialize.py (original) +++ pypy/trunk/pypy/annotation/specialize.py Fri Sep 18 15:14:30 2009 @@ -322,113 +322,6 @@ for value in lstlst[0]: yield (value,) + tuple_tail -## """NOT_RPYTHON""" -## if len(arglist_s) != 1: -## raise Exception("memo call: only 1 argument functions supported" -## " at the moment (%r)" % (funcdesc,)) -## s, = arglist_s -## from pypy.annotation.model import SomeImpossibleValue -## return memo1(funcdesc, func, s) - -### XXX OBSCURE to support methodmemo()... needs to find something more -### reasonable :-( -##KEY_NUMBERS = {} - -##def memo1(funcdesc, func, s, key='memo1'): -## from pypy.annotation.model import SomeImpossibleValue -## # compute the concrete results and store them directly on the descs, -## # using a strange attribute name -## num = KEY_NUMBERS.setdefault(key, len(KEY_NUMBERS)) -## attrname = '$memo%d_%d_%s' % (uid(funcdesc), num, funcdesc.name) -## for desc in s.descriptions: -## s_result = desc.s_read_attribute(attrname) -## if isinstance(s_result, SomeImpossibleValue): -## # first time we see this 'desc' -## if desc.pyobj is None: -## raise Exception("memo call with a class or PBC that has no " -## "corresponding Python object (%r)" % (desc,)) -## result = func(desc.pyobj) -## desc.create_new_attribute(attrname, result) -## # get or build the graph of the function that reads this strange attr -## def memoized(x, y=None): -## return getattr(x, attrname) -## def builder(translator, func): -## return translator.buildflowgraph(memoized) # instead of 'func' -## return funcdesc.cachedgraph(key, alt_name='memo_%s' % funcdesc.name, -## builder=builder) - -##def methodmemo(funcdesc, arglist_s): -## """NOT_RPYTHON""" -## from pypy.annotation.model import SomePBC, SomeImpossibleValue -## # call the function now, and collect possible results -## for s in arglist_s: -## if not isinstance(s, SomePBC): -## if isinstance(s, SomeImpossibleValue): -## return s # we will probably get more possible args later -## raise Exception("method-memo call: argument must be a class or" -## " a frozen PBC, got %r" % (s,)) -## if len(arglist_s) != 2: -## raise Exception("method-memo call: expected 2 arguments function" -## " at the moment (%r)" % (funcdesc,)) -## from pypy.annotation.model import SomeImpossibleValue -## from pypy.annotation.description import FrozenDesc -## func = funcdesc.pyobj -## if func is None: -## raise Exception("method-memo call: no Python function object to call" -## " (%r)" % (funcdesc,)) -## # compute the concrete results and store them directly on the descs, -## # using a strange attribute name. The goal is to store in the pbcs of -## # 's1' under the common 'attrname' a reader function; each reader function -## # will read a field 'attrname2' from the pbcs of 's2', where 'attrname2' -## # differs for each pbc of 's1'. This is all specialized also -## # considering the type of s1 to support return value -## # polymorphism. -## s1, s2 = arglist_s -## s1_type = s1.knowntype -## if s2.is_constant(): -## return memo1(funcdesc, lambda val1: func(val1, s2.const), -## s1, ('memo1of2', s1_type, Constant(s2.const))) -## memosig = "%d_%d_%s" % (uid(funcdesc), uid(s1_type), funcdesc.name) - -## attrname = '$memoreader%s' % memosig -## for desc1 in s1.descriptions: -## attrname2 = '$memofield%d_%s' % (uid(desc1), memosig) -## s_reader = desc1.s_read_attribute(attrname) -## if isinstance(s_reader, SomeImpossibleValue): -## # first time we see this 'desc1': sanity-check 'desc1' and -## # create its reader function -## assert isinstance(desc1, FrozenDesc), ( -## "XXX not implemented: memo call with a class as first arg") -## if desc1.pyobj is None: -## raise Exception("method-memo call with a class or PBC" -## " that has no " -## "corresponding Python object (%r)" % (desc1,)) -## def reader(y, attrname2=attrname2): -## return getattr(y, attrname2) -## desc1.create_new_attribute(attrname, reader) -## for desc2 in s2.descriptions: -## s_result = desc2.s_read_attribute(attrname2) -## if isinstance(s_result, SomeImpossibleValue): -## # first time we see this 'desc1+desc2' combination -## if desc2.pyobj is None: -## raise Exception("method-memo call with a class or PBC" -## " that has no " -## "corresponding Python object (%r)" % (desc2,)) -## # concrete call, to get the concrete result -## result = func(desc1.pyobj, desc2.pyobj) -## #print 'func(%s, %s) -> %s' % (desc1.pyobj, desc2.pyobj, result) -## #print 'goes into %s.%s'% (desc2,attrname2) -## #print 'with reader %s.%s'% (desc1,attrname) -## desc2.create_new_attribute(attrname2, result) -## # get or build the graph of the function that reads this indirect -## # settings of attributes -## def memoized(x, y): -## reader_fn = getattr(x, attrname) -## return reader_fn(y) -## def builder(translator, func): -## return translator.buildflowgraph(memoized) # instead of 'func' -## return funcdesc.cachedgraph(s1_type, alt_name='memo_%s' % funcdesc.name, -## builder=builder) def make_constgraphbuilder(n, v=None, factory=None, srcmodule=None): def constgraphbuilder(translator, ignore): From cfbolz at codespeak.net Fri Sep 18 15:34:55 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 18 Sep 2009 15:34:55 +0200 (CEST) Subject: [pypy-svn] r67773 - in pypy/trunk/pypy: annotation annotation/test rpython Message-ID: <20090918133455.436C6168010@codespeak.net> Author: cfbolz Date: Fri Sep 18 15:34:53 2009 New Revision: 67773 Modified: pypy/trunk/pypy/annotation/specialize.py pypy/trunk/pypy/annotation/test/test_annrpython.py pypy/trunk/pypy/rpython/annlowlevel.py Log: (pedronis, cfbolz): remove some code that changed the name of some graphs. the default naming is good enough. Modified: pypy/trunk/pypy/annotation/specialize.py ============================================================================== --- pypy/trunk/pypy/annotation/specialize.py (original) +++ pypy/trunk/pypy/annotation/specialize.py Fri Sep 18 15:34:53 2009 @@ -48,16 +48,15 @@ checkgraph(graph) return graph - key = nb_extra_args - name_suffix = '_star%d' % (nb_extra_args,) # xxx kill - return flattened_s, key, name_suffix, builder + key = ('star', nb_extra_args) + return flattened_s, key, builder else: - return args_s, None, '', None + return args_s, None, None def default_specialize(funcdesc, args_s): # first flatten the *args - args_s, key, name_suffix, builder = flatten_star_args(funcdesc, args_s) + args_s, key, builder = flatten_star_args(funcdesc, args_s) # two versions: a regular one and one for instances with 'access_directly' jit_look_inside = getattr(funcdesc.pyobj, '_look_inside_me_', True) # change args_s in place, "official" interface @@ -68,7 +67,6 @@ if jit_look_inside: access_directly = True key = (AccessDirect, key) - name_suffix += '_AccessDirect' break else: new_flags = s_obj.flags.copy() @@ -78,11 +76,7 @@ args_s[i] = new_s_obj # done - if name_suffix: - alt_name = '%s%s' % (funcdesc.name, name_suffix) - else: - alt_name = None - graph = funcdesc.cachedgraph(key, alt_name=alt_name, builder=builder) + graph = funcdesc.cachedgraph(key, builder=builder) if access_directly: graph.access_directly = True return graph @@ -336,9 +330,9 @@ return constgraphbuilder def maybe_star_args(funcdesc, key, args_s): - args_s, key1, ignore, builder = flatten_star_args(funcdesc, args_s) + args_s, key1, builder = flatten_star_args(funcdesc, args_s) if key1 is not None: - key = key + (key1,) # xxx make sure key1 is already a tuple + key = key + key1 return funcdesc.cachedgraph(key, builder=builder) def specialize_argvalue(funcdesc, args_s, *argindices): Modified: pypy/trunk/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/trunk/pypy/annotation/test/test_annrpython.py (original) +++ pypy/trunk/pypy/annotation/test/test_annrpython.py Fri Sep 18 15:34:53 2009 @@ -1141,8 +1141,8 @@ executedesc = a.bookkeeper.getdesc(I.execute.im_func) assert len(executedesc._cache) == 2 - assert len(executedesc._cache[(0, 2)].startblock.inputargs) == 4 - assert len(executedesc._cache[(1, 3)].startblock.inputargs) == 5 + assert len(executedesc._cache[(0, 'star', 2)].startblock.inputargs) == 4 + assert len(executedesc._cache[(1, 'star', 3)].startblock.inputargs) == 5 def test_assert_list_doesnt_lose_info(self): class T(object): Modified: pypy/trunk/pypy/rpython/annlowlevel.py ============================================================================== --- pypy/trunk/pypy/rpython/annlowlevel.py (original) +++ pypy/trunk/pypy/rpython/annlowlevel.py Fri Sep 18 15:34:53 2009 @@ -42,7 +42,7 @@ pol.rtyper = rtyper def lowlevelspecialize(funcdesc, args_s, key_for_args): - args_s, key1, ignored, builder = flatten_star_args(funcdesc, args_s) + args_s, key1, builder = flatten_star_args(funcdesc, args_s) key = [] new_args_s = [] for i, s_obj in enumerate(args_s): From cfbolz at codespeak.net Fri Sep 18 15:37:47 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 18 Sep 2009 15:37:47 +0200 (CEST) Subject: [pypy-svn] r67774 - pypy/branch/execute-star-args-jit Message-ID: <20090918133747.28EFB168010@codespeak.net> Author: cfbolz Date: Fri Sep 18 15:37:46 2009 New Revision: 67774 Added: pypy/branch/execute-star-args-jit/ - copied from r67773, pypy/trunk/ Log: (pedronis, cfbolz): make a branch that tries to make the jit use less memory From cfbolz at codespeak.net Fri Sep 18 16:20:38 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 18 Sep 2009 16:20:38 +0200 (CEST) Subject: [pypy-svn] r67775 - pypy/branch/execute-star-args-jit/pypy/jit/metainterp Message-ID: <20090918142038.260AA168013@codespeak.net> Author: cfbolz Date: Fri Sep 18 16:20:37 2009 New Revision: 67775 Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py Log: (pedronis, cfbolz, arigo around): construct lists a bit later in the metainterp. Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py Fri Sep 18 16:20:37 2009 @@ -235,14 +235,14 @@ exec py.code.Source(''' @arguments("box", "box") def opimpl_%s(self, b1, b2): - self.execute(rop.%s, [b1, b2]) + self.execute(rop.%s, b1, b2) ''' % (_opimpl, _opimpl.upper())).compile() for _opimpl in ['int_add_ovf', 'int_sub_ovf', 'int_mul_ovf']: exec py.code.Source(''' @arguments("box", "box") def opimpl_%s(self, b1, b2): - self.execute(rop.%s, [b1, b2]) + self.execute(rop.%s, b1, b2) return self.metainterp.handle_overflow_error() ''' % (_opimpl, _opimpl.upper())).compile() @@ -254,7 +254,7 @@ exec py.code.Source(''' @arguments("box") def opimpl_%s(self, b): - self.execute(rop.%s, [b]) + self.execute(rop.%s, b) ''' % (_opimpl, _opimpl.upper())).compile() @arguments() @@ -321,50 +321,47 @@ @arguments("descr") def opimpl_new(self, size): - self.execute(rop.NEW, [], descr=size) + self.execute_with_descr(rop.NEW, descr=size) @arguments("constbox") def opimpl_new_with_vtable(self, vtablebox): - self.execute(rop.NEW_WITH_VTABLE, [vtablebox]) + self.execute(rop.NEW_WITH_VTABLE, vtablebox) @arguments("box") def opimpl_runtimenew(self, classbox): - self.execute(rop.RUNTIMENEW, [classbox]) + self.execute(rop.RUNTIMENEW, classbox) @arguments("box", "descr") def opimpl_instanceof(self, box, typedescr): - self.execute(rop.INSTANCEOF, [box], descr=typedescr) + self.execute_with_descr(rop.INSTANCEOF, typedescr, box) @arguments("box", "box") def opimpl_subclassof(self, box1, box2): - self.execute(rop.SUBCLASSOF, [box1, box2], descr=None) + self.execute(rop.SUBCLASSOF, box1, box2) @arguments("box") def opimpl_ooidentityhash(self, box): - self.execute(rop.OOIDENTITYHASH, [box], descr=None) + self.execute(rop.OOIDENTITYHASH, box) @arguments("descr", "box") def opimpl_new_array(self, itemsize, countbox): - self.execute(rop.NEW_ARRAY, [countbox], descr=itemsize) + self.execute_with_descr(rop.NEW_ARRAY, itemsize, countbox) @arguments("box", "descr", "box") def opimpl_getarrayitem_gc(self, arraybox, arraydesc, indexbox): - self.execute(rop.GETARRAYITEM_GC, [arraybox, indexbox], - descr=arraydesc) + self.execute_with_descr(rop.GETARRAYITEM_GC, arraydesc, arraybox, indexbox) @arguments("box", "descr", "box") def opimpl_getarrayitem_gc_pure(self, arraybox, arraydesc, indexbox): - self.execute(rop.GETARRAYITEM_GC_PURE, [arraybox, indexbox], - descr=arraydesc) + self.execute_with_descr(rop.GETARRAYITEM_GC_PURE, arraydesc, arraybox, indexbox) @arguments("box", "descr", "box", "box") def opimpl_setarrayitem_gc(self, arraybox, arraydesc, indexbox, itembox): - self.execute(rop.SETARRAYITEM_GC, [arraybox, indexbox, itembox], - descr=arraydesc) + self.execute_with_descr(rop.SETARRAYITEM_GC, arraydesc, arraybox, indexbox, itembox) @arguments("box", "descr") def opimpl_arraylen_gc(self, arraybox, arraydesc): - self.execute(rop.ARRAYLEN_GC, [arraybox], descr=arraydesc) + self.execute_with_descr(rop.ARRAYLEN_GC, arraydesc, arraybox) @arguments("orgpc", "box", "descr", "box") def opimpl_check_neg_index(self, pc, arraybox, arraydesc, indexbox): @@ -397,16 +394,14 @@ def opimpl_getlistitem_gc(self, listbox, itemsdescr, arraydescr, indexbox): arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, [listbox], descr=itemsdescr) - self.execute(rop.GETARRAYITEM_GC, [arraybox, indexbox], - descr=arraydescr) + self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) @arguments("box", "descr", "descr", "box", "box") def opimpl_setlistitem_gc(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, [listbox], descr=itemsdescr) - self.execute(rop.SETARRAYITEM_GC, [arraybox, indexbox, valuebox], - descr=arraydescr) + self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, valuebox) @arguments("orgpc", "box", "descr", "box") def opimpl_check_resizable_neg_index(self, pc, listbox, lengthdesc, @@ -466,49 +461,49 @@ if nonneg.getint(): self.make_result_box(box) else: - self.execute(rop.INT_NEG, [box]) + self.execute(rop.INT_NEG, box) @arguments("box") def opimpl_ptr_nonzero(self, box): - self.execute(rop.OONONNULL, [box]) + self.execute(rop.OONONNULL, box) @arguments("box") def opimpl_ptr_iszero(self, box): - self.execute(rop.OOISNULL, [box]) + self.execute(rop.OOISNULL, box) opimpl_oononnull = opimpl_ptr_nonzero opimpl_ooisnull = opimpl_ptr_iszero @arguments("box", "box") def opimpl_ptr_eq(self, box1, box2): - self.execute(rop.OOIS, [box1, box2]) + self.execute(rop.OOIS, box1, box2) @arguments("box", "box") def opimpl_ptr_ne(self, box1, box2): - self.execute(rop.OOISNOT, [box1, box2]) + self.execute(rop.OOISNOT, box1, box2) opimpl_oois = opimpl_ptr_eq opimpl_ooisnot = opimpl_ptr_ne @arguments("box", "descr") def opimpl_getfield_gc(self, box, fielddesc): - self.execute(rop.GETFIELD_GC, [box], descr=fielddesc) + self.execute_with_descr(rop.GETFIELD_GC, fielddesc, box) @arguments("box", "descr") def opimpl_getfield_gc_pure(self, box, fielddesc): - self.execute(rop.GETFIELD_GC_PURE, [box], descr=fielddesc) + self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddesc, box) @arguments("box", "descr", "box") def opimpl_setfield_gc(self, box, fielddesc, valuebox): - self.execute(rop.SETFIELD_GC, [box, valuebox], descr=fielddesc) + self.execute_with_descr(rop.SETFIELD_GC, fielddesc, box, valuebox) @arguments("box", "descr") def opimpl_getfield_raw(self, box, fielddesc): - self.execute(rop.GETFIELD_RAW, [box], descr=fielddesc) + self.execute_with_descr(rop.GETFIELD_RAW, fielddesc, box) @arguments("box", "descr") def opimpl_getfield_raw_pure(self, box, fielddesc): - self.execute(rop.GETFIELD_RAW_PURE, [box], descr=fielddesc) + self.execute_with_descr(rop.GETFIELD_RAW_PURE, fielddesc, box) @arguments("box", "descr", "box") def opimpl_setfield_raw(self, box, fielddesc, valuebox): - self.execute(rop.SETFIELD_RAW, [box, valuebox], descr=fielddesc) + self.execute_with_descr(rop.SETFIELD_RAW, fielddesc, box, valuebox) def _nonstandard_virtualizable(self, pc, box): # returns True if 'box' is actually not the "standard" virtualizable @@ -539,8 +534,7 @@ @arguments("orgpc", "box", "int") def opimpl_getfield_vable(self, pc, basebox, index): if self._nonstandard_virtualizable(pc, basebox): - self.execute(rop.GETFIELD_GC, [basebox], - descr=self._get_virtualizable_field_descr(index)) + self.execute_with_descr(rop.GETFIELD_GC, self._get_virtualizable_field_descr(index), basebox) return self.metainterp.check_synchronized_virtualizable() resbox = self.metainterp.virtualizable_boxes[index] @@ -548,8 +542,7 @@ @arguments("orgpc", "box", "int", "box") def opimpl_setfield_vable(self, pc, basebox, index, valuebox): if self._nonstandard_virtualizable(pc, basebox): - self.execute(rop.SETFIELD_GC, [basebox, valuebox], - descr=self._get_virtualizable_field_descr(index)) + self.execute_with_descr(rop.SETFIELD_GC, self._get_virtualizable_field_descr(index), basebox, valuebox) return self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -624,12 +617,12 @@ if jitcode.cfnptr is not None: # for non-oosends varargs = [jitcode.cfnptr] + varargs - res = self.execute_with_exc(rop.CALL, varargs, - descr=jitcode.calldescr) + res = self.execute_varargs(rop.CALL, varargs, + descr=jitcode.calldescr, exc=True) else: # for oosends (ootype only): calldescr is a MethDescr - res = self.execute_with_exc(rop.OOSEND, varargs, - descr=jitcode.calldescr) + res = self.execute_varargs(rop.OOSEND, varargs, + descr=jitcode.calldescr, exc=True) if vi: globaldata.blackhole_virtualizable = vi.null_vable return res @@ -645,7 +638,7 @@ @arguments("descr", "varargs") def opimpl_residual_call(self, calldescr, varargs): - return self.execute_with_exc(rop.CALL, varargs, descr=calldescr) + return self.execute_varargs(rop.CALL, varargs, descr=calldescr, exc=True) @arguments("varargs") def opimpl_recursion_leave_prep(self, varargs): @@ -669,68 +662,18 @@ greenkey = varargs[1:num_green_args + 1] if warmrunnerstate.can_inline_callable(greenkey): return self.perform_call(portal_code, varargs[1:]) - return self.execute_with_exc(rop.CALL, varargs, descr=calldescr) + return self.execute_varargs(rop.CALL, varargs, descr=calldescr, exc=True) @arguments("descr", "varargs") def opimpl_residual_call_noexception(self, calldescr, varargs): if not we_are_translated(): self.metainterp._debug_history.append(['call', varargs[0], varargs[1:]]) - self.execute(rop.CALL, varargs, descr=calldescr) + self.execute_varargs(rop.CALL, varargs, descr=calldescr, exc=False) @arguments("descr", "varargs") def opimpl_residual_call_pure(self, calldescr, varargs): - self.execute(rop.CALL_PURE, varargs, descr=calldescr) - -## @arguments("fixedlist", "box", "box") -## def opimpl_list_getitem(self, descr, listbox, indexbox): -## args = [descr.getfunc, listbox, indexbox] -## return self.execute_with_exc(rop.LIST_GETITEM, args, descr.tp) - -## @arguments("fixedlist", "box", "box", "box") -## def opimpl_list_setitem(self, descr, listbox, indexbox, newitembox): -## args = [descr.setfunc, listbox, indexbox, newitembox] -## return self.execute_with_exc(rop.LIST_SETITEM, args, 'void') - -## @arguments("builtin", "varargs") -## def opimpl_getitem_foldable(self, descr, varargs): -## args = [descr.getfunc] + varargs -## return self.execute_with_exc('getitem', args, descr.tp, True) - -## @arguments("builtin", "varargs") -## def opimpl_setitem_foldable(self, descr, varargs): -## args = [descr.setfunc] + varargs -## return self.execute_with_exc('setitem', args, 'void', True) - -## @arguments("fixedlist", "box", "box") -## def opimpl_newlist(self, descr, countbox, defaultbox): -## args = [descr.malloc_func, countbox, defaultbox] -## return self.execute_with_exc(rop.NEWLIST, args, 'ptr') - -## @arguments("builtin", "varargs") -## def opimpl_append(self, descr, varargs): -## args = [descr.append_func] + varargs -## return self.execute_with_exc('append', args, 'void') - -## @arguments("builtin", "varargs") -## def opimpl_insert(self, descr, varargs): -## args = [descr.insert_func] + varargs -## return self.execute_with_exc('insert', args, 'void') - -## @arguments("builtin", "varargs") -## def opimpl_pop(self, descr, varargs): -## args = [descr.pop_func] + varargs -## return self.execute_with_exc('pop', args, descr.tp) - -## @arguments("builtin", "varargs") -## def opimpl_len(self, descr, varargs): -## args = [descr.len_func] + varargs -## return self.execute_with_exc('len', args, 'int') - -## @arguments("builtin", "varargs") -## def opimpl_listnonzero(self, descr, varargs): -## args = [descr.nonzero_func] + varargs -## return self.execute_with_exc('listnonzero', args, 'int') + self.execute_varargs(rop.CALL_PURE, varargs, descr=calldescr, exc=False) @arguments("orgpc", "indirectcallset", "box", "varargs") @@ -755,55 +698,47 @@ @arguments("box") def opimpl_strlen(self, str): - self.execute(rop.STRLEN, [str]) + self.execute(rop.STRLEN, str) @arguments("box") def opimpl_unicodelen(self, str): - self.execute(rop.UNICODELEN, [str]) + self.execute(rop.UNICODELEN, str) @arguments("box", "box") def opimpl_strgetitem(self, str, index): - self.execute(rop.STRGETITEM, [str, index]) + self.execute(rop.STRGETITEM, str, index) @arguments("box", "box") def opimpl_unicodegetitem(self, str, index): - self.execute(rop.UNICODEGETITEM, [str, index]) + self.execute(rop.UNICODEGETITEM, str, index) @arguments("box", "box", "box") def opimpl_strsetitem(self, str, index, newchar): - self.execute(rop.STRSETITEM, [str, index, newchar]) + self.execute(rop.STRSETITEM, str, index, newchar) @arguments("box", "box", "box") def opimpl_unicodesetitem(self, str, index, newchar): - self.execute(rop.UNICODESETITEM, [str, index, newchar]) + self.execute(rop.UNICODESETITEM, str, index, newchar) @arguments("box") def opimpl_newstr(self, length): - self.execute(rop.NEWSTR, [length]) + self.execute(rop.NEWSTR, length) @arguments("box") def opimpl_newunicode(self, length): - self.execute(rop.NEWUNICODE, [length]) + self.execute(rop.NEWUNICODE, length) @arguments("descr", "varargs") def opimpl_residual_oosend_canraise(self, methdescr, varargs): - return self.execute_with_exc(rop.OOSEND, varargs, descr=methdescr) + return self.execute_varargs(rop.OOSEND, varargs, descr=methdescr, exc=True) @arguments("descr", "varargs") def opimpl_residual_oosend_noraise(self, methdescr, varargs): - self.execute(rop.OOSEND, varargs, descr=methdescr) + self.execute_varargs(rop.OOSEND, varargs, descr=methdescr, exc=False) @arguments("descr", "varargs") def opimpl_residual_oosend_pure(self, methdescr, boxes): - self.execute(rop.OOSEND_PURE, boxes, descr=methdescr) - -# @arguments("box", "box") -# def opimpl_oostring_char(self, obj, base): -# self.execute(rop.OOSTRING_CHAR, [obj, base]) -# -# @arguments("box", "box") -# def opimpl_oounicode_unichar(self, obj, base): -# self.execute(rop.OOUNICODE_UNICHAR, [obj, base]) + self.execute_varargs(rop.OOSEND_PURE, boxes, descr=methdescr, exc=False) @arguments("orgpc", "box") def opimpl_guard_value(self, pc, box): @@ -1010,18 +945,26 @@ return self.metainterp.cpu.ts.cls_of_box(self.metainterp.cpu, box) @specialize.arg(1) - def execute(self, opnum, argboxes, descr=None): - resbox = self.metainterp.execute_and_record(opnum, argboxes, descr) + def execute(self, opnum, *argboxes): + self.execute_with_descr(opnum, None, *argboxes) + + @specialize.arg(1) + def execute_with_descr(self, opnum, descr, *argboxes): + resbox = self.metainterp.execute_and_record(opnum, list(argboxes), descr=descr) if resbox is not None: self.make_result_box(resbox) @specialize.arg(1) - def execute_with_exc(self, opnum, argboxes, descr=None): - self.execute(opnum, argboxes, descr) + def execute_varargs(self, opnum, argboxes, descr, exc): + resbox = self.metainterp.execute_and_record(opnum, list(argboxes), descr=descr) + if resbox is not None: + self.make_result_box(resbox) if not we_are_translated(): self.metainterp._debug_history.append(['call', argboxes[0], argboxes[1:]]) - return self.metainterp.handle_exception() + if exc: + return self.metainterp.handle_exception() + return False # ____________________________________________________________ From antocuni at codespeak.net Fri Sep 18 16:47:46 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 18 Sep 2009 16:47:46 +0200 (CEST) Subject: [pypy-svn] r67776 - in pypy/trunk/pypy/jit/backend: . cli llgraph Message-ID: <20090918144746.719A8168015@codespeak.net> Author: antocuni Date: Fri Sep 18 16:47:45 2009 New Revision: 67776 Modified: pypy/trunk/pypy/jit/backend/cli/runner.py pypy/trunk/pypy/jit/backend/llgraph/runner.py pypy/trunk/pypy/jit/backend/model.py Log: turn typedescr2classbox into a non static method. This fixes translation Modified: pypy/trunk/pypy/jit/backend/cli/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/runner.py (original) +++ pypy/trunk/pypy/jit/backend/cli/runner.py Fri Sep 18 16:47:45 2009 @@ -86,8 +86,7 @@ T1, _ = T._lookup_field(fieldname) return FieldDescr.new(T1, fieldname) - @staticmethod - def typedescr2classbox(descr): + def typedescr2classbox(self, descr): assert isinstance(descr, TypeDescr) return ConstObj(ootype.cast_to_object(descr.ooclass)) Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/runner.py Fri Sep 18 16:47:45 2009 @@ -507,8 +507,7 @@ TYPE = A.ITEM return TypeDescr.new(TYPE) - @staticmethod - def typedescr2classbox(descr): + def typedescr2classbox(self, descr): assert isinstance(descr, TypeDescr) return history.ConstObj(ootype.cast_to_object( ootype.runtimeClass(descr.TYPE))) Modified: pypy/trunk/pypy/jit/backend/model.py ============================================================================== --- pypy/trunk/pypy/jit/backend/model.py (original) +++ pypy/trunk/pypy/jit/backend/model.py Fri Sep 18 16:47:45 2009 @@ -185,6 +185,5 @@ def do_instanceof(self, args, descr=None): raise NotImplementedError - @staticmethod - def typedescr2classbox(descr): + def typedescr2classbox(self, descr): raise NotImplementedError From cfbolz at codespeak.net Fri Sep 18 17:21:45 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 18 Sep 2009 17:21:45 +0200 (CEST) Subject: [pypy-svn] r67777 - pypy/branch/execute-star-args-jit/pypy/jit/metainterp Message-ID: <20090918152145.2E9C616801E@codespeak.net> Author: cfbolz Date: Fri Sep 18 17:21:44 2009 New Revision: 67777 Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resume.py Log: (pedronis, cfbolz, arigo) Progress in making *arg versions of the functions. Not finished yet. Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py Fri Sep 18 17:21:44 2009 @@ -366,62 +366,61 @@ @arguments("orgpc", "box", "descr", "box") def opimpl_check_neg_index(self, pc, arraybox, arraydesc, indexbox): negbox = self.metainterp.execute_and_record( - rop.INT_LT, [indexbox, ConstInt(0)]) + rop.INT_LT, None, indexbox, ConstInt(0)) # xxx inefficient negbox = self.implement_guard_value(pc, negbox) if negbox.getint(): # the index is < 0; add the array length to it lenbox = self.metainterp.execute_and_record( - rop.ARRAYLEN_GC, [arraybox], descr=arraydesc) + rop.ARRAYLEN_GC, arraydesc, arraybox) indexbox = self.metainterp.execute_and_record( - rop.INT_ADD, [indexbox, lenbox]) + rop.INT_ADD, None, indexbox, lenbox) self.make_result_box(indexbox) @arguments("descr", "descr", "descr", "descr", "box") def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): - sbox = self.metainterp.execute_and_record(rop.NEW, [], - descr=structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, [sbox, sizebox], - descr=lengthdescr) - abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, [sizebox], - descr=arraydescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, [sbox, abox], - descr=itemsdescr) + sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) + self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, + sbox, sizebox) + abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, + sizebox) + self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, + sbox, abox) self.make_result_box(sbox) @arguments("box", "descr", "descr", "box") def opimpl_getlistitem_gc(self, listbox, itemsdescr, arraydescr, indexbox): arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - [listbox], descr=itemsdescr) + itemsdescr, listbox) self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) @arguments("box", "descr", "descr", "box", "box") def opimpl_setlistitem_gc(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - [listbox], descr=itemsdescr) + itemsdescr, listbox) self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, valuebox) @arguments("orgpc", "box", "descr", "box") def opimpl_check_resizable_neg_index(self, pc, listbox, lengthdesc, indexbox): negbox = self.metainterp.execute_and_record( - rop.INT_LT, [indexbox, ConstInt(0)]) + rop.INT_LT, None, indexbox, ConstInt(0)) # xxx inefficient negbox = self.implement_guard_value(pc, negbox) if negbox.getint(): # the index is < 0; add the array length to it lenbox = self.metainterp.execute_and_record( - rop.GETFIELD_GC, [listbox], descr=lengthdesc) + rop.GETFIELD_GC, lengthdesc, listbox) indexbox = self.metainterp.execute_and_record( - rop.INT_ADD, [indexbox, lenbox]) + rop.INT_ADD, None, indexbox, lenbox) self.make_result_box(indexbox) @arguments("orgpc", "box") def opimpl_check_zerodivisionerror(self, pc, box): nonzerobox = self.metainterp.execute_and_record( - rop.INT_NE, [box, ConstInt(0)]) + rop.INT_NE, None, box, ConstInt(0)) # xxx inefficient nonzerobox = self.implement_guard_value(pc, nonzerobox) if nonzerobox.getint(): @@ -435,11 +434,11 @@ # detect the combination "box1 = -sys.maxint-1, box2 = -1". import sys tmp1 = self.metainterp.execute_and_record( # combination to detect: - rop.INT_ADD, [box1, ConstInt(sys.maxint)]) # tmp1=-1, box2=-1 + rop.INT_ADD, None, box1, ConstInt(sys.maxint)) # tmp1=-1, box2=-1 tmp2 = self.metainterp.execute_and_record( - rop.INT_AND, [tmp1, box2]) # tmp2=-1 + rop.INT_AND, None, tmp1, box2) # tmp2=-1 tmp3 = self.metainterp.execute_and_record( - rop.INT_EQ, [tmp2, ConstInt(-1)]) # tmp3? + rop.INT_EQ, None, tmp2, ConstInt(-1)) # tmp3? # xxx inefficient tmp4 = self.implement_guard_value(pc, tmp3) # tmp4? if not tmp4.getint(): @@ -455,7 +454,7 @@ @arguments("orgpc", "box") def opimpl_int_abs(self, pc, box): nonneg = self.metainterp.execute_and_record( - rop.INT_GE, [box, ConstInt(0)]) + rop.INT_GE, None, box, ConstInt(0)) # xxx inefficient nonneg = self.implement_guard_value(pc, nonneg) if nonneg.getint(): @@ -511,8 +510,8 @@ standard_box = self.metainterp.virtualizable_boxes[-1] if standard_box is box: return False - eqbox = self.metainterp.execute_and_record(rop.OOIS, - [box, standard_box]) + eqbox = self.metainterp.execute_and_record(rop.OOIS, None, + box, standard_box) eqbox = self.implement_guard_value(pc, eqbox) isstandard = eqbox.getint() if isstandard: @@ -562,12 +561,12 @@ @arguments("orgpc", "box", "int", "box") def opimpl_getarrayitem_vable(self, pc, basebox, arrayindex, indexbox): if self._nonstandard_virtualizable(pc, basebox): - arraybox = self.metainterp.execute_and_record( - rop.GETFIELD_GC, [basebox], - descr=self._get_virtualizable_array_field_descr(arrayindex)) - self.execute( - rop.GETARRAYITEM_GC, [arraybox, indexbox], - descr=self._get_virtualizable_array_descr(arrayindex)) + descr = self._get_virtualizable_array_field_descr(arrayindex) + arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, + descr, basebox) + descr = self._get_virtualizable_array_descr(arrayindex) + self.execute_with_descr(rop.GETARRAYITEM_GC, descr, + arraybox, indexbox) return self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, arrayindex, indexbox) @@ -577,12 +576,12 @@ def opimpl_setarrayitem_vable(self, pc, basebox, arrayindex, indexbox, valuebox): if self._nonstandard_virtualizable(pc, basebox): - arraybox = self.metainterp.execute_and_record( - rop.GETFIELD_GC, [basebox], - descr=self._get_virtualizable_array_field_descr(arrayindex)) - self.execute( - rop.SETARRAYITEM_GC, [arraybox, indexbox, valuebox], - descr=self._get_virtualizable_array_descr(arrayindex)) + descr = self._get_virtualizable_array_field_descr(arrayindex) + arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, + descr, basebox) + descr = self._get_virtualizable_array_descr(arrayindex) + self.execute_with_descr(rop.SETARRAYITEM_GC, descr, + arraybox, indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, arrayindex, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox @@ -591,12 +590,11 @@ @arguments("orgpc", "box", "int") def opimpl_arraylen_vable(self, pc, basebox, arrayindex): if self._nonstandard_virtualizable(pc, basebox): - arraybox = self.metainterp.execute_and_record( - rop.GETFIELD_GC, [basebox], - descr=self._get_virtualizable_array_field_descr(arrayindex)) - self.execute( - rop.ARRAYLEN_GC, [arraybox], - descr=self._get_virtualizable_array_descr(arrayindex)) + descr = self._get_virtualizable_array_field_descr(arrayindex) + arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, + descr, basebox) + descr = self._get_virtualizable_array_descr(arrayindex) + self.execute_with_descr(rop.ARRAYLEN_GC, descr, arraybox) return vinfo = self.metainterp.staticdata.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] @@ -950,13 +948,14 @@ @specialize.arg(1) def execute_with_descr(self, opnum, descr, *argboxes): - resbox = self.metainterp.execute_and_record(opnum, list(argboxes), descr=descr) + resbox = self.metainterp.execute_and_record(opnum, descr, *argboxes) if resbox is not None: self.make_result_box(resbox) @specialize.arg(1) def execute_varargs(self, opnum, argboxes, descr, exc): - resbox = self.metainterp.execute_and_record(opnum, list(argboxes), descr=descr) + resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes, + descr=descr) if resbox is not None: self.make_result_box(resbox) if not we_are_translated(): @@ -1200,7 +1199,21 @@ return True @specialize.arg(1) - def execute_and_record(self, opnum, argboxes, descr=None): + def execute_and_record(self, opnum, descr, *argboxes): + history.check_descr(descr) + assert opnum != rop.CALL and opnum != rop.OOSEND + # execute the operation + profiler = self.staticdata.profiler + profiler.count_ops(opnum) + resbox = executor.execute(self.cpu, opnum, list(argboxes), descr) + if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: + return self._record_helper_pure(opnum, resbox, descr, *argboxes) + else: + return self._record_helper_nonpure_varargs(opnum, resbox, descr, + list(argboxes)) + + @specialize.arg(1) + def execute_and_record_varargs(self, opnum, argboxes, descr=None): history.check_descr(descr) # residual calls require attention to keep virtualizables in-sync. # CALL_PURE doesn't need it because so far 'promote_virtualizable' @@ -1209,32 +1222,45 @@ if require_attention: self.before_residual_call() # execute the operation + profiler = self.staticdata.profiler + profiler.count_ops(opnum) resbox = executor.execute(self.cpu, opnum, argboxes, descr) if require_attention: require_attention = self.after_residual_call() # check if the operation can be constant-folded away - canfold = False if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: - # this part disappears if execute() is specialized for an - # opnum that is not within the range - canfold = self._all_constants(argboxes) - if canfold: - resbox = resbox.constbox() # ensure it is a Const - else: - resbox = resbox.nonconstbox() # ensure it is a Box + resbox = self._record_helper_pure_varargs(opnum, resbox, descr, argboxes) else: - assert resbox is None or isinstance(resbox, Box) - profiler = self.staticdata.profiler - profiler.count_ops(opnum) - # record the operation if not constant-folded away - if not canfold: - op = self.history.record(opnum, argboxes, resbox, descr) - profiler.count_ops(opnum, self.history.OPS_KIND) - self.attach_debug_info(op) + resbox = self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes) if require_attention: self.after_generate_residual_call() return resbox + def _record_helper_pure(self, opnum, resbox, descr, *argboxes): + canfold = self._all_constants(list(argboxes)) # xxx not list() + if canfold: + resbox = resbox.constbox() # ensure it is a Const + return resbox + else: + resbox = resbox.nonconstbox() # ensure it is a Box + return self._record_helper_nonpure_varargs(opnum, resbox, descr, list(argboxes)) + + def _record_helper_pure_varargs(self, opnum, resbox, descr, argboxes): + canfold = self._all_constants(argboxes) + if canfold: + resbox = resbox.constbox() # ensure it is a Const + return resbox + else: + resbox = resbox.nonconstbox() # ensure it is a Box + return self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes) + + def _record_helper_nonpure_varargs(self, opnum, resbox, descr, argboxes): + assert resbox is None or isinstance(resbox, Box) + # record the operation + op = self.history.record(opnum, argboxes, resbox, descr) + self.attach_debug_info(op) + return resbox + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1692,18 +1718,19 @@ if vinfo is not None: vbox = self.virtualizable_boxes[-1] for i in range(vinfo.num_static_extra_boxes): - fieldbox = self.execute_and_record(rop.GETFIELD_GC, [vbox], - descr=vinfo.static_field_descrs[i]) + descr = vinfo.static_field_descrs[i] + fieldbox = self.execute_and_record(rop.GETFIELD_GC, descr, + vbox) self.virtualizable_boxes[i] = fieldbox i = vinfo.num_static_extra_boxes virtualizable = vinfo.unwrap_virtualizable_box(vbox) for k in range(vinfo.num_arrays): - abox = self.execute_and_record(rop.GETFIELD_GC, [vbox], - descr=vinfo.array_field_descrs[k]) + descr = vinfo.array_field_descrs[k] + abox = self.execute_and_record(rop.GETFIELD_GC, descr, vbox) + descr = vinfo.array_descrs[k] for j in range(vinfo.get_array_length(virtualizable, k)): itembox = self.execute_and_record(rop.GETARRAYITEM_GC, - [abox, ConstInt(j)], - descr=vinfo.array_descrs[k]) + descr, abox, ConstInt(j)) self.virtualizable_boxes[i] = itembox i += 1 assert i + 1 == len(self.virtualizable_boxes) @@ -1715,19 +1742,19 @@ vbox = self.virtualizable_boxes[-1] for i in range(vinfo.num_static_extra_boxes): fieldbox = self.virtualizable_boxes[i] - self.execute_and_record(rop.SETFIELD_GC, [vbox, fieldbox], - descr=vinfo.static_field_descrs[i]) + descr = vinfo.static_field_descrs[i] + self.execute_and_record(rop.SETFIELD_GC, descr, vbox, fieldbox) i = vinfo.num_static_extra_boxes virtualizable = vinfo.unwrap_virtualizable_box(vbox) for k in range(vinfo.num_arrays): - abox = self.execute_and_record(rop.GETFIELD_GC, [vbox], - descr=vinfo.array_field_descrs[k]) + descr = vinfo.array_field_descrs[k] + abox = self.execute_and_record(rop.GETFIELD_GC, descr, vbox) + descr = vinfo.array_descrs[k] for j in range(vinfo.get_array_length(virtualizable, k)): itembox = self.virtualizable_boxes[i] i += 1 - self.execute_and_record(rop.SETARRAYITEM_GC, - [abox, ConstInt(j), itembox], - descr=vinfo.array_descrs[k]) + self.execute_and_record(rop.SETARRAYITEM_GC, descr, + abox, ConstInt(j), itembox) assert i + 1 == len(self.virtualizable_boxes) def gen_store_back_in_virtualizable_no_perform(self): Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resume.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resume.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resume.py Fri Sep 18 17:21:44 2009 @@ -153,8 +153,8 @@ for i in range(len(self.fielddescrs)): fieldbox = fn_decode_box(self.fieldnums[i]) metainterp.execute_and_record(rop.SETFIELD_GC, - [box, fieldbox], - descr=self.fielddescrs[i]) + self.fielddescrs[i], + box, fieldbox) class VirtualInfo(AbstractVirtualStructInfo): def __init__(self, known_class, fielddescrs): @@ -163,7 +163,7 @@ def allocate(self, metainterp): return metainterp.execute_and_record(rop.NEW_WITH_VTABLE, - [self.known_class]) + None, self.known_class) def repr_rpython(self): return 'VirtualInfo("%s", %s, %s)' % ( @@ -177,8 +177,7 @@ self.typedescr = typedescr def allocate(self, metainterp): - return metainterp.execute_and_record(rop.NEW, [], - descr=self.typedescr) + return metainterp.execute_and_record(rop.NEW, self.typedescr) def repr_rpython(self): return 'VStructInfo("%s", %s, %s)' % ( @@ -194,15 +193,15 @@ def allocate(self, metainterp): length = len(self.fieldnums) return metainterp.execute_and_record(rop.NEW_ARRAY, - [ConstInt(length)], - descr=self.arraydescr) + self.arraydescr, + ConstInt(length)) def setfields(self, metainterp, box, fn_decode_box): for i in range(len(self.fieldnums)): itembox = fn_decode_box(self.fieldnums[i]) metainterp.execute_and_record(rop.SETARRAYITEM_GC, - [box, ConstInt(i), itembox], - descr=self.arraydescr) + self.arraydescr, + box, ConstInt(i), itembox) def repr_rpython(self): return 'VArrayInfo("%s", %s)' % (self.arraydescr, From cfbolz at codespeak.net Fri Sep 18 17:38:12 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 18 Sep 2009 17:38:12 +0200 (CEST) Subject: [pypy-svn] r67778 - in pypy/branch/execute-star-args-jit/pypy/jit/metainterp: . test Message-ID: <20090918153812.D741716801B@codespeak.net> Author: cfbolz Date: Fri Sep 18 17:38:12 2009 New Revision: 67778 Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_resume.py Log: (arigo, pedronis, cfbolz) Fixes for tests, and unroll _all_constants to avoid making a list. Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py Fri Sep 18 17:38:12 2009 @@ -664,9 +664,6 @@ @arguments("descr", "varargs") def opimpl_residual_call_noexception(self, calldescr, varargs): - if not we_are_translated(): - self.metainterp._debug_history.append(['call', - varargs[0], varargs[1:]]) self.execute_varargs(rop.CALL, varargs, descr=calldescr, exc=False) @arguments("descr", "varargs") @@ -959,6 +956,8 @@ if resbox is not None: self.make_result_box(resbox) if not we_are_translated(): + # this assumes that execute_varargs() is only used for calls, + # which is the case so far self.metainterp._debug_history.append(['call', argboxes[0], argboxes[1:]]) if exc: @@ -1192,7 +1191,12 @@ if self.staticdata.stats is not None: self.staticdata.stats.history = self.history - def _all_constants(self, boxes): + def _all_constants(self, *boxes): + if len(boxes) == 0: + return True + return isinstance(boxes[0], Const) and self._all_constants(*boxes[1:]) + + def _all_constants_varargs(self, boxes): for box in boxes: if not isinstance(box, Const): return False @@ -1237,7 +1241,7 @@ return resbox def _record_helper_pure(self, opnum, resbox, descr, *argboxes): - canfold = self._all_constants(list(argboxes)) # xxx not list() + canfold = self._all_constants(*argboxes) if canfold: resbox = resbox.constbox() # ensure it is a Const return resbox @@ -1246,7 +1250,7 @@ return self._record_helper_nonpure_varargs(opnum, resbox, descr, list(argboxes)) def _record_helper_pure_varargs(self, opnum, resbox, descr, argboxes): - canfold = self._all_constants(argboxes) + canfold = self._all_constants_varargs(argboxes) if canfold: resbox = resbox.constbox() # ensure it is a Const return resbox Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_resume.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_resume.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_resume.py Fri Sep 18 17:38:12 2009 @@ -61,7 +61,7 @@ def __init__(self, cpu): self.cpu = cpu self.trace = [] - def execute_and_record(self, opnum, argboxes, descr=None): + def execute_and_record(self, opnum, descr, *argboxes): resbox = executor.execute(self.cpu, opnum, argboxes, descr) self.trace.append((opnum, [box.value for box in argboxes], From cfbolz at codespeak.net Fri Sep 18 18:44:59 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 18 Sep 2009 18:44:59 +0200 (CEST) Subject: [pypy-svn] r67779 - in pypy/branch/execute-star-args-jit/pypy/jit/metainterp: . test Message-ID: <20090918164459.E91FE16801B@codespeak.net> Author: cfbolz Date: Fri Sep 18 18:44:58 2009 New Revision: 67779 Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/history.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_virtualizable.py Log: (pedronis, arigo, cfbolz): change the way the black hole is implemented: if in blackholing mode, the history on the metainterp is simply None. clarify some code as well. Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/history.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/history.py Fri Sep 18 18:44:58 2009 @@ -757,28 +757,16 @@ # ____________________________________________________________ -class RunningMatcher(Base): +class History(Base): def __init__(self, cpu): self.cpu = cpu self.inputargs = None self.operations = [] def record(self, opnum, argboxes, resbox, descr=None): - raise NotImplementedError - -class History(RunningMatcher): - OPS_KIND = RECORDED_OPS - extratext = '' - def record(self, opnum, argboxes, resbox, descr=None): op = ResOperation(opnum, argboxes, resbox, descr) self.operations.append(op) return op -class BlackHole(RunningMatcher): - OPS_KIND = BLACKHOLED_OPS - extratext = ' (BlackHole)' - def record(self, opnum, argboxes, resbox, descr=None): - return None - # ____________________________________________________________ Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py Fri Sep 18 18:44:58 2009 @@ -762,31 +762,30 @@ pass # xxx? def generate_merge_point(self, pc, varargs): - if self.metainterp.is_blackholing(): - if self.metainterp.in_recursion: - portal_code = self.metainterp.staticdata.portal_code - # small hack: fish for the result box - lenenv = len(self.env) - raised = self.perform_call(portal_code, varargs) - # in general this cannot be assumed, but when blackholing, - # perform_call returns True only if an exception is called. In - # this case perform_call has called finishframe_exception - # already, so we need to return. - if raised: - return True - if lenenv == len(self.env): - res = None - else: - assert lenenv == len(self.env) - 1 - res = self.env.pop() - self.metainterp.finishframe(res) - return True - else: - raise self.metainterp.staticdata.ContinueRunningNormally(varargs) num_green_args = self.metainterp.staticdata.num_green_args for i in range(num_green_args): varargs[i] = self.implement_guard_value(pc, varargs[i]) - return False + + def blackhole_reached_merge_point(self, varargs): + if self.metainterp.in_recursion: + portal_code = self.metainterp.staticdata.portal_code + # small hack: fish for the result box + lenenv = len(self.env) + raised = self.perform_call(portal_code, varargs) + # in general this cannot be assumed, but when blackholing, + # perform_call returns True only if an exception is called. In + # this case perform_call has called finishframe_exception + # already, so we need to return. + if raised: + return + if lenenv == len(self.env): + res = None + else: + assert lenenv == len(self.env) - 1 + res = self.env.pop() + self.metainterp.finishframe(res) + else: + raise self.metainterp.staticdata.ContinueRunningNormally(varargs) @arguments("orgpc") def opimpl_can_enter_jit(self, pc): @@ -801,13 +800,17 @@ @arguments("orgpc") def opimpl_jit_merge_point(self, pc): - res = self.generate_merge_point(pc, self.env) - if DEBUG > 0: - self.debug_merge_point() - if self.metainterp.seen_can_enter_jit: - self.metainterp.seen_can_enter_jit = False - self.metainterp.reached_can_enter_jit(self.env) - return res + if self.metainterp.is_blackholing(): + self.blackhole_reached_merge_point(self.env) + return True + else: + self.generate_merge_point(pc, self.env) + if DEBUG > 0: + self.debug_merge_point() + if self.metainterp.seen_can_enter_jit: + self.metainterp.seen_can_enter_jit = False + self.metainterp.reached_can_enter_jit(self.env) + return False def debug_merge_point(self): # debugging: produce a DEBUG_MERGE_POINT operation @@ -1089,7 +1092,13 @@ self._debug_history = staticdata.globaldata._debug_history def is_blackholing(self): - return isinstance(self.history, history.BlackHole) + return self.history is None + + def blackholing_text(self): + if self.history is None: + return " (BlackHole)" + else: + return "" def newframe(self, jitcode): if not we_are_translated(): @@ -1210,6 +1219,8 @@ profiler = self.staticdata.profiler profiler.count_ops(opnum) resbox = executor.execute(self.cpu, opnum, list(argboxes), descr) + if self.is_blackholing(): + return resbox if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: return self._record_helper_pure(opnum, resbox, descr, *argboxes) else: @@ -1223,19 +1234,21 @@ # CALL_PURE doesn't need it because so far 'promote_virtualizable' # as an operation is enough to make the called function non-pure. require_attention = (opnum == rop.CALL or opnum == rop.OOSEND) - if require_attention: + if require_attention and not self.is_blackholing(): self.before_residual_call() # execute the operation profiler = self.staticdata.profiler profiler.count_ops(opnum) resbox = executor.execute(self.cpu, opnum, argboxes, descr) - if require_attention: - require_attention = self.after_residual_call() - # check if the operation can be constant-folded away - if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: - resbox = self._record_helper_pure_varargs(opnum, resbox, descr, argboxes) - else: - resbox = self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes) + if not self.is_blackholing(): + if require_attention: + require_attention = self.after_residual_call() + # check if the operation can be constant-folded away + if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: + resbox = self._record_helper_pure_varargs(opnum, resbox, descr, argboxes) + else: + resbox = self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes) + # if we are blackholing require_attention has the initial meaning if require_attention: self.after_generate_residual_call() return resbox @@ -1275,12 +1288,12 @@ if not self.is_blackholing(): warmrunnerstate = self.staticdata.state if len(self.history.operations) > warmrunnerstate.trace_limit: - self.history = history.BlackHole(self.cpu) + self.history = None # start blackholing if not we_are_translated(): self.staticdata.stats.aborted_count += 1 - history.log.event('ABORTING TRACING' + self.history.extratext) + history.log.event('ABORTING TRACING') elif DEBUG: - debug_print('~~~ ABORTING TRACING', self.history.extratext) + debug_print('~~~ ABORTING TRACING') self.staticdata.profiler.end_tracing() self.staticdata.profiler.start_blackhole() @@ -1288,10 +1301,10 @@ # Execute the frames forward until we raise a DoneWithThisFrame, # a ContinueRunningNormally, or a GenerateMergePoint exception. if not we_are_translated(): - history.log.event('ENTER' + self.history.extratext) + history.log.event('ENTER' + self.blackholing_text()) self.staticdata.stats.enter_count += 1 elif DEBUG: - debug_print('~~~ ENTER', self.history.extratext) + debug_print('~~~ ENTER', self.blackholing_text()) try: while True: self.framestack[-1].run_one_step() @@ -1304,9 +1317,9 @@ else: self.staticdata.profiler.end_tracing() if not we_are_translated(): - history.log.event('LEAVE' + self.history.extratext) + history.log.event('LEAVE' + self.blackholing_text()) elif DEBUG: - debug_print('~~~ LEAVE', self.history.extratext) + debug_print('~~~ LEAVE', self.blackholing_text()) def interpret(self): if we_are_translated(): @@ -1597,9 +1610,7 @@ self.staticdata.profiler.start_tracing() else: self.staticdata.profiler.start_blackhole() - self.history = history.BlackHole(self.cpu) - # the BlackHole is invalid because it doesn't start with - # guard_failure.key.guard_op.suboperations, but that's fine + self.history = None # this means that is_blackholing() is true self.rebuild_state_after_failure(resumedescr, guard_failure.args) return resumedescr @@ -1643,9 +1654,8 @@ # as it contains the old values (before the call)! self.gen_store_back_in_virtualizable_no_perform() return True # must call after_generate_residual_call() - # xxx don't call after_generate_residual_call() or - # in the case of blackholing abuse it to resynchronize - return self.is_blackholing() + # otherwise, don't call after_generate_residual_call() + return False def after_generate_residual_call(self): # Called after generating a residual call, and only if Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_virtualizable.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_virtualizable.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_virtualizable.py Fri Sep 18 18:44:58 2009 @@ -909,6 +909,8 @@ somewhere_else = SomewhereElse() def g(frame): + assert frame.x == 2 + assert frame.y == 52 frame.y += 100 def f(n): @@ -928,6 +930,42 @@ assert res == 155 self.check_loops(getfield_gc=0, setfield_gc=0) + def test_blackhole_should_synchronize(self): + myjitdriver = JitDriver(greens = [], reds = ['frame'], + virtualizables = ['frame']) + + class Frame(object): + _virtualizable2_ = ['x', 'y'] + + def __init__(self, x, y): + self.x = x + self.y = y + + class SomewhereElse: + pass + somewhere_else = SomewhereElse() + + def g(frame): + assert frame.x == 2 + assert frame.y == 52 + frame.y += 100 + + def f(n): + frame = Frame(n, 0) + somewhere_else.top_frame = frame # escapes + while frame.x > 0: + myjitdriver.can_enter_jit(frame=frame) + myjitdriver.jit_merge_point(frame=frame) + if frame.x == 2: + g(frame) + frame.y += frame.x + frame.x -= 1 + return somewhere_else.top_frame.y + + res = self.meta_interp(f, [10]) + assert res == 155 + self.check_loops(getfield_gc=0, setfield_gc=0) + def test_blackhole_should_not_reenter(self): from pypy.jit.backend.test.support import BaseCompiledMixin if isinstance(self, BaseCompiledMixin): From iko at codespeak.net Fri Sep 18 22:39:18 2009 From: iko at codespeak.net (iko at codespeak.net) Date: Fri, 18 Sep 2009 22:39:18 +0200 (CEST) Subject: [pypy-svn] r67780 - in pypy/build/benchmark: . test Message-ID: <20090918203918.C692A168014@codespeak.net> Author: iko Date: Fri Sep 18 22:39:17 2009 New Revision: 67780 Modified: pypy/build/benchmark/statdb.py pypy/build/benchmark/test/test_statdb.py Log: Retrieve statistics from store Modified: pypy/build/benchmark/statdb.py ============================================================================== --- pypy/build/benchmark/statdb.py (original) +++ pypy/build/benchmark/statdb.py Fri Sep 18 22:39:17 2009 @@ -4,7 +4,7 @@ import sqlalchemy from sqlalchemy import Column, String, Integer, Float, DateTime from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import sessionmaker, relation +from sqlalchemy.orm import sessionmaker, relation, aliased Base = declarative_base() @@ -54,6 +54,9 @@ self.session = sessionmaker(bind=engine)() def get_interp(self, interp, commit=True): + if isinstance(interp, Interpreter): + return interp + try: interp_obj = self.session.query(Interpreter).filter_by( name=interp).one() @@ -66,6 +69,9 @@ return interp_obj def get_benchmark(self, benchmark, commit=True): + if isinstance(benchmark, Benchmark): + return benchmark + try: benchmark_obj = self.session.query(Benchmark).filter_by( name=benchmark).one() @@ -92,3 +98,16 @@ self.session.add(stat) self.session.commit() + + def get_interpreters(self): + return self.session.query(Interpreter).all() + + def get_benchmarks(self): + return self.session.query(Benchmark).all() + + def get_statistic(self, interp, benchmark, statistic): + runs = self.session.query(Run).filter_by(interpreter = interp).filter_by(benchmark = benchmark).subquery() + runalias = aliased(Run, runs) + + stats = self.session.query(Statistic).join((runalias, Statistic.run)).filter(Statistic.key == statistic) + return stats.all() Modified: pypy/build/benchmark/test/test_statdb.py ============================================================================== --- pypy/build/benchmark/test/test_statdb.py (original) +++ pypy/build/benchmark/test/test_statdb.py Fri Sep 18 22:39:17 2009 @@ -1,6 +1,7 @@ import py import time +from datetime import datetime from benchmark.statdb import StatDB, Interpreter, Benchmark class TestStatDB(object): @@ -17,6 +18,9 @@ interp2 = self.statdb.get_interp('foo') assert interp2 is interp + interp2 = self.statdb.get_interp(interp) + assert interp2 is interp + def test_get_benchmark(self): benchmark = self.statdb.get_benchmark('foo') assert isinstance(benchmark, Benchmark) @@ -24,7 +28,41 @@ benchmark2 = self.statdb.get_benchmark('foo') assert benchmark2 is benchmark + benchmark2 = self.statdb.get_benchmark(benchmark) + assert benchmark2 is benchmark + + def test_get_interpreters(self): + foo = self.statdb.get_interp('foo') + bar = self.statdb.get_interp('bar') + + interps = self.statdb.get_interpreters() + assert set(interps) == set([foo, bar]) + + def test_get_benchmarks(self): + foo = self.statdb.get_benchmark('foo') + bar = self.statdb.get_benchmark('bar') + + benchmarks = self.statdb.get_benchmarks() + assert set(benchmarks) == set([foo, bar]) def test_store(self): self.statdb.store_statistics('interp_name', 'benchmark_name', {'stat1' : 42.3, 'stat2' : 12345 }) + + interp = self.statdb.get_interp('interp_name') + benchmark = self.statdb.get_benchmark('benchmark_name') + stats = self.statdb.get_statistic(interp, benchmark, 'stat1') + + assert len(stats) == 1 + stat = stats[0] + assert stat.key == 'stat1' + assert stat.value == 42.3 + assert stat.run.time == datetime.utcfromtimestamp(self._fake_time()) + + self.statdb.store_statistics('interp_name', 'benchmark_name', + {'stat1' : 44.3, 'stat2' : 12347 }) + + stats = self.statdb.get_statistic(interp, benchmark, 'stat1') + + assert len(stats) == 2 + From afa at codespeak.net Fri Sep 18 23:57:27 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Fri, 18 Sep 2009 23:57:27 +0200 (CEST) Subject: [pypy-svn] r67782 - pypy/trunk/pypy/translator/c/gcc Message-ID: <20090918215727.C4A44168015@codespeak.net> Author: afa Date: Fri Sep 18 23:57:27 2009 New Revision: 67782 Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Log: Fix trackgcroot output on Windows: globals are prefixed with _ Problably also fixes some tests on Darwin Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Fri Sep 18 23:57:27 2009 @@ -132,7 +132,7 @@ /* the return value is the one of the 'call' above, */ /* because %eax (and possibly %edx) are unmodified */ ret -""" +""".replace("__gcrootanchor", _globalname("__gcrootanchor")) _variant(elf='.size pypy_asm_stackwalk, .-pypy_asm_stackwalk', darwin='', mingw32='') @@ -140,10 +140,12 @@ print >> output, '\t.align\t4' _globl('__gcrootanchor') _label('__gcrootanchor') - print >> output, '\t/* A circular doubly-linked list of all */' - print >> output, '\t/* the ASM_FRAMEDATAs currently alive */' - print >> output, '\t.long\t__gcrootanchor /* prev */' - print >> output, '\t.long\t__gcrootanchor /* next */' + print >> output, """\ + /* A circular doubly-linked list of all */ + /* the ASM_FRAMEDATAs currently alive */ + .long\t__gcrootanchor /* prev */ + .long\t__gcrootanchor /* next */ +""".replace("__gcrootanchor", _globalname("__gcrootanchor")) _globl('__gcmapstart') _label('__gcmapstart') for label, state, is_range in self.gcmaptable: From pedronis at codespeak.net Sat Sep 19 00:30:40 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 19 Sep 2009 00:30:40 +0200 (CEST) Subject: [pypy-svn] r67783 - pypy/extradoc/planning Message-ID: <20090918223040.A319C168015@codespeak.net> Author: pedronis Date: Sat Sep 19 00:30:39 2009 New Revision: 67783 Modified: pypy/extradoc/planning/jit.txt Log: updates Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Sat Sep 19 00:30:39 2009 @@ -28,7 +28,7 @@ - compare backend vs gcc quality -- asmgcc: support callbacks (threads?) +- jit/asmgcc + threads? - jit should inline the fast path of mallocs @@ -65,8 +65,6 @@ backend: - speed of backend? -- support threads again! - Python interpreter: - lookups of various kinds - calls From afa at codespeak.net Sat Sep 19 00:47:33 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Sat, 19 Sep 2009 00:47:33 +0200 (CEST) Subject: [pypy-svn] r67784 - in pypy/trunk/pypy/translator/c: . src Message-ID: <20090918224733.0588F168015@codespeak.net> Author: afa Date: Sat Sep 19 00:47:33 2009 New Revision: 67784 Modified: pypy/trunk/pypy/translator/c/gc.py pypy/trunk/pypy/translator/c/src/mem.h Log: Code specific to asmgcroot should be emitted only when using the corresponding gc policy. This fixes various translation tests on Windows. Modified: pypy/trunk/pypy/translator/c/gc.py ============================================================================== --- pypy/trunk/pypy/translator/c/gc.py (original) +++ pypy/trunk/pypy/translator/c/gc.py Sat Sep 19 00:47:33 2009 @@ -86,6 +86,9 @@ def OP_GC_ASSUME_YOUNG_POINTERS(self, funcgen, op): return '' + def OP_GC_STACK_BOTTOM(self, funcgen, op): + return '' + class RefcountingInfo: static_deallocator = None @@ -325,6 +328,9 @@ def GC_KEEPALIVE(self, funcgen, v): return 'pypy_asm_keepalive(%s);' % funcgen.expr(v) + def OP_GC_STACK_BOTTOM(self, funcgen, v): + return 'pypy_asm_stack_bottom(%s);' % funcgen.expr(v) + name_to_gcpolicy = { 'boehm': BoehmGcPolicy, Modified: pypy/trunk/pypy/translator/c/src/mem.h ============================================================================== --- pypy/trunk/pypy/translator/c/src/mem.h (original) +++ pypy/trunk/pypy/translator/c/src/mem.h Sat Sep 19 00:47:33 2009 @@ -49,7 +49,7 @@ "g" (v)) /* marker for trackgcroot.py */ -#define OP_GC_STACK_BOTTOM(r) asm volatile ("/* GC_STACK_BOTTOM */" : : ) +#define pypy_asm_stack_bottom(r) asm volatile ("/* asm_stack_bottom */" : : ) #define OP_GC_ASMGCROOT_STATIC(i, r) r = \ i == 0 ? (void*)&__gcmapstart : \ From pedronis at codespeak.net Sat Sep 19 00:51:10 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 19 Sep 2009 00:51:10 +0200 (CEST) Subject: [pypy-svn] r67785 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090918225110.39CE1168015@codespeak.net> Author: pedronis Date: Sat Sep 19 00:51:09 2009 New Revision: 67785 Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: produce a correct blackholed op count including canfold ops Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Sat Sep 19 00:51:09 2009 @@ -1288,6 +1288,9 @@ op = self.history.record(opnum, argboxes, resbox, descr) profiler.count_ops(opnum, self.history.OPS_KIND) self.attach_debug_info(op) + else: + if self.is_blackholing(): + profiler.count_ops(opnum, self.history.OPS_KIND) # canfold blackholed if require_attention: self.after_generate_residual_call() return resbox From afa at codespeak.net Sat Sep 19 01:24:39 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Sat, 19 Sep 2009 01:24:39 +0200 (CEST) Subject: [pypy-svn] r67786 - pypy/trunk/pypy/translator/c Message-ID: <20090918232439.12783168015@codespeak.net> Author: afa Date: Sat Sep 19 01:24:39 2009 New Revision: 67786 Modified: pypy/trunk/pypy/translator/c/gc.py Log: oops, correctly emit the OP_GC_STACK_BOTTOM operation Modified: pypy/trunk/pypy/translator/c/gc.py ============================================================================== --- pypy/trunk/pypy/translator/c/gc.py (original) +++ pypy/trunk/pypy/translator/c/gc.py Sat Sep 19 01:24:39 2009 @@ -328,8 +328,8 @@ def GC_KEEPALIVE(self, funcgen, v): return 'pypy_asm_keepalive(%s);' % funcgen.expr(v) - def OP_GC_STACK_BOTTOM(self, funcgen, v): - return 'pypy_asm_stack_bottom(%s);' % funcgen.expr(v) + def OP_GC_STACK_BOTTOM(self, funcgen, op): + return 'pypy_asm_stack_bottom(%s);' % funcgen.expr(op.result) name_to_gcpolicy = { From arigo at codespeak.net Sat Sep 19 09:55:14 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 19 Sep 2009 09:55:14 +0200 (CEST) Subject: [pypy-svn] r67789 - pypy/branch/weakdict Message-ID: <20090919075514.8F276168015@codespeak.net> Author: arigo Date: Sat Sep 19 09:55:13 2009 New Revision: 67789 Removed: pypy/branch/weakdict/ Log: Kill that branch, as it's unlikely to be looked at again soon. From arigo at codespeak.net Sat Sep 19 11:55:08 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 19 Sep 2009 11:55:08 +0200 (CEST) Subject: [pypy-svn] r67790 - in pypy/branch/execute-star-args-jit/pypy/jit: backend/llgraph backend/test metainterp metainterp/test Message-ID: <20090919095508.33AB2168013@codespeak.net> Author: arigo Date: Sat Sep 19 11:55:06 2009 New Revision: 67790 Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/llgraph/llimpl.py pypy/branch/execute-star-args-jit/pypy/jit/backend/llgraph/runner.py pypy/branch/execute-star-args-jit/pypy/jit/backend/test/runner_test.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/executor.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/optimizefindnode.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/optimizeopt.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resoperation.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/specnode.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_basic.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_executor.py Log: (arigo, pedronis around) Refactor the do_xxx() operations in executor.py and on the CPU to take arguments directly instead of in a list. Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/llgraph/llimpl.py Sat Sep 19 11:55:06 2009 @@ -523,7 +523,7 @@ else: boxedargs.append(BoxPtr(x)) # xxx this passes the 'llimpl' module as the CPU argument - resbox = impl(llimpl, boxedargs) + resbox = impl(llimpl, *boxedargs) return getattr(resbox, 'value', None) op = _op_default_implementation # Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/llgraph/runner.py Sat Sep 19 11:55:06 2009 @@ -283,36 +283,32 @@ # ---------- the backend-dependent operations ---------- - def do_arraylen_gc(self, args, arraydescr): - array = args[0].getref_base() + def do_arraylen_gc(self, arraybox, arraydescr): + array = arraybox.getref_base() return history.BoxInt(llimpl.do_arraylen_gc(arraydescr, array)) - def do_strlen(self, args, descr=None): - assert descr is None - string = args[0].getref_base() + def do_strlen(self, stringbox): + string = stringbox.getref_base() return history.BoxInt(llimpl.do_strlen(0, string)) - def do_strgetitem(self, args, descr=None): - assert descr is None - string = args[0].getref_base() - index = args[1].getint() + def do_strgetitem(self, stringbox, indexbox): + string = stringbox.getref_base() + index = indexbox.getint() return history.BoxInt(llimpl.do_strgetitem(0, string, index)) - def do_unicodelen(self, args, descr=None): - assert descr is None - string = args[0].getref_base() + def do_unicodelen(self, stringbox): + string = stringbox.getref_base() return history.BoxInt(llimpl.do_unicodelen(0, string)) - def do_unicodegetitem(self, args, descr=None): - assert descr is None - string = args[0].getref_base() - index = args[1].getint() + def do_unicodegetitem(self, stringbox, indexbox): + string = stringbox.getref_base() + index = indexbox.getint() return history.BoxInt(llimpl.do_unicodegetitem(0, string, index)) - def do_getarrayitem_gc(self, args, arraydescr): + def do_getarrayitem_gc(self, arraybox, indexbox, arraydescr): assert isinstance(arraydescr, Descr) - array = args[0].getref_base() - index = args[1].getint() + array = arraybox.getref_base() + index = indexbox.getint() if arraydescr.typeinfo == REF: return history.BoxPtr(llimpl.do_getarrayitem_gc_ptr(array, index)) elif arraydescr.typeinfo == INT: @@ -324,9 +320,9 @@ else: raise NotImplementedError - def do_getfield_gc(self, args, fielddescr): + def do_getfield_gc(self, structbox, fielddescr): assert isinstance(fielddescr, Descr) - struct = args[0].getref_base() + struct = structbox.getref_base() if fielddescr.typeinfo == REF: return history.BoxPtr(llimpl.do_getfield_gc_ptr(struct, fielddescr.ofs)) @@ -340,9 +336,9 @@ else: raise NotImplementedError - def do_getfield_raw(self, args, fielddescr): + def do_getfield_raw(self, structbox, fielddescr): assert isinstance(fielddescr, Descr) - struct = self.cast_int_to_adr(args[0].getint()) + struct = self.cast_int_to_adr(structbox.getint()) if fielddescr.typeinfo == REF: return history.BoxPtr(llimpl.do_getfield_raw_ptr(struct, fielddescr.ofs, @@ -358,100 +354,95 @@ else: raise NotImplementedError - def do_new(self, args, size): + def do_new(self, size): assert isinstance(size, Descr) return history.BoxPtr(llimpl.do_new(size.ofs)) - def do_new_with_vtable(self, args, descr=None): - assert descr is None - vtable = args[0].getint() + def do_new_with_vtable(self, vtablebox): + vtable = vtablebox.getint() size = self.class_sizes[vtable] result = llimpl.do_new(size.ofs) llimpl.do_setfield_gc_int(result, self.fielddescrof_vtable.ofs, vtable, self.memo_cast) return history.BoxPtr(result) - def do_new_array(self, args, size): + def do_new_array(self, countbox, size): assert isinstance(size, Descr) - count = args[0].getint() + count = countbox.getint() return history.BoxPtr(llimpl.do_new_array(size.ofs, count)) - def do_setarrayitem_gc(self, args, arraydescr): + def do_setarrayitem_gc(self, arraybox, indexbox, newvaluebox, arraydescr): assert isinstance(arraydescr, Descr) - array = args[0].getref_base() - index = args[1].getint() + array = arraybox.getref_base() + index = indexbox.getint() if arraydescr.typeinfo == REF: - newvalue = args[2].getref_base() + newvalue = newvaluebox.getref_base() llimpl.do_setarrayitem_gc_ptr(array, index, newvalue) elif arraydescr.typeinfo == INT: - newvalue = args[2].getint() + newvalue = newvaluebox.getint() llimpl.do_setarrayitem_gc_int(array, index, newvalue, self.memo_cast) elif arraydescr.typeinfo == FLOAT: - newvalue = args[2].getfloat() + newvalue = newvaluebox.getfloat() llimpl.do_setarrayitem_gc_float(array, index, newvalue) else: raise NotImplementedError - def do_setfield_gc(self, args, fielddescr): + def do_setfield_gc(self, structbox, newvaluebox, fielddescr): assert isinstance(fielddescr, Descr) - struct = args[0].getref_base() + struct = structbox.getref_base() if fielddescr.typeinfo == REF: - newvalue = args[1].getref_base() + newvalue = newvaluebox.getref_base() llimpl.do_setfield_gc_ptr(struct, fielddescr.ofs, newvalue) elif fielddescr.typeinfo == INT: - newvalue = args[1].getint() + newvalue = newvaluebox.getint() llimpl.do_setfield_gc_int(struct, fielddescr.ofs, newvalue, self.memo_cast) elif fielddescr.typeinfo == FLOAT: - newvalue = args[1].getfloat() + newvalue = newvaluebox.getfloat() llimpl.do_setfield_gc_float(struct, fielddescr.ofs, newvalue) else: raise NotImplementedError - def do_setfield_raw(self, args, fielddescr): + def do_setfield_raw(self, structbox, newvaluebox, fielddescr): assert isinstance(fielddescr, Descr) - struct = self.cast_int_to_adr(args[0].getint()) + struct = self.cast_int_to_adr(structbox.getint()) if fielddescr.typeinfo == REF: - newvalue = args[1].getref_base() + newvalue = newvaluebox.getref_base() llimpl.do_setfield_raw_ptr(struct, fielddescr.ofs, newvalue, self.memo_cast) elif fielddescr.typeinfo == INT: - newvalue = args[1].getint() + newvalue = newvaluebox.getint() llimpl.do_setfield_raw_int(struct, fielddescr.ofs, newvalue, self.memo_cast) elif fielddescr.typeinfo == FLOAT: - newvalue = args[1].getfloat() + newvalue = newvaluebox.getfloat() llimpl.do_setfield_raw_float(struct, fielddescr.ofs, newvalue, self.memo_cast) else: raise NotImplementedError - def do_same_as(self, args, descr=None): - return args[0].clonebox() + def do_same_as(self, box1): + return box1.clonebox() - def do_newstr(self, args, descr=None): - assert descr is None - length = args[0].getint() + def do_newstr(self, lengthbox): + length = lengthbox.getint() return history.BoxPtr(llimpl.do_newstr(0, length)) - def do_newunicode(self, args, descr=None): - assert descr is None - length = args[0].getint() + def do_newunicode(self, lengthbox): + length = lengthbox.getint() return history.BoxPtr(llimpl.do_newunicode(0, length)) - def do_strsetitem(self, args, descr=None): - assert descr is None - string = args[0].getref_base() - index = args[1].getint() - newvalue = args[2].getint() + def do_strsetitem(self, stringbox, indexbox, newvaluebox): + string = stringbox.getref_base() + index = indexbox.getint() + newvalue = newvaluebox.getint() llimpl.do_strsetitem(0, string, index, newvalue) - def do_unicodesetitem(self, args, descr=None): - assert descr is None - string = args[0].getref_base() - index = args[1].getint() - newvalue = args[2].getint() + def do_unicodesetitem(self, stringbox, indexbox, newvaluebox): + string = stringbox.getref_base() + index = indexbox.getint() + newvalue = newvaluebox.getint() llimpl.do_unicodesetitem(0, string, index, newvalue) def do_call(self, args, calldescr): @@ -474,9 +465,8 @@ else: raise NotImplementedError - def do_cast_ptr_to_int(self, args, descr=None): - assert descr is None - return history.BoxInt(llimpl.cast_to_int(args[0].getref_base(), + def do_cast_ptr_to_int(self, ptrbox): + return history.BoxInt(llimpl.cast_to_int(ptrbox.getref_base(), self.memo_cast)) class OOtypeCPU(BaseCPU): @@ -537,57 +527,48 @@ return (ootype.cast_to_object(ll_err.args[0]), ootype.cast_to_object(ll_err.args[1])) - def do_new_with_vtable(self, args, descr=None): - assert descr is None - assert len(args) == 1 - cls = args[0].getref_base() + def do_new_with_vtable(self, clsbox): + cls = clsbox.getref_base() typedescr = self.class_sizes[cls] return typedescr.create() - def do_new_array(self, args, typedescr): + def do_new_array(self, lengthbox, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 1 - return typedescr.create_array(args[0]) + return typedescr.create_array(lengthbox) - def do_new(self, args, typedescr): + def do_new(self, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 0 return typedescr.create() - def do_runtimenew(self, args, descr): + def do_runtimenew(self, classbox): "NOT_RPYTHON" - classbox = args[0] classobj = classbox.getref(ootype.Class) res = ootype.runtimenew(classobj) return history.BoxObj(ootype.cast_to_object(res)) - def do_instanceof(self, args, typedescr): + def do_instanceof(self, box1, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 1 - return typedescr.instanceof(args[0]) + return typedescr.instanceof(box1) - def do_getfield_gc(self, args, fielddescr): + def do_getfield_gc(self, box1, fielddescr): assert isinstance(fielddescr, FieldDescr) - return fielddescr.getfield(args[0]) + return fielddescr.getfield(box1) - def do_setfield_gc(self, args, fielddescr): + def do_setfield_gc(self, box1, box2, fielddescr): assert isinstance(fielddescr, FieldDescr) - return fielddescr.setfield(args[0], args[1]) + return fielddescr.setfield(box1, box2) - def do_getarrayitem_gc(self, args, typedescr): + def do_getarrayitem_gc(self, box1, box2, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 2 - return typedescr.getarrayitem(*args) + return typedescr.getarrayitem(box1, box2) - def do_setarrayitem_gc(self, args, typedescr): + def do_setarrayitem_gc(self, box1, box2, box3, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 3 - return typedescr.setarrayitem(*args) + return typedescr.setarrayitem(box1, box2, box3) - def do_arraylen_gc(self, args, typedescr): + def do_arraylen_gc(self, box1, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 1 - return typedescr.getarraylength(*args) + return typedescr.getarraylength(box1) def do_call(self, args, descr): assert isinstance(descr, StaticMethDescr) Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/test/runner_test.py Sat Sep 19 11:55:06 2009 @@ -124,14 +124,14 @@ def test_executor(self): cpu = self.cpu - x = execute(cpu, rop.INT_ADD, [BoxInt(100), ConstInt(42)]) + x = execute(cpu, rop.INT_ADD, None, BoxInt(100), ConstInt(42)) assert x.value == 142 if self.type_system == 'lltype': - s = execute(cpu, rop.NEWSTR, [BoxInt(8)]) + s = execute(cpu, rop.NEWSTR, None, BoxInt(8)) assert len(s.getref(lltype.Ptr(rstr.STR)).chars) == 8 def test_lshift(self): - res = execute(self.cpu, rop.INT_LSHIFT, [BoxInt(10), ConstInt(4)]) + res = execute(self.cpu, rop.INT_LSHIFT, None, BoxInt(10), ConstInt(4)) assert res.value == 10 << 4 res = self.execute_operation(rop.INT_LSHIFT, [BoxInt(10), BoxInt(4)], 'int') @@ -293,8 +293,8 @@ fielddescr = self.cpu.fielddescrof(self.S, 'value') assert not fielddescr.is_pointer_field() # - self.cpu.do_setfield_gc([t_box, BoxInt(1333)], fielddescr) - r = self.cpu.do_getfield_gc([t_box], fielddescr) + self.cpu.do_setfield_gc(t_box, BoxInt(1333), fielddescr) + r = self.cpu.do_getfield_gc(t_box, fielddescr) assert r.value == 1333 # res = self.execute_operation(rop.SETFIELD_GC, [t_box, BoxInt(39082)], @@ -422,10 +422,10 @@ arraydescr = self.cpu.arraydescrof(A) assert not arraydescr.is_array_of_pointers() # - r = self.cpu.do_arraylen_gc([a_box], arraydescr) + r = self.cpu.do_arraylen_gc(a_box, arraydescr) assert r.value == 342 - self.cpu.do_setarrayitem_gc([a_box, BoxInt(311), BoxInt(170)], arraydescr) - r = self.cpu.do_getarrayitem_gc([a_box, BoxInt(311)], arraydescr) + self.cpu.do_setarrayitem_gc(a_box, BoxInt(311), BoxInt(170), arraydescr) + r = self.cpu.do_getarrayitem_gc(a_box, BoxInt(311), arraydescr) assert r.value == 170 # r = self.execute_operation(rop.ARRAYLEN_GC, [a_box], @@ -536,9 +536,9 @@ assert r.value == 153 def test_unicode_basic(self): - u_box = self.cpu.do_newunicode([ConstInt(5)]) - self.cpu.do_unicodesetitem([u_box, BoxInt(4), BoxInt(123)]) - r = self.cpu.do_unicodegetitem([u_box, BoxInt(4)]) + u_box = self.cpu.do_newunicode(ConstInt(5)) + self.cpu.do_unicodesetitem(u_box, BoxInt(4), BoxInt(123)) + r = self.cpu.do_unicodegetitem(u_box, BoxInt(4)) assert r.value == 123 # u_box = self.alloc_unicode(u"hello\u1234") @@ -696,10 +696,10 @@ s = lltype.cast_opaque_ptr(lltype.Ptr(self.T), r1.value) assert s.parent.chr1 == chr(190) assert s.parent.chr2 == chr(150) - r = self.cpu.do_getfield_gc([r1], descrshort) + r = self.cpu.do_getfield_gc(r1, descrshort) assert r.value == 1313 - self.cpu.do_setfield_gc([r1, BoxInt(1333)], descrshort) - r = self.cpu.do_getfield_gc([r1], descrshort) + self.cpu.do_setfield_gc(r1, BoxInt(1333), descrshort) + r = self.cpu.do_getfield_gc(r1, descrshort) assert r.value == 1333 r = self.execute_operation(rop.GETFIELD_GC, [r1], 'int', descr=descrshort) @@ -740,13 +740,13 @@ descr_A = cpu.arraydescrof(A) a = lltype.malloc(A, 5) x = cpu.do_arraylen_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, a))], + BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, a)), descr_A) assert x.value == 5 # a[2] = 'Y' x = cpu.do_getarrayitem_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, a)), BoxInt(2)], + BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, a)), BoxInt(2), descr_A) assert x.value == ord('Y') # @@ -755,19 +755,19 @@ b = lltype.malloc(B, 4) b[3] = a x = cpu.do_getarrayitem_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, b)), BoxInt(3)], + BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, b)), BoxInt(3), descr_B) assert isinstance(x, BoxPtr) assert x.getref(lltype.Ptr(A)) == a # s = rstr.mallocstr(6) x = cpu.do_strlen( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s))]) + BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s))) assert x.value == 6 # s.chars[3] = 'X' x = cpu.do_strgetitem( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), BoxInt(3)]) + BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), BoxInt(3)) assert x.value == ord('X') # S = lltype.GcStruct('S', ('x', lltype.Char), ('y', lltype.Ptr(A))) @@ -775,27 +775,27 @@ s = lltype.malloc(S) s.x = 'Z' x = cpu.do_getfield_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s))], + BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), descrfld_x) assert x.value == ord('Z') # cpu.do_setfield_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), - BoxInt(ord('4'))], + BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), + BoxInt(ord('4')), descrfld_x) assert s.x == '4' # descrfld_y = cpu.fielddescrof(S, 'y') s.y = a x = cpu.do_getfield_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s))], + BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), descrfld_y) assert isinstance(x, BoxPtr) assert x.getref(lltype.Ptr(A)) == a # s.y = lltype.nullptr(A) cpu.do_setfield_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), x], + BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), x, descrfld_y) assert s.y == a # @@ -804,13 +804,13 @@ rs = lltype.malloc(RS, immortal=True) rs.x = '?' x = cpu.do_getfield_raw( - [BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs)))], + BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))), descrfld_rx) assert x.value == ord('?') # cpu.do_setfield_raw( - [BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))), - BoxInt(ord('!'))], + BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))), + BoxInt(ord('!')), descrfld_rx) assert rs.x == '!' # @@ -819,19 +819,19 @@ #descrfld_ry = cpu.fielddescrof(RS, 'y') #rs.y = a #x = cpu.do_getfield_raw( - # [BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs)))], + # BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))), # descrfld_ry) #assert isinstance(x, BoxPtr) #assert x.getref(lltype.Ptr(A)) == a # #rs.y = lltype.nullptr(A) #cpu.do_setfield_raw( - # [BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))), x], + # BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))), x, # descrfld_ry) #assert rs.y == a # descrsize = cpu.sizeof(S) - x = cpu.do_new([], descrsize) + x = cpu.do_new(descrsize) assert isinstance(x, BoxPtr) x.getref(lltype.Ptr(S)) # @@ -839,35 +839,35 @@ vtable2 = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) vtable2_int = cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(vtable2)) cpu.set_class_sizes({vtable2_int: descrsize2}) - x = cpu.do_new_with_vtable([ConstInt(vtable2_int)]) + x = cpu.do_new_with_vtable(ConstInt(vtable2_int)) assert isinstance(x, BoxPtr) # well... #assert x.getref(rclass.OBJECTPTR).typeptr == vtable2 # arraydescr = cpu.arraydescrof(A) - x = cpu.do_new_array([BoxInt(7)], arraydescr) + x = cpu.do_new_array(BoxInt(7), arraydescr) assert isinstance(x, BoxPtr) assert len(x.getref(lltype.Ptr(A))) == 7 # cpu.do_setarrayitem_gc( - [x, BoxInt(5), BoxInt(ord('*'))], descr_A) + x, BoxInt(5), BoxInt(ord('*')), descr_A) assert x.getref(lltype.Ptr(A))[5] == '*' # cpu.do_setarrayitem_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, b)), - BoxInt(1), x], + BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, b)), + BoxInt(1), x, descr_B) assert b[1] == x.getref(lltype.Ptr(A)) # - x = cpu.do_newstr([BoxInt(5)]) + x = cpu.do_newstr(BoxInt(5)) assert isinstance(x, BoxPtr) assert len(x.getref(lltype.Ptr(rstr.STR)).chars) == 5 # - cpu.do_strsetitem([x, BoxInt(4), BoxInt(ord('/'))]) + cpu.do_strsetitem(x, BoxInt(4), BoxInt(ord('/'))) assert x.getref(lltype.Ptr(rstr.STR)).chars[4] == '/' # - x = cpu.do_newstr([BoxInt(5)]) - y = cpu.do_cast_ptr_to_int([x]) + x = cpu.do_newstr(BoxInt(5)) + y = cpu.do_cast_ptr_to_int(x) assert isinstance(y, BoxInt) assert y.value == cpu.cast_gcref_to_int(x.value) Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/executor.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/executor.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/executor.py Sat Sep 19 11:55:06 2009 @@ -8,6 +8,7 @@ from pypy.rlib.rarithmetic import ovfcheck, r_uint, intmask from pypy.jit.metainterp.history import BoxInt, ConstInt, check_descr from pypy.jit.metainterp.history import INT, REF, ConstFloat +from pypy.jit.metainterp import resoperation from pypy.jit.metainterp.resoperation import rop @@ -17,166 +18,145 @@ # ____________________________________________________________ -def do_int_add(cpu, args, descr=None): - return ConstInt(intmask(args[0].getint() + args[1].getint())) +def do_int_add(cpu, box1, box2): + return ConstInt(intmask(box1.getint() + box2.getint())) -def do_int_sub(cpu, args, descr=None): - return ConstInt(intmask(args[0].getint() - args[1].getint())) +def do_int_sub(cpu, box1, box2): + return ConstInt(intmask(box1.getint() - box2.getint())) -def do_int_mul(cpu, args, descr=None): - return ConstInt(intmask(args[0].getint() * args[1].getint())) +def do_int_mul(cpu, box1, box2): + return ConstInt(intmask(box1.getint() * box2.getint())) -def do_int_floordiv(cpu, args, descr=None): - z = llop.int_floordiv(lltype.Signed, args[0].getint(), args[1].getint()) +def do_int_floordiv(cpu, box1, box2): + z = llop.int_floordiv(lltype.Signed, box1.getint(), box2.getint()) return ConstInt(z) -def do_int_mod(cpu, args, descr=None): - z = llop.int_mod(lltype.Signed, args[0].getint(), args[1].getint()) +def do_int_mod(cpu, box1, box2): + z = llop.int_mod(lltype.Signed, box1.getint(), box2.getint()) return ConstInt(z) -def do_int_and(cpu, args, descr=None): - return ConstInt(args[0].getint() & args[1].getint()) +def do_int_and(cpu, box1, box2): + return ConstInt(box1.getint() & box2.getint()) -def do_int_or(cpu, args, descr=None): - return ConstInt(args[0].getint() | args[1].getint()) +def do_int_or(cpu, box1, box2): + return ConstInt(box1.getint() | box2.getint()) -def do_int_xor(cpu, args, descr=None): - return ConstInt(args[0].getint() ^ args[1].getint()) +def do_int_xor(cpu, box1, box2): + return ConstInt(box1.getint() ^ box2.getint()) -def do_int_rshift(cpu, args, descr=None): - return ConstInt(args[0].getint() >> args[1].getint()) +def do_int_rshift(cpu, box1, box2): + return ConstInt(box1.getint() >> box2.getint()) -def do_int_lshift(cpu, args, descr=None): - return ConstInt(intmask(args[0].getint() << args[1].getint())) +def do_int_lshift(cpu, box1, box2): + return ConstInt(intmask(box1.getint() << box2.getint())) -def do_uint_rshift(cpu, args, descr=None): - v = r_uint(args[0].getint()) >> r_uint(args[1].getint()) +def do_uint_rshift(cpu, box1, box2): + v = r_uint(box1.getint()) >> r_uint(box2.getint()) return ConstInt(intmask(v)) # ---------- -def do_int_lt(cpu, args, descr=None): - return ConstInt(args[0].getint() < args[1].getint()) +def do_int_lt(cpu, box1, box2): + return ConstInt(box1.getint() < box2.getint()) -def do_int_le(cpu, args, descr=None): - return ConstInt(args[0].getint() <= args[1].getint()) +def do_int_le(cpu, box1, box2): + return ConstInt(box1.getint() <= box2.getint()) -def do_int_eq(cpu, args, descr=None): - return ConstInt(args[0].getint() == args[1].getint()) +def do_int_eq(cpu, box1, box2): + return ConstInt(box1.getint() == box2.getint()) -def do_int_ne(cpu, args, descr=None): - return ConstInt(args[0].getint() != args[1].getint()) +def do_int_ne(cpu, box1, box2): + return ConstInt(box1.getint() != box2.getint()) -def do_int_gt(cpu, args, descr=None): - return ConstInt(args[0].getint() > args[1].getint()) +def do_int_gt(cpu, box1, box2): + return ConstInt(box1.getint() > box2.getint()) -def do_int_ge(cpu, args, descr=None): - return ConstInt(args[0].getint() >= args[1].getint()) +def do_int_ge(cpu, box1, box2): + return ConstInt(box1.getint() >= box2.getint()) -def do_uint_lt(cpu, args, descr=None): - return ConstInt(r_uint(args[0].getint()) < r_uint(args[1].getint())) +def do_uint_lt(cpu, box1, box2): + return ConstInt(r_uint(box1.getint()) < r_uint(box2.getint())) -def do_uint_le(cpu, args, descr=None): - return ConstInt(r_uint(args[0].getint()) <= r_uint(args[1].getint())) +def do_uint_le(cpu, box1, box2): + return ConstInt(r_uint(box1.getint()) <= r_uint(box2.getint())) -def do_uint_gt(cpu, args, descr=None): - return ConstInt(r_uint(args[0].getint()) > r_uint(args[1].getint())) +def do_uint_gt(cpu, box1, box2): + return ConstInt(r_uint(box1.getint()) > r_uint(box2.getint())) -def do_uint_ge(cpu, args, descr=None): - return ConstInt(r_uint(args[0].getint()) >= r_uint(args[1].getint())) +def do_uint_ge(cpu, box1, box2): + return ConstInt(r_uint(box1.getint()) >= r_uint(box2.getint())) # ---------- -def do_int_is_true(cpu, args, descr=None): - return ConstInt(bool(args[0].getint())) +def do_int_is_true(cpu, box1): + return ConstInt(bool(box1.getint())) -def do_int_neg(cpu, args, descr=None): - return ConstInt(intmask(-args[0].getint())) +def do_int_neg(cpu, box1): + return ConstInt(intmask(-box1.getint())) -def do_int_invert(cpu, args, descr=None): - return ConstInt(~args[0].getint()) +def do_int_invert(cpu, box1): + return ConstInt(~box1.getint()) -def do_bool_not(cpu, args, descr=None): - return ConstInt(not args[0].getint()) +def do_bool_not(cpu, box1): + return ConstInt(not box1.getint()) -def do_same_as(cpu, args, descr=None): - return args[0] +def do_same_as(cpu, box1): + return box1 -def do_oononnull(cpu, args, descr=None): - tp = args[0].type +def do_oononnull(cpu, box1): + tp = box1.type if tp == INT: - x = bool(args[0].getint()) + x = bool(box1.getint()) elif tp == REF: - x = bool(args[0].getref_base()) + x = bool(box1.getref_base()) else: assert False return ConstInt(x) -def do_ooisnull(cpu, args, descr=None): - tp = args[0].type +def do_ooisnull(cpu, box1): + tp = box1.type if tp == INT: - x = bool(args[0].getint()) + x = bool(box1.getint()) elif tp == REF: - x = bool(args[0].getref_base()) + x = bool(box1.getref_base()) else: assert False return ConstInt(not x) -def do_oois(cpu, args, descr=None): - tp = args[0].type - assert tp == args[1].type +def do_oois(cpu, box1, box2): + tp = box1.type + assert tp == box2.type if tp == INT: - x = args[0].getint() == args[1].getint() + x = box1.getint() == box2.getint() elif tp == REF: - x = args[0].getref_base() == args[1].getref_base() + x = box1.getref_base() == box2.getref_base() else: assert False return ConstInt(x) -def do_ooisnot(cpu, args, descr=None): - tp = args[0].type - assert tp == args[1].type +def do_ooisnot(cpu, box1, box2): + tp = box1.type + assert tp == box2.type if tp == INT: - x = args[0].getint() != args[1].getint() + x = box1.getint() != box2.getint() elif tp == REF: - x = args[0].getref_base() != args[1].getref_base() + x = box1.getref_base() != box2.getref_base() else: assert False return ConstInt(x) -def do_ooidentityhash(cpu, args, descr=None): - obj = args[0].getref_base() +def do_ooidentityhash(cpu, box1): + obj = box1.getref_base() return ConstInt(cpu.ts.ooidentityhash(obj)) -def do_subclassof(cpu, args, descr=None): - assert len(args) == 2 - box1, box2 = args +def do_subclassof(cpu, box1, box2): return ConstInt(cpu.ts.subclassOf(cpu, box1, box2)) # ---------- -# the following operations just delegate to the cpu: -# do_arraylen_gc -# do_strlen -# do_strgetitem -# do_getarrayitem_gc -# do_getfield_gc -# do_getfield_raw -# do_new -# do_new_with_vtable -# do_new_array -# do_setarrayitem_gc -# do_setfield_gc -# do_setfield_raw -# do_newstr -# do_strsetitem -# do_call - -# ---------- - -def do_int_add_ovf(cpu, args, descr=None): - x = args[0].getint() - y = args[1].getint() +def do_int_add_ovf(cpu, box1, box2): + x = box1.getint() + y = box2.getint() try: z = ovfcheck(x + y) except OverflowError: @@ -187,9 +167,9 @@ cpu._overflow_flag = ovf return BoxInt(z) -def do_int_sub_ovf(cpu, args, descr=None): - x = args[0].getint() - y = args[1].getint() +def do_int_sub_ovf(cpu, box1, box2): + x = box1.getint() + y = box2.getint() try: z = ovfcheck(x - y) except OverflowError: @@ -200,9 +180,9 @@ cpu._overflow_flag = ovf return BoxInt(z) -def do_int_mul_ovf(cpu, args, descr=None): - x = args[0].getint() - y = args[1].getint() +def do_int_mul_ovf(cpu, box1, box2): + x = box1.getint() + y = box2.getint() try: z = ovfcheck(x * y) except OverflowError: @@ -215,56 +195,56 @@ # ---------- -def do_float_neg(cpu, args, descr=None): - return ConstFloat(-args[0].getfloat()) +def do_float_neg(cpu, box1): + return ConstFloat(-box1.getfloat()) -def do_float_abs(cpu, args, descr=None): - return ConstFloat(abs(args[0].getfloat())) +def do_float_abs(cpu, box1): + return ConstFloat(abs(box1.getfloat())) -def do_float_is_true(cpu, args, descr=None): - return ConstInt(bool(args[0].getfloat())) +def do_float_is_true(cpu, box1): + return ConstInt(bool(box1.getfloat())) -def do_float_add(cpu, args, descr=None): - return ConstFloat(args[0].getfloat() + args[1].getfloat()) +def do_float_add(cpu, box1, box2): + return ConstFloat(box1.getfloat() + box2.getfloat()) -def do_float_sub(cpu, args, descr=None): - return ConstFloat(args[0].getfloat() - args[1].getfloat()) +def do_float_sub(cpu, box1, box2): + return ConstFloat(box1.getfloat() - box2.getfloat()) -def do_float_mul(cpu, args, descr=None): - return ConstFloat(args[0].getfloat() * args[1].getfloat()) +def do_float_mul(cpu, box1, box2): + return ConstFloat(box1.getfloat() * box2.getfloat()) -def do_float_truediv(cpu, args, descr=None): - return ConstFloat(args[0].getfloat() / args[1].getfloat()) +def do_float_truediv(cpu, box1, box2): + return ConstFloat(box1.getfloat() / box2.getfloat()) -def do_float_lt(cpu, args, descr=None): - return ConstInt(args[0].getfloat() < args[1].getfloat()) +def do_float_lt(cpu, box1, box2): + return ConstInt(box1.getfloat() < box2.getfloat()) -def do_float_le(cpu, args, descr=None): - return ConstInt(args[0].getfloat() <= args[1].getfloat()) +def do_float_le(cpu, box1, box2): + return ConstInt(box1.getfloat() <= box2.getfloat()) -def do_float_eq(cpu, args, descr=None): - return ConstInt(args[0].getfloat() == args[1].getfloat()) +def do_float_eq(cpu, box1, box2): + return ConstInt(box1.getfloat() == box2.getfloat()) -def do_float_ne(cpu, args, descr=None): - return ConstInt(args[0].getfloat() != args[1].getfloat()) +def do_float_ne(cpu, box1, box2): + return ConstInt(box1.getfloat() != box2.getfloat()) -def do_float_gt(cpu, args, descr=None): - return ConstInt(args[0].getfloat() > args[1].getfloat()) +def do_float_gt(cpu, box1, box2): + return ConstInt(box1.getfloat() > box2.getfloat()) -def do_float_ge(cpu, args, descr=None): - return ConstInt(args[0].getfloat() >= args[1].getfloat()) +def do_float_ge(cpu, box1, box2): + return ConstInt(box1.getfloat() >= box2.getfloat()) -def do_cast_float_to_int(cpu, args, descr=None): - return ConstInt(int(args[0].getfloat())) +def do_cast_float_to_int(cpu, box1): + return ConstInt(int(box1.getfloat())) -def do_cast_int_to_float(cpu, args, descr=None): - return ConstFloat(float(args[0].getint())) +def do_cast_int_to_float(cpu, box1): + return ConstFloat(float(box1.getint())) # ____________________________________________________________ -def do_debug_merge_point(cpu, args, descr=None): +def do_debug_merge_point(cpu, box1): from pypy.jit.metainterp.warmspot import get_stats - loc = args[0]._get_str() + loc = box1._get_str() get_stats().locations.append(loc) # ____________________________________________________________ @@ -284,12 +264,22 @@ else: def wrap(fn): return fn - execute = [None] * (rop._LAST+1) + # + execute_by_num_args = {} for key, value in rop.__dict__.items(): if not key.startswith('_'): if (rop._FINAL_FIRST <= value <= rop._FINAL_LAST or rop._GUARD_FIRST <= value <= rop._GUARD_LAST): continue + # find which list to store the operation in, based on num_args + num_args = resoperation.oparity[value] + withdescr = resoperation.opwithdescr[value] + if withdescr and num_args >= 0: + num_args += 1 + if num_args not in execute_by_num_args: + execute_by_num_args[num_args] = [None] * (rop._LAST+1) + execute = execute_by_num_args[num_args] + # if execute[value] is not None: raise Exception("duplicate entry for op number %d" % value) if key.endswith('_PURE'): @@ -301,23 +291,78 @@ execute[value] = wrap(globals()[name]) else: assert hasattr(AbstractCPU, name), name - cpuclass._execute_list = execute + cpuclass._execute_by_num_args = execute_by_num_args + -def get_execute_function(cpu, opnum): +def get_execute_funclist(cpu, num_args): + # workaround, similar to the next one + return cpu._execute_by_num_args[num_args] +get_execute_funclist._annspecialcase_ = 'specialize:memo' + +def get_execute_function(cpu, opnum, num_args): # workaround for an annotation limitation: putting this code in # a specialize:memo function makes sure the following line is - # constant-folded away. Only works if opnum is a constant, of course. - return cpu._execute_list[opnum] + # constant-folded away. Only works if opnum and num_args are + # constants, of course. + return cpu._execute_by_num_args[num_args][opnum] get_execute_function._annspecialcase_ = 'specialize:memo' -def execute(cpu, opnum, argboxes, descr=None): - check_descr(descr) - func = get_execute_function(cpu, opnum) +def has_descr(opnum): + # workaround, similar to the previous one + return resoperation.opwithdescr[opnum] +has_descr._annspecialcase_ = 'specialize:memo' + + +def execute(cpu, opnum, descr, *argboxes): + # only for opnums with a fixed arity + if has_descr(opnum): + check_descr(descr) + argboxes = argboxes + (descr,) + else: + assert descr is None + func = get_execute_function(cpu, opnum, len(argboxes)) assert func is not None - return func(cpu, argboxes, descr) + return func(cpu, *argboxes) execute._annspecialcase_ = 'specialize:arg(1)' -def _execute_nonspec(cpu, opnum, argboxes, descr=None): +def execute_varargs(cpu, opnum, argboxes, descr): + # only for opnums with a variable arity (calls, typically) check_descr(descr) - func = cpu._execute_list[opnum] + func = get_execute_function(cpu, opnum, -1) + assert func is not None return func(cpu, argboxes, descr) +execute_varargs._annspecialcase_ = 'specialize:arg(1)' + + +def execute_nonspec(cpu, opnum, argboxes, descr=None): + arity = resoperation.oparity[opnum] + assert arity == -1 or len(argboxes) == arity + if resoperation.opwithdescr[opnum]: + check_descr(descr) + if arity == -1: + func = get_execute_funclist(cpu, -1)[opnum] + return func(cpu, argboxes, descr) + if arity == 0: + func = get_execute_funclist(cpu, 1)[opnum] + return func(cpu, descr) + if arity == 1: + func = get_execute_funclist(cpu, 2)[opnum] + return func(cpu, argboxes[0], descr) + if arity == 2: + func = get_execute_funclist(cpu, 3)[opnum] + return func(cpu, argboxes[0], argboxes[1], descr) + if arity == 3: + func = get_execute_funclist(cpu, 4)[opnum] + return func(cpu, argboxes[0], argboxes[1], argboxes[2], descr) + else: + assert descr is None + if arity == 1: + func = get_execute_funclist(cpu, 1)[opnum] + return func(cpu, argboxes[0]) + if arity == 2: + func = get_execute_funclist(cpu, 2)[opnum] + return func(cpu, argboxes[0], argboxes[1]) + if arity == 3: + func = get_execute_funclist(cpu, 3)[opnum] + return func(cpu, argboxes[0], argboxes[1], argboxes[2]) + raise NotImplementedError Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/optimizefindnode.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/optimizefindnode.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/optimizefindnode.py Sat Sep 19 11:55:06 2009 @@ -6,7 +6,7 @@ from pypy.jit.metainterp.specnode import VirtualStructSpecNode from pypy.jit.metainterp.history import AbstractValue, ConstInt, Const from pypy.jit.metainterp.resoperation import rop -from pypy.jit.metainterp.executor import _execute_nonspec +from pypy.jit.metainterp.executor import execute_nonspec from pypy.jit.metainterp.optimizeutil import av_newdict, _findall, sort_descrs from pypy.jit.metainterp.optimizeutil import InvalidLoop @@ -159,7 +159,7 @@ else: # all constant arguments: we can constant-fold argboxes = [self.get_constant_box(arg) for arg in op.args] - resbox = _execute_nonspec(self.cpu, op.opnum, argboxes, op.descr) + resbox = execute_nonspec(self.cpu, op.opnum, argboxes, op.descr) self.set_constant_node(op.result, resbox.constbox()) # default case: mark the arguments as escaping for box in op.args: Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/optimizeopt.py Sat Sep 19 11:55:06 2009 @@ -1,7 +1,7 @@ from pypy.jit.metainterp.history import Box, BoxInt from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstObj, REF from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.metainterp.executor import _execute_nonspec +from pypy.jit.metainterp.executor import execute_nonspec from pypy.jit.metainterp.specnode import SpecNode, NotSpecNode, ConstantSpecNode from pypy.jit.metainterp.specnode import AbstractVirtualStructSpecNode from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode @@ -553,7 +553,7 @@ else: # all constant arguments: constant-fold away argboxes = [self.get_constant_box(arg) for arg in op.args] - resbox = _execute_nonspec(self.cpu, op.opnum, argboxes, op.descr) + resbox = execute_nonspec(self.cpu, op.opnum, argboxes, op.descr) self.make_constant(op.result, resbox.constbox()) return elif not op.has_no_side_effect() and not op.is_ovf(): Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py Sat Sep 19 11:55:06 2009 @@ -1218,7 +1218,7 @@ # execute the operation profiler = self.staticdata.profiler profiler.count_ops(opnum) - resbox = executor.execute(self.cpu, opnum, list(argboxes), descr) + resbox = executor.execute(self.cpu, opnum, descr, *argboxes) if self.is_blackholing(): return resbox if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: @@ -1239,7 +1239,7 @@ # execute the operation profiler = self.staticdata.profiler profiler.count_ops(opnum) - resbox = executor.execute(self.cpu, opnum, argboxes, descr) + resbox = executor.execute_varargs(self.cpu, opnum, argboxes, descr) if not self.is_blackholing(): if require_attention: require_attention = self.after_residual_call() Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resoperation.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resoperation.py Sat Sep 19 11:55:06 2009 @@ -126,97 +126,97 @@ 'OOSEND_PURE', # ootype operation 'CALL_PURE', # - 'CAST_PTR_TO_INT', - 'INT_ADD', - 'INT_SUB', - 'INT_MUL', - 'INT_FLOORDIV', - 'INT_MOD', - 'INT_AND', - 'INT_OR', - 'INT_XOR', - 'INT_RSHIFT', - 'INT_LSHIFT', - 'UINT_RSHIFT', - 'FLOAT_ADD', - 'FLOAT_SUB', - 'FLOAT_MUL', - 'FLOAT_TRUEDIV', - 'FLOAT_NEG', - 'FLOAT_ABS', - 'FLOAT_IS_TRUE', - 'CAST_FLOAT_TO_INT', - 'CAST_INT_TO_FLOAT', + 'CAST_PTR_TO_INT/1', + 'INT_ADD/2', + 'INT_SUB/2', + 'INT_MUL/2', + 'INT_FLOORDIV/2', + 'INT_MOD/2', + 'INT_AND/2', + 'INT_OR/2', + 'INT_XOR/2', + 'INT_RSHIFT/2', + 'INT_LSHIFT/2', + 'UINT_RSHIFT/2', + 'FLOAT_ADD/2', + 'FLOAT_SUB/2', + 'FLOAT_MUL/2', + 'FLOAT_TRUEDIV/2', + 'FLOAT_NEG/1', + 'FLOAT_ABS/1', + 'FLOAT_IS_TRUE/1', + 'CAST_FLOAT_TO_INT/1', + 'CAST_INT_TO_FLOAT/1', # '_COMPARISON_FIRST', - 'INT_LT', - 'INT_LE', - 'INT_EQ', - 'INT_NE', - 'INT_GT', - 'INT_GE', - 'UINT_LT', - 'UINT_LE', - 'UINT_GT', - 'UINT_GE', + 'INT_LT/2', + 'INT_LE/2', + 'INT_EQ/2', + 'INT_NE/2', + 'INT_GT/2', + 'INT_GE/2', + 'UINT_LT/2', + 'UINT_LE/2', + 'UINT_GT/2', + 'UINT_GE/2', '_COMPARISON_LAST', - 'FLOAT_LT', # maybe these ones should be comparisons too - 'FLOAT_LE', - 'FLOAT_EQ', - 'FLOAT_NE', - 'FLOAT_GT', - 'FLOAT_GE', - # - 'INT_IS_TRUE', - 'INT_NEG', - 'INT_INVERT', - 'BOOL_NOT', - # - 'SAME_AS', # gets a Const, turns it into a Box - # - 'OONONNULL', - 'OOISNULL', - 'OOIS', - 'OOISNOT', - # - 'ARRAYLEN_GC', - 'STRLEN', - 'STRGETITEM', - 'GETFIELD_GC_PURE', - 'GETFIELD_RAW_PURE', - 'GETARRAYITEM_GC_PURE', - 'UNICODELEN', - 'UNICODEGETITEM', + 'FLOAT_LT/2', # maybe these ones should be comparisons too + 'FLOAT_LE/2', + 'FLOAT_EQ/2', + 'FLOAT_NE/2', + 'FLOAT_GT/2', + 'FLOAT_GE/2', + # + 'INT_IS_TRUE/1', + 'INT_NEG/1', + 'INT_INVERT/1', + 'BOOL_NOT/1', + # + 'SAME_AS/1', # gets a Const, turns it into a Box + # + 'OONONNULL/1', + 'OOISNULL/1', + 'OOIS/2', + 'OOISNOT/2', + # + 'ARRAYLEN_GC/1d', + 'STRLEN/1', + 'STRGETITEM/2', + 'GETFIELD_GC_PURE/1d', + 'GETFIELD_RAW_PURE/1d', + 'GETARRAYITEM_GC_PURE/2d', + 'UNICODELEN/1', + 'UNICODEGETITEM/2', # # ootype operations - 'OOIDENTITYHASH', - 'INSTANCEOF', - 'SUBCLASSOF', + 'OOIDENTITYHASH/1', + 'INSTANCEOF/1d', + 'SUBCLASSOF/2', # '_ALWAYS_PURE_LAST', # ----- end of always_pure operations ----- - 'GETARRAYITEM_GC', - 'GETFIELD_GC', - 'GETFIELD_RAW', - 'NEW', - 'NEW_WITH_VTABLE', - 'NEW_ARRAY', + 'GETARRAYITEM_GC/2d', + 'GETFIELD_GC/1d', + 'GETFIELD_RAW/1d', + 'NEW/0d', + 'NEW_WITH_VTABLE/1', + 'NEW_ARRAY/1d', '_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations ----- - 'SETARRAYITEM_GC', - 'SETARRAYITEM_RAW', # only added by backend.llsupport.gc.rewrite_assembler - 'SETFIELD_GC', - 'SETFIELD_RAW', - 'NEWSTR', - 'STRSETITEM', - 'UNICODESETITEM', - 'NEWUNICODE', - 'RUNTIMENEW', # ootype operation + 'SETARRAYITEM_GC/3d', + 'SETARRAYITEM_RAW/3d',#only added by backend.llsupport.gc.rewrite_assembler + 'SETFIELD_GC/2d', + 'SETFIELD_RAW/2d', + 'NEWSTR/1', + 'STRSETITEM/3', + 'UNICODESETITEM/3', + 'NEWUNICODE/1', + 'RUNTIMENEW/1', # ootype operation 'COND_CALL_GC_WB', # [cond, imm_and, if_true_call, args_for_call...] # => no result (for the write barrier) 'COND_CALL_GC_MALLOC', # [a, b, if_(a<=b)_result, if_(a>b)_call, args...] # => result (for mallocs) - 'DEBUG_MERGE_POINT', # debugging only + 'DEBUG_MERGE_POINT/1', # debugging only '_CANRAISE_FIRST', # ----- start of can_raise operations ----- 'CALL', @@ -224,27 +224,41 @@ '_CANRAISE_LAST', # ----- end of can_raise operations ----- '_OVF_FIRST', # ----- start of is_ovf operations ----- - 'INT_ADD_OVF', - 'INT_SUB_OVF', - 'INT_MUL_OVF', + 'INT_ADD_OVF/2', + 'INT_SUB_OVF/2', + 'INT_MUL_OVF/2', '_OVF_LAST', # ----- end of is_ovf operations ----- '_LAST', # for the backend to add more internal operations ] +# ____________________________________________________________ + class rop(object): pass -i = 0 -for opname in _oplist: - if __name__ == '__main__': - print '%30s = %d' % (opname, i) # print out the table when run directly - setattr(rop, opname, i) - i += 1 -del _oplist - opname = {} # mapping numbers to the original names, for debugging -for _key, _value in rop.__dict__.items(): - if type(_value) is int and _key.isupper() and not _key.startswith('_'): - assert _value not in opname, "collision! %s and %s" % ( - opname[_value], _key) - opname[_value] = _key +oparity = [] # mapping numbers to the arity of the operation or -1 +opwithdescr = [] # mapping numbers to a flag "takes a descr" + + +def setup(debug_print=False): + i = 0 + for name in _oplist: + if debug_print: + print '%30s = %d' % (name, i) + if '/' in name: + name, arity = name.split('/') + withdescr = arity.endswith('d') + arity = int(arity.rstrip('d')) + else: + arity, withdescr = -1, True # default + setattr(rop, name, i) + opname[i] = name + oparity.append(arity) + opwithdescr.append(withdescr) + i += 1 + assert len(oparity) == i + assert len(opwithdescr) == i + +setup(__name__ == '__main__') # print out the table when run directly +del _oplist Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/specnode.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/specnode.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/specnode.py Sat Sep 19 11:55:06 2009 @@ -58,7 +58,7 @@ for ofs, subspecnode in self.fields: assert isinstance(ofs, history.AbstractDescr) fieldbox = executor.execute(cpu, resoperation.rop.GETFIELD_GC, - [valuebox], ofs) + ofs, valuebox) subspecnode.extract_runtime_data(cpu, fieldbox, resultlist) @@ -96,8 +96,8 @@ from pypy.jit.metainterp import executor, history, resoperation for i in range(len(self.items)): itembox = executor.execute(cpu, resoperation.rop.GETARRAYITEM_GC, - [valuebox, history.ConstInt(i)], - self.arraydescr) + self.arraydescr, + valuebox, history.ConstInt(i)) subspecnode = self.items[i] subspecnode.extract_runtime_data(cpu, itembox, resultlist) Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_basic.py Sat Sep 19 11:55:06 2009 @@ -1001,7 +1001,7 @@ x = lltype.malloc(TP) res = self.interp_operations(f, [x]) expected = self.metainterp.cpu.do_cast_ptr_to_int( - [history.BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, x))]).value + history.BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, x))).value assert res == expected class TestLLtype(BaseLLtypeTests, LLJitMixin): Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_executor.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_executor.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_executor.py Sat Sep 19 11:55:06 2009 @@ -1,19 +1,93 @@ import py from pypy.jit.metainterp.executor import make_execute_list, execute +from pypy.jit.metainterp.executor import execute_varargs, execute_nonspec from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp.history import BoxInt, ConstInt from pypy.jit.metainterp.history import BoxFloat, ConstFloat +from pypy.jit.metainterp.history import AbstractDescr, Box from pypy.jit.backend.model import AbstractCPU +class FakeDescr(AbstractDescr): + pass + +class FakeBox(Box): + def __init__(self, *args): + self.args = args + class FakeCPU(AbstractCPU): supports_floats = True + + def do_new(self, descr): + return FakeBox('new', descr) + + def do_arraylen_gc(self, box1, descr): + return FakeBox('arraylen_gc', box1, descr) + + def do_setfield_gc(self, box1, box2, descr): + return FakeBox('setfield_gc', box1, box2, descr) + + def do_setarrayitem_gc(self, box1, box2, box3, descr): + return FakeBox('setarrayitem_gc', box1, box2, box3, descr) + + def do_call(self, args, descr): + return FakeBox('call', args, descr) + + def do_strsetitem(self, box1, box2, box3): + return FakeBox('strsetitem', box1, box2, box3) + make_execute_list(FakeCPU) -def test_int_ops(): - box = execute(FakeCPU(), rop.INT_ADD, [BoxInt(40), ConstInt(2)]) +def test_execute(): + cpu = FakeCPU() + descr = FakeDescr() + box = execute(cpu, rop.INT_ADD, None, BoxInt(40), ConstInt(2)) assert box.value == 42 + box = execute(cpu, rop.NEW, descr) + assert box.args == ('new', descr) + +def test_execute_varargs(): + cpu = FakeCPU() + descr = FakeDescr() + argboxes = [BoxInt(321), ConstInt(123)] + box = execute_varargs(cpu, rop.CALL, argboxes, descr) + assert box.args == ('call', argboxes, descr) + +def test_execute_nonspec(): + cpu = FakeCPU() + descr = FakeDescr() + # cases with a descr + # arity == -1 + argboxes = [BoxInt(321), ConstInt(123)] + box = execute_nonspec(cpu, rop.CALL, argboxes, descr) + assert box.args == ('call', argboxes, descr) + # arity == 0 + box = execute_nonspec(cpu, rop.NEW, [], descr) + assert box.args == ('new', descr) + # arity == 1 + box1 = BoxInt(515) + box = execute_nonspec(cpu, rop.ARRAYLEN_GC, [box1], descr) + assert box.args == ('arraylen_gc', box1, descr) + # arity == 2 + box2 = BoxInt(222) + box = execute_nonspec(cpu, rop.SETFIELD_GC, [box1, box2], descr) + assert box.args == ('setfield_gc', box1, box2, descr) + # arity == 3 + box3 = BoxInt(-33) + box = execute_nonspec(cpu, rop.SETARRAYITEM_GC, [box1, box2, box3], descr) + assert box.args == ('setarrayitem_gc', box1, box2, box3, descr) + # cases without descr + # arity == 1 + box = execute_nonspec(cpu, rop.INT_INVERT, [box1]) + assert box.value == ~515 + # arity == 2 + box = execute_nonspec(cpu, rop.INT_LSHIFT, [box1, BoxInt(3)]) + assert box.value == 515 << 3 + # arity == 3 + box = execute_nonspec(cpu, rop.STRSETITEM, [box1, box2, box3]) + assert box.args == ('strsetitem', box1, box2, box3) + def _float_binary_operations(): for opnum, testcases in [ @@ -63,7 +137,7 @@ def test_float_ops(): cpu = FakeCPU() for opnum, boxargs, rettype, retvalue in get_float_tests(cpu): - box = execute(cpu, opnum, boxargs) + box = execute_nonspec(cpu, opnum, boxargs) if rettype == 'float': assert box.getfloat() == retvalue elif rettype == 'int': From arigo at codespeak.net Sat Sep 19 12:13:15 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 19 Sep 2009 12:13:15 +0200 (CEST) Subject: [pypy-svn] r67791 - in pypy/branch/execute-star-args-jit/pypy/jit: backend backend/llsupport metainterp metainterp/test Message-ID: <20090919101315.445C4168015@codespeak.net> Author: arigo Date: Sat Sep 19 12:13:14 2009 New Revision: 67791 Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/llsupport/llmodel.py pypy/branch/execute-star-args-jit/pypy/jit/backend/model.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resoperation.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_optimizeopt.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_resume.py Log: Fix model and llmodel. Fix tests in metainterp. Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/llsupport/llmodel.py Sat Sep 19 12:13:14 2009 @@ -247,16 +247,16 @@ # ____________________________________________________________ - def do_arraylen_gc(self, args, arraydescr): + def do_arraylen_gc(self, arraybox, arraydescr): assert isinstance(arraydescr, BaseArrayDescr) ofs = arraydescr.get_ofs_length(self.translate_support_code) - gcref = args[0].getref_base() + gcref = arraybox.getref_base() length = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref)[ofs/WORD] return BoxInt(length) - def do_getarrayitem_gc(self, args, arraydescr): - itemindex = args[1].getint() - gcref = args[0].getref_base() + def do_getarrayitem_gc(self, arraybox, indexbox, arraydescr): + itemindex = indexbox.getint() + gcref = arraybox.getref_base() ofs, size, ptr = self.unpack_arraydescr(arraydescr) # for TYPE, itemsize in unroll_basic_sizes: @@ -272,11 +272,10 @@ else: return BoxInt(val) - def do_setarrayitem_gc(self, args, arraydescr): - itemindex = args[1].getint() - gcref = args[0].getref_base() + def do_setarrayitem_gc(self, arraybox, indexbox, vbox, arraydescr): + itemindex = indexbox.getint() + gcref = arraybox.getref_base() ofs, size, ptr = self.unpack_arraydescr(arraydescr) - vbox = args[2] # if ptr: vboxptr = vbox.getref_base() @@ -294,10 +293,10 @@ raise NotImplementedError("size = %d" % size) def _new_do_len(TP): - def do_strlen(self, args, descr=None): + def do_strlen(self, stringbox): basesize, itemsize, ofs_length = symbolic.get_array_token(TP, self.translate_support_code) - gcref = args[0].getref_base() + gcref = stringbox.getref_base() v = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref)[ofs_length/WORD] return BoxInt(v) return do_strlen @@ -305,19 +304,19 @@ do_strlen = _new_do_len(rstr.STR) do_unicodelen = _new_do_len(rstr.UNICODE) - def do_strgetitem(self, args, descr=None): + def do_strgetitem(self, stringbox, indexbox): basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR, self.translate_support_code) - gcref = args[0].getref_base() - i = args[1].getint() + gcref = stringbox.getref_base() + i = indexbox.getint() v = rffi.cast(rffi.CArrayPtr(lltype.Char), gcref)[basesize + i] return BoxInt(ord(v)) - def do_unicodegetitem(self, args, descr=None): + def do_unicodegetitem(self, stringbox, indexbox): basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE, self.translate_support_code) - gcref = args[0].getref_base() - i = args[1].getint() + gcref = stringbox.getref_base() + i = indexbox.getint() basesize = basesize // itemsize v = rffi.cast(rffi.CArrayPtr(lltype.UniChar), gcref)[basesize + i] return BoxInt(ord(v)) @@ -337,12 +336,12 @@ else: return BoxInt(val) - def do_getfield_gc(self, args, fielddescr): - gcref = args[0].getref_base() + def do_getfield_gc(self, structbox, fielddescr): + gcref = structbox.getref_base() return self._base_do_getfield(gcref, fielddescr) - def do_getfield_raw(self, args, fielddescr): - return self._base_do_getfield(args[0].getint(), fielddescr) + def do_getfield_raw(self, structbox, fielddescr): + return self._base_do_getfield(structbox.getint(), fielddescr) @specialize.argtype(1) def _base_do_setfield(self, gcref, vbox, fielddescr): @@ -364,55 +363,54 @@ else: raise NotImplementedError("size = %d" % size) - def do_setfield_gc(self, args, fielddescr): - gcref = args[0].getref_base() - self._base_do_setfield(gcref, args[1], fielddescr) + def do_setfield_gc(self, structbox, vbox, fielddescr): + gcref = structbox.getref_base() + self._base_do_setfield(gcref, vbox, fielddescr) - def do_setfield_raw(self, args, fielddescr): - self._base_do_setfield(args[0].getint(), args[1], fielddescr) + def do_setfield_raw(self, structbox, vbox, fielddescr): + self._base_do_setfield(structbox.getint(), vbox, fielddescr) - def do_new(self, args, sizedescr): + def do_new(self, sizedescr): res = self.gc_ll_descr.gc_malloc(sizedescr) return BoxPtr(res) - def do_new_with_vtable(self, args, descr=None): - assert descr is None - classint = args[0].getint() + def do_new_with_vtable(self, classbox): + classint = classbox.getint() descrsize = self.class_sizes[classint] res = self.gc_ll_descr.gc_malloc(descrsize) as_array = rffi.cast(rffi.CArrayPtr(lltype.Signed), res) as_array[self.vtable_offset/WORD] = classint return BoxPtr(res) - def do_new_array(self, args, arraydescr): - num_elem = args[0].getint() + def do_new_array(self, countbox, arraydescr): + num_elem = countbox.getint() res = self.gc_ll_descr.gc_malloc_array(arraydescr, num_elem) return BoxPtr(res) - def do_newstr(self, args, descr=None): - num_elem = args[0].getint() + def do_newstr(self, countbox): + num_elem = countbox.getint() res = self.gc_ll_descr.gc_malloc_str(num_elem) return BoxPtr(res) - def do_newunicode(self, args, descr=None): - num_elem = args[0].getint() + def do_newunicode(self, countbox): + num_elem = countbox.getint() res = self.gc_ll_descr.gc_malloc_unicode(num_elem) return BoxPtr(res) - def do_strsetitem(self, args, descr=None): + def do_strsetitem(self, stringbox, indexbox, vbox): basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR, self.translate_support_code) - index = args[1].getint() - v = args[2].getint() - a = args[0].getref_base() + index = indexbox.getint() + v = vbox.getint() + a = stringbox.getref_base() rffi.cast(rffi.CArrayPtr(lltype.Char), a)[index + basesize] = chr(v) - def do_unicodesetitem(self, args, descr=None): + def do_unicodesetitem(self, stringbox, indexbox, vbox): basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE, self.translate_support_code) - index = args[1].getint() - v = args[2].getint() - a = args[0].getref_base() + index = indexbox.getint() + v = vbox.getint() + a = stringbox.getref_base() basesize = basesize // itemsize rffi.cast(rffi.CArrayPtr(lltype.UniChar), a)[index + basesize] = unichr(v) @@ -434,8 +432,8 @@ else: return None - def do_cast_ptr_to_int(self, args, descr=None): - return BoxInt(self.cast_gcref_to_int(args[0].getref_base())) + def do_cast_ptr_to_int(self, ptrbox): + return BoxInt(self.cast_gcref_to_int(ptrbox.getref_base())) import pypy.jit.metainterp.executor Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/backend/model.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/model.py Sat Sep 19 12:13:14 2009 @@ -103,61 +103,61 @@ # lltype specific operations # -------------------------- - def do_arraylen_gc(self, args, arraydescr): + def do_arraylen_gc(self, arraybox, arraydescr): raise NotImplementedError - def do_strlen(self, args, descr=None): + def do_strlen(self, stringbox): raise NotImplementedError - def do_strgetitem(self, args, descr=None): + def do_strgetitem(self, stringbox, indexbox): raise NotImplementedError - def do_unicodelen(self, args, descr=None): + def do_unicodelen(self, stringbox): raise NotImplementedError - def do_unicodegetitem(self, args, descr=None): + def do_unicodegetitem(self, stringbox, indexbox): raise NotImplementedError - def do_getarrayitem_gc(self, args, arraydescr): + def do_getarrayitem_gc(self, arraybox, indexbox, arraydescr): raise NotImplementedError - def do_getfield_gc(self, args, fielddescr): + def do_getfield_gc(self, structbox, fielddescr): raise NotImplementedError - def do_getfield_raw(self, args, fielddescr): + def do_getfield_raw(self, structbox, fielddescr): raise NotImplementedError - def do_new(self, args, sizedescr): + def do_new(self, sizedescr): raise NotImplementedError - def do_new_with_vtable(self, args, descr=None): + def do_new_with_vtable(self, classbox): raise NotImplementedError - def do_new_array(self, args, arraydescr): + def do_new_array(self, lengthbox, arraydescr): raise NotImplementedError - def do_setarrayitem_gc(self, args, arraydescr): + def do_setarrayitem_gc(self, arraybox, indexbox, newvaluebox, arraydescr): raise NotImplementedError - def do_setarrayitem_raw(self, args, arraydescr): + def do_setarrayitem_raw(self, arraybox, indexbox, newvaluebox, arraydescr): raise NotImplementedError - def do_setfield_gc(self, args, fielddescr): + def do_setfield_gc(self, structbox, newvaluebox, fielddescr): raise NotImplementedError - def do_setfield_raw(self, args, fielddescr): + def do_setfield_raw(self, structbox, newvaluebox, fielddescr): raise NotImplementedError - def do_newstr(self, args, descr=None): + def do_newstr(self, lengthbox): raise NotImplementedError - def do_newunicode(self, args, descr=None): + def do_newunicode(self, lengthbox): raise NotImplementedError - def do_strsetitem(self, args, descr=None): + def do_strsetitem(self, stringbox, indexbox, charbox): raise NotImplementedError - def do_unicodesetitem(self, args, descr=None): + def do_unicodesetitem(self, stringbox, indexbox, charbox): raise NotImplementedError def do_call(self, args, calldescr): @@ -170,19 +170,19 @@ def do_cond_call_gc_malloc(self, args, calldescr): raise NotImplementedError - def do_cast_ptr_to_int(self, args, descr=None): + def do_cast_ptr_to_int(self, ptrbox): raise NotImplementedError # ootype specific operations # -------------------------- - def do_runtimenew(self, args, descr=None): + def do_runtimenew(self, classbox): raise NotImplementedError - def do_oosend(self, args, descr=None): + def do_oosend(self, args, descr): raise NotImplementedError - def do_instanceof(self, args, descr=None): + def do_instanceof(self, instancebox, typedescr): raise NotImplementedError @staticmethod Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resoperation.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resoperation.py Sat Sep 19 12:13:14 2009 @@ -242,8 +242,7 @@ def setup(debug_print=False): - i = 0 - for name in _oplist: + for i, name in enumerate(_oplist): if debug_print: print '%30s = %d' % (name, i) if '/' in name: @@ -253,12 +252,11 @@ else: arity, withdescr = -1, True # default setattr(rop, name, i) - opname[i] = name + if not name.startswith('_'): + opname[i] = name oparity.append(arity) opwithdescr.append(withdescr) - i += 1 - assert len(oparity) == i - assert len(opwithdescr) == i + assert len(oparity) == len(opwithdescr) == len(_oplist) setup(__name__ == '__main__') # print out the table when run directly del _oplist Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_optimizeopt.py Sat Sep 19 12:13:14 2009 @@ -152,7 +152,7 @@ def test_constfold_all(self): from pypy.jit.backend.llgraph.llimpl import TYPES # xxx fish - from pypy.jit.metainterp.executor import _execute_nonspec + from pypy.jit.metainterp.executor import execute_nonspec from pypy.jit.metainterp.history import BoxInt import random for opnum in range(rop.INT_ADD, rop.BOOL_NOT+1): @@ -175,8 +175,8 @@ jump() """ % (op.lower(), ', '.join(map(str, args))) argboxes = [BoxInt(a) for a in args] - expected_value = _execute_nonspec(self.cpu, opnum, - argboxes).getint() + expected_value = execute_nonspec(self.cpu, opnum, + argboxes).getint() expected = """ [] escape(%d) @@ -1386,14 +1386,14 @@ fielddescr = self.namespace[fieldname.strip()] fieldbox = executor.execute(self.cpu, rop.GETFIELD_GC, - [resolved], - descr=fielddescr) + fielddescr, + resolved) elif tag[0] == 'varray': fieldvalue = fieldtext fieldbox = executor.execute(self.cpu, rop.GETARRAYITEM_GC, - [resolved, ConstInt(index)], - descr=tag[1]) + tag[1], + resolved, ConstInt(index)) else: assert 0 _variables_equal(fieldbox, fieldvalue.strip(), strict=False) Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_resume.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_resume.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_resume.py Sat Sep 19 12:13:14 2009 @@ -62,7 +62,7 @@ self.cpu = cpu self.trace = [] def execute_and_record(self, opnum, descr, *argboxes): - resbox = executor.execute(self.cpu, opnum, argboxes, descr) + resbox = executor.execute(self.cpu, opnum, descr, *argboxes) self.trace.append((opnum, [box.value for box in argboxes], resbox and resbox.value, From arigo at codespeak.net Sat Sep 19 12:40:55 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 19 Sep 2009 12:40:55 +0200 (CEST) Subject: [pypy-svn] r67792 - in pypy/trunk/pypy/translator/c: . src Message-ID: <20090919104055.E2384168015@codespeak.net> Author: arigo Date: Sat Sep 19 12:40:55 2009 New Revision: 67792 Modified: pypy/trunk/pypy/translator/c/gc.py pypy/trunk/pypy/translator/c/src/mem.h Log: Two fixes: * we don't need op.result, so don't pass it * the comment must be exactly GC_STACK_BOTTOM! Renaming the macro does not mean the comment should also be renamed, because trackgcroot.py will no longer find it. Fixes c/gcc/test/. Modified: pypy/trunk/pypy/translator/c/gc.py ============================================================================== --- pypy/trunk/pypy/translator/c/gc.py (original) +++ pypy/trunk/pypy/translator/c/gc.py Sat Sep 19 12:40:55 2009 @@ -329,7 +329,7 @@ return 'pypy_asm_keepalive(%s);' % funcgen.expr(v) def OP_GC_STACK_BOTTOM(self, funcgen, op): - return 'pypy_asm_stack_bottom(%s);' % funcgen.expr(op.result) + return 'pypy_asm_stack_bottom();' name_to_gcpolicy = { Modified: pypy/trunk/pypy/translator/c/src/mem.h ============================================================================== --- pypy/trunk/pypy/translator/c/src/mem.h (original) +++ pypy/trunk/pypy/translator/c/src/mem.h Sat Sep 19 12:40:55 2009 @@ -49,7 +49,7 @@ "g" (v)) /* marker for trackgcroot.py */ -#define pypy_asm_stack_bottom(r) asm volatile ("/* asm_stack_bottom */" : : ) +#define pypy_asm_stack_bottom() asm volatile ("/* GC_STACK_BOTTOM */" : : ) #define OP_GC_ASMGCROOT_STATIC(i, r) r = \ i == 0 ? (void*)&__gcmapstart : \ From arigo at codespeak.net Sat Sep 19 12:42:13 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 19 Sep 2009 12:42:13 +0200 (CEST) Subject: [pypy-svn] r67793 - pypy/branch/execute-star-args-jit/pypy/jit/backend/cli Message-ID: <20090919104213.575E2168015@codespeak.net> Author: arigo Date: Sat Sep 19 12:42:12 2009 New Revision: 67793 Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/cli/runner.py Log: Fix the cli backend too. Not really tested. Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/cli/runner.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/backend/cli/runner.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/cli/runner.py Sat Sep 19 12:42:12 2009 @@ -163,38 +163,30 @@ # ---------------------- - def do_new_with_vtable(self, args, descr): - #assert isinstance(typedescr, TypeDescr) - #assert len(args) == 1 # but we don't need it, so ignore - assert descr is None - assert len(args) == 1 - cls = args[0].getref_base() + def do_new_with_vtable(self, classbox): + cls = classbox.getref_base() typedescr = self.class_sizes[cls] return typedescr.create() - def do_new_array(self, args, typedescr): + def do_new_array(self, lengthbox, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 1 - return typedescr.create_array(args[0]) + return typedescr.create_array(lengthbox) - def do_runtimenew(self, args, descr): - classbox = args[0] + def do_runtimenew(self, classbox): classobj = classbox.getref(ootype.Class) res = ootype.runtimenew(classobj) return BoxObj(ootype.cast_to_object(res)) - def do_instanceof(self, args, typedescr): - assert isinstance(typedescr, TypeDescr) - assert len(args) == 1 - return typedescr.instanceof(args[0]) + def do_instanceof(self, instancebox, typedescr): + return typedescr.instanceof(instancebox) - def do_getfield_gc(self, args, fielddescr): + def do_getfield_gc(self, instancebox, fielddescr): assert isinstance(fielddescr, FieldDescr) - return fielddescr.getfield(args[0]) + return fielddescr.getfield(instancebox) - def do_setfield_gc(self, args, fielddescr): + def do_setfield_gc(self, instancebox, newvaluebox, fielddescr): assert isinstance(fielddescr, FieldDescr) - return fielddescr.setfield(args[0], args[1]) + return fielddescr.setfield(instancebox, newvaluebox) def do_call(self, args, calldescr): assert isinstance(calldescr, StaticMethDescr) @@ -213,31 +205,22 @@ obj = ootype.cast_to_object(inst) # SomeOOObject return dotnet.cast_to_native_object(obj) # System.Object - def do_oosend(self, args, descr=None): + def do_oosend(self, args, descr): assert isinstance(descr, MethDescr) selfbox = args[0] argboxes = args[1:] return descr.callmeth(selfbox, argboxes) - def do_getarrayitem_gc(self, args, descr): + def do_getarrayitem_gc(self, arraybox, indexbox, descr): assert isinstance(descr, TypeDescr) - assert len(args) == 2 - arraybox = args[0] - ibox = args[1] - return descr.getarrayitem(arraybox, ibox) + return descr.getarrayitem(arraybox, indexbox) - def do_setarrayitem_gc(self, args, descr): + def do_setarrayitem_gc(self, arraybox, indexbox, newvaluebox, descr): assert isinstance(descr, TypeDescr) - assert len(args) == 3 - arraybox = args[0] - ibox = args[1] - valuebox = args[2] - descr.setarrayitem(arraybox, ibox, valuebox) + descr.setarrayitem(arraybox, indexbox, newvaluebox) - def do_arraylen_gc(self, args, descr): + def do_arraylen_gc(self, arraybox, descr): assert isinstance(descr, TypeDescr) - assert len(args) == 1 - arraybox = args[0] return descr.getarraylength(arraybox) # ---------------------------------------------------------------------- From arigo at codespeak.net Sat Sep 19 12:42:37 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 19 Sep 2009 12:42:37 +0200 (CEST) Subject: [pypy-svn] r67794 - in pypy/branch/execute-star-args-jit/pypy/jit/backend: test x86/test Message-ID: <20090919104237.5C49E168015@codespeak.net> Author: arigo Date: Sat Sep 19 12:42:36 2009 New Revision: 67794 Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/test/test_random.py pypy/branch/execute-star-args-jit/pypy/jit/backend/x86/test/test_runner.py Log: Two test fixes. Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/backend/test/test_random.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/test/test_random.py Sat Sep 19 12:42:36 2009 @@ -5,7 +5,7 @@ from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt from pypy.jit.metainterp.history import BoxPtr, ConstPtr, ConstAddr from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.executor import execute +from pypy.jit.metainterp.executor import execute_nonspec from pypy.jit.metainterp.resoperation import opname class PleaseRewriteMe(Exception): @@ -32,7 +32,7 @@ return fork def do(self, opnum, argboxes, descr=None): - v_result = execute(self.cpu, opnum, argboxes, descr) + v_result = execute_nonspec(self.cpu, opnum, argboxes, descr) if isinstance(v_result, ConstInt): v_result = BoxInt(v_result.value) self.loop.operations.append(ResOperation(opnum, argboxes, v_result, Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/x86/test/test_runner.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/backend/x86/test/test_runner.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/x86/test/test_runner.py Sat Sep 19 12:42:36 2009 @@ -336,9 +336,9 @@ r = self.cpu.execute_operations(loop) result = self.cpu.get_latest_value_int(0) if guard == rop.GUARD_FALSE: - assert result == execute(self.cpu, op, [b]).value + assert result == execute(self.cpu, op, None, b).value else: - assert result != execute(self.cpu, op, [b]).value + assert result != execute(self.cpu, op, None, b).value def test_stuff_followed_by_guard(self): @@ -378,10 +378,11 @@ self.cpu.set_future_value_int(i, box.value) r = self.cpu.execute_operations(loop) result = self.cpu.get_latest_value_int(0) + expected = execute(self.cpu, op, None, a, b).value if guard == rop.GUARD_FALSE: - assert result == execute(self.cpu, op, (a, b)).value + assert result == expected else: - assert result != execute(self.cpu, op, (a, b)).value + assert result != expected def test_overflow_mc(self): from pypy.jit.backend.x86.assembler import MachineCodeBlockWrapper @@ -404,6 +405,7 @@ loop.operations = ops loop.inputargs = [base_v] self.cpu.compile_operations(loop) + assert self.cpu.assembler.mc != old_mc # overflowed self.cpu.set_future_value_int(0, base_v.value) op = self.cpu.execute_operations(loop) assert self.cpu.get_latest_value_int(0) == 1024 From antocuni at codespeak.net Sat Sep 19 13:38:03 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 19 Sep 2009 13:38:03 +0200 (CEST) Subject: [pypy-svn] r67795 - pypy/branch/blocklist Message-ID: <20090919113803.0F9CD168015@codespeak.net> Author: antocuni Date: Sat Sep 19 13:38:03 2009 New Revision: 67795 Added: pypy/branch/blocklist/ - copied from r67794, pypy/trunk/ Log: a branch in which to turn frame.blockstack into a linked list of blocks From antocuni at codespeak.net Sat Sep 19 13:40:00 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 19 Sep 2009 13:40:00 +0200 (CEST) Subject: [pypy-svn] r67796 - in pypy/branch/blocklist/pypy: interpreter objspace/flow Message-ID: <20090919114000.EB92D168015@codespeak.net> Author: antocuni Date: Sat Sep 19 13:40:00 2009 New Revision: 67796 Modified: pypy/branch/blocklist/pypy/interpreter/generator.py pypy/branch/blocklist/pypy/interpreter/pyframe.py pypy/branch/blocklist/pypy/interpreter/pyopcode.py pypy/branch/blocklist/pypy/objspace/flow/framestate.py Log: turn frame.blockstack into a linked list of blocks Modified: pypy/branch/blocklist/pypy/interpreter/generator.py ============================================================================== --- pypy/branch/blocklist/pypy/interpreter/generator.py (original) +++ pypy/branch/blocklist/pypy/interpreter/generator.py Sat Sep 19 13:40:00 2009 @@ -126,10 +126,12 @@ # Only bother raising an exception if the frame is still not # finished and finally or except blocks are present. if not self.frame.frame_finished_execution: - for block in self.frame.blockstack: + block = self.frame.lastblock + while block is not None: if not isinstance(block, LoopBlock): self.descr_close() return + block = block.previous def __del__(self): self._enqueue_for_destruction(self.space) Modified: pypy/branch/blocklist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/branch/blocklist/pypy/interpreter/pyframe.py (original) +++ pypy/branch/blocklist/pypy/interpreter/pyframe.py Sat Sep 19 13:40:00 2009 @@ -55,7 +55,8 @@ eval.Frame.__init__(self, space, w_globals, code.co_nlocals) self.valuestack_w = [None] * code.co_stacksize self.valuestackdepth = 0 - self.blockstack = [] + self.lastblock = None + self.blockcount = 0 if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. @@ -66,6 +67,34 @@ self.f_lineno = code.co_firstlineno ExecutionContext._init_chaining_attributes(self) + def append_block(self, block): + block.previous = self.lastblock + self.lastblock = block + self.blockcount += 1 + + def pop_block(self): + block = self.lastblock + self.lastblock = block.previous + self.blockcount -= 1 + return block + + def get_blocklist(self): + """Returns a list containing all the blocks in the frame""" + lst = [None] * self.blockcount + block = self.lastblock + i = 0 + while block is not None: + lst[i] = block + i += 1 + block = block.previous + return lst + + def set_blocklist(self, lst): + self.lastblock = None + self.blockcount = 0 + for block in lst[::-1]: + self.append_block(block) + def get_builtin(self): if self.space.config.objspace.honor__builtins__: return self.builtin @@ -277,7 +306,7 @@ values_w = self.valuestack_w[0:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) - w_blockstack = nt([block._get_state_(space) for block in self.blockstack]) + w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) if self.last_exception is None: w_exc_value = space.w_None @@ -343,8 +372,8 @@ new_frame.f_back_forced = True new_frame.builtin = space.interp_w(Module, w_builtin) - new_frame.blockstack = [unpickle_block(space, w_blk) - for w_blk in space.unpackiterable(w_blockstack)] + new_frame.set_blocklist([unpickle_block(space, w_blk) + for w_blk in space.unpackiterable(w_blockstack)]) values_w = maker.slp_from_tuple_with_nulls(space, w_valuestack) for w_value in values_w: new_frame.pushvalue(w_value) @@ -532,7 +561,7 @@ else: addr += 1 - f_iblock = len(self.blockstack) + f_iblock = self.blockcount min_iblock = f_iblock + min_delta_iblock if new_lasti > self.last_instr: new_iblock = f_iblock + delta_iblock @@ -544,7 +573,7 @@ space.wrap("can't jump into the middle of a block")) while f_iblock > new_iblock: - block = self.blockstack.pop() + block = self.pop_block() block.cleanup(self) f_iblock -= 1 Modified: pypy/branch/blocklist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/branch/blocklist/pypy/interpreter/pyopcode.py (original) +++ pypy/branch/blocklist/pypy/interpreter/pyopcode.py Sat Sep 19 13:40:00 2009 @@ -273,10 +273,10 @@ return next_instr def unrollstack(self, unroller_kind): - n = len(self.blockstack) + n = self.blockcount n = hint(n, promote=True) while n > 0: - block = self.blockstack.pop() + block = self.pop_block() n -= 1 if (block.handling_mask & unroller_kind) != 0: return block @@ -591,7 +591,7 @@ f.setdictscope(w_locals) def POP_BLOCK(f, *ignored): - block = f.blockstack.pop() + block = f.pop_block() block.cleanup(f) # the block knows how to clean up the value stack def end_finally(f): @@ -860,15 +860,15 @@ def SETUP_LOOP(f, offsettoend, next_instr, *ignored): block = LoopBlock(f, next_instr + offsettoend) - f.blockstack.append(block) + f.append_block(block) def SETUP_EXCEPT(f, offsettoend, next_instr, *ignored): block = ExceptBlock(f, next_instr + offsettoend) - f.blockstack.append(block) + f.append_block(block) def SETUP_FINALLY(f, offsettoend, next_instr, *ignored): block = FinallyBlock(f, next_instr + offsettoend) - f.blockstack.append(block) + f.append_block(block) def WITH_CLEANUP(f, *ignored): # see comment in END_FINALLY for stack state @@ -1130,6 +1130,7 @@ def __init__(self, frame, handlerposition): self.handlerposition = handlerposition self.valuestackdepth = frame.valuestackdepth + self.previous = None # this makes a linked list of blocks def __eq__(self, other): return (self.__class__ is other.__class__ and @@ -1175,7 +1176,7 @@ # re-push the loop block without cleaning up the value stack, # and jump to the beginning of the loop, stored in the # exception's argument - frame.blockstack.append(self) + frame.append_block(self) return unroller.jump_to else: # jump to the end of the loop Modified: pypy/branch/blocklist/pypy/objspace/flow/framestate.py ============================================================================== --- pypy/branch/blocklist/pypy/objspace/flow/framestate.py (original) +++ pypy/branch/blocklist/pypy/objspace/flow/framestate.py Sat Sep 19 13:40:00 2009 @@ -20,7 +20,7 @@ recursively_flatten(state.space, data) self.mergeable = data self.nonmergeable = ( - state.blockstack[:], + state.get_blocklist(), state.last_instr, # == next_instr when between bytecodes state.w_locals, ) @@ -47,10 +47,11 @@ else: frame.last_exception = OperationError(data[-2], data[-1]) ( - frame.blockstack[:], + blocklist, frame.last_instr, frame.w_locals, ) = self.nonmergeable + frame.set_blocklist(blocklist) else: raise TypeError("can't set framestate for %r" % frame.__class__.__name__) From antocuni at codespeak.net Sat Sep 19 13:58:39 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 19 Sep 2009 13:58:39 +0200 (CEST) Subject: [pypy-svn] r67797 - pypy/branch/blocklist/pypy/interpreter Message-ID: <20090919115839.B23A616801D@codespeak.net> Author: antocuni Date: Sat Sep 19 13:58:39 2009 New Revision: 67797 Modified: pypy/branch/blocklist/pypy/interpreter/pyframe.py Log: rpython fix; slices such as [::-1] are not supported Modified: pypy/branch/blocklist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/branch/blocklist/pypy/interpreter/pyframe.py (original) +++ pypy/branch/blocklist/pypy/interpreter/pyframe.py Sat Sep 19 13:58:39 2009 @@ -92,7 +92,10 @@ def set_blocklist(self, lst): self.lastblock = None self.blockcount = 0 - for block in lst[::-1]: + i = len(lst) + while i > 0: + block = lst[i-1] + i -= 1 self.append_block(block) def get_builtin(self): From pedronis at codespeak.net Sat Sep 19 14:27:08 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 19 Sep 2009 14:27:08 +0200 (CEST) Subject: [pypy-svn] r67798 - in pypy/branch/execute-star-args-jit/pypy/jit/metainterp: . test Message-ID: <20090919122708.B524B168013@codespeak.net> Author: pedronis Date: Sat Sep 19 14:27:08 2009 New Revision: 67798 Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/history.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_jitprof.py Log: fix profiler op counting, some more testing Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/history.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/history.py Sat Sep 19 14:27:08 2009 @@ -8,7 +8,6 @@ from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.jitprof import BLACKHOLED_OPS, RECORDED_OPS import py from pypy.tool.ansi_print import ansi_log Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py Sat Sep 19 14:27:08 2009 @@ -10,7 +10,8 @@ from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import codewriter, executor from pypy.jit.backend.logger import Logger -from pypy.jit.metainterp.jitprof import EmptyProfiler, GUARDS +from pypy.jit.metainterp.jitprof import EmptyProfiler, BLACKHOLED_OPS +from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize @@ -1220,6 +1221,7 @@ profiler.count_ops(opnum) resbox = executor.execute(self.cpu, opnum, descr, *argboxes) if self.is_blackholing(): + profiler.count_ops(opnum, BLACKHOLED_OPS) return resbox if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: return self._record_helper_pure(opnum, resbox, descr, *argboxes) @@ -1240,7 +1242,9 @@ profiler = self.staticdata.profiler profiler.count_ops(opnum) resbox = executor.execute_varargs(self.cpu, opnum, argboxes, descr) - if not self.is_blackholing(): + if self.is_blackholing(): + profiler.count_ops(opnum, BLACKHOLED_OPS) + else: if require_attention: require_attention = self.after_residual_call() # check if the operation can be constant-folded away @@ -1274,6 +1278,8 @@ def _record_helper_nonpure_varargs(self, opnum, resbox, descr, argboxes): assert resbox is None or isinstance(resbox, Box) # record the operation + profiler = self.staticdata.profiler + profiler.count_ops(opnum, RECORDED_OPS) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) return resbox Modified: pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_jitprof.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_jitprof.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_jitprof.py Sat Sep 19 14:27:08 2009 @@ -1,6 +1,6 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp -from pypy.rlib.jit import JitDriver, dont_look_inside +from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction from pypy.jit.metainterp.test.test_basic import LLJitMixin from pypy.jit.metainterp import pyjitpl from pypy.jit.metainterp.jitprof import * @@ -78,3 +78,24 @@ # calls = (executed, recorded, blackholed) x (inpure, pure) assert profiler.calls == [[1, 0], [1, 0], [0, 0]] + def test_blackhole_pure(self): + @purefunction + def g(n): + return n+1 + + myjitdriver = JitDriver(greens = ['z'], reds = ['y', 'x','res']) + def f(x, y, z): + res = 0 + while y > 0: + myjitdriver.can_enter_jit(x=x, y=y, res=res, z=z) + myjitdriver.jit_merge_point(x=x, y=y, res=res, z=z) + res += x + if y == 1: + res += g(z) + y -= 1 + return res * 2 + res = self.meta_interp(f, [6, 7, 2]) + assert res == 90 + profiler = pyjitpl._warmrunnerdesc.metainterp_sd.profiler + # calls = (executed, recorded, blackholed) x (inpure, pure) + assert profiler.calls == [[0, 1], [0, 0], [0, 1]] From antocuni at codespeak.net Sat Sep 19 15:01:28 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 19 Sep 2009 15:01:28 +0200 (CEST) Subject: [pypy-svn] r67799 - pypy/trunk/pypy/jit/backend/test Message-ID: <20090919130128.E5552168015@codespeak.net> Author: antocuni Date: Sat Sep 19 15:01:27 2009 New Revision: 67799 Modified: pypy/trunk/pypy/jit/backend/test/support.py Log: fix compiled jit tests using the listcomp keyword argument Modified: pypy/trunk/pypy/jit/backend/test/support.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/support.py (original) +++ pypy/trunk/pypy/jit/backend/test/support.py Sat Sep 19 15:01:27 2009 @@ -16,7 +16,8 @@ raise NotImplementedError # XXX backendopt is ignored - def meta_interp(self, function, args, repeat=1, inline=False, trace_limit=sys.maxint, backendopt=None, **kwds): # XXX ignored + def meta_interp(self, function, args, repeat=1, inline=False, trace_limit=sys.maxint, + backendopt=None, listcomp=False, **kwds): # XXX ignored from pypy.jit.metainterp.warmspot import WarmRunnerDesc from pypy.annotation.listdef import s_list_of_strings from pypy.annotation import model as annmodel @@ -26,6 +27,9 @@ t = self._get_TranslationContext() t.config.translation.type_system = self.type_system # force typesystem-specific options + if listcomp: + t.config.translation.list_comprehension_operations = True + if repeat != 1: src = py.code.Source(""" def entry_point(argv): From arigo at codespeak.net Sat Sep 19 19:14:55 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 19 Sep 2009 19:14:55 +0200 (CEST) Subject: [pypy-svn] r67800 - pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm Message-ID: <20090919171455.E67CD168015@codespeak.net> Author: arigo Date: Sat Sep 19 19:14:54 2009 New Revision: 67800 Added: pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/conftest.py (contents, props changed) Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/compile.py pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/runner.py Log: Add a conftest in order to skip the llvm tests. Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/compile.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/compile.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/compile.py Sat Sep 19 19:14:54 2009 @@ -6,7 +6,7 @@ from pypy.jit.backend.llvm import llvm_rffi from pypy.jit.metainterp import resoperation from pypy.jit.metainterp.resoperation import rop -from pypy.jit.backend.x86 import symbolic # xxx +from pypy.jit.backend.llsupport import symbolic from pypy.jit.backend.llvm.runner import SizeDescr, CallDescr from pypy.jit.backend.llvm.runner import FieldDescr, ArrayDescr Added: pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/conftest.py ============================================================================== --- (empty file) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/conftest.py Sat Sep 19 19:14:54 2009 @@ -0,0 +1,5 @@ +import py + +class Directory(py.test.collect.Directory): + def collect(self): + py.test.skip("llvm backend tests skipped for now") Modified: pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/runner.py ============================================================================== --- pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/runner.py (original) +++ pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/runner.py Sat Sep 19 19:14:54 2009 @@ -9,7 +9,7 @@ from pypy.jit.backend.llvm import llvm_rffi from pypy.jit.metainterp import history from pypy.jit.metainterp.resoperation import rop, ResOperation -from pypy.jit.backend.x86 import symbolic # xxx +from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.typesystem import llhelper history.TreeLoop._llvm_compiled_index = -1 From pedronis at codespeak.net Sat Sep 19 20:31:53 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 19 Sep 2009 20:31:53 +0200 (CEST) Subject: [pypy-svn] r67801 - pypy/branch/get_fresh_parent_resumedata Message-ID: <20090919183153.81B9C168015@codespeak.net> Author: pedronis Date: Sat Sep 19 20:31:53 2009 New Revision: 67801 Added: pypy/branch/get_fresh_parent_resumedata/ - copied from r67800, pypy/trunk/ Log: a branch to check in for the purpose of testing some code based on lazily precomputing only once the resume data of the parent frames of the current frames, this speeds up richards tracing of ~30% a further direction to go would be use keeping chains of infos instead of copying, it would help with mem usage too From pedronis at codespeak.net Sat Sep 19 20:34:02 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 19 Sep 2009 20:34:02 +0200 (CEST) Subject: [pypy-svn] r67802 - in pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp: . test Message-ID: <20090919183402.775A5168015@codespeak.net> Author: pedronis Date: Sat Sep 19 20:34:00 2009 New Revision: 67802 Modified: pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/pyjitpl.py pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/resume.py pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/test/test_resume.py Log: the code, additional tests in test_resume.py move the frame walking logic into resume.py, makes it easier to reorganize how exactly the information is walked Modified: pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/pyjitpl.py Sat Sep 19 20:34:00 2009 @@ -118,6 +118,7 @@ class MIFrame(object): exception_box = None exc_value_box = None + parent_resumedata = None # for resume.py operation def __init__(self, metainterp, jitcode): assert isinstance(jitcode, codewriter.JitCode) @@ -975,13 +976,9 @@ return saved_pc = self.pc self.pc = pc - resumebuilder = resume.ResumeDataBuilder() + resumebuilder = resume.ResumeDataBuilder.make(metainterp.framestack) if metainterp.staticdata.virtualizable_info is not None: resumebuilder.generate_boxes(metainterp.virtualizable_boxes) - for frame in metainterp.framestack: - resumebuilder.generate_frame_info(frame.jitcode, frame.pc, - frame.exception_target) - resumebuilder.generate_boxes(frame.env) if box is not None: moreargs = [box] + extraargs else: @@ -1717,6 +1714,12 @@ self._debug_history.append(['guard_failure', None, None]) vinfo = self.staticdata.virtualizable_info resumereader = resume.ResumeDataReader(resumedescr, newboxes, self) + self.framestack = [] + while resumereader.has_more_frame_infos(): + jitcode, pc, exception_target = resumereader.consume_frame_info() + env = resumereader.consume_boxes() + f = self.newframe(jitcode) + f.setup_resume_at_op(pc, exception_target, env) if vinfo is not None: self.virtualizable_boxes = resumereader.consume_boxes() # just jumped away from assembler (case 4 in the comment in @@ -1726,13 +1729,6 @@ virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box) assert not virtualizable.vable_rti self.synchronize_virtualizable() - # - self.framestack = [] - while resumereader.has_more_frame_infos(): - jitcode, pc, exception_target = resumereader.consume_frame_info() - env = resumereader.consume_boxes() - f = self.newframe(jitcode) - f.setup_resume_at_op(pc, exception_target, env) def check_synchronized_virtualizable(self): if not we_are_translated(): Modified: pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/resume.py ============================================================================== --- pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/resume.py (original) +++ pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/resume.py Sat Sep 19 20:34:00 2009 @@ -12,16 +12,26 @@ debug = False - +# xxx we would like more "chaining" instead of copying class ResumeDataBuilder(object): - def __init__(self): - self.memo = {} - self.liveboxes = [] - self.consts = [] - self.nums = [] - self.frame_infos = [] - + def __init__(self, _other=None): + if _other is None: + self.memo = {} + self.liveboxes = [] + self.consts = [] + self.nums = [] + self.frame_infos = [] + else: + self.memo = _other.memo.copy() + self.liveboxes = _other.liveboxes[:] + self.consts = _other.consts[:] + self.nums = _other.nums[:] + self.frame_infos = _other.frame_infos[:] + + def clone(self): + return ResumeDataBuilder(self) + def generate_boxes(self, boxes): for box in boxes: assert box is not None @@ -41,6 +51,32 @@ def generate_frame_info(self, *frame_info): self.frame_infos.append(frame_info) + def _add_level(self, frame): + self.generate_frame_info(frame.jitcode, frame.pc, + frame.exception_target) + self.generate_boxes(frame.env) + + @staticmethod + def _get_fresh_parent_resumedata(framestack, n): + target = framestack[n] + if target.parent_resumedata is not None: + return target.parent_resumedata.clone() + if n == 0: + parent_resumedata = ResumeDataBuilder() + else: + parent_resumedata = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n-1) + parent_resumedata._add_level(framestack[n-1]) + target.parent_resumedata = parent_resumedata + return parent_resumedata.clone() + + @staticmethod + def make(framestack): + n = len(framestack)-1 + top = framestack[-1] + builder = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n) + builder._add_level(top) + return builder + def finish(self, storage): storage.rd_frame_infos = self.frame_infos[:] storage.rd_nums = self.nums[:] Modified: pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/test/test_resume.py ============================================================================== --- pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/test/test_resume.py (original) +++ pypy/branch/get_fresh_parent_resumedata/pypy/jit/metainterp/test/test_resume.py Sat Sep 19 20:34:00 2009 @@ -57,6 +57,111 @@ assert not reader.has_more_frame_infos() +class FakeFrame(object): + parent_resumedata = None + + def __init__(self, code, pc, exc_target, *boxes): + self.jitcode = code + self.pc = pc + self.exception_target = exc_target + self.env = list(boxes) + +def test_ResumeDataBuilder_clone(): + b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] + c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] + rd = ResumeDataBuilder() + rd.generate_boxes([b1, c1, b2]) + rd.generate_frame_info(('code1', 2, -1)) + + rd1 = rd.clone() + assert rd1.liveboxes == rd.liveboxes + assert rd1.memo == rd.memo + assert rd1.consts == rd.consts + assert rd1.nums == rd.nums + assert rd1.frame_infos == rd.frame_infos + + assert rd1 is not rd + assert rd1.liveboxes is not rd.liveboxes + assert rd1.memo is not rd.memo + assert rd1.consts is not rd.consts + assert rd1.nums is not rd.nums + assert rd1.frame_infos is not rd.frame_infos + + +def test_ResumeDataBuilder_make(): + b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] + c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] + fs = [FakeFrame("code0", 0, -1, b1, c1, b2)] + rd = ResumeDataBuilder.make(fs) + assert rd.liveboxes == [b1, b2] + assert rd.consts == [c1] + assert rd.nums == [0, -2, 1, -1] + assert rd.frame_infos == [('code0', 0, -1)] + + assert fs[0].parent_resumedata is not None + prd = fs[0].parent_resumedata + assert prd.nums == [] + + assert rd is not prd + + fs = [FakeFrame("code0", 0, -1, b1, c1, b2), + FakeFrame("code1", 3, 7, b3, c2, b1), + FakeFrame("code2", 9, -1, c3, b2)] + rd = ResumeDataBuilder.make(fs) + assert rd.liveboxes == [b1, b2, b3] + assert rd.consts == [c1, c2, c3] + assert rd.nums == [0, -2, 1, -1, + 2, -3, 0, -1, + -4, 1, -1] + + assert rd.frame_infos == [('code0', 0, -1), + ('code1', 3, 7), + ('code2', 9, -1)] + + assert fs[0].parent_resumedata is not None + assert fs[1].parent_resumedata is not None + assert fs[2].parent_resumedata is not None + + prd = fs[0].parent_resumedata + assert prd.nums == [] + + prd = fs[1].parent_resumedata + assert prd.nums == [0, -2, 1, -1] + + prd = fs[2].parent_resumedata + assert prd.nums == [0, -2, 1, -1, + 2, -3, 0, -1] + + rds = (rd, fs[0].parent_resumedata, fs[1].parent_resumedata, + fs[2].parent_resumedata) + for i in range(len(rds)): + for j in range(i+1, len(rds)): + assert rds[i] is not rds[j] + + fs[2].env = [b2, b3] + fs[2].pc = 15 + rd = ResumeDataBuilder.make(fs) + assert rd.liveboxes == [b1, b2, b3] + assert rd.consts == [c1, c2] + assert rd.nums == [0, -2, 1, -1, + 2, -3, 0, -1, + 1, 2, -1] + + assert rd.frame_infos == [('code0', 0, -1), + ('code1', 3, 7), + ('code2', 15, -1)] + + assert fs[2].parent_resumedata is prd + + rds = (rd, fs[0].parent_resumedata, fs[1].parent_resumedata, + fs[2].parent_resumedata) + for i in range(len(rds)): + for j in range(i+1, len(rds)): + assert rds[i] is not rds[j] + + +# ____________________________________________________________ + class MyMetaInterp: def __init__(self, cpu): self.cpu = cpu From antocuni at codespeak.net Sat Sep 19 20:34:30 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 19 Sep 2009 20:34:30 +0200 (CEST) Subject: [pypy-svn] r67803 - in pypy/trunk/pypy: interpreter objspace/flow Message-ID: <20090919183430.1528F168015@codespeak.net> Author: antocuni Date: Sat Sep 19 20:34:29 2009 New Revision: 67803 Modified: pypy/trunk/pypy/interpreter/generator.py pypy/trunk/pypy/interpreter/pyframe.py pypy/trunk/pypy/interpreter/pyopcode.py pypy/trunk/pypy/objspace/flow/framestate.py Log: merge the blocklist branch: it turns the rpython list frame.blockstack into a linked list. This way, it's more ootype-jit friendly (and slightly more efficient in the non jit case too) Modified: pypy/trunk/pypy/interpreter/generator.py ============================================================================== --- pypy/trunk/pypy/interpreter/generator.py (original) +++ pypy/trunk/pypy/interpreter/generator.py Sat Sep 19 20:34:29 2009 @@ -126,10 +126,12 @@ # Only bother raising an exception if the frame is still not # finished and finally or except blocks are present. if not self.frame.frame_finished_execution: - for block in self.frame.blockstack: + block = self.frame.lastblock + while block is not None: if not isinstance(block, LoopBlock): self.descr_close() return + block = block.previous def __del__(self): self._enqueue_for_destruction(self.space) Modified: pypy/trunk/pypy/interpreter/pyframe.py ============================================================================== --- pypy/trunk/pypy/interpreter/pyframe.py (original) +++ pypy/trunk/pypy/interpreter/pyframe.py Sat Sep 19 20:34:29 2009 @@ -55,7 +55,8 @@ eval.Frame.__init__(self, space, w_globals, code.co_nlocals) self.valuestack_w = [None] * code.co_stacksize self.valuestackdepth = 0 - self.blockstack = [] + self.lastblock = None + self.blockcount = 0 if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. @@ -66,6 +67,37 @@ self.f_lineno = code.co_firstlineno ExecutionContext._init_chaining_attributes(self) + def append_block(self, block): + block.previous = self.lastblock + self.lastblock = block + self.blockcount += 1 + + def pop_block(self): + block = self.lastblock + self.lastblock = block.previous + self.blockcount -= 1 + return block + + def get_blocklist(self): + """Returns a list containing all the blocks in the frame""" + lst = [None] * self.blockcount + block = self.lastblock + i = 0 + while block is not None: + lst[i] = block + i += 1 + block = block.previous + return lst + + def set_blocklist(self, lst): + self.lastblock = None + self.blockcount = 0 + i = len(lst) + while i > 0: + block = lst[i-1] + i -= 1 + self.append_block(block) + def get_builtin(self): if self.space.config.objspace.honor__builtins__: return self.builtin @@ -277,7 +309,7 @@ values_w = self.valuestack_w[0:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) - w_blockstack = nt([block._get_state_(space) for block in self.blockstack]) + w_blockstack = nt([block._get_state_(space) for block in self.get_blocklist()]) w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) if self.last_exception is None: w_exc_value = space.w_None @@ -343,8 +375,8 @@ new_frame.f_back_forced = True new_frame.builtin = space.interp_w(Module, w_builtin) - new_frame.blockstack = [unpickle_block(space, w_blk) - for w_blk in space.unpackiterable(w_blockstack)] + new_frame.set_blocklist([unpickle_block(space, w_blk) + for w_blk in space.unpackiterable(w_blockstack)]) values_w = maker.slp_from_tuple_with_nulls(space, w_valuestack) for w_value in values_w: new_frame.pushvalue(w_value) @@ -532,7 +564,7 @@ else: addr += 1 - f_iblock = len(self.blockstack) + f_iblock = self.blockcount min_iblock = f_iblock + min_delta_iblock if new_lasti > self.last_instr: new_iblock = f_iblock + delta_iblock @@ -544,7 +576,7 @@ space.wrap("can't jump into the middle of a block")) while f_iblock > new_iblock: - block = self.blockstack.pop() + block = self.pop_block() block.cleanup(self) f_iblock -= 1 Modified: pypy/trunk/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/pypy/interpreter/pyopcode.py Sat Sep 19 20:34:29 2009 @@ -273,10 +273,10 @@ return next_instr def unrollstack(self, unroller_kind): - n = len(self.blockstack) + n = self.blockcount n = hint(n, promote=True) while n > 0: - block = self.blockstack.pop() + block = self.pop_block() n -= 1 if (block.handling_mask & unroller_kind) != 0: return block @@ -591,7 +591,7 @@ f.setdictscope(w_locals) def POP_BLOCK(f, *ignored): - block = f.blockstack.pop() + block = f.pop_block() block.cleanup(f) # the block knows how to clean up the value stack def end_finally(f): @@ -860,15 +860,15 @@ def SETUP_LOOP(f, offsettoend, next_instr, *ignored): block = LoopBlock(f, next_instr + offsettoend) - f.blockstack.append(block) + f.append_block(block) def SETUP_EXCEPT(f, offsettoend, next_instr, *ignored): block = ExceptBlock(f, next_instr + offsettoend) - f.blockstack.append(block) + f.append_block(block) def SETUP_FINALLY(f, offsettoend, next_instr, *ignored): block = FinallyBlock(f, next_instr + offsettoend) - f.blockstack.append(block) + f.append_block(block) def WITH_CLEANUP(f, *ignored): # see comment in END_FINALLY for stack state @@ -1130,6 +1130,7 @@ def __init__(self, frame, handlerposition): self.handlerposition = handlerposition self.valuestackdepth = frame.valuestackdepth + self.previous = None # this makes a linked list of blocks def __eq__(self, other): return (self.__class__ is other.__class__ and @@ -1175,7 +1176,7 @@ # re-push the loop block without cleaning up the value stack, # and jump to the beginning of the loop, stored in the # exception's argument - frame.blockstack.append(self) + frame.append_block(self) return unroller.jump_to else: # jump to the end of the loop Modified: pypy/trunk/pypy/objspace/flow/framestate.py ============================================================================== --- pypy/trunk/pypy/objspace/flow/framestate.py (original) +++ pypy/trunk/pypy/objspace/flow/framestate.py Sat Sep 19 20:34:29 2009 @@ -20,7 +20,7 @@ recursively_flatten(state.space, data) self.mergeable = data self.nonmergeable = ( - state.blockstack[:], + state.get_blocklist(), state.last_instr, # == next_instr when between bytecodes state.w_locals, ) @@ -47,10 +47,11 @@ else: frame.last_exception = OperationError(data[-2], data[-1]) ( - frame.blockstack[:], + blocklist, frame.last_instr, frame.w_locals, ) = self.nonmergeable + frame.set_blocklist(blocklist) else: raise TypeError("can't set framestate for %r" % frame.__class__.__name__) From antocuni at codespeak.net Sat Sep 19 20:34:42 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 19 Sep 2009 20:34:42 +0200 (CEST) Subject: [pypy-svn] r67804 - pypy/branch/blocklist Message-ID: <20090919183442.6EE0A16801D@codespeak.net> Author: antocuni Date: Sat Sep 19 20:34:42 2009 New Revision: 67804 Removed: pypy/branch/blocklist/ Log: remove merged branch From antocuni at codespeak.net Sat Sep 19 20:53:02 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 19 Sep 2009 20:53:02 +0200 (CEST) Subject: [pypy-svn] r67805 - pypy/trunk/pypy/translator Message-ID: <20090919185302.3762E168016@codespeak.net> Author: antocuni Date: Sat Sep 19 20:53:01 2009 New Revision: 67805 Modified: pypy/trunk/pypy/translator/driver.py Log: make inline=True the default for ootype jits too Modified: pypy/trunk/pypy/translator/driver.py ============================================================================== --- pypy/trunk/pypy/translator/driver.py (original) +++ pypy/trunk/pypy/translator/driver.py Sat Sep 19 20:53:01 2009 @@ -377,7 +377,7 @@ from pypy.jit.metainterp.warmspot import apply_jit apply_jit(self.translator, policy=self.jitpolicy, debug_level=self.config.translation.jit_debug, - backend_name='cli') #XXX + backend_name='cli', inline=True) #XXX # self.log.info("the JIT compiler was generated") # From antocuni at codespeak.net Sat Sep 19 21:01:15 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 19 Sep 2009 21:01:15 +0200 (CEST) Subject: [pypy-svn] r67806 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090919190115.3B661168015@codespeak.net> Author: antocuni Date: Sat Sep 19 21:01:15 2009 New Revision: 67806 Modified: pypy/trunk/pypy/jit/metainterp/policy.py Log: (antocuni, arigo) this TODO is nonsense: the portal can be called only through a rop.CALL, there is no way to do it via an OOSEND Modified: pypy/trunk/pypy/jit/metainterp/policy.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/policy.py (original) +++ pypy/trunk/pypy/jit/metainterp/policy.py Sat Sep 19 21:01:15 2009 @@ -69,8 +69,6 @@ SELFTYPE, methname, opargs = support.decompose_oosend(op) if SELFTYPE.oopspec_name is not None: return 'builtin' - # TODO: return 'recursive' if the oosend ends with calling the - # portal if self.graphs_from(op, supports_floats) is None: return 'residual' return 'regular' From arigo at codespeak.net Sat Sep 19 22:38:24 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 19 Sep 2009 22:38:24 +0200 (CEST) Subject: [pypy-svn] r67807 - pypy/trunk/pypy/translator/c/gcc Message-ID: <20090919203824.07AAB168015@codespeak.net> Author: arigo Date: Sat Sep 19 22:38:23 2009 New Revision: 67807 Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Log: Obscure. I am now seeing a "pushw" instruction. Oh well. Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Sat Sep 19 22:38:23 2009 @@ -688,6 +688,9 @@ source = match.group(1) return [InsnStackAdjust(-4)] + self.insns_for_copy(source, '0(%esp)') + def visit_pushw(self, line): + return [InsnStackAdjust(-2)] # rare but not impossible + def _visit_pop(self, target): return self.insns_for_copy('0(%esp)', target) + [InsnStackAdjust(+4)] @@ -907,8 +910,8 @@ class InsnStackAdjust(Insn): _args_ = ['delta'] def __init__(self, delta): - assert delta % 4 == 0 - self.delta = delta + assert delta % 2 == 0 # should be "% 4", but there is the special + self.delta = delta # case of 'pushw' to handle class InsnCannotFollowEsp(InsnStackAdjust): def __init__(self): From pedronis at codespeak.net Sun Sep 20 01:25:39 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 20 Sep 2009 01:25:39 +0200 (CEST) Subject: [pypy-svn] r67808 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090919232539.8FF72168013@codespeak.net> Author: pedronis Date: Sun Sep 20 01:25:38 2009 New Revision: 67808 Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/resume.py pypy/trunk/pypy/jit/metainterp/test/test_resume.py Log: merge branch/get_fresh_parent_resumedata/ lazily precompute only once the resume data of the parent frames of the current frames, this speeds up richards tracing of ~30% - additional tests in test_resume.py - move the frame walking logic into resume.py, makes it easier to reorganize how exactly the information is walked a further direction to go would be use keeping chains of infos instead of copying, it would help with mem usage too Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Sun Sep 20 01:25:38 2009 @@ -118,6 +118,7 @@ class MIFrame(object): exception_box = None exc_value_box = None + parent_resumedata = None # for resume.py operation def __init__(self, metainterp, jitcode): assert isinstance(jitcode, codewriter.JitCode) @@ -975,13 +976,9 @@ return saved_pc = self.pc self.pc = pc - resumebuilder = resume.ResumeDataBuilder() + resumebuilder = resume.ResumeDataBuilder.make(metainterp.framestack) if metainterp.staticdata.virtualizable_info is not None: resumebuilder.generate_boxes(metainterp.virtualizable_boxes) - for frame in metainterp.framestack: - resumebuilder.generate_frame_info(frame.jitcode, frame.pc, - frame.exception_target) - resumebuilder.generate_boxes(frame.env) if box is not None: moreargs = [box] + extraargs else: @@ -1717,6 +1714,12 @@ self._debug_history.append(['guard_failure', None, None]) vinfo = self.staticdata.virtualizable_info resumereader = resume.ResumeDataReader(resumedescr, newboxes, self) + self.framestack = [] + while resumereader.has_more_frame_infos(): + jitcode, pc, exception_target = resumereader.consume_frame_info() + env = resumereader.consume_boxes() + f = self.newframe(jitcode) + f.setup_resume_at_op(pc, exception_target, env) if vinfo is not None: self.virtualizable_boxes = resumereader.consume_boxes() # just jumped away from assembler (case 4 in the comment in @@ -1726,13 +1729,6 @@ virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box) assert not virtualizable.vable_rti self.synchronize_virtualizable() - # - self.framestack = [] - while resumereader.has_more_frame_infos(): - jitcode, pc, exception_target = resumereader.consume_frame_info() - env = resumereader.consume_boxes() - f = self.newframe(jitcode) - f.setup_resume_at_op(pc, exception_target, env) def check_synchronized_virtualizable(self): if not we_are_translated(): Modified: pypy/trunk/pypy/jit/metainterp/resume.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resume.py (original) +++ pypy/trunk/pypy/jit/metainterp/resume.py Sun Sep 20 01:25:38 2009 @@ -12,16 +12,26 @@ debug = False - +# xxx we would like more "chaining" instead of copying class ResumeDataBuilder(object): - def __init__(self): - self.memo = {} - self.liveboxes = [] - self.consts = [] - self.nums = [] - self.frame_infos = [] - + def __init__(self, _other=None): + if _other is None: + self.memo = {} + self.liveboxes = [] + self.consts = [] + self.nums = [] + self.frame_infos = [] + else: + self.memo = _other.memo.copy() + self.liveboxes = _other.liveboxes[:] + self.consts = _other.consts[:] + self.nums = _other.nums[:] + self.frame_infos = _other.frame_infos[:] + + def clone(self): + return ResumeDataBuilder(self) + def generate_boxes(self, boxes): for box in boxes: assert box is not None @@ -41,6 +51,32 @@ def generate_frame_info(self, *frame_info): self.frame_infos.append(frame_info) + def _add_level(self, frame): + self.generate_frame_info(frame.jitcode, frame.pc, + frame.exception_target) + self.generate_boxes(frame.env) + + @staticmethod + def _get_fresh_parent_resumedata(framestack, n): + target = framestack[n] + if target.parent_resumedata is not None: + return target.parent_resumedata.clone() + if n == 0: + parent_resumedata = ResumeDataBuilder() + else: + parent_resumedata = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n-1) + parent_resumedata._add_level(framestack[n-1]) + target.parent_resumedata = parent_resumedata + return parent_resumedata.clone() + + @staticmethod + def make(framestack): + n = len(framestack)-1 + top = framestack[-1] + builder = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n) + builder._add_level(top) + return builder + def finish(self, storage): storage.rd_frame_infos = self.frame_infos[:] storage.rd_nums = self.nums[:] Modified: pypy/trunk/pypy/jit/metainterp/test/test_resume.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_resume.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_resume.py Sun Sep 20 01:25:38 2009 @@ -57,6 +57,111 @@ assert not reader.has_more_frame_infos() +class FakeFrame(object): + parent_resumedata = None + + def __init__(self, code, pc, exc_target, *boxes): + self.jitcode = code + self.pc = pc + self.exception_target = exc_target + self.env = list(boxes) + +def test_ResumeDataBuilder_clone(): + b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] + c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] + rd = ResumeDataBuilder() + rd.generate_boxes([b1, c1, b2]) + rd.generate_frame_info(('code1', 2, -1)) + + rd1 = rd.clone() + assert rd1.liveboxes == rd.liveboxes + assert rd1.memo == rd.memo + assert rd1.consts == rd.consts + assert rd1.nums == rd.nums + assert rd1.frame_infos == rd.frame_infos + + assert rd1 is not rd + assert rd1.liveboxes is not rd.liveboxes + assert rd1.memo is not rd.memo + assert rd1.consts is not rd.consts + assert rd1.nums is not rd.nums + assert rd1.frame_infos is not rd.frame_infos + + +def test_ResumeDataBuilder_make(): + b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] + c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] + fs = [FakeFrame("code0", 0, -1, b1, c1, b2)] + rd = ResumeDataBuilder.make(fs) + assert rd.liveboxes == [b1, b2] + assert rd.consts == [c1] + assert rd.nums == [0, -2, 1, -1] + assert rd.frame_infos == [('code0', 0, -1)] + + assert fs[0].parent_resumedata is not None + prd = fs[0].parent_resumedata + assert prd.nums == [] + + assert rd is not prd + + fs = [FakeFrame("code0", 0, -1, b1, c1, b2), + FakeFrame("code1", 3, 7, b3, c2, b1), + FakeFrame("code2", 9, -1, c3, b2)] + rd = ResumeDataBuilder.make(fs) + assert rd.liveboxes == [b1, b2, b3] + assert rd.consts == [c1, c2, c3] + assert rd.nums == [0, -2, 1, -1, + 2, -3, 0, -1, + -4, 1, -1] + + assert rd.frame_infos == [('code0', 0, -1), + ('code1', 3, 7), + ('code2', 9, -1)] + + assert fs[0].parent_resumedata is not None + assert fs[1].parent_resumedata is not None + assert fs[2].parent_resumedata is not None + + prd = fs[0].parent_resumedata + assert prd.nums == [] + + prd = fs[1].parent_resumedata + assert prd.nums == [0, -2, 1, -1] + + prd = fs[2].parent_resumedata + assert prd.nums == [0, -2, 1, -1, + 2, -3, 0, -1] + + rds = (rd, fs[0].parent_resumedata, fs[1].parent_resumedata, + fs[2].parent_resumedata) + for i in range(len(rds)): + for j in range(i+1, len(rds)): + assert rds[i] is not rds[j] + + fs[2].env = [b2, b3] + fs[2].pc = 15 + rd = ResumeDataBuilder.make(fs) + assert rd.liveboxes == [b1, b2, b3] + assert rd.consts == [c1, c2] + assert rd.nums == [0, -2, 1, -1, + 2, -3, 0, -1, + 1, 2, -1] + + assert rd.frame_infos == [('code0', 0, -1), + ('code1', 3, 7), + ('code2', 15, -1)] + + assert fs[2].parent_resumedata is prd + + rds = (rd, fs[0].parent_resumedata, fs[1].parent_resumedata, + fs[2].parent_resumedata) + for i in range(len(rds)): + for j in range(i+1, len(rds)): + assert rds[i] is not rds[j] + + +# ____________________________________________________________ + class MyMetaInterp: def __init__(self, cpu): self.cpu = cpu From pedronis at codespeak.net Sun Sep 20 01:26:11 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 20 Sep 2009 01:26:11 +0200 (CEST) Subject: [pypy-svn] r67809 - pypy/branch/get_fresh_parent_resumedata Message-ID: <20090919232611.18658168013@codespeak.net> Author: pedronis Date: Sun Sep 20 01:26:10 2009 New Revision: 67809 Removed: pypy/branch/get_fresh_parent_resumedata/ Log: kill merged branch From arigo at codespeak.net Sun Sep 20 13:54:54 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Sep 2009 13:54:54 +0200 (CEST) Subject: [pypy-svn] r67810 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090920115454.34F2D168013@codespeak.net> Author: arigo Date: Sun Sep 20 13:54:52 2009 New Revision: 67810 Removed: pypy/trunk/pypy/jit/backend/x86/inp Log: Remove this old file, as I think its best-consume-before date is long expired. From cfbolz at codespeak.net Mon Sep 21 10:35:53 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 10:35:53 +0200 (CEST) Subject: [pypy-svn] r67811 - pypy/trunk/pypy/jit/backend Message-ID: <20090921083553.7A6EE168010@codespeak.net> Author: cfbolz Date: Mon Sep 21 10:35:52 2009 New Revision: 67811 Added: pypy/trunk/pypy/jit/backend/model.py.merge.tmp - copied, changed from r67810, pypy/trunk/pypy/jit/backend/model.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/execute-star-args-jit/pypy/jit/backend/model.py revisions 67773 to 67810: ------------------------------------------------------------------------ r67791 | arigo | 2009-09-19 12:13:14 +0200 (Sat, 19 Sep 2009) | 2 lines Fix model and llmodel. Fix tests in metainterp. ------------------------------------------------------------------------ r67774 | cfbolz | 2009-09-18 15:37:46 +0200 (Fri, 18 Sep 2009) | 2 lines (pedronis, cfbolz): make a branch that tries to make the jit use less memory ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/backend/model.py.merge.tmp (from r67810, pypy/trunk/pypy/jit/backend/model.py) ============================================================================== --- pypy/trunk/pypy/jit/backend/model.py (original) +++ pypy/trunk/pypy/jit/backend/model.py.merge.tmp Mon Sep 21 10:35:52 2009 @@ -103,61 +103,61 @@ # lltype specific operations # -------------------------- - def do_arraylen_gc(self, args, arraydescr): + def do_arraylen_gc(self, arraybox, arraydescr): raise NotImplementedError - def do_strlen(self, args, descr=None): + def do_strlen(self, stringbox): raise NotImplementedError - def do_strgetitem(self, args, descr=None): + def do_strgetitem(self, stringbox, indexbox): raise NotImplementedError - def do_unicodelen(self, args, descr=None): + def do_unicodelen(self, stringbox): raise NotImplementedError - def do_unicodegetitem(self, args, descr=None): + def do_unicodegetitem(self, stringbox, indexbox): raise NotImplementedError - def do_getarrayitem_gc(self, args, arraydescr): + def do_getarrayitem_gc(self, arraybox, indexbox, arraydescr): raise NotImplementedError - def do_getfield_gc(self, args, fielddescr): + def do_getfield_gc(self, structbox, fielddescr): raise NotImplementedError - def do_getfield_raw(self, args, fielddescr): + def do_getfield_raw(self, structbox, fielddescr): raise NotImplementedError - def do_new(self, args, sizedescr): + def do_new(self, sizedescr): raise NotImplementedError - def do_new_with_vtable(self, args, descr=None): + def do_new_with_vtable(self, classbox): raise NotImplementedError - def do_new_array(self, args, arraydescr): + def do_new_array(self, lengthbox, arraydescr): raise NotImplementedError - def do_setarrayitem_gc(self, args, arraydescr): + def do_setarrayitem_gc(self, arraybox, indexbox, newvaluebox, arraydescr): raise NotImplementedError - def do_setarrayitem_raw(self, args, arraydescr): + def do_setarrayitem_raw(self, arraybox, indexbox, newvaluebox, arraydescr): raise NotImplementedError - def do_setfield_gc(self, args, fielddescr): + def do_setfield_gc(self, structbox, newvaluebox, fielddescr): raise NotImplementedError - def do_setfield_raw(self, args, fielddescr): + def do_setfield_raw(self, structbox, newvaluebox, fielddescr): raise NotImplementedError - def do_newstr(self, args, descr=None): + def do_newstr(self, lengthbox): raise NotImplementedError - def do_newunicode(self, args, descr=None): + def do_newunicode(self, lengthbox): raise NotImplementedError - def do_strsetitem(self, args, descr=None): + def do_strsetitem(self, stringbox, indexbox, charbox): raise NotImplementedError - def do_unicodesetitem(self, args, descr=None): + def do_unicodesetitem(self, stringbox, indexbox, charbox): raise NotImplementedError def do_call(self, args, calldescr): @@ -170,19 +170,19 @@ def do_cond_call_gc_malloc(self, args, calldescr): raise NotImplementedError - def do_cast_ptr_to_int(self, args, descr=None): + def do_cast_ptr_to_int(self, ptrbox): raise NotImplementedError # ootype specific operations # -------------------------- - def do_runtimenew(self, args, descr=None): + def do_runtimenew(self, classbox): raise NotImplementedError - def do_oosend(self, args, descr=None): + def do_oosend(self, args, descr): raise NotImplementedError - def do_instanceof(self, args, descr=None): + def do_instanceof(self, instancebox, typedescr): raise NotImplementedError def typedescr2classbox(self, descr): From cfbolz at codespeak.net Mon Sep 21 10:35:55 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 10:35:55 +0200 (CEST) Subject: [pypy-svn] r67812 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090921083555.1BEF0168010@codespeak.net> Author: cfbolz Date: Mon Sep 21 10:35:54 2009 New Revision: 67812 Added: pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp - copied, changed from r67810, pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/execute-star-args-jit/pypy/jit/metainterp/pyjitpl.py revisions 67773 to 67810: ------------------------------------------------------------------------ r67798 | pedronis | 2009-09-19 14:27:08 +0200 (Sat, 19 Sep 2009) | 1 line fix profiler op counting, some more testing ------------------------------------------------------------------------ r67790 | arigo | 2009-09-19 11:55:06 +0200 (Sat, 19 Sep 2009) | 4 lines (arigo, pedronis around) Refactor the do_xxx() operations in executor.py and on the CPU to take arguments directly instead of in a list. ------------------------------------------------------------------------ r67779 | cfbolz | 2009-09-18 18:44:58 +0200 (Fri, 18 Sep 2009) | 3 lines (pedronis, arigo, cfbolz): change the way the black hole is implemented: if in blackholing mode, the history on the metainterp is simply None. clarify some code as well. ------------------------------------------------------------------------ r67778 | cfbolz | 2009-09-18 17:38:12 +0200 (Fri, 18 Sep 2009) | 3 lines (arigo, pedronis, cfbolz) Fixes for tests, and unroll _all_constants to avoid making a list. ------------------------------------------------------------------------ r67777 | cfbolz | 2009-09-18 17:21:44 +0200 (Fri, 18 Sep 2009) | 3 lines (pedronis, cfbolz, arigo) Progress in making *arg versions of the functions. Not finished yet. ------------------------------------------------------------------------ r67775 | cfbolz | 2009-09-18 16:20:37 +0200 (Fri, 18 Sep 2009) | 2 lines (pedronis, cfbolz, arigo around): construct lists a bit later in the metainterp. ------------------------------------------------------------------------ r67774 | cfbolz | 2009-09-18 15:37:46 +0200 (Fri, 18 Sep 2009) | 2 lines (pedronis, cfbolz): make a branch that tries to make the jit use less memory ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp (from r67810, pypy/trunk/pypy/jit/metainterp/pyjitpl.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp Mon Sep 21 10:35:54 2009 @@ -10,7 +10,8 @@ from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import codewriter, executor from pypy.jit.backend.logger import Logger -from pypy.jit.metainterp.jitprof import EmptyProfiler, GUARDS +from pypy.jit.metainterp.jitprof import EmptyProfiler, BLACKHOLED_OPS +from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize @@ -236,14 +237,14 @@ exec py.code.Source(''' @arguments("box", "box") def opimpl_%s(self, b1, b2): - self.execute(rop.%s, [b1, b2]) + self.execute(rop.%s, b1, b2) ''' % (_opimpl, _opimpl.upper())).compile() for _opimpl in ['int_add_ovf', 'int_sub_ovf', 'int_mul_ovf']: exec py.code.Source(''' @arguments("box", "box") def opimpl_%s(self, b1, b2): - self.execute(rop.%s, [b1, b2]) + self.execute(rop.%s, b1, b2) return self.metainterp.handle_overflow_error() ''' % (_opimpl, _opimpl.upper())).compile() @@ -255,7 +256,7 @@ exec py.code.Source(''' @arguments("box") def opimpl_%s(self, b): - self.execute(rop.%s, [b]) + self.execute(rop.%s, b) ''' % (_opimpl, _opimpl.upper())).compile() @arguments() @@ -322,112 +323,106 @@ @arguments("descr") def opimpl_new(self, size): - self.execute(rop.NEW, [], descr=size) + self.execute_with_descr(rop.NEW, descr=size) @arguments("constbox") def opimpl_new_with_vtable(self, vtablebox): - self.execute(rop.NEW_WITH_VTABLE, [vtablebox]) + self.execute(rop.NEW_WITH_VTABLE, vtablebox) @arguments("box") def opimpl_runtimenew(self, classbox): - self.execute(rop.RUNTIMENEW, [classbox]) + self.execute(rop.RUNTIMENEW, classbox) @arguments("box", "descr") def opimpl_instanceof(self, box, typedescr): - self.execute(rop.INSTANCEOF, [box], descr=typedescr) + self.execute_with_descr(rop.INSTANCEOF, typedescr, box) @arguments("box", "box") def opimpl_subclassof(self, box1, box2): - self.execute(rop.SUBCLASSOF, [box1, box2], descr=None) + self.execute(rop.SUBCLASSOF, box1, box2) @arguments("box") def opimpl_ooidentityhash(self, box): - self.execute(rop.OOIDENTITYHASH, [box], descr=None) + self.execute(rop.OOIDENTITYHASH, box) @arguments("descr", "box") def opimpl_new_array(self, itemsize, countbox): - self.execute(rop.NEW_ARRAY, [countbox], descr=itemsize) + self.execute_with_descr(rop.NEW_ARRAY, itemsize, countbox) @arguments("box", "descr", "box") def opimpl_getarrayitem_gc(self, arraybox, arraydesc, indexbox): - self.execute(rop.GETARRAYITEM_GC, [arraybox, indexbox], - descr=arraydesc) + self.execute_with_descr(rop.GETARRAYITEM_GC, arraydesc, arraybox, indexbox) @arguments("box", "descr", "box") def opimpl_getarrayitem_gc_pure(self, arraybox, arraydesc, indexbox): - self.execute(rop.GETARRAYITEM_GC_PURE, [arraybox, indexbox], - descr=arraydesc) + self.execute_with_descr(rop.GETARRAYITEM_GC_PURE, arraydesc, arraybox, indexbox) @arguments("box", "descr", "box", "box") def opimpl_setarrayitem_gc(self, arraybox, arraydesc, indexbox, itembox): - self.execute(rop.SETARRAYITEM_GC, [arraybox, indexbox, itembox], - descr=arraydesc) + self.execute_with_descr(rop.SETARRAYITEM_GC, arraydesc, arraybox, indexbox, itembox) @arguments("box", "descr") def opimpl_arraylen_gc(self, arraybox, arraydesc): - self.execute(rop.ARRAYLEN_GC, [arraybox], descr=arraydesc) + self.execute_with_descr(rop.ARRAYLEN_GC, arraydesc, arraybox) @arguments("orgpc", "box", "descr", "box") def opimpl_check_neg_index(self, pc, arraybox, arraydesc, indexbox): negbox = self.metainterp.execute_and_record( - rop.INT_LT, [indexbox, ConstInt(0)]) + rop.INT_LT, None, indexbox, ConstInt(0)) # xxx inefficient negbox = self.implement_guard_value(pc, negbox) if negbox.getint(): # the index is < 0; add the array length to it lenbox = self.metainterp.execute_and_record( - rop.ARRAYLEN_GC, [arraybox], descr=arraydesc) + rop.ARRAYLEN_GC, arraydesc, arraybox) indexbox = self.metainterp.execute_and_record( - rop.INT_ADD, [indexbox, lenbox]) + rop.INT_ADD, None, indexbox, lenbox) self.make_result_box(indexbox) @arguments("descr", "descr", "descr", "descr", "box") def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr, sizebox): - sbox = self.metainterp.execute_and_record(rop.NEW, [], - descr=structdescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, [sbox, sizebox], - descr=lengthdescr) - abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, [sizebox], - descr=arraydescr) - self.metainterp.execute_and_record(rop.SETFIELD_GC, [sbox, abox], - descr=itemsdescr) + sbox = self.metainterp.execute_and_record(rop.NEW, structdescr) + self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr, + sbox, sizebox) + abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr, + sizebox) + self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr, + sbox, abox) self.make_result_box(sbox) @arguments("box", "descr", "descr", "box") def opimpl_getlistitem_gc(self, listbox, itemsdescr, arraydescr, indexbox): arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - [listbox], descr=itemsdescr) - self.execute(rop.GETARRAYITEM_GC, [arraybox, indexbox], - descr=arraydescr) + itemsdescr, listbox) + self.execute_with_descr(rop.GETARRAYITEM_GC, arraydescr, arraybox, indexbox) @arguments("box", "descr", "descr", "box", "box") def opimpl_setlistitem_gc(self, listbox, itemsdescr, arraydescr, indexbox, valuebox): arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, - [listbox], descr=itemsdescr) - self.execute(rop.SETARRAYITEM_GC, [arraybox, indexbox, valuebox], - descr=arraydescr) + itemsdescr, listbox) + self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox, indexbox, valuebox) @arguments("orgpc", "box", "descr", "box") def opimpl_check_resizable_neg_index(self, pc, listbox, lengthdesc, indexbox): negbox = self.metainterp.execute_and_record( - rop.INT_LT, [indexbox, ConstInt(0)]) + rop.INT_LT, None, indexbox, ConstInt(0)) # xxx inefficient negbox = self.implement_guard_value(pc, negbox) if negbox.getint(): # the index is < 0; add the array length to it lenbox = self.metainterp.execute_and_record( - rop.GETFIELD_GC, [listbox], descr=lengthdesc) + rop.GETFIELD_GC, lengthdesc, listbox) indexbox = self.metainterp.execute_and_record( - rop.INT_ADD, [indexbox, lenbox]) + rop.INT_ADD, None, indexbox, lenbox) self.make_result_box(indexbox) @arguments("orgpc", "box") def opimpl_check_zerodivisionerror(self, pc, box): nonzerobox = self.metainterp.execute_and_record( - rop.INT_NE, [box, ConstInt(0)]) + rop.INT_NE, None, box, ConstInt(0)) # xxx inefficient nonzerobox = self.implement_guard_value(pc, nonzerobox) if nonzerobox.getint(): @@ -441,11 +436,11 @@ # detect the combination "box1 = -sys.maxint-1, box2 = -1". import sys tmp1 = self.metainterp.execute_and_record( # combination to detect: - rop.INT_ADD, [box1, ConstInt(sys.maxint)]) # tmp1=-1, box2=-1 + rop.INT_ADD, None, box1, ConstInt(sys.maxint)) # tmp1=-1, box2=-1 tmp2 = self.metainterp.execute_and_record( - rop.INT_AND, [tmp1, box2]) # tmp2=-1 + rop.INT_AND, None, tmp1, box2) # tmp2=-1 tmp3 = self.metainterp.execute_and_record( - rop.INT_EQ, [tmp2, ConstInt(-1)]) # tmp3? + rop.INT_EQ, None, tmp2, ConstInt(-1)) # tmp3? # xxx inefficient tmp4 = self.implement_guard_value(pc, tmp3) # tmp4? if not tmp4.getint(): @@ -461,55 +456,55 @@ @arguments("orgpc", "box") def opimpl_int_abs(self, pc, box): nonneg = self.metainterp.execute_and_record( - rop.INT_GE, [box, ConstInt(0)]) + rop.INT_GE, None, box, ConstInt(0)) # xxx inefficient nonneg = self.implement_guard_value(pc, nonneg) if nonneg.getint(): self.make_result_box(box) else: - self.execute(rop.INT_NEG, [box]) + self.execute(rop.INT_NEG, box) @arguments("box") def opimpl_ptr_nonzero(self, box): - self.execute(rop.OONONNULL, [box]) + self.execute(rop.OONONNULL, box) @arguments("box") def opimpl_ptr_iszero(self, box): - self.execute(rop.OOISNULL, [box]) + self.execute(rop.OOISNULL, box) opimpl_oononnull = opimpl_ptr_nonzero opimpl_ooisnull = opimpl_ptr_iszero @arguments("box", "box") def opimpl_ptr_eq(self, box1, box2): - self.execute(rop.OOIS, [box1, box2]) + self.execute(rop.OOIS, box1, box2) @arguments("box", "box") def opimpl_ptr_ne(self, box1, box2): - self.execute(rop.OOISNOT, [box1, box2]) + self.execute(rop.OOISNOT, box1, box2) opimpl_oois = opimpl_ptr_eq opimpl_ooisnot = opimpl_ptr_ne @arguments("box", "descr") def opimpl_getfield_gc(self, box, fielddesc): - self.execute(rop.GETFIELD_GC, [box], descr=fielddesc) + self.execute_with_descr(rop.GETFIELD_GC, fielddesc, box) @arguments("box", "descr") def opimpl_getfield_gc_pure(self, box, fielddesc): - self.execute(rop.GETFIELD_GC_PURE, [box], descr=fielddesc) + self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddesc, box) @arguments("box", "descr", "box") def opimpl_setfield_gc(self, box, fielddesc, valuebox): - self.execute(rop.SETFIELD_GC, [box, valuebox], descr=fielddesc) + self.execute_with_descr(rop.SETFIELD_GC, fielddesc, box, valuebox) @arguments("box", "descr") def opimpl_getfield_raw(self, box, fielddesc): - self.execute(rop.GETFIELD_RAW, [box], descr=fielddesc) + self.execute_with_descr(rop.GETFIELD_RAW, fielddesc, box) @arguments("box", "descr") def opimpl_getfield_raw_pure(self, box, fielddesc): - self.execute(rop.GETFIELD_RAW_PURE, [box], descr=fielddesc) + self.execute_with_descr(rop.GETFIELD_RAW_PURE, fielddesc, box) @arguments("box", "descr", "box") def opimpl_setfield_raw(self, box, fielddesc, valuebox): - self.execute(rop.SETFIELD_RAW, [box, valuebox], descr=fielddesc) + self.execute_with_descr(rop.SETFIELD_RAW, fielddesc, box, valuebox) def _nonstandard_virtualizable(self, pc, box): # returns True if 'box' is actually not the "standard" virtualizable @@ -517,8 +512,8 @@ standard_box = self.metainterp.virtualizable_boxes[-1] if standard_box is box: return False - eqbox = self.metainterp.execute_and_record(rop.OOIS, - [box, standard_box]) + eqbox = self.metainterp.execute_and_record(rop.OOIS, None, + box, standard_box) eqbox = self.implement_guard_value(pc, eqbox) isstandard = eqbox.getint() if isstandard: @@ -540,8 +535,7 @@ @arguments("orgpc", "box", "int") def opimpl_getfield_vable(self, pc, basebox, index): if self._nonstandard_virtualizable(pc, basebox): - self.execute(rop.GETFIELD_GC, [basebox], - descr=self._get_virtualizable_field_descr(index)) + self.execute_with_descr(rop.GETFIELD_GC, self._get_virtualizable_field_descr(index), basebox) return self.metainterp.check_synchronized_virtualizable() resbox = self.metainterp.virtualizable_boxes[index] @@ -549,8 +543,7 @@ @arguments("orgpc", "box", "int", "box") def opimpl_setfield_vable(self, pc, basebox, index, valuebox): if self._nonstandard_virtualizable(pc, basebox): - self.execute(rop.SETFIELD_GC, [basebox, valuebox], - descr=self._get_virtualizable_field_descr(index)) + self.execute_with_descr(rop.SETFIELD_GC, self._get_virtualizable_field_descr(index), basebox, valuebox) return self.metainterp.virtualizable_boxes[index] = valuebox self.metainterp.synchronize_virtualizable() @@ -570,12 +563,12 @@ @arguments("orgpc", "box", "int", "box") def opimpl_getarrayitem_vable(self, pc, basebox, arrayindex, indexbox): if self._nonstandard_virtualizable(pc, basebox): - arraybox = self.metainterp.execute_and_record( - rop.GETFIELD_GC, [basebox], - descr=self._get_virtualizable_array_field_descr(arrayindex)) - self.execute( - rop.GETARRAYITEM_GC, [arraybox, indexbox], - descr=self._get_virtualizable_array_descr(arrayindex)) + descr = self._get_virtualizable_array_field_descr(arrayindex) + arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, + descr, basebox) + descr = self._get_virtualizable_array_descr(arrayindex) + self.execute_with_descr(rop.GETARRAYITEM_GC, descr, + arraybox, indexbox) return self.metainterp.check_synchronized_virtualizable() index = self._get_arrayitem_vable_index(pc, arrayindex, indexbox) @@ -585,12 +578,12 @@ def opimpl_setarrayitem_vable(self, pc, basebox, arrayindex, indexbox, valuebox): if self._nonstandard_virtualizable(pc, basebox): - arraybox = self.metainterp.execute_and_record( - rop.GETFIELD_GC, [basebox], - descr=self._get_virtualizable_array_field_descr(arrayindex)) - self.execute( - rop.SETARRAYITEM_GC, [arraybox, indexbox, valuebox], - descr=self._get_virtualizable_array_descr(arrayindex)) + descr = self._get_virtualizable_array_field_descr(arrayindex) + arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, + descr, basebox) + descr = self._get_virtualizable_array_descr(arrayindex) + self.execute_with_descr(rop.SETARRAYITEM_GC, descr, + arraybox, indexbox, valuebox) return index = self._get_arrayitem_vable_index(pc, arrayindex, indexbox) self.metainterp.virtualizable_boxes[index] = valuebox @@ -599,12 +592,11 @@ @arguments("orgpc", "box", "int") def opimpl_arraylen_vable(self, pc, basebox, arrayindex): if self._nonstandard_virtualizable(pc, basebox): - arraybox = self.metainterp.execute_and_record( - rop.GETFIELD_GC, [basebox], - descr=self._get_virtualizable_array_field_descr(arrayindex)) - self.execute( - rop.ARRAYLEN_GC, [arraybox], - descr=self._get_virtualizable_array_descr(arrayindex)) + descr = self._get_virtualizable_array_field_descr(arrayindex) + arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC, + descr, basebox) + descr = self._get_virtualizable_array_descr(arrayindex) + self.execute_with_descr(rop.ARRAYLEN_GC, descr, arraybox) return vinfo = self.metainterp.staticdata.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] @@ -625,12 +617,12 @@ if jitcode.cfnptr is not None: # for non-oosends varargs = [jitcode.cfnptr] + varargs - res = self.execute_with_exc(rop.CALL, varargs, - descr=jitcode.calldescr) + res = self.execute_varargs(rop.CALL, varargs, + descr=jitcode.calldescr, exc=True) else: # for oosends (ootype only): calldescr is a MethDescr - res = self.execute_with_exc(rop.OOSEND, varargs, - descr=jitcode.calldescr) + res = self.execute_varargs(rop.OOSEND, varargs, + descr=jitcode.calldescr, exc=True) if vi: globaldata.blackhole_virtualizable = vi.null_vable return res @@ -646,7 +638,7 @@ @arguments("descr", "varargs") def opimpl_residual_call(self, calldescr, varargs): - return self.execute_with_exc(rop.CALL, varargs, descr=calldescr) + return self.execute_varargs(rop.CALL, varargs, descr=calldescr, exc=True) @arguments("varargs") def opimpl_recursion_leave_prep(self, varargs): @@ -670,68 +662,15 @@ greenkey = varargs[1:num_green_args + 1] if warmrunnerstate.can_inline_callable(greenkey): return self.perform_call(portal_code, varargs[1:]) - return self.execute_with_exc(rop.CALL, varargs, descr=calldescr) + return self.execute_varargs(rop.CALL, varargs, descr=calldescr, exc=True) @arguments("descr", "varargs") def opimpl_residual_call_noexception(self, calldescr, varargs): - if not we_are_translated(): - self.metainterp._debug_history.append(['call', - varargs[0], varargs[1:]]) - self.execute(rop.CALL, varargs, descr=calldescr) + self.execute_varargs(rop.CALL, varargs, descr=calldescr, exc=False) @arguments("descr", "varargs") def opimpl_residual_call_pure(self, calldescr, varargs): - self.execute(rop.CALL_PURE, varargs, descr=calldescr) - -## @arguments("fixedlist", "box", "box") -## def opimpl_list_getitem(self, descr, listbox, indexbox): -## args = [descr.getfunc, listbox, indexbox] -## return self.execute_with_exc(rop.LIST_GETITEM, args, descr.tp) - -## @arguments("fixedlist", "box", "box", "box") -## def opimpl_list_setitem(self, descr, listbox, indexbox, newitembox): -## args = [descr.setfunc, listbox, indexbox, newitembox] -## return self.execute_with_exc(rop.LIST_SETITEM, args, 'void') - -## @arguments("builtin", "varargs") -## def opimpl_getitem_foldable(self, descr, varargs): -## args = [descr.getfunc] + varargs -## return self.execute_with_exc('getitem', args, descr.tp, True) - -## @arguments("builtin", "varargs") -## def opimpl_setitem_foldable(self, descr, varargs): -## args = [descr.setfunc] + varargs -## return self.execute_with_exc('setitem', args, 'void', True) - -## @arguments("fixedlist", "box", "box") -## def opimpl_newlist(self, descr, countbox, defaultbox): -## args = [descr.malloc_func, countbox, defaultbox] -## return self.execute_with_exc(rop.NEWLIST, args, 'ptr') - -## @arguments("builtin", "varargs") -## def opimpl_append(self, descr, varargs): -## args = [descr.append_func] + varargs -## return self.execute_with_exc('append', args, 'void') - -## @arguments("builtin", "varargs") -## def opimpl_insert(self, descr, varargs): -## args = [descr.insert_func] + varargs -## return self.execute_with_exc('insert', args, 'void') - -## @arguments("builtin", "varargs") -## def opimpl_pop(self, descr, varargs): -## args = [descr.pop_func] + varargs -## return self.execute_with_exc('pop', args, descr.tp) - -## @arguments("builtin", "varargs") -## def opimpl_len(self, descr, varargs): -## args = [descr.len_func] + varargs -## return self.execute_with_exc('len', args, 'int') - -## @arguments("builtin", "varargs") -## def opimpl_listnonzero(self, descr, varargs): -## args = [descr.nonzero_func] + varargs -## return self.execute_with_exc('listnonzero', args, 'int') + self.execute_varargs(rop.CALL_PURE, varargs, descr=calldescr, exc=False) @arguments("orgpc", "indirectcallset", "box", "varargs") @@ -756,55 +695,47 @@ @arguments("box") def opimpl_strlen(self, str): - self.execute(rop.STRLEN, [str]) + self.execute(rop.STRLEN, str) @arguments("box") def opimpl_unicodelen(self, str): - self.execute(rop.UNICODELEN, [str]) + self.execute(rop.UNICODELEN, str) @arguments("box", "box") def opimpl_strgetitem(self, str, index): - self.execute(rop.STRGETITEM, [str, index]) + self.execute(rop.STRGETITEM, str, index) @arguments("box", "box") def opimpl_unicodegetitem(self, str, index): - self.execute(rop.UNICODEGETITEM, [str, index]) + self.execute(rop.UNICODEGETITEM, str, index) @arguments("box", "box", "box") def opimpl_strsetitem(self, str, index, newchar): - self.execute(rop.STRSETITEM, [str, index, newchar]) + self.execute(rop.STRSETITEM, str, index, newchar) @arguments("box", "box", "box") def opimpl_unicodesetitem(self, str, index, newchar): - self.execute(rop.UNICODESETITEM, [str, index, newchar]) + self.execute(rop.UNICODESETITEM, str, index, newchar) @arguments("box") def opimpl_newstr(self, length): - self.execute(rop.NEWSTR, [length]) + self.execute(rop.NEWSTR, length) @arguments("box") def opimpl_newunicode(self, length): - self.execute(rop.NEWUNICODE, [length]) + self.execute(rop.NEWUNICODE, length) @arguments("descr", "varargs") def opimpl_residual_oosend_canraise(self, methdescr, varargs): - return self.execute_with_exc(rop.OOSEND, varargs, descr=methdescr) + return self.execute_varargs(rop.OOSEND, varargs, descr=methdescr, exc=True) @arguments("descr", "varargs") def opimpl_residual_oosend_noraise(self, methdescr, varargs): - self.execute(rop.OOSEND, varargs, descr=methdescr) + self.execute_varargs(rop.OOSEND, varargs, descr=methdescr, exc=False) @arguments("descr", "varargs") def opimpl_residual_oosend_pure(self, methdescr, boxes): - self.execute(rop.OOSEND_PURE, boxes, descr=methdescr) - -# @arguments("box", "box") -# def opimpl_oostring_char(self, obj, base): -# self.execute(rop.OOSTRING_CHAR, [obj, base]) -# -# @arguments("box", "box") -# def opimpl_oounicode_unichar(self, obj, base): -# self.execute(rop.OOUNICODE_UNICHAR, [obj, base]) + self.execute_varargs(rop.OOSEND_PURE, boxes, descr=methdescr, exc=False) @arguments("orgpc", "box") def opimpl_guard_value(self, pc, box): @@ -833,31 +764,30 @@ pass # xxx? def generate_merge_point(self, pc, varargs): - if self.metainterp.is_blackholing(): - if self.metainterp.in_recursion: - portal_code = self.metainterp.staticdata.portal_code - # small hack: fish for the result box - lenenv = len(self.env) - raised = self.perform_call(portal_code, varargs) - # in general this cannot be assumed, but when blackholing, - # perform_call returns True only if an exception is called. In - # this case perform_call has called finishframe_exception - # already, so we need to return. - if raised: - return True - if lenenv == len(self.env): - res = None - else: - assert lenenv == len(self.env) - 1 - res = self.env.pop() - self.metainterp.finishframe(res) - return True - else: - raise self.metainterp.staticdata.ContinueRunningNormally(varargs) num_green_args = self.metainterp.staticdata.num_green_args for i in range(num_green_args): varargs[i] = self.implement_guard_value(pc, varargs[i]) - return False + + def blackhole_reached_merge_point(self, varargs): + if self.metainterp.in_recursion: + portal_code = self.metainterp.staticdata.portal_code + # small hack: fish for the result box + lenenv = len(self.env) + raised = self.perform_call(portal_code, varargs) + # in general this cannot be assumed, but when blackholing, + # perform_call returns True only if an exception is called. In + # this case perform_call has called finishframe_exception + # already, so we need to return. + if raised: + return + if lenenv == len(self.env): + res = None + else: + assert lenenv == len(self.env) - 1 + res = self.env.pop() + self.metainterp.finishframe(res) + else: + raise self.metainterp.staticdata.ContinueRunningNormally(varargs) @arguments("orgpc") def opimpl_can_enter_jit(self, pc): @@ -872,13 +802,17 @@ @arguments("orgpc") def opimpl_jit_merge_point(self, pc): - res = self.generate_merge_point(pc, self.env) - if DEBUG > 0: - self.debug_merge_point() - if self.metainterp.seen_can_enter_jit: - self.metainterp.seen_can_enter_jit = False - self.metainterp.reached_can_enter_jit(self.env) - return res + if self.metainterp.is_blackholing(): + self.blackhole_reached_merge_point(self.env) + return True + else: + self.generate_merge_point(pc, self.env) + if DEBUG > 0: + self.debug_merge_point() + if self.metainterp.seen_can_enter_jit: + self.metainterp.seen_can_enter_jit = False + self.metainterp.reached_can_enter_jit(self.env) + return False def debug_merge_point(self): # debugging: produce a DEBUG_MERGE_POINT operation @@ -1007,18 +941,29 @@ return self.metainterp.cpu.ts.cls_of_box(self.metainterp.cpu, box) @specialize.arg(1) - def execute(self, opnum, argboxes, descr=None): - resbox = self.metainterp.execute_and_record(opnum, argboxes, descr) + def execute(self, opnum, *argboxes): + self.execute_with_descr(opnum, None, *argboxes) + + @specialize.arg(1) + def execute_with_descr(self, opnum, descr, *argboxes): + resbox = self.metainterp.execute_and_record(opnum, descr, *argboxes) if resbox is not None: self.make_result_box(resbox) @specialize.arg(1) - def execute_with_exc(self, opnum, argboxes, descr=None): - self.execute(opnum, argboxes, descr) + def execute_varargs(self, opnum, argboxes, descr, exc): + resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes, + descr=descr) + if resbox is not None: + self.make_result_box(resbox) if not we_are_translated(): + # this assumes that execute_varargs() is only used for calls, + # which is the case so far self.metainterp._debug_history.append(['call', argboxes[0], argboxes[1:]]) - return self.metainterp.handle_exception() + if exc: + return self.metainterp.handle_exception() + return False # ____________________________________________________________ @@ -1145,7 +1090,13 @@ self._debug_history = staticdata.globaldata._debug_history def is_blackholing(self): - return isinstance(self.history, history.BlackHole) + return self.history is None + + def blackholing_text(self): + if self.history is None: + return " (BlackHole)" + else: + return "" def newframe(self, jitcode): if not we_are_translated(): @@ -1247,44 +1198,58 @@ if self.staticdata.stats is not None: self.staticdata.stats.history = self.history - def _all_constants(self, boxes): + def _all_constants(self, *boxes): + if len(boxes) == 0: + return True + return isinstance(boxes[0], Const) and self._all_constants(*boxes[1:]) + + def _all_constants_varargs(self, boxes): for box in boxes: if not isinstance(box, Const): return False return True @specialize.arg(1) - def execute_and_record(self, opnum, argboxes, descr=None): + def execute_and_record(self, opnum, descr, *argboxes): + history.check_descr(descr) + assert opnum != rop.CALL and opnum != rop.OOSEND + # execute the operation + profiler = self.staticdata.profiler + profiler.count_ops(opnum) + resbox = executor.execute(self.cpu, opnum, descr, *argboxes) + if self.is_blackholing(): + profiler.count_ops(opnum, BLACKHOLED_OPS) + return resbox + if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: + return self._record_helper_pure(opnum, resbox, descr, *argboxes) + else: + return self._record_helper_nonpure_varargs(opnum, resbox, descr, + list(argboxes)) + + @specialize.arg(1) + def execute_and_record_varargs(self, opnum, argboxes, descr=None): history.check_descr(descr) # residual calls require attention to keep virtualizables in-sync. # CALL_PURE doesn't need it because so far 'promote_virtualizable' # as an operation is enough to make the called function non-pure. require_attention = (opnum == rop.CALL or opnum == rop.OOSEND) - if require_attention: + if require_attention and not self.is_blackholing(): self.before_residual_call() # execute the operation - resbox = executor.execute(self.cpu, opnum, argboxes, descr) - if require_attention: - require_attention = self.after_residual_call() - # check if the operation can be constant-folded away - canfold = False - if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: - # this part disappears if execute() is specialized for an - # opnum that is not within the range - canfold = self._all_constants(argboxes) - if canfold: - resbox = resbox.constbox() # ensure it is a Const - else: - resbox = resbox.nonconstbox() # ensure it is a Box - else: - assert resbox is None or isinstance(resbox, Box) profiler = self.staticdata.profiler profiler.count_ops(opnum) - # record the operation if not constant-folded away - if not canfold: - op = self.history.record(opnum, argboxes, resbox, descr) - profiler.count_ops(opnum, self.history.OPS_KIND) - self.attach_debug_info(op) + resbox = executor.execute_varargs(self.cpu, opnum, argboxes, descr) + if self.is_blackholing(): + profiler.count_ops(opnum, BLACKHOLED_OPS) + else: + if require_attention: + require_attention = self.after_residual_call() + # check if the operation can be constant-folded away + if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST: + resbox = self._record_helper_pure_varargs(opnum, resbox, descr, argboxes) + else: + resbox = self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes) + # if we are blackholing require_attention has the initial meaning else: if self.is_blackholing(): profiler.count_ops(opnum, self.history.OPS_KIND) # canfold blackholed @@ -1292,6 +1257,33 @@ self.after_generate_residual_call() return resbox + def _record_helper_pure(self, opnum, resbox, descr, *argboxes): + canfold = self._all_constants(*argboxes) + if canfold: + resbox = resbox.constbox() # ensure it is a Const + return resbox + else: + resbox = resbox.nonconstbox() # ensure it is a Box + return self._record_helper_nonpure_varargs(opnum, resbox, descr, list(argboxes)) + + def _record_helper_pure_varargs(self, opnum, resbox, descr, argboxes): + canfold = self._all_constants_varargs(argboxes) + if canfold: + resbox = resbox.constbox() # ensure it is a Const + return resbox + else: + resbox = resbox.nonconstbox() # ensure it is a Box + return self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes) + + def _record_helper_nonpure_varargs(self, opnum, resbox, descr, argboxes): + assert resbox is None or isinstance(resbox, Box) + # record the operation + profiler = self.staticdata.profiler + profiler.count_ops(opnum, RECORDED_OPS) + op = self.history.record(opnum, argboxes, resbox, descr) + self.attach_debug_info(op) + return resbox + def attach_debug_info(self, op): if (not we_are_translated() and op is not None and getattr(self, 'framestack', None)): @@ -1302,12 +1294,12 @@ if not self.is_blackholing(): warmrunnerstate = self.staticdata.state if len(self.history.operations) > warmrunnerstate.trace_limit: - self.history = history.BlackHole(self.cpu) + self.history = None # start blackholing if not we_are_translated(): self.staticdata.stats.aborted_count += 1 - history.log.event('ABORTING TRACING' + self.history.extratext) + history.log.event('ABORTING TRACING') elif DEBUG: - debug_print('~~~ ABORTING TRACING', self.history.extratext) + debug_print('~~~ ABORTING TRACING') self.staticdata.profiler.end_tracing() self.staticdata.profiler.start_blackhole() @@ -1315,10 +1307,10 @@ # Execute the frames forward until we raise a DoneWithThisFrame, # a ContinueRunningNormally, or a GenerateMergePoint exception. if not we_are_translated(): - history.log.event('ENTER' + self.history.extratext) + history.log.event('ENTER' + self.blackholing_text()) self.staticdata.stats.enter_count += 1 elif DEBUG: - debug_print('~~~ ENTER', self.history.extratext) + debug_print('~~~ ENTER', self.blackholing_text()) try: while True: self.framestack[-1].run_one_step() @@ -1331,9 +1323,9 @@ else: self.staticdata.profiler.end_tracing() if not we_are_translated(): - history.log.event('LEAVE' + self.history.extratext) + history.log.event('LEAVE' + self.blackholing_text()) elif DEBUG: - debug_print('~~~ LEAVE', self.history.extratext) + debug_print('~~~ LEAVE', self.blackholing_text()) def interpret(self): if we_are_translated(): @@ -1624,9 +1616,7 @@ self.staticdata.profiler.start_tracing() else: self.staticdata.profiler.start_blackhole() - self.history = history.BlackHole(self.cpu) - # the BlackHole is invalid because it doesn't start with - # guard_failure.key.guard_op.suboperations, but that's fine + self.history = None # this means that is_blackholing() is true self.rebuild_state_after_failure(resumedescr, guard_failure.args) return resumedescr @@ -1670,9 +1660,8 @@ # as it contains the old values (before the call)! self.gen_store_back_in_virtualizable_no_perform() return True # must call after_generate_residual_call() - # xxx don't call after_generate_residual_call() or - # in the case of blackholing abuse it to resynchronize - return self.is_blackholing() + # otherwise, don't call after_generate_residual_call() + return False def after_generate_residual_call(self): # Called after generating a residual call, and only if @@ -1748,18 +1737,19 @@ if vinfo is not None: vbox = self.virtualizable_boxes[-1] for i in range(vinfo.num_static_extra_boxes): - fieldbox = self.execute_and_record(rop.GETFIELD_GC, [vbox], - descr=vinfo.static_field_descrs[i]) + descr = vinfo.static_field_descrs[i] + fieldbox = self.execute_and_record(rop.GETFIELD_GC, descr, + vbox) self.virtualizable_boxes[i] = fieldbox i = vinfo.num_static_extra_boxes virtualizable = vinfo.unwrap_virtualizable_box(vbox) for k in range(vinfo.num_arrays): - abox = self.execute_and_record(rop.GETFIELD_GC, [vbox], - descr=vinfo.array_field_descrs[k]) + descr = vinfo.array_field_descrs[k] + abox = self.execute_and_record(rop.GETFIELD_GC, descr, vbox) + descr = vinfo.array_descrs[k] for j in range(vinfo.get_array_length(virtualizable, k)): itembox = self.execute_and_record(rop.GETARRAYITEM_GC, - [abox, ConstInt(j)], - descr=vinfo.array_descrs[k]) + descr, abox, ConstInt(j)) self.virtualizable_boxes[i] = itembox i += 1 assert i + 1 == len(self.virtualizable_boxes) @@ -1771,19 +1761,19 @@ vbox = self.virtualizable_boxes[-1] for i in range(vinfo.num_static_extra_boxes): fieldbox = self.virtualizable_boxes[i] - self.execute_and_record(rop.SETFIELD_GC, [vbox, fieldbox], - descr=vinfo.static_field_descrs[i]) + descr = vinfo.static_field_descrs[i] + self.execute_and_record(rop.SETFIELD_GC, descr, vbox, fieldbox) i = vinfo.num_static_extra_boxes virtualizable = vinfo.unwrap_virtualizable_box(vbox) for k in range(vinfo.num_arrays): - abox = self.execute_and_record(rop.GETFIELD_GC, [vbox], - descr=vinfo.array_field_descrs[k]) + descr = vinfo.array_field_descrs[k] + abox = self.execute_and_record(rop.GETFIELD_GC, descr, vbox) + descr = vinfo.array_descrs[k] for j in range(vinfo.get_array_length(virtualizable, k)): itembox = self.virtualizable_boxes[i] i += 1 - self.execute_and_record(rop.SETARRAYITEM_GC, - [abox, ConstInt(j), itembox], - descr=vinfo.array_descrs[k]) + self.execute_and_record(rop.SETARRAYITEM_GC, descr, + abox, ConstInt(j), itembox) assert i + 1 == len(self.virtualizable_boxes) def gen_store_back_in_virtualizable_no_perform(self): From cfbolz at codespeak.net Mon Sep 21 10:35:58 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 10:35:58 +0200 (CEST) Subject: [pypy-svn] r67813 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090921083558.AA22D168010@codespeak.net> Author: cfbolz Date: Mon Sep 21 10:35:57 2009 New Revision: 67813 Added: pypy/trunk/pypy/jit/metainterp/resume.py.merge.tmp - copied, changed from r67810, pypy/trunk/pypy/jit/metainterp/resume.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resume.py revisions 67773 to 67810: ------------------------------------------------------------------------ r67777 | cfbolz | 2009-09-18 17:21:44 +0200 (Fri, 18 Sep 2009) | 3 lines (pedronis, cfbolz, arigo) Progress in making *arg versions of the functions. Not finished yet. ------------------------------------------------------------------------ r67774 | cfbolz | 2009-09-18 15:37:46 +0200 (Fri, 18 Sep 2009) | 2 lines (pedronis, cfbolz): make a branch that tries to make the jit use less memory ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/resume.py.merge.tmp (from r67810, pypy/trunk/pypy/jit/metainterp/resume.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resume.py (original) +++ pypy/trunk/pypy/jit/metainterp/resume.py.merge.tmp Mon Sep 21 10:35:57 2009 @@ -189,8 +189,8 @@ for i in range(len(self.fielddescrs)): fieldbox = fn_decode_box(self.fieldnums[i]) metainterp.execute_and_record(rop.SETFIELD_GC, - [box, fieldbox], - descr=self.fielddescrs[i]) + self.fielddescrs[i], + box, fieldbox) class VirtualInfo(AbstractVirtualStructInfo): def __init__(self, known_class, fielddescrs): @@ -199,7 +199,7 @@ def allocate(self, metainterp): return metainterp.execute_and_record(rop.NEW_WITH_VTABLE, - [self.known_class]) + None, self.known_class) def repr_rpython(self): return 'VirtualInfo("%s", %s, %s)' % ( @@ -213,8 +213,7 @@ self.typedescr = typedescr def allocate(self, metainterp): - return metainterp.execute_and_record(rop.NEW, [], - descr=self.typedescr) + return metainterp.execute_and_record(rop.NEW, self.typedescr) def repr_rpython(self): return 'VStructInfo("%s", %s, %s)' % ( @@ -230,15 +229,15 @@ def allocate(self, metainterp): length = len(self.fieldnums) return metainterp.execute_and_record(rop.NEW_ARRAY, - [ConstInt(length)], - descr=self.arraydescr) + self.arraydescr, + ConstInt(length)) def setfields(self, metainterp, box, fn_decode_box): for i in range(len(self.fieldnums)): itembox = fn_decode_box(self.fieldnums[i]) metainterp.execute_and_record(rop.SETARRAYITEM_GC, - [box, ConstInt(i), itembox], - descr=self.arraydescr) + self.arraydescr, + box, ConstInt(i), itembox) def repr_rpython(self): return 'VArrayInfo("%s", %s)' % (self.arraydescr, From cfbolz at codespeak.net Mon Sep 21 10:36:04 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 10:36:04 +0200 (CEST) Subject: [pypy-svn] r67814 - pypy/trunk/pypy/jit/backend/cli Message-ID: <20090921083604.554B8168010@codespeak.net> Author: cfbolz Date: Mon Sep 21 10:36:03 2009 New Revision: 67814 Added: pypy/trunk/pypy/jit/backend/cli/runner.py.merge.tmp - copied, changed from r67810, pypy/trunk/pypy/jit/backend/cli/runner.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/execute-star-args-jit/pypy/jit/backend/cli/runner.py revisions 67773 to 67810: ------------------------------------------------------------------------ r67793 | arigo | 2009-09-19 12:42:12 +0200 (Sat, 19 Sep 2009) | 2 lines Fix the cli backend too. Not really tested. ------------------------------------------------------------------------ r67774 | cfbolz | 2009-09-18 15:37:46 +0200 (Fri, 18 Sep 2009) | 2 lines (pedronis, cfbolz): make a branch that tries to make the jit use less memory ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/backend/cli/runner.py.merge.tmp (from r67810, pypy/trunk/pypy/jit/backend/cli/runner.py) ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/runner.py (original) +++ pypy/trunk/pypy/jit/backend/cli/runner.py.merge.tmp Mon Sep 21 10:36:03 2009 @@ -162,38 +162,30 @@ # ---------------------- - def do_new_with_vtable(self, args, descr): - #assert isinstance(typedescr, TypeDescr) - #assert len(args) == 1 # but we don't need it, so ignore - assert descr is None - assert len(args) == 1 - cls = args[0].getref_base() + def do_new_with_vtable(self, classbox): + cls = classbox.getref_base() typedescr = self.class_sizes[cls] return typedescr.create() - def do_new_array(self, args, typedescr): + def do_new_array(self, lengthbox, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 1 - return typedescr.create_array(args[0]) + return typedescr.create_array(lengthbox) - def do_runtimenew(self, args, descr): - classbox = args[0] + def do_runtimenew(self, classbox): classobj = classbox.getref(ootype.Class) res = ootype.runtimenew(classobj) return BoxObj(ootype.cast_to_object(res)) - def do_instanceof(self, args, typedescr): - assert isinstance(typedescr, TypeDescr) - assert len(args) == 1 - return typedescr.instanceof(args[0]) + def do_instanceof(self, instancebox, typedescr): + return typedescr.instanceof(instancebox) - def do_getfield_gc(self, args, fielddescr): + def do_getfield_gc(self, instancebox, fielddescr): assert isinstance(fielddescr, FieldDescr) - return fielddescr.getfield(args[0]) + return fielddescr.getfield(instancebox) - def do_setfield_gc(self, args, fielddescr): + def do_setfield_gc(self, instancebox, newvaluebox, fielddescr): assert isinstance(fielddescr, FieldDescr) - return fielddescr.setfield(args[0], args[1]) + return fielddescr.setfield(instancebox, newvaluebox) def do_call(self, args, calldescr): assert isinstance(calldescr, StaticMethDescr) @@ -212,31 +204,22 @@ obj = ootype.cast_to_object(inst) # SomeOOObject return dotnet.cast_to_native_object(obj) # System.Object - def do_oosend(self, args, descr=None): + def do_oosend(self, args, descr): assert isinstance(descr, MethDescr) selfbox = args[0] argboxes = args[1:] return descr.callmeth(selfbox, argboxes) - def do_getarrayitem_gc(self, args, descr): + def do_getarrayitem_gc(self, arraybox, indexbox, descr): assert isinstance(descr, TypeDescr) - assert len(args) == 2 - arraybox = args[0] - ibox = args[1] - return descr.getarrayitem(arraybox, ibox) + return descr.getarrayitem(arraybox, indexbox) - def do_setarrayitem_gc(self, args, descr): + def do_setarrayitem_gc(self, arraybox, indexbox, newvaluebox, descr): assert isinstance(descr, TypeDescr) - assert len(args) == 3 - arraybox = args[0] - ibox = args[1] - valuebox = args[2] - descr.setarrayitem(arraybox, ibox, valuebox) + descr.setarrayitem(arraybox, indexbox, newvaluebox) - def do_arraylen_gc(self, args, descr): + def do_arraylen_gc(self, arraybox, descr): assert isinstance(descr, TypeDescr) - assert len(args) == 1 - arraybox = args[0] return descr.getarraylength(arraybox) # ---------------------------------------------------------------------- From cfbolz at codespeak.net Mon Sep 21 10:36:07 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 10:36:07 +0200 (CEST) Subject: [pypy-svn] r67815 - pypy/trunk/pypy/jit/backend/llgraph Message-ID: <20090921083607.A92BB168010@codespeak.net> Author: cfbolz Date: Mon Sep 21 10:36:06 2009 New Revision: 67815 Added: pypy/trunk/pypy/jit/backend/llgraph/runner.py.merge.tmp - copied, changed from r67810, pypy/trunk/pypy/jit/backend/llgraph/runner.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/execute-star-args-jit/pypy/jit/backend/llgraph/runner.py revisions 67773 to 67810: ------------------------------------------------------------------------ r67790 | arigo | 2009-09-19 11:55:06 +0200 (Sat, 19 Sep 2009) | 4 lines (arigo, pedronis around) Refactor the do_xxx() operations in executor.py and on the CPU to take arguments directly instead of in a list. ------------------------------------------------------------------------ r67774 | cfbolz | 2009-09-18 15:37:46 +0200 (Fri, 18 Sep 2009) | 2 lines (pedronis, cfbolz): make a branch that tries to make the jit use less memory ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/backend/llgraph/runner.py.merge.tmp (from r67810, pypy/trunk/pypy/jit/backend/llgraph/runner.py) ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/runner.py.merge.tmp Mon Sep 21 10:36:06 2009 @@ -283,36 +283,32 @@ # ---------- the backend-dependent operations ---------- - def do_arraylen_gc(self, args, arraydescr): - array = args[0].getref_base() + def do_arraylen_gc(self, arraybox, arraydescr): + array = arraybox.getref_base() return history.BoxInt(llimpl.do_arraylen_gc(arraydescr, array)) - def do_strlen(self, args, descr=None): - assert descr is None - string = args[0].getref_base() + def do_strlen(self, stringbox): + string = stringbox.getref_base() return history.BoxInt(llimpl.do_strlen(0, string)) - def do_strgetitem(self, args, descr=None): - assert descr is None - string = args[0].getref_base() - index = args[1].getint() + def do_strgetitem(self, stringbox, indexbox): + string = stringbox.getref_base() + index = indexbox.getint() return history.BoxInt(llimpl.do_strgetitem(0, string, index)) - def do_unicodelen(self, args, descr=None): - assert descr is None - string = args[0].getref_base() + def do_unicodelen(self, stringbox): + string = stringbox.getref_base() return history.BoxInt(llimpl.do_unicodelen(0, string)) - def do_unicodegetitem(self, args, descr=None): - assert descr is None - string = args[0].getref_base() - index = args[1].getint() + def do_unicodegetitem(self, stringbox, indexbox): + string = stringbox.getref_base() + index = indexbox.getint() return history.BoxInt(llimpl.do_unicodegetitem(0, string, index)) - def do_getarrayitem_gc(self, args, arraydescr): + def do_getarrayitem_gc(self, arraybox, indexbox, arraydescr): assert isinstance(arraydescr, Descr) - array = args[0].getref_base() - index = args[1].getint() + array = arraybox.getref_base() + index = indexbox.getint() if arraydescr.typeinfo == REF: return history.BoxPtr(llimpl.do_getarrayitem_gc_ptr(array, index)) elif arraydescr.typeinfo == INT: @@ -324,9 +320,9 @@ else: raise NotImplementedError - def do_getfield_gc(self, args, fielddescr): + def do_getfield_gc(self, structbox, fielddescr): assert isinstance(fielddescr, Descr) - struct = args[0].getref_base() + struct = structbox.getref_base() if fielddescr.typeinfo == REF: return history.BoxPtr(llimpl.do_getfield_gc_ptr(struct, fielddescr.ofs)) @@ -340,9 +336,9 @@ else: raise NotImplementedError - def do_getfield_raw(self, args, fielddescr): + def do_getfield_raw(self, structbox, fielddescr): assert isinstance(fielddescr, Descr) - struct = self.cast_int_to_adr(args[0].getint()) + struct = self.cast_int_to_adr(structbox.getint()) if fielddescr.typeinfo == REF: return history.BoxPtr(llimpl.do_getfield_raw_ptr(struct, fielddescr.ofs, @@ -358,100 +354,95 @@ else: raise NotImplementedError - def do_new(self, args, size): + def do_new(self, size): assert isinstance(size, Descr) return history.BoxPtr(llimpl.do_new(size.ofs)) - def do_new_with_vtable(self, args, descr=None): - assert descr is None - vtable = args[0].getint() + def do_new_with_vtable(self, vtablebox): + vtable = vtablebox.getint() size = self.class_sizes[vtable] result = llimpl.do_new(size.ofs) llimpl.do_setfield_gc_int(result, self.fielddescrof_vtable.ofs, vtable, self.memo_cast) return history.BoxPtr(result) - def do_new_array(self, args, size): + def do_new_array(self, countbox, size): assert isinstance(size, Descr) - count = args[0].getint() + count = countbox.getint() return history.BoxPtr(llimpl.do_new_array(size.ofs, count)) - def do_setarrayitem_gc(self, args, arraydescr): + def do_setarrayitem_gc(self, arraybox, indexbox, newvaluebox, arraydescr): assert isinstance(arraydescr, Descr) - array = args[0].getref_base() - index = args[1].getint() + array = arraybox.getref_base() + index = indexbox.getint() if arraydescr.typeinfo == REF: - newvalue = args[2].getref_base() + newvalue = newvaluebox.getref_base() llimpl.do_setarrayitem_gc_ptr(array, index, newvalue) elif arraydescr.typeinfo == INT: - newvalue = args[2].getint() + newvalue = newvaluebox.getint() llimpl.do_setarrayitem_gc_int(array, index, newvalue, self.memo_cast) elif arraydescr.typeinfo == FLOAT: - newvalue = args[2].getfloat() + newvalue = newvaluebox.getfloat() llimpl.do_setarrayitem_gc_float(array, index, newvalue) else: raise NotImplementedError - def do_setfield_gc(self, args, fielddescr): + def do_setfield_gc(self, structbox, newvaluebox, fielddescr): assert isinstance(fielddescr, Descr) - struct = args[0].getref_base() + struct = structbox.getref_base() if fielddescr.typeinfo == REF: - newvalue = args[1].getref_base() + newvalue = newvaluebox.getref_base() llimpl.do_setfield_gc_ptr(struct, fielddescr.ofs, newvalue) elif fielddescr.typeinfo == INT: - newvalue = args[1].getint() + newvalue = newvaluebox.getint() llimpl.do_setfield_gc_int(struct, fielddescr.ofs, newvalue, self.memo_cast) elif fielddescr.typeinfo == FLOAT: - newvalue = args[1].getfloat() + newvalue = newvaluebox.getfloat() llimpl.do_setfield_gc_float(struct, fielddescr.ofs, newvalue) else: raise NotImplementedError - def do_setfield_raw(self, args, fielddescr): + def do_setfield_raw(self, structbox, newvaluebox, fielddescr): assert isinstance(fielddescr, Descr) - struct = self.cast_int_to_adr(args[0].getint()) + struct = self.cast_int_to_adr(structbox.getint()) if fielddescr.typeinfo == REF: - newvalue = args[1].getref_base() + newvalue = newvaluebox.getref_base() llimpl.do_setfield_raw_ptr(struct, fielddescr.ofs, newvalue, self.memo_cast) elif fielddescr.typeinfo == INT: - newvalue = args[1].getint() + newvalue = newvaluebox.getint() llimpl.do_setfield_raw_int(struct, fielddescr.ofs, newvalue, self.memo_cast) elif fielddescr.typeinfo == FLOAT: - newvalue = args[1].getfloat() + newvalue = newvaluebox.getfloat() llimpl.do_setfield_raw_float(struct, fielddescr.ofs, newvalue, self.memo_cast) else: raise NotImplementedError - def do_same_as(self, args, descr=None): - return args[0].clonebox() + def do_same_as(self, box1): + return box1.clonebox() - def do_newstr(self, args, descr=None): - assert descr is None - length = args[0].getint() + def do_newstr(self, lengthbox): + length = lengthbox.getint() return history.BoxPtr(llimpl.do_newstr(0, length)) - def do_newunicode(self, args, descr=None): - assert descr is None - length = args[0].getint() + def do_newunicode(self, lengthbox): + length = lengthbox.getint() return history.BoxPtr(llimpl.do_newunicode(0, length)) - def do_strsetitem(self, args, descr=None): - assert descr is None - string = args[0].getref_base() - index = args[1].getint() - newvalue = args[2].getint() + def do_strsetitem(self, stringbox, indexbox, newvaluebox): + string = stringbox.getref_base() + index = indexbox.getint() + newvalue = newvaluebox.getint() llimpl.do_strsetitem(0, string, index, newvalue) - def do_unicodesetitem(self, args, descr=None): - assert descr is None - string = args[0].getref_base() - index = args[1].getint() - newvalue = args[2].getint() + def do_unicodesetitem(self, stringbox, indexbox, newvaluebox): + string = stringbox.getref_base() + index = indexbox.getint() + newvalue = newvaluebox.getint() llimpl.do_unicodesetitem(0, string, index, newvalue) def do_call(self, args, calldescr): @@ -474,9 +465,8 @@ else: raise NotImplementedError - def do_cast_ptr_to_int(self, args, descr=None): - assert descr is None - return history.BoxInt(llimpl.cast_to_int(args[0].getref_base(), + def do_cast_ptr_to_int(self, ptrbox): + return history.BoxInt(llimpl.cast_to_int(ptrbox.getref_base(), self.memo_cast)) class OOtypeCPU(BaseCPU): @@ -536,57 +526,48 @@ return (ootype.cast_to_object(ll_err.args[0]), ootype.cast_to_object(ll_err.args[1])) - def do_new_with_vtable(self, args, descr=None): - assert descr is None - assert len(args) == 1 - cls = args[0].getref_base() + def do_new_with_vtable(self, clsbox): + cls = clsbox.getref_base() typedescr = self.class_sizes[cls] return typedescr.create() - def do_new_array(self, args, typedescr): + def do_new_array(self, lengthbox, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 1 - return typedescr.create_array(args[0]) + return typedescr.create_array(lengthbox) - def do_new(self, args, typedescr): + def do_new(self, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 0 return typedescr.create() - def do_runtimenew(self, args, descr): + def do_runtimenew(self, classbox): "NOT_RPYTHON" - classbox = args[0] classobj = classbox.getref(ootype.Class) res = ootype.runtimenew(classobj) return history.BoxObj(ootype.cast_to_object(res)) - def do_instanceof(self, args, typedescr): + def do_instanceof(self, box1, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 1 - return typedescr.instanceof(args[0]) + return typedescr.instanceof(box1) - def do_getfield_gc(self, args, fielddescr): + def do_getfield_gc(self, box1, fielddescr): assert isinstance(fielddescr, FieldDescr) - return fielddescr.getfield(args[0]) + return fielddescr.getfield(box1) - def do_setfield_gc(self, args, fielddescr): + def do_setfield_gc(self, box1, box2, fielddescr): assert isinstance(fielddescr, FieldDescr) - return fielddescr.setfield(args[0], args[1]) + return fielddescr.setfield(box1, box2) - def do_getarrayitem_gc(self, args, typedescr): + def do_getarrayitem_gc(self, box1, box2, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 2 - return typedescr.getarrayitem(*args) + return typedescr.getarrayitem(box1, box2) - def do_setarrayitem_gc(self, args, typedescr): + def do_setarrayitem_gc(self, box1, box2, box3, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 3 - return typedescr.setarrayitem(*args) + return typedescr.setarrayitem(box1, box2, box3) - def do_arraylen_gc(self, args, typedescr): + def do_arraylen_gc(self, box1, typedescr): assert isinstance(typedescr, TypeDescr) - assert len(args) == 1 - return typedescr.getarraylength(*args) + return typedescr.getarraylength(box1) def do_call(self, args, descr): assert isinstance(descr, StaticMethDescr) From cfbolz at codespeak.net Mon Sep 21 10:36:10 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 10:36:10 +0200 (CEST) Subject: [pypy-svn] r67816 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090921083610.DDEC6168010@codespeak.net> Author: cfbolz Date: Mon Sep 21 10:36:09 2009 New Revision: 67816 Added: pypy/trunk/pypy/jit/metainterp/test/test_resume.py.merge.tmp - copied, changed from r67810, pypy/trunk/pypy/jit/metainterp/test/test_resume.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_resume.py revisions 67773 to 67810: ------------------------------------------------------------------------ r67791 | arigo | 2009-09-19 12:13:14 +0200 (Sat, 19 Sep 2009) | 2 lines Fix model and llmodel. Fix tests in metainterp. ------------------------------------------------------------------------ r67778 | cfbolz | 2009-09-18 17:38:12 +0200 (Fri, 18 Sep 2009) | 3 lines (arigo, pedronis, cfbolz) Fixes for tests, and unroll _all_constants to avoid making a list. ------------------------------------------------------------------------ r67774 | cfbolz | 2009-09-18 15:37:46 +0200 (Fri, 18 Sep 2009) | 2 lines (pedronis, cfbolz): make a branch that tries to make the jit use less memory ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/test/test_resume.py.merge.tmp (from r67810, pypy/trunk/pypy/jit/metainterp/test/test_resume.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_resume.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_resume.py.merge.tmp Mon Sep 21 10:36:09 2009 @@ -166,8 +166,8 @@ def __init__(self, cpu): self.cpu = cpu self.trace = [] - def execute_and_record(self, opnum, argboxes, descr=None): - resbox = executor.execute(self.cpu, opnum, argboxes, descr) + def execute_and_record(self, opnum, descr, *argboxes): + resbox = executor.execute(self.cpu, opnum, descr, *argboxes) self.trace.append((opnum, [box.value for box in argboxes], resbox and resbox.value, From cfbolz at codespeak.net Mon Sep 21 10:37:41 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 10:37:41 +0200 (CEST) Subject: [pypy-svn] r67817 - in pypy/trunk/pypy/jit: backend backend/cli backend/llgraph backend/llsupport backend/llvm backend/test backend/x86/test metainterp metainterp/test Message-ID: <20090921083741.580ED168010@codespeak.net> Author: cfbolz Date: Mon Sep 21 10:37:40 2009 New Revision: 67817 Added: pypy/trunk/pypy/jit/backend/cli/runner.py - copied unchanged from r67816, pypy/trunk/pypy/jit/backend/cli/runner.py.merge.tmp pypy/trunk/pypy/jit/backend/llgraph/llimpl.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/backend/llgraph/llimpl.py pypy/trunk/pypy/jit/backend/llgraph/runner.py - copied unchanged from r67816, pypy/trunk/pypy/jit/backend/llgraph/runner.py.merge.tmp pypy/trunk/pypy/jit/backend/llsupport/ - copied from r67816, pypy/branch/execute-star-args-jit/pypy/jit/backend/llsupport/ pypy/trunk/pypy/jit/backend/llvm/ - copied from r67816, pypy/branch/execute-star-args-jit/pypy/jit/backend/llvm/ pypy/trunk/pypy/jit/backend/model.py - copied unchanged from r67816, pypy/trunk/pypy/jit/backend/model.py.merge.tmp pypy/trunk/pypy/jit/backend/test/runner_test.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/backend/test/runner_test.py pypy/trunk/pypy/jit/backend/test/test_random.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/backend/test/test_random.py pypy/trunk/pypy/jit/backend/x86/test/ - copied from r67816, pypy/branch/execute-star-args-jit/pypy/jit/backend/x86/test/ pypy/trunk/pypy/jit/metainterp/executor.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/executor.py pypy/trunk/pypy/jit/metainterp/history.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/optimizefindnode.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/optimizefindnode.py pypy/trunk/pypy/jit/metainterp/optimizeopt.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/optimizeopt.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py - copied unchanged from r67816, pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp pypy/trunk/pypy/jit/metainterp/resoperation.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/resoperation.py pypy/trunk/pypy/jit/metainterp/resume.py - copied unchanged from r67816, pypy/trunk/pypy/jit/metainterp/resume.py.merge.tmp pypy/trunk/pypy/jit/metainterp/specnode.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/specnode.py pypy/trunk/pypy/jit/metainterp/test/test_basic.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_basic.py pypy/trunk/pypy/jit/metainterp/test/test_executor.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_executor.py pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_jitprof.py pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_optimizeopt.py pypy/trunk/pypy/jit/metainterp/test/test_resume.py - copied unchanged from r67816, pypy/trunk/pypy/jit/metainterp/test/test_resume.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_virtualizable.py - copied unchanged from r67816, pypy/branch/execute-star-args-jit/pypy/jit/metainterp/test/test_virtualizable.py Removed: pypy/trunk/pypy/jit/backend/cli/runner.py.merge.tmp pypy/trunk/pypy/jit/backend/llgraph/runner.py.merge.tmp pypy/trunk/pypy/jit/backend/model.py.merge.tmp pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp pypy/trunk/pypy/jit/metainterp/resume.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_resume.py.merge.tmp Log: merge execute-star-args-jit From pedronis at codespeak.net Mon Sep 21 10:42:46 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 21 Sep 2009 10:42:46 +0200 (CEST) Subject: [pypy-svn] r67818 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090921084246.C7631168009@codespeak.net> Author: pedronis Date: Mon Sep 21 10:42:46 2009 New Revision: 67818 Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: oops, we got both versions of the profiling fix Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Mon Sep 21 10:42:46 2009 @@ -1250,9 +1250,6 @@ else: resbox = self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes) # if we are blackholing require_attention has the initial meaning - else: - if self.is_blackholing(): - profiler.count_ops(opnum, self.history.OPS_KIND) # canfold blackholed if require_attention: self.after_generate_residual_call() return resbox From cfbolz at codespeak.net Mon Sep 21 10:44:26 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 10:44:26 +0200 (CEST) Subject: [pypy-svn] r67819 - pypy/branch/bigint-rlonglong Message-ID: <20090921084426.68954168009@codespeak.net> Author: cfbolz Date: Mon Sep 21 10:44:25 2009 New Revision: 67819 Added: pypy/branch/bigint-rlonglong/ - copied from r67818, pypy/trunk/ Log: A branch to test the rbigint changes I did this weekend. From cfbolz at codespeak.net Mon Sep 21 10:56:27 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 10:56:27 +0200 (CEST) Subject: [pypy-svn] r67820 - pypy/branch/bigint-rlonglong/pypy/module/marshal/test Message-ID: <20090921085627.088DA168009@codespeak.net> Author: cfbolz Date: Mon Sep 21 10:56:26 2009 New Revision: 67820 Modified: pypy/branch/bigint-rlonglong/pypy/module/marshal/test/test_marshal.py Log: Make test_marshal.py a lot saner. I have no clue why it was written in that strange way. Modified: pypy/branch/bigint-rlonglong/pypy/module/marshal/test/test_marshal.py ============================================================================== --- pypy/branch/bigint-rlonglong/pypy/module/marshal/test/test_marshal.py (original) +++ pypy/branch/bigint-rlonglong/pypy/module/marshal/test/test_marshal.py Mon Sep 21 10:56:26 2009 @@ -1,561 +1,149 @@ from pypy.tool.udir import udir +def make_check(space): + return space.appexec([], """(): + import sys + import marshal, StringIO + def marshal_check(case): + s = marshal.dumps(case) + print repr(s) + x = marshal.loads(s) + assert x == case and type(x) is type(case) + f = StringIO.StringIO() + marshal.dump(case, f) + f.seek(0) + x = marshal.load(f) + assert x == case and type(x) is type(case) + return marshal_check + """) + class AppTestMarshal: def setup_class(cls): tmpfile = udir.join('AppTestMarshal.tmp') cls.w_tmpfile = cls.space.wrap(str(tmpfile)) + cls.w_marshal_check = make_check(cls.space) def test_None(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = None - print "case: %-30s func=None" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_False(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = False - print "case: %-30s func=False" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_True(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = True - print "case: %-30s func=True" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_StopIteration(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = StopIteration - print "case: %-30s func=StopIteration" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_Ellipsis(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = Ellipsis - print "case: %-30s func=Ellipsis" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_42(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = 42 - print "case: %-30s func=42" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test__minus_17(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = -17 - print "case: %-30s func=_minus_17" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_sys_dot_maxint(self): import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = sys.maxint - print "case: %-30s func=sys_dot_maxint" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test__minus_1_dot_25(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = -1.25 - print "case: %-30s func=_minus_1_dot_25" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test__minus_1_dot_25__2(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = -1.25 #2 - print "case: %-30s func=_minus_1_dot_25__2" % (case, ) - s = marshal.dumps(case, 2); assert len(s) in (9, 17) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_2_plus_5j(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = 2+5j - print "case: %-30s func=2_plus_5j" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_2_plus_5j__2(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = 2+5j #2 - print "case: %-30s func=2_plus_5j__2" % (case, ) - s = marshal.dumps(case, 2); assert len(s) in (9, 17) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) - def test_42L(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO - case = 42L - print "case: %-30s func=42L" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) - - def test__minus_1234567890123456789012345678901234567890L(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO + def test_long(self): + self.marshal_check(42L) case = -1234567890123456789012345678901234567890L - print "case: %-30s func=_minus_1234567890123456789012345678901234567890L" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_hello_____not_interned(self): - import sys hello = "he" hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = hello # not interned - print "case: %-30s func=hello_____not_interned" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test__Quote_hello_Quote_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = "hello" - print "case: %-30s func=_Quote_hello_Quote_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test__brace__ecarb_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = () - print "case: %-30s func=_brace__ecarb_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test__brace_1_comma__2_ecarb_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = (1, 2) - print "case: %-30s func=_brace_1_comma__2_ecarb_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test__list__tsil_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = [] - print "case: %-30s func=_list__tsil_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test__list_3_comma__4_tsil_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = [3, 4] - print "case: %-30s func=_list_3_comma__4_tsil_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test__dict__tcid_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = {} - print "case: %-30s func=_dict__tcid_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test__dict_5_colon__6_comma__7_colon__8_tcid_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = {5: 6, 7: 8} - print "case: %-30s func=_dict_5_colon__6_comma__7_colon__8_tcid_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_func_dot_func_code(self): - import sys - hello = "he" - hello += "llo" def func(x): return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = func.func_code - print "case: %-30s func=func_dot_func_code" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_scopefunc_dot_func_code(self): - import sys - hello = "he" - hello += "llo" def func(x): return lambda y: x+y scopefunc = func(42) - import marshal, StringIO case = scopefunc.func_code - print "case: %-30s func=scopefunc_dot_func_code" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_u_quote_hello_quote_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = u'hello' - print "case: %-30s func=u_quote_hello_quote_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_set_brace__ecarb_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = set() - print "case: %-30s func=set_brace__ecarb_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_set_brace__list_1_comma__2_tsil__ecarb_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = set([1, 2]) - print "case: %-30s func=set_brace__list_1_comma__2_tsil__ecarb_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_frozenset_brace__ecarb_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = frozenset() - print "case: %-30s func=frozenset_brace__ecarb_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_frozenset_brace__list_3_comma__4_tsil__ecarb_(self): - import sys - hello = "he" - hello += "llo" - def func(x): - return lambda y: x+y - scopefunc = func(42) - import marshal, StringIO case = frozenset([3, 4]) - print "case: %-30s func=frozenset_brace__list_3_comma__4_tsil__ecarb_" % (case, ) - s = marshal.dumps(case) - x = marshal.loads(s) - assert x == case and type(x) is type(case) - f = StringIO.StringIO() - marshal.dump(case, f) - f.seek(0) - x = marshal.load(f) - assert x == case and type(x) is type(case) + self.marshal_check(case) def test_stream_reader_writer(self): # for performance, we have a special case when reading/writing real @@ -579,20 +167,16 @@ def test_unicode(self): import marshal, sys + self.marshal_check(u'\uFFFF') - u = u'\uFFFF' - u1 = marshal.loads(marshal.dumps(u)) - assert u == u1 - - u = unichr(sys.maxunicode) - u1 = marshal.loads(marshal.dumps(u)) - assert u == u1 + self.marshal_check(unichr(sys.maxunicode)) class AppTestMultiDict(object): def setup_class(cls): from pypy.conftest import gettestobjspace cls.space = gettestobjspace(**{"objspace.std.withmultidict": True}) + AppTestMarshal.setup_class.im_func(cls) test__dict__tcid_ = AppTestMarshal.test__dict__tcid_.im_func test__dict_5_colon__6_comma__7_colon__8_tcid_ = AppTestMarshal.test__dict_5_colon__6_comma__7_colon__8_tcid_.im_func From cfbolz at codespeak.net Mon Sep 21 11:09:24 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 11:09:24 +0200 (CEST) Subject: [pypy-svn] r67821 - in pypy/branch/bigint-rlonglong/pypy: objspace/std rlib rlib/test Message-ID: <20090921090924.733E8168009@codespeak.net> Author: cfbolz Date: Mon Sep 21 11:09:23 2009 New Revision: 67821 Modified: pypy/branch/bigint-rlonglong/pypy/objspace/std/longobject.py pypy/branch/bigint-rlonglong/pypy/objspace/std/marshal_impl.py pypy/branch/bigint-rlonglong/pypy/rlib/rbigint.py pypy/branch/bigint-rlonglong/pypy/rlib/test/test_rbigint.py Log: Give the rbigint implementation an overhaul. So far it used 15 bit digits, stored a C longs, which is rather silly, particularly on 64 bit platforms. I changed the following: - use 31 bit digits stored as C longs. Use long longs for the computation. - change the infrastructure to make it less tedious to change such things in the future - change the marshal implementation accordingly, marshal is now less efficient but it remains compatible with CPython's marshal - use fixed-sized lists for the digit lists - clean up the code a bit, less code duplication - prebuilt 0L and 1L - the rshift and lshift methods now take ints as arguments instead of an rbigint. This makes sense, because before we would just convert to an int anyway. Modified: pypy/branch/bigint-rlonglong/pypy/objspace/std/longobject.py ============================================================================== --- pypy/branch/bigint-rlonglong/pypy/objspace/std/longobject.py (original) +++ pypy/branch/bigint-rlonglong/pypy/objspace/std/longobject.py Mon Sep 21 11:09:23 2009 @@ -220,10 +220,11 @@ raise OperationError(space.w_ValueError, space.wrap("negative shift count")) try: - return W_LongObject(w_long1.num.lshift(w_long2.num)) + shift = w_long2.num.toint() except OverflowError: # b too big raise OperationError(space.w_OverflowError, space.wrap("shift count too large")) + return W_LongObject(w_long1.num.lshift(shift)) def rshift__Long_Long(space, w_long1, w_long2): # XXX need to replicate some of the logic, to get the errors right @@ -231,10 +232,11 @@ raise OperationError(space.w_ValueError, space.wrap("negative shift count")) try: - return W_LongObject(w_long1.num.rshift(w_long2.num)) + shift = w_long2.num.toint() except OverflowError: # b too big # XXX maybe just return 0L instead? raise OperationError(space.w_OverflowError, space.wrap("shift count too large")) + return W_LongObject(w_long1.num.rshift(shift)) def and__Long_Long(space, w_long1, w_long2): return W_LongObject(w_long1.num.and_(w_long2.num)) Modified: pypy/branch/bigint-rlonglong/pypy/objspace/std/marshal_impl.py ============================================================================== --- pypy/branch/bigint-rlonglong/pypy/objspace/std/marshal_impl.py (original) +++ pypy/branch/bigint-rlonglong/pypy/objspace/std/marshal_impl.py Mon Sep 21 11:09:23 2009 @@ -226,13 +226,25 @@ register(TYPE_BINARY_COMPLEX, unmarshal_Complex_bin) def marshal_w__Long(space, w_long, m): - assert long_bits == 15, """if long_bits is not 15, - we need to write much more general code for marshal - that breaks things into pieces, or invent a new - typecode and have our own magic number for pickling""" - + from pypy.rlib.rbigint import rbigint m.start(TYPE_LONG) # XXX access internals + if long_bits != 15: + SHIFT = 15 + MASK = (1 << SHIFT) - 1 + BIGMASK = rbigint.fromint(MASK) + num = w_long.num + sign = num.sign + num = num.abs() + ints = [] + while num.tobool(): + next = num.and_(BIGMASK).toint() + ints.append(next) + num = num.rshift(SHIFT) + m.put_int(len(ints) * sign) + for i in ints: + m.put_short(i) + return lng = len(w_long.num.digits) if w_long.num.sign < 0: m.put_int(-lng) @@ -242,7 +254,8 @@ m.put_short(digit) def unmarshal_Long(space, u, tc): - from pypy.rlib import rbigint + # XXX access internals + from pypy.rlib.rbigint import rbigint lng = u.get_int() if lng < 0: sign = -1 @@ -251,17 +264,22 @@ sign = 1 else: sign = 0 - digits = [0] * lng - i = 0 - while i < lng: - digit = u.get_short() - if digit < 0: - raise_exception(space, 'bad marshal data') - digits[i] = digit - i += 1 - # XXX poking at internals - w_long = W_LongObject(rbigint.rbigint(digits, sign)) - w_long.num._normalize() + if long_bits != 15: + SHIFT = 15 + result = rbigint([0], 0) + for i in range(lng): + shift = i * SHIFT + result = result.add(rbigint.fromint(u.get_short()).lshift(shift)) + result.sign = sign + else: + digits = [0] * lng + for i in range(lng): + digit = u.get_int() + if digit < 0: + raise_exception(space, 'bad marshal data') + digits[i] = digit + result = rbigint(digits, sign) + w_long = W_LongObject(result) return w_long register(TYPE_LONG, unmarshal_Long) Modified: pypy/branch/bigint-rlonglong/pypy/rlib/rbigint.py ============================================================================== --- pypy/branch/bigint-rlonglong/pypy/rlib/rbigint.py (original) +++ pypy/branch/bigint-rlonglong/pypy/rlib/rbigint.py Mon Sep 21 11:09:23 2009 @@ -3,60 +3,15 @@ import math, sys -# It took many days of debugging and testing, until -# I (chris) finally understood how things work and where -# to expect overflows in the division code. -# In the end, I decided to throw this all out and to use -# plain integer expressions. r_uint and friends should go away! -# Unsignedness can be completely deduced by back-propagation -# of masking. I will change the annotator to do this. -# Having no special types at all, but describing everything -# in terms of operations and masks is the stronger way. - -# Digit size: -# SHIFT cannot be larger than below, for the moment. +# note about digit sizes: # In division, the native integer type must be able to hold # a sign bit plus two digits plus 1 overflow bit. -# As a result, our digits will be 15 bits with one unused -# bit, exactly as it is in CPython. -# -# The algorithms are anyway not bound to a given digit size. -# There are different models possible, if we support more -# native integer sizes. To support this, the annotator should -# be extended to do some basic size tracking of integers. -# -# Examples: -# C -# Most C implementations have support for signed long long. -# use an unsigned 16 bit unsigned short for the digits. -# The operations which must hold two digits become unsigned long. -# The sign+two digits+overflow register in division becomes -# a 64 bit signed long long. -# -# X86 assembler -# Given that we support some more primitive types for integers, -# this might become a nicer layout for an X86 assembly backend: -# The digit would be 32 bit long unsigned int, -# two digits would be 64 bit long long unsigned int, -# and the signed type mentioned above would be 80 bit extended. -# -# Emulation of different integer types -# Even if we don't have machine support for certain types, -# it might be worth trying to emulate them by providing some -# means of multi-precision integers in rpython. -# It is possible to write primitive code that emits the -# necessary operations for emulation of larger types. -# But we should do some careful testing how fast this code -# will be, compared to just working with native types. -# Probably the primitive types will outperform this. - -SHIFT = (LONG_BIT // 2) - 1 - -# XXX -# SHIFT cannot be anything but 15 at the moment, or we break marshal -SHIFT = 15 + +#SHIFT = (LONG_BIT // 2) - 1 +SHIFT = 31 MASK = int((1 << SHIFT) - 1) +FLOAT_MULTIPLIER = float(1 << SHIFT) # Debugging digit array access. @@ -64,24 +19,12 @@ # False == no checking at all # True == check 0 <= value <= MASK -CHECK_DIGITS = False # True - -if CHECK_DIGITS: - class DigitArray(list): - def __setitem__(self, idx, value): - assert value >=0 - assert value <= MASK - list.__setitem__(self, idx, value) -else: - DigitArray = list - - -USE_KARATSUBA = True # set to False for comparison # For long multiplication, use the O(N**2) school algorithm unless # both operands contain more than KARATSUBA_CUTOFF digits (this # being an internal Python long digit, in base BASE). +USE_KARATSUBA = True # set to False for comparison KARATSUBA_CUTOFF = 70 KARATSUBA_SQUARE_CUTOFF = 2 * KARATSUBA_CUTOFF @@ -93,6 +36,15 @@ FIVEARY_CUTOFF = 8 +def mask_digit(x): + return intmask(x & MASK) +mask_digit._annspecialcase_ = 'specialize:argtype(0)' + +def widen_digit(x): + if SHIFT <= 15: + return int(x) + return r_longlong(x) + class rbigint(object): """This is a reimplementation of longs using a list of digits.""" @@ -100,9 +52,19 @@ def __init__(self, digits, sign=0): if len(digits) == 0: digits = [0] - self.digits = DigitArray(digits) + self.digits = digits self.sign = sign + def _digit(self, x): + return widen_digit(self.digits[x]) + def _setdigit(self, x, val): + val = mask_digit(val) + assert val >= 0 + self.digits[x] = int(val) + _setdigit._annspecialcase_ = 'specialize:argtype(2)' + def _numdigits(self): + return len(self.digits) + def fromint(intval): if intval < 0: sign = -1 @@ -111,7 +73,7 @@ sign = 1 ival = r_uint(intval) else: - return rbigint([0], 0) + return rbigint.ZERO # Count the number of Python digits. # We used to pick 5 ("big enough for anything"), but that's a # waste of time and space given that 5*15 = 75 bits are rarely @@ -125,14 +87,16 @@ t = ival p = 0 while t: - v.digits[p] = intmask(t & MASK) + v._setdigit(p, t) t >>= SHIFT p += 1 return v fromint = staticmethod(fromint) def frombool(b): - return rbigint([b & MASK], int(b)) + if b: + return rbigint.ONE + return rbigint.ZERO frombool = staticmethod(frombool) def fromlong(l): @@ -149,13 +113,13 @@ dval = -dval frac, expo = math.frexp(dval) # dval = frac*2**expo; 0.0 <= frac < 1.0 if expo <= 0: - return rbigint([0], 0) + return rbigint.ZERO ndig = (expo-1) // SHIFT + 1 # Number of 'digits' in result v = rbigint([0] * ndig, 1) frac = math.ldexp(frac, (expo-1) % SHIFT + 1) for i in range(ndig-1, -1, -1): - bits = int(frac) & MASK # help the future annotator? - v.digits[i] = bits + bits = mask_digit(int(frac)) + v._setdigit(i, bits) frac -= float(bits) frac = math.ldexp(frac, SHIFT) if neg: @@ -173,7 +137,19 @@ fromdecimalstr = staticmethod(fromdecimalstr) def toint(self): - return _AsLong(self) + """ + Get an integer from a bigint object. + Raises OverflowError if overflow occurs. + """ + x = self._touint_helper() + # Haven't lost any bits, but if the sign bit is set we're in + # trouble *unless* this is the min negative number. So, + # trouble iff sign bit set && (positive || some bit set other + # than the sign bit). + sign = self.sign + if intmask(x) < 0 and (sign > 0 or (x << 1) != 0): + raise OverflowError + return intmask(x * sign) def tolonglong(self): return _AsLongLong(self) @@ -184,11 +160,14 @@ def touint(self): if self.sign == -1: raise ValueError("cannot convert negative integer to unsigned int") + return self._touint_helper() + + def _touint_helper(self): x = r_uint(0) - i = len(self.digits) - 1 + i = self._numdigits() - 1 while i >= 0: prev = x - x = (x << SHIFT) + self.digits[i] + x = r_uint((x << SHIFT) + self.digits[i]) if (x >> SHIFT) != prev: raise OverflowError( "long int too large to convert to unsigned int") @@ -210,25 +189,25 @@ def tofloat(self): return _AsDouble(self) - def _count_bits(a): + def _count_bits(self): # return the number of bits in the digits - if a.sign == 0: + if self.sign == 0: return 0 - p = len(a.digits) - 1 + p = self._numdigits() - 1 bits = SHIFT * p - digit = a.digits[p] + digit = self.digits[p] while digit: digit >>= 1 bits += 1 return bits - def is_odd(a): + def is_odd(self): # Note: this is a tiny optimization. # Instead of implementing a general "get_bit" operation, # which would be expensive for negative numbers, # get_odd has the nice feature that it is always correct, # no matter what the sign is (two's complement) - return a.digits[0] & 1 + return self.digits[0] & 1 def format(self, digits, prefix='', suffix=''): # 'digits' is a string whose length is the base to use, @@ -243,23 +222,26 @@ def eq(self, other): if (self.sign != other.sign or - len(self.digits) != len(other.digits)): + self._numdigits() != other._numdigits()): return False i = 0 - ld = len(self.digits) + ld = self._numdigits() while i < ld: if self.digits[i] != other.digits[i]: return False i += 1 return True + def ne(self, other): + return not self.eq(other) + def lt(self, other): if self.sign > other.sign: return False if self.sign < other.sign: return True - ld1 = len(self.digits) - ld2 = len(other.digits) + ld1 = self._numdigits() + ld2 = other._numdigits() if ld1 > ld2: if other.sign > 0: return False @@ -287,37 +269,41 @@ i -= 1 return False + def le(self, other): + return self.lt(other) or self.eq(other) + + def gt(self, other): + return other.le(self) + + def ge(self, other): + return other.lt(self) + def hash(self): return _hash(self) def add(self, other): - if self.sign < 0: - if other.sign < 0: - result = _x_add(self, other) - if result.sign != 0: - result.sign = -result.sign - else: - result = _x_sub(other, self) + if self.sign == 0: + return other + if other.sign == 0: + return self + if self.sign == other.sign: + result = _x_add(self, other) else: - if other.sign < 0: - result = _x_sub(self, other) - else: - result = _x_add(self, other) + result = _x_sub(other, self) + result.sign *= other.sign result._normalize() return result def sub(self, other): - if self.sign < 0: - if other.sign < 0: - result = _x_sub(self, other) - else: - result = _x_add(self, other) - result.sign = -result.sign + if other.sign == 0: + return self + if self.sign == 0: + return rbigint(other.digits[:], -other.sign) + if self.sign == other.sign: + result = _x_sub(self, other) else: - if other.sign < 0: - result = _x_add(self, other) - else: - result = _x_sub(self, other) + result = _x_add(self, other) + result.sign *= self.sign result._normalize() return result @@ -364,8 +350,7 @@ div, mod = _divrem(v, w) if mod.sign * w.sign == -1: mod = mod.add(w) - one = rbigint([1], 1) - div = div.sub(one) + div = div.sub(rbigint.ONE) return div, mod def pow(a, b, c=None): @@ -396,8 +381,8 @@ # if modulus == 1: # return 0 - if len(c.digits) == 1 and c.digits[0] == 1: - return rbigint([0], 0) + if c._numdigits() == 1 and c.digits[0] == 1: + return rbigint.ZERO # if base < 0: # base = base % modulus @@ -413,10 +398,10 @@ # python adaptation: moved macros REDUCE(X) and MULT(X, Y, result) # into helper function result = _help_mult(x, y, c) - if len(b.digits) <= FIVEARY_CUTOFF: + if b._numdigits() <= FIVEARY_CUTOFF: # Left-to-right binary exponentiation (HAC Algorithm 14.79) # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf - i = len(b.digits) - 1 + i = b._numdigits() - 1 while i >= 0: bi = b.digits[i] j = 1 << (SHIFT-1) @@ -433,10 +418,10 @@ table[0] = z; for i in range(1, 32): table[i] = _help_mult(table[i-1], a, c) - i = len(b.digits) - 1 + i = b._numdigits() - 1 while i >= 0: bi = b.digits[i] - j = j = SHIFT - 5 + j = SHIFT - 5 while j >= 0: index = (bi >> j) & 0x1f for k in range(5): @@ -459,18 +444,17 @@ def invert(self): #Implement ~x as -(x + 1) return self.add(rbigint([1], 1)).neg() - def lshift(self, other): - if other.sign < 0: + def lshift(self, int_other): + if int_other < 0: raise ValueError("negative shift count") - elif other.sign == 0: + elif int_other == 0: return self - shiftby = other.toint() - # wordshift, remshift = divmod(shiftby, SHIFT) - wordshift = shiftby // SHIFT - remshift = shiftby - wordshift * SHIFT + # wordshift, remshift = divmod(int_other, SHIFT) + wordshift = int_other // SHIFT + remshift = int_other - wordshift * SHIFT - oldsize = len(self.digits) + oldsize = self._numdigits() newsize = oldsize + wordshift if remshift: newsize += 1 @@ -479,35 +463,34 @@ i = wordshift j = 0 while j < oldsize: - accum |= self.digits[j] << remshift - z.digits[i] = accum & MASK + accum |= self._digit(j) << remshift + z._setdigit(i, accum) accum >>= SHIFT i += 1 j += 1 if remshift: - z.digits[newsize-1] = accum + z._setdigit(newsize - 1, accum) else: assert not accum z._normalize() return z - def rshift(self, other): - if other.sign < 0: + def rshift(self, int_other): + if int_other < 0: raise ValueError("negative shift count") - elif other.sign == 0: + elif int_other == 0: return self if self.sign == -1: a1 = self.invert() - a2 = a1.rshift(other) + a2 = a1.rshift(int_other) return a2.invert() - shiftby = other.toint() - wordshift = shiftby // SHIFT - newsize = len(self.digits) - wordshift + wordshift = int_other // SHIFT + newsize = self._numdigits() - wordshift if newsize <= 0: - return rbigint([0], 0) + return rbigint.ZERO - loshift = shiftby % SHIFT + loshift = int_other % SHIFT hishift = SHIFT - loshift lomask = (1 << hishift) - 1 himask = MASK ^ lomask @@ -560,17 +543,24 @@ return l * self.sign def _normalize(self): - if len(self.digits) == 0: + if self._numdigits() == 0: self.sign = 0 self.digits = [0] return - i = len(self.digits) - 1 - while i != 0 and self.digits[i] == 0: - self.digits.pop(-1) + i = self._numdigits() + while i > 1 and self.digits[i - 1] == 0: i -= 1 - if len(self.digits) == 1 and self.digits[0] == 0: + assert i >= 1 + self.digits = self.digits[:i] + if self._numdigits() == 1 and self.digits[0] == 0: self.sign = 0 + + def __repr__(self): + return "" % (self.digits, self.sign, self.str()) +rbigint.ZERO = rbigint([0], 0) +rbigint.ONE = rbigint([1], 1) + #_________________________________________________________________ # Helper Functions @@ -579,7 +569,7 @@ def _help_mult(x, y, c): """ Multiply two values, then reduce the result: - result = X*Y % c. If c is NULL, skip the mod. + result = X*Y % c. If c is None, skip the mod. """ res = x.mul(y) # Perform a modular reduction, X = X % c, but leave X alone if c @@ -594,7 +584,7 @@ def digits_from_nonneg_long(l): digits = [] while True: - digits.append(intmask(l) & MASK) + digits.append(mask_digit(l)) l = l >> SHIFT if not l: return digits @@ -604,7 +594,7 @@ # This helper only works if 'l' is the most negative integer of its # type, which in base 2 looks like: 1000000..0000 digits = [] - while (intmask(l) & MASK) == 0: + while (mask_digit(l)) == 0: digits.append(0) l = l >> SHIFT # now 'l' looks like: ...111100000 @@ -654,36 +644,35 @@ def _x_add(a, b): """ Add the absolute values of two bigint integers. """ - size_a = len(a.digits) - size_b = len(b.digits) + size_a = a._numdigits() + size_b = b._numdigits() # Ensure a is the larger of the two: if size_a < size_b: a, b = b, a size_a, size_b = size_b, size_a - z = rbigint([0] * (len(a.digits) + 1), 1) + z = rbigint([0] * (a._numdigits() + 1), 1) i = 0 carry = 0 while i < size_b: - carry += a.digits[i] + b.digits[i] - z.digits[i] = carry & MASK + carry += a._digit(i) + b._digit(i) + z._setdigit(i, carry) carry >>= SHIFT i += 1 while i < size_a: - carry += a.digits[i] - z.digits[i] = carry & MASK + carry += a._digit(i) + z._setdigit(i, carry) carry >>= SHIFT i += 1 - z.digits[i] = carry + z._setdigit(i, carry) z._normalize() return z def _x_sub(a, b): """ Subtract the absolute values of two integers. """ - size_a = len(a.digits) - size_b = len(b.digits) + size_a = a._numdigits() + size_b = b._numdigits() sign = 1 - borrow = 0 # Ensure a is the larger of the two: if size_a < size_b: @@ -701,19 +690,20 @@ sign = -1 a, b = b, a size_a = size_b = i+1 + borrow = 0 z = rbigint([0] * size_a, 1) i = 0 while i < size_b: # The following assumes unsigned arithmetic # works modulo 2**N for some N>SHIFT. - borrow = a.digits[i] - b.digits[i] - borrow - z.digits[i] = borrow & MASK + borrow = a._digit(i) - b._digit(i) - borrow + z._setdigit(i, borrow) borrow >>= SHIFT borrow &= 1 # Keep only one sign bit i += 1 while i < size_a: - borrow = a.digits[i] - borrow - z.digits[i] = borrow & MASK + borrow = a._digit(i) - borrow + z._setdigit(i, borrow) borrow >>= SHIFT borrow &= 1 # Keep only one sign bit i += 1 @@ -727,13 +717,13 @@ def _x_mul(a, b): """ Grade school multiplication, ignoring the signs. - Returns the absolute value of the product, or NULL if error. + Returns the absolute value of the product, or None if error. """ - size_a = len(a.digits) - size_b = len(b.digits) + size_a = a._numdigits() + size_b = b._numdigits() z = rbigint([0] * (size_a + size_b), 1) - if a == b: + if a is b: # Efficient squaring per HAC, Algorithm 14.16: # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf # Gives slightly less than a 2x speedup when a == b, @@ -741,13 +731,13 @@ # pyramid appears twice (except for the size_a squares). i = 0 while i < size_a: - f = a.digits[i] + f = a._digit(i) pz = i << 1 pa = i + 1 paend = size_a - carry = z.digits[pz] + f * f - z.digits[pz] = carry & MASK + carry = z._digit(pz) + f * f + z._setdigit(pz, carry) pz += 1 carry >>= SHIFT assert carry <= MASK @@ -756,19 +746,19 @@ # pyramid it appears. Same as adding f<<1 once. f <<= 1 while pa < paend: - carry += z.digits[pz] + a.digits[pa] * f + carry += z._digit(pz) + a._digit(pa) * f pa += 1 - z.digits[pz] = carry & MASK + z._setdigit(pz, carry) pz += 1 carry >>= SHIFT - assert carry <= (MASK << 1) + assert carry <= (widen_digit(MASK) << 1) if carry: - carry += z.digits[pz] - z.digits[pz] = carry & MASK + carry += z._digit(pz) + z._setdigit(pz, carry) pz += 1 carry >>= SHIFT if carry: - z.digits[pz] += carry & MASK + z._setdigit(pz, z._digit(pz) + carry) assert (carry >> SHIFT) == 0 i += 1 else: @@ -776,19 +766,19 @@ i = 0 while i < size_a: carry = 0 - f = a.digits[i] + f = a._digit(i) pz = i pb = 0 pbend = size_b while pb < pbend: - carry += z.digits[pz] + b.digits[pb] * f + carry += z._digit(pz) + b._digit(pb) * f pb += 1 - z.digits[pz] = carry & MASK + z._setdigit(pz, carry) pz += 1 carry >>= SHIFT assert carry <= MASK if carry: - z.digits[pz] += carry & MASK + z._setdigit(pz, z._digit(pz) + carry) assert (carry >> SHIFT) == 0 i += 1 z._normalize() @@ -803,7 +793,7 @@ viewing the shift as being by digits. The sign bit is ignored, and the return values are >= 0. """ - size_n = len(n.digits) + size_n = n._numdigits() size_lo = min(size_n, size) lo = rbigint(n.digits[:size_lo], 1) @@ -818,8 +808,8 @@ absolute value of the product (or raises if error). See Knuth Vol. 2 Chapter 4.3.3 (Pp. 294-295). """ - asize = len(a.digits) - bsize = len(b.digits) + asize = a._numdigits() + bsize = b._numdigits() # (ah*X+al)(bh*X+bl) = ah*bh*X*X + (ah*bl + al*bh)*X + al*bl # Let k = (ah+al)*(bh+bl) = ah*bl + al*bh + ah*bh + al*bl # Then the original product is @@ -833,7 +823,7 @@ a, b, asize, bsize = b, a, bsize, asize # Use gradeschool math when either number is too small. - if a == b: + if a is b: i = KARATSUBA_SQUARE_CUTOFF else: i = KARATSUBA_CUTOFF @@ -883,8 +873,8 @@ # 2. t1 <- ah*bh, and copy into high digits of result. t1 = _k_mul(ah, bh) assert t1.sign >= 0 - assert 2*shift + len(t1.digits) <= len(ret.digits) - ret.digits[2*shift : 2*shift + len(t1.digits)] = t1.digits + assert 2*shift + t1._numdigits() <= ret._numdigits() + ret.digits[2*shift : 2*shift + t1._numdigits()] = t1.digits # Zero-out the digits higher than the ah*bh copy. */ ## ignored, assuming that we initialize to zero @@ -896,8 +886,8 @@ # 3. t2 <- al*bl, and copy into the low digits. t2 = _k_mul(al, bl) assert t2.sign >= 0 - assert len(t2.digits) <= 2*shift # no overlap with high digits - ret.digits[:len(t2.digits)] = t2.digits + assert t2._numdigits() <= 2*shift # no overlap with high digits + ret.digits[:t2._numdigits()] = t2.digits # Zero out remaining digits. ## ignored, assuming that we initialize to zero @@ -907,9 +897,9 @@ # 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first # because it's fresher in cache. - i = len(ret.digits) - shift # # digits after shift - _v_isub(ret.digits, shift, i, t2.digits, len(t2.digits)) - _v_isub(ret.digits, shift, i, t1.digits, len(t1.digits)) + i = ret._numdigits() - shift # # digits after shift + _v_isub(ret, shift, i, t2, t2._numdigits()) + _v_isub(ret, shift, i, t1, t1._numdigits()) del t1, t2 # 6. t3 <- (ah+al)(bh+bl), and add into result. @@ -928,7 +918,7 @@ # Add t3. It's not obvious why we can't run out of room here. # See the (*) comment after this function. - _v_iadd(ret.digits, shift, i, t3.digits, len(t3.digits)) + _v_iadd(ret, shift, i, t3, t3._numdigits()) del t3 ret._normalize() @@ -989,8 +979,8 @@ at a time, then move on, never bactracking except for the helpful single-width slice overlap between successive partial sums). """ - asize = len(a.digits) - bsize = len(b.digits) + asize = a._numdigits() + bsize = b._numdigits() # nbdone is # of b digits already multiplied assert asize > KARATSUBA_CUTOFF @@ -1018,8 +1008,8 @@ product = _k_mul(a, bslice) # Add into result. - _v_iadd(ret.digits, nbdone, len(ret.digits) - nbdone, - product.digits, len(product.digits)) + _v_iadd(ret, nbdone, ret._numdigits() - nbdone, + product, product._numdigits()) del product bsize -= nbtouse @@ -1034,18 +1024,18 @@ Divide bigint pin by non-zero digit n, storing quotient in pout, and returning the remainder. It's OK for pin == pout on entry. """ - rem = 0 + rem = widen_digit(0) assert n > 0 and n <= MASK if not size: - size = len(pin.digits) + size = pin._numdigits() size -= 1 while size >= 0: - rem = (rem << SHIFT) + pin.digits[size] + rem = (rem << SHIFT) + pin._digit(size) hi = rem // n - pout.digits[size] = hi + pout._setdigit(size, hi) rem -= hi * n size -= 1 - return rem + return mask_digit(rem) def _divrem1(a, n): """ @@ -1054,7 +1044,7 @@ The sign of a is ignored; n should not be zero. """ assert n > 0 and n <= MASK - size = len(a.digits) + size = a._numdigits() z = rbigint([0] * size, 1) rem = _inplace_divrem1(z, a, n) z._normalize() @@ -1062,8 +1052,8 @@ def _v_iadd(x, xofs, m, y, n): """ - x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n] - is modified in place, by adding y to it. Carries are propagated as far as + x and y are rbigints, m >= n required. x.digits[0:n] is modified in place, + by adding y.digits[0:m] to it. Carries are propagated as far as x[m-1], and the remaining carry (0 or 1) is returned. Python adaptation: x is addressed relative to xofs! """ @@ -1073,15 +1063,15 @@ i = xofs iend = xofs + n while i < iend: - carry += x[i] + y[i-xofs] - x[i] = carry & MASK + carry += x._digit(i) + y._digit(i-xofs) + x._setdigit(i, carry) carry >>= SHIFT assert (carry & 1) == carry i += 1 iend = xofs + m while carry and i < iend: - carry += x[i] - x[i] = carry & MASK + carry += x._digit(i) + x._setdigit(i, carry) carry >>= SHIFT assert (carry & 1) == carry i += 1 @@ -1089,8 +1079,8 @@ def _v_isub(x, xofs, m, y, n): """ - x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n] - is modified in place, by subtracting y from it. Borrows are propagated as + x and y are rbigints, m >= n required. x.digits[0:n] is modified in place, + by substracting y.digits[0:m] to it. Borrows are propagated as far as x[m-1], and the remaining borrow (0 or 1) is returned. Python adaptation: x is addressed relative to xofs! """ @@ -1100,47 +1090,47 @@ i = xofs iend = xofs + n while i < iend: - borrow = x[i] - y[i-xofs] - borrow - x[i] = borrow & MASK + borrow = x._digit(i) - y._digit(i-xofs) - borrow + x._setdigit(i, borrow) borrow >>= SHIFT borrow &= 1 # keep only 1 sign bit i += 1 iend = xofs + m while borrow and i < iend: - borrow = x[i] - borrow - x[i] = borrow & MASK + borrow = x._digit(i) - borrow + x._setdigit(i, borrow) borrow >>= SHIFT borrow &= 1 i += 1 return borrow -def _muladd1(a, n, extra): +def _muladd1(a, n, extra=widen_digit(0)): """Multiply by a single digit and add a single digit, ignoring the sign. """ - size_a = len(a.digits) + size_a = a._numdigits() z = rbigint([0] * (size_a+1), 1) carry = extra assert carry & MASK == carry i = 0 while i < size_a: - carry += a.digits[i] * n - z.digits[i] = carry & MASK + carry += a._digit(i) * n + z._setdigit(i, carry) carry >>= SHIFT i += 1 - z.digits[i] = carry + z._setdigit(i, carry) z._normalize() return z def _x_divrem(v1, w1): """ Unsigned bigint division with remainder -- the algorithm """ - size_w = len(w1.digits) - d = (MASK+1) // (w1.digits[size_w-1] + 1) - v = _muladd1(v1, d, 0) - w = _muladd1(w1, d, 0) - size_v = len(v.digits) - size_w = len(w.digits) + size_w = w1._numdigits() + d = (widen_digit(MASK)+1) // (w1._digit(size_w-1) + 1) + v = _muladd1(v1, d) + w = _muladd1(w1, d) + size_v = v._numdigits() + size_w = w._numdigits() assert size_v >= size_w and size_w > 1 # Assert checks by div() size_a = size_v - size_w + 1 @@ -1152,50 +1142,50 @@ if j >= size_v: vj = 0 else: - vj = v.digits[j] + vj = v._digit(j) carry = 0 - if vj == w.digits[size_w-1]: + if vj == w._digit(size_w-1): q = MASK else: - q = ((vj << SHIFT) + v.digits[j-1]) // w.digits[size_w-1] + q = ((vj << SHIFT) + v._digit(j-1)) // w._digit(size_w-1) - while (w.digits[size_w-2] * q > + while (w._digit(size_w-2) * q > (( (vj << SHIFT) - + v.digits[j-1] - - q * w.digits[size_w-1] + + v._digit(j-1) + - q * w._digit(size_w-1) ) << SHIFT) - + v.digits[j-2]): + + v._digit(j-2)): q -= 1 i = 0 while i < size_w and i+k < size_v: - z = w.digits[i] * q + z = w._digit(i) * q zz = z >> SHIFT - carry += v.digits[i+k] - z + (zz << SHIFT) - v.digits[i+k] = carry & MASK + carry += v._digit(i+k) - z + (zz << SHIFT) + v._setdigit(i+k, carry) carry >>= SHIFT carry -= zz i += 1 if i+k < size_v: - carry += v.digits[i+k] - v.digits[i+k] = 0 + carry += v._digit(i+k) + v._setdigit(i+k, 0) if carry == 0: - a.digits[k] = q & MASK + a._setdigit(k, q) assert not q >> SHIFT else: assert carry == -1 q -= 1 - a.digits[k] = q & MASK + a._setdigit(k, q) assert not q >> SHIFT carry = 0 i = 0 while i < size_w and i+k < size_v: - carry += v.digits[i+k] + w.digits[i] - v.digits[i+k] = carry & MASK + carry += v._digit(i+k) + w._digit(i) + v._setdigit(i+k, carry) carry >>= SHIFT i += 1 j -= 1 @@ -1208,8 +1198,8 @@ def _divrem(a, b): """ Long division with remainder, top-level routine """ - size_a = len(a.digits) - size_b = len(b.digits) + size_a = a._numdigits() + size_b = b._numdigits() if b.sign == 0: raise ZeroDivisionError("long division or modulo by zero") @@ -1222,7 +1212,7 @@ rem = a return z, rem if size_b == 1: - z, urem = _divrem1(a, b.digits[0]) + z, urem = _divrem1(a, b._digit(0)) rem = rbigint([urem], int(urem != 0)) else: z, rem = _x_divrem(a, b) @@ -1251,17 +1241,16 @@ least one round bit to stand in for the ignored least-significant bits. """ NBITS_WANTED = 57 - multiplier = float(1 << SHIFT) if v.sign == 0: return 0.0, 0 - i = len(v.digits) - 1 + i = v._numdigits() - 1 sign = v.sign x = float(v.digits[i]) nbitsneeded = NBITS_WANTED - 1 # Invariant: i Python digits remain unaccounted for. while i > 0 and nbitsneeded > 0: i -= 1 - x = x * multiplier + float(v.digits[i]) + x = x * FLOAT_MULTIPLIER + float(v.digits[i]) nbitsneeded -= SHIFT # There are i digits we didn't shift in. Pretending they're all # zeroes, the true value is x * 2**(i*SHIFT). @@ -1346,7 +1335,7 @@ Convert a bigint object to a string, using a given conversion base. Return a string object. """ - size_a = len(a.digits) + size_a = a._numdigits() base = len(digits) assert base >= 2 and base <= 36 @@ -1382,7 +1371,7 @@ basebits += 1 for i in range(size_a): - accum |= a.digits[i] << accumbits + accum |= a._digit(i) << accumbits accumbits += SHIFT assert accumbits >= basebits while 1: @@ -1405,7 +1394,7 @@ size = size_a pin = a # just for similarity to C source which uses the array # powbase <- largest power of base that fits in a digit. - powbase = base # powbase == base ** power + powbase = widen_digit(base) # powbase == base ** power power = 1 while 1: newpow = powbase * base @@ -1499,8 +1488,8 @@ # iff one of these cases applies, and mask will be non-0 for operands # whose length should be ignored. - size_a = len(a.digits) - size_b = len(b.digits) + size_a = a._numdigits() + size_b = b._numdigits() if op == '&': if maska: size_z = size_b @@ -1536,31 +1525,6 @@ return z.invert() _bitwise._annspecialcase_ = "specialize:arg(1)" -def _AsLong(v): - """ - Get an integer from a bigint object. - Raises OverflowError if overflow occurs. - """ - # This version by Tim Peters - i = len(v.digits) - 1 - sign = v.sign - if not sign: - return 0 - x = r_uint(0) - while i >= 0: - prev = x - x = (x << SHIFT) + v.digits[i] - if (x >> SHIFT) != prev: - raise OverflowError - i -= 1 - - # Haven't lost any bits, but if the sign bit is set we're in - # trouble *unless* this is the min negative number. So, - # trouble iff sign bit set && (positive || some bit set other - # than the sign bit). - if intmask(x) < 0 and (sign > 0 or (x << 1) != 0): - raise OverflowError - return intmask(x * sign) ULONGLONG_BOUND = r_ulonglong(1L << (r_longlong.BITS-1)) LONGLONG_MIN = r_longlong(-(1L << (r_longlong.BITS-1))) @@ -1585,10 +1549,10 @@ def _AsULonglong_ignore_sign(v): x = r_ulonglong(0) - i = len(v.digits) - 1 + i = v._numdigits() - 1 while i >= 0: prev = x - x = (x << SHIFT) + v.digits[i] + x = (x << SHIFT) + v._digit(i) if (x >> SHIFT) != prev: raise OverflowError( "long int too large to convert to unsigned long long int") @@ -1598,10 +1562,10 @@ def make_unsigned_mask_conversion(T): def _As_unsigned_mask(v): x = T(0) - i = len(v.digits) - 1 + i = v._numdigits() - 1 while i >= 0: prev = x - x = (x << SHIFT) + v.digits[i] + x = (x << SHIFT) + T(v._digit(i)) i -= 1 if v.sign < 0: x = -x @@ -1615,7 +1579,7 @@ # This is designed so that Python ints and longs with the # same value hash to the same value, otherwise comparisons # of mapping keys will turn out weird - i = len(v.digits) - 1 + i = v._numdigits() - 1 sign = v.sign x = 0 LONG_BIT_SHIFT = LONG_BIT - SHIFT Modified: pypy/branch/bigint-rlonglong/pypy/rlib/test/test_rbigint.py ============================================================================== --- pypy/branch/bigint-rlonglong/pypy/rlib/test/test_rbigint.py (original) +++ pypy/branch/bigint-rlonglong/pypy/rlib/test/test_rbigint.py Mon Sep 21 11:09:23 2009 @@ -1,10 +1,11 @@ from __future__ import division import py -from random import random, randint -from pypy.rlib.rbigint import rbigint, SHIFT, MASK -from pypy.rlib import rbigint as lobj -from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong import operator, sys +from random import random, randint, sample +from pypy.rlib.rbigint import rbigint, SHIFT, MASK, KARATSUBA_CUTOFF +from pypy.rlib import rbigint as lobj +from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong, intmask +from pypy.rpython.test.test_llinterp import interpret class TestRLong(object): def test_simple(self): @@ -75,11 +76,11 @@ BASE = 1 << SHIFT assert rbigint.fromlong(0).eq(rbigint([0], 0)) assert rbigint.fromlong(17).eq(rbigint([17], 1)) - assert rbigint.fromlong(BASE-1).eq(rbigint([BASE-1], 1)) + assert rbigint.fromlong(BASE-1).eq(rbigint([intmask(BASE-1)], 1)) assert rbigint.fromlong(BASE).eq(rbigint([0, 1], 1)) assert rbigint.fromlong(BASE**2).eq(rbigint([0, 0, 1], 1)) assert rbigint.fromlong(-17).eq(rbigint([17], -1)) - assert rbigint.fromlong(-(BASE-1)).eq(rbigint([BASE-1], -1)) + assert rbigint.fromlong(-(BASE-1)).eq(rbigint([intmask(BASE-1)], -1)) assert rbigint.fromlong(-BASE).eq(rbigint([0, 1], -1)) assert rbigint.fromlong(-(BASE**2)).eq(rbigint([0, 0, 1], -1)) # assert rbigint.fromlong(-sys.maxint-1).eq( @@ -89,11 +90,11 @@ BASE = 1 << SHIFT assert rbigint.fromrarith_int(0).eq(rbigint([0], 0)) assert rbigint.fromrarith_int(17).eq(rbigint([17], 1)) - assert rbigint.fromrarith_int(BASE-1).eq(rbigint([BASE-1], 1)) + assert rbigint.fromrarith_int(BASE-1).eq(rbigint([intmask(BASE-1)], 1)) assert rbigint.fromrarith_int(BASE).eq(rbigint([0, 1], 1)) assert rbigint.fromrarith_int(BASE**2).eq(rbigint([0, 0, 1], 1)) assert rbigint.fromrarith_int(-17).eq(rbigint([17], -1)) - assert rbigint.fromrarith_int(-(BASE-1)).eq(rbigint([BASE-1], -1)) + assert rbigint.fromrarith_int(-(BASE-1)).eq(rbigint([intmask(BASE-1)], -1)) assert rbigint.fromrarith_int(-BASE).eq(rbigint([0, 1], -1)) assert rbigint.fromrarith_int(-(BASE**2)).eq(rbigint([0, 0, 1], -1)) # assert rbigint.fromrarith_int(-sys.maxint-1).eq(( @@ -103,9 +104,9 @@ BASE = 1 << SHIFT assert rbigint.fromrarith_int(r_uint(0)).eq(rbigint([0], 0)) assert rbigint.fromrarith_int(r_uint(17)).eq(rbigint([17], 1)) - assert rbigint.fromrarith_int(r_uint(BASE-1)).eq(rbigint([BASE-1], 1)) + assert rbigint.fromrarith_int(r_uint(BASE-1)).eq(rbigint([intmask(BASE-1)], 1)) assert rbigint.fromrarith_int(r_uint(BASE)).eq(rbigint([0, 1], 1)) - assert rbigint.fromrarith_int(r_uint(BASE**2)).eq(rbigint([0, 0, 1], 1)) + assert rbigint.fromrarith_int(r_uint(BASE**2)).eq(rbigint([0], 0)) assert rbigint.fromrarith_int(r_uint(sys.maxint)).eq( rbigint.fromint(sys.maxint)) assert rbigint.fromrarith_int(r_uint(sys.maxint+1)).eq( @@ -156,6 +157,9 @@ x = x ** 100 f1 = rbigint.fromlong(x) assert raises(OverflowError, f1.tofloat) + f2 = rbigint([0, 2097152], 1) + d = f2.tofloat() + assert d == float(2097152 << SHIFT) def test_fromfloat(self): x = 1234567890.1234567890 @@ -274,18 +278,14 @@ assert r2.tolong() == -(-x + 1) def test_shift(self): - negative = rbigint.fromlong(-23) - big = rbigint.fromlong(2L ** 100L) + negative = -23 for x in gen_signs([3L ** 30L, 5L ** 20L, 7 ** 300, 0L, 1L]): f1 = rbigint.fromlong(x) py.test.raises(ValueError, f1.lshift, negative) py.test.raises(ValueError, f1.rshift, negative) - py.test.raises(OverflowError, f1.lshift, big) - py.test.raises(OverflowError, f1.rshift, big) for y in [0L, 1L, 32L, 2304L, 11233L, 3 ** 9]: - f2 = rbigint.fromlong(y) - res1 = f1.lshift(f2).tolong() - res2 = f1.rshift(f2).tolong() + res1 = f1.lshift(int(y)).tolong() + res2 = f1.rshift(int(y)).tolong() assert res1 == x << y assert res2 == x >> y @@ -318,12 +318,13 @@ class TestInternalFunctions(object): def test__inplace_divrem1(self): # signs are not handled in the helpers! - x = 1238585838347L - y = 3 - f1 = rbigint.fromlong(x) - f2 = y - remainder = lobj._inplace_divrem1(f1, f1, f2) - assert (f1.tolong(), remainder) == divmod(x, y) + for x, y in [(1238585838347L, 3), (1234123412311231L, 1231231), (99, 100)]: + f1 = rbigint.fromlong(x) + f2 = y + remainder = lobj._inplace_divrem1(f1, f1, f2) + assert (f1.tolong(), remainder) == divmod(x, y) + out = rbigint([99, 99], 1) + remainder = lobj._inplace_divrem1(out, out, 100) def test__divrem1(self): # signs are not handled in the helpers! @@ -373,14 +374,14 @@ def test__v_iadd(self): f1 = rbigint([lobj.MASK] * 10, 1) f2 = rbigint([1], 1) - carry = lobj._v_iadd(f1.digits, 1, len(f1.digits)-1, f2.digits, 1) + carry = lobj._v_iadd(f1, 1, len(f1.digits)-1, f2, 1) assert carry == 1 assert f1.tolong() == lobj.MASK def test__v_isub(self): f1 = rbigint([lobj.MASK] + [0] * 9 + [1], 1) f2 = rbigint([1], 1) - borrow = lobj._v_isub(f1.digits, 1, len(f1.digits)-1, f2.digits, 1) + borrow = lobj._v_isub(f1, 1, len(f1.digits)-1, f2, 1) assert borrow == 0 assert f1.tolong() == (1 << lobj.SHIFT) ** 10 - 1 @@ -394,14 +395,14 @@ assert hi.digits == dighi def test__k_mul(self): - digs= lobj.KARATSUBA_CUTOFF * 5 + digs = KARATSUBA_CUTOFF * 5 f1 = rbigint([lobj.MASK] * digs, 1) f2 = lobj._x_add(f1,rbigint([1], 1)) ret = lobj._k_mul(f1, f2) assert ret.tolong() == f1.tolong() * f2.tolong() def test__k_lopsided_mul(self): - digs_a = lobj.KARATSUBA_CUTOFF + 3 + digs_a = KARATSUBA_CUTOFF + 3 digs_b = 3 * digs_a f1 = rbigint([lobj.MASK] * digs_a, 1) f2 = rbigint([lobj.MASK] * digs_b, 1) @@ -437,11 +438,28 @@ assert (rbigint.fromlong(-9**50).ulonglongmask() == r_ulonglong(-9**50)) +BASE = 2 ** SHIFT class TestTranslatable(object): + def test_square(self): + def test(): + x = rbigint([1410065408, 4], 1) + y = x.mul(x) + return y.str() + res = interpret(test, []) + assert "".join(res.chars) == test() + + def test_add(self): + x = rbigint.fromint(-2147483647) + y = rbigint.fromint(-1) + z = rbigint.fromint(-2147483648) + def test(): + return x.add(y).eq(z) + assert test() + res = interpret(test, []) + assert res def test_args_from_rarith_int(self): - from pypy.rpython.test.test_llinterp import interpret from pypy.rpython.tool.rfficache import platform classlist = platform.numbertype_to_rclass.values() fnlist = [] @@ -462,5 +480,7 @@ return n.str() for i in range(len(values)): + res = fn(i) + assert res == str(long(values[i])) res = interpret(fn, [i]) assert ''.join(res.chars) == str(long(values[i])) From pedronis at codespeak.net Mon Sep 21 11:12:07 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 21 Sep 2009 11:12:07 +0200 (CEST) Subject: [pypy-svn] r67822 - pypy/extradoc/planning Message-ID: <20090921091207.F2EF5168009@codespeak.net> Author: pedronis Date: Mon Sep 21 11:12:07 2009 New Revision: 67822 Modified: pypy/extradoc/planning/jit.txt Log: (micke, pedronis) some updates Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Mon Sep 21 11:12:07 2009 @@ -5,7 +5,6 @@ - streamline calls - stability! -- upgrade python on wyvern - improve test running, compile only once - sort out a benchmark infrastructure. graphs!!! (iko is going to do @@ -59,7 +58,6 @@ - float support -- speed of tracing and fallbacks? - save space on all the guard operations (see resume.py) backend: From cfbolz at codespeak.net Mon Sep 21 11:28:47 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 21 Sep 2009 11:28:47 +0200 (CEST) Subject: [pypy-svn] r67823 - in pypy/trunk/pypy/module: __builtin__ pypyjit Message-ID: <20090921092847.14EDD168009@codespeak.net> Author: cfbolz Date: Mon Sep 21 11:28:46 2009 New Revision: 67823 Modified: pypy/trunk/pypy/module/__builtin__/abstractinst.py pypy/trunk/pypy/module/pypyjit/policy.py Log: Start letting the JIT see parts of the __builtin__ module: Those things that just forward to space operations and isinstance/issubclass. Modified: pypy/trunk/pypy/module/__builtin__/abstractinst.py ============================================================================== --- pypy/trunk/pypy/module/__builtin__/abstractinst.py (original) +++ pypy/trunk/pypy/module/__builtin__/abstractinst.py Mon Sep 21 11:28:46 2009 @@ -7,6 +7,7 @@ addition to checking for instances and subtypes in the normal way. """ +from pypy.rlib.jit import dont_look_inside from pypy.interpreter.error import OperationError from pypy.module.__builtin__.interp_classobj import W_ClassObject from pypy.module.__builtin__.interp_classobj import W_InstanceObject @@ -76,7 +77,10 @@ oldstyleinst = space.interpclass_w(w_obj) if isinstance(oldstyleinst, W_InstanceObject): return oldstyleinst.w_class.is_subclass_of(oldstyleclass) + return _abstract_isinstance_w_helper(space, w_obj, w_klass_or_tuple) + at dont_look_inside +def _abstract_isinstance_w_helper(space, w_obj, w_klass_or_tuple): # -- case (anything, tuple) if space.is_true(space.isinstance(w_klass_or_tuple, space.w_tuple)): for w_klass in space.viewiterable(w_klass_or_tuple): @@ -98,6 +102,7 @@ return _issubclass_recurse(space, w_abstractclass, w_klass_or_tuple) + at dont_look_inside def _issubclass_recurse(space, w_derived, w_top): """Internal helper for abstract cases. Here, w_top cannot be a tuple.""" if space.is_w(w_derived, w_top): Modified: pypy/trunk/pypy/module/pypyjit/policy.py ============================================================================== --- pypy/trunk/pypy/module/pypyjit/policy.py (original) +++ pypy/trunk/pypy/module/pypyjit/policy.py Mon Sep 21 11:28:46 2009 @@ -46,6 +46,10 @@ if mod.startswith('pypy.interpreter.pyparser.'): return False if mod.startswith('pypy.module.'): + if mod.startswith('pypy.module.__builtin__'): + if mod.endswith('operation') or mod.endswith('abstractinst'): + return True + if (not mod.startswith('pypy.module.pypyjit.') and not mod.startswith('pypy.module.signal.') and not mod.startswith('pypy.module.micronumpy.')): From antocuni at codespeak.net Mon Sep 21 14:25:19 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 21 Sep 2009 14:25:19 +0200 (CEST) Subject: [pypy-svn] r67824 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090921122519.C29FF168016@codespeak.net> Author: antocuni Date: Mon Sep 21 14:25:18 2009 New Revision: 67824 Modified: pypy/trunk/pypy/jit/metainterp/policy.py pypy/trunk/pypy/jit/metainterp/warmspot.py Log: (antocuni, pedronis around) simplify&sanitize the way recursive portal calls are detected: part of the previous code ("except DelayedPointer") was untested and broken on ootype. Moreover, it's much simpler to just check the function pointer that we are calling than some attribute attached to the python callable Modified: pypy/trunk/pypy/jit/metainterp/policy.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/policy.py (original) +++ pypy/trunk/pypy/jit/metainterp/policy.py Mon Sep 21 14:25:18 2009 @@ -4,6 +4,8 @@ class JitPolicy(object): + portal_runner_ptr = None # set by WarmRunnerDesc.rewrite_jit_merge_point + def look_inside_function(self, func): if hasattr(func, '_look_inside_me_'): return func._look_inside_me_ @@ -50,14 +52,9 @@ def guess_call_kind(self, op, supports_floats): if op.opname == 'direct_call': - funcobj = get_funcobj(op.args[0].value) - if isinstance(lltype.typeOf(funcobj), lltype.Ptr): - try: - funcobj._obj - except lltype.DelayedPointer: - return 'recursive' - if (hasattr(funcobj, '_callable') and - getattr(funcobj._callable, '_recursive_portal_call_', False)): + funcptr = op.args[0].value + funcobj = get_funcobj(funcptr) + if funcptr is self.portal_runner_ptr: return 'recursive' if getattr(funcobj, 'graph', None) is None: return 'residual' Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Mon Sep 21 14:25:18 2009 @@ -155,7 +155,7 @@ self.build_meta_interp(CPUClass, **kwds) self.make_args_specification() - self.rewrite_jit_merge_point() + self.rewrite_jit_merge_point(policy) self.make_driverhook_graph() if self.jitdriver.virtualizables: from pypy.jit.metainterp.virtualizable import VirtualizableInfo @@ -361,7 +361,7 @@ graph = self.annhelper.getgraph(func, args_s, s_result) return self.annhelper.graph2delayed(graph, FUNC) - def rewrite_jit_merge_point(self): + def rewrite_jit_merge_point(self, policy): # # Mutate the original portal graph from this: # @@ -496,10 +496,10 @@ else: value = cast_base_ptr_to_instance(Exception, value) raise Exception, value - ll_portal_runner._recursive_portal_call_ = True - + portal_runner_ptr = self.helper_func(self.PTR_PORTAL_FUNCTYPE, ll_portal_runner) + policy.portal_runner_ptr = portal_runner_ptr # ____________________________________________________________ # Now mutate origportalgraph to end with a call to portal_runner_ptr From afa at codespeak.net Mon Sep 21 14:48:01 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Mon, 21 Sep 2009 14:48:01 +0200 (CEST) Subject: [pypy-svn] r67825 - pypy/trunk/pypy/translator/c/test Message-ID: <20090921124801.9AADC168016@codespeak.net> Author: afa Date: Mon Sep 21 14:48:00 2009 New Revision: 67825 Modified: pypy/trunk/pypy/translator/c/test/test_standalone.py Log: On windows, increase the recursion limit, to be sure that the reserved size is exceeded. This fixes the test Modified: pypy/trunk/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/trunk/pypy/translator/c/test/test_standalone.py (original) +++ pypy/trunk/pypy/translator/c/test/test_standalone.py Mon Sep 21 14:48:00 2009 @@ -332,9 +332,21 @@ time.sleep(0.2) # invokes before/after return 0 + # recurse a lot + RECURSION = 19500 + if sys.platform == 'win32': + # If I understand it correctly: + # - The stack size "reserved" for a new thread is a compile-time + # option (by default: 1Mb). This is a minimum that user code + # cannot control. + # - set_stacksize() only sets the initially "committed" size, + # which eventually requires a larger "reserved" size. + # - The limit below is large enough to exceed the "reserved" size, + # for small values of set_stacksize(). + RECURSION = 150 * 1000 + def bootstrap(): - # recurse a lot, like 19500 times - recurse(19500) + recurse(RECURSION) state.count += 1 def entry_point(argv): From antocuni at codespeak.net Mon Sep 21 14:50:56 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 21 Sep 2009 14:50:56 +0200 (CEST) Subject: [pypy-svn] r67826 - pypy/trunk/pypy/jit/tl Message-ID: <20090921125056.2BA48168016@codespeak.net> Author: antocuni Date: Mon Sep 21 14:50:55 2009 New Revision: 67826 Modified: pypy/trunk/pypy/jit/tl/pypyjit_demo.py Log: more jit demos Modified: pypy/trunk/pypy/jit/tl/pypyjit_demo.py ============================================================================== --- pypy/trunk/pypy/jit/tl/pypyjit_demo.py (original) +++ pypy/trunk/pypy/jit/tl/pypyjit_demo.py Mon Sep 21 14:50:55 2009 @@ -57,10 +57,36 @@ for i in range(10000): g(i) + +class B(object): + def foo(self, n): + return n+1 + + +def method(n): + obj = B() + i = 0 + while i Author: afa Date: Mon Sep 21 15:08:09 2009 New Revision: 67827 Modified: pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py pypy/trunk/pypy/translator/c/gcc/test/test_thread.py pypy/trunk/pypy/translator/c/test/test_standalone.py Log: Fix the new asmgccroot tests on Windows Modified: pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py Mon Sep 21 15:08:09 2009 @@ -6,10 +6,11 @@ from pypy.annotation.listdef import s_list_of_strings from pypy import conftest -if sys.platform == 'win32': - if not ('mingw' in os.popen('gcc --version').read() and - 'GNU' in os.popen('make --version').read()): - py.test.skip("mingw32 and MSYS are required for asmgcc on Windows") +def setup_module(module): + if sys.platform == 'win32': + if not ('mingw' in os.popen('gcc --version').read() and + 'GNU' in os.popen('make --version').read()): + py.test.skip("mingw32 and MSYS are required for asmgcc on Windows") class AbstractTestAsmGCRoot: # the asmgcroot gc transformer doesn't generate gc_reload_possibly_moved @@ -126,3 +127,7 @@ c_fn = self.getcompiled(f) assert c_fn() == 4900 + + if sys.platform == 'win32': + def test_callback_with_collect(self): + py.test.skip("No libffi yet with mingw32") Modified: pypy/trunk/pypy/translator/c/gcc/test/test_thread.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/test/test_thread.py (original) +++ pypy/trunk/pypy/translator/c/gcc/test/test_thread.py Mon Sep 21 15:08:09 2009 @@ -1,4 +1,18 @@ +import py +import sys, os from pypy.translator.c.test import test_standalone +def setup_module(module): + if sys.platform == 'win32': + if not ('mingw' in os.popen('gcc --version').read() and + 'GNU' in os.popen('make --version').read()): + py.test.skip("mingw32 and MSYS are required for asmgcc on Windows") + class TestThreadedAsmGcc(test_standalone.TestThread): gcrootfinder = 'asmgcc' + + def setup_class(cls): + if sys.platform == 'win32': + from pypy.config.pypyoption import get_pypy_config + cls.config = get_pypy_config(translating=True) + cls.config.translation.cc = 'mingw32' Modified: pypy/trunk/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/trunk/pypy/translator/c/test/test_standalone.py (original) +++ pypy/trunk/pypy/translator/c/test/test_standalone.py Mon Sep 21 15:08:09 2009 @@ -288,9 +288,10 @@ class TestThread(object): gcrootfinder = 'shadowstack' + config = None def compile(self, entry_point): - t = TranslationContext() + t = TranslationContext(self.config) t.config.translation.gc = "semispace" t.config.translation.gcrootfinder = self.gcrootfinder t.config.translation.thread = True From arigo at codespeak.net Mon Sep 21 15:51:56 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Sep 2009 15:51:56 +0200 (CEST) Subject: [pypy-svn] r67828 - pypy/trunk/pypy/lib/app_test/ctypes_tests Message-ID: <20090921135156.73C4B168016@codespeak.net> Author: arigo Date: Mon Sep 21 15:51:55 2009 New Revision: 67828 Modified: pypy/trunk/pypy/lib/app_test/ctypes_tests/conftest.py Log: These tests are meant to be run on top of pypy-c only. There are issues with different versions of ctypes. Modified: pypy/trunk/pypy/lib/app_test/ctypes_tests/conftest.py ============================================================================== --- pypy/trunk/pypy/lib/app_test/ctypes_tests/conftest.py (original) +++ pypy/trunk/pypy/lib/app_test/ctypes_tests/conftest.py Mon Sep 21 15:51:55 2009 @@ -1,6 +1,12 @@ import py import sys +class Directory(py.test.collect.Directory): + def collect(self): + if '__pypy__' not in sys.builtin_module_names: + py.test.skip("these tests are meant to be run on top of pypy-c") + return super(Directory, self).collect() + def compile_so_file(): from pypy.translator.platform import platform from pypy.translator.tool.cbuild import ExternalCompilationInfo From arigo at codespeak.net Mon Sep 21 16:28:45 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Sep 2009 16:28:45 +0200 (CEST) Subject: [pypy-svn] r67829 - pypy/trunk/pypy/jit/backend Message-ID: <20090921142845.8E4DE168016@codespeak.net> Author: arigo Date: Mon Sep 21 16:28:44 2009 New Revision: 67829 Removed: pypy/trunk/pypy/jit/backend/loopviewer.py Log: This is useless right now, because it crashes on the first ConstClass from the dump. It's unclear how useful this is, too. For now I will just kill it. From arigo at codespeak.net Mon Sep 21 18:11:05 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Sep 2009 18:11:05 +0200 (CEST) Subject: [pypy-svn] r67830 - pypy/branch/remove-plfbid Message-ID: <20090921161105.19AC3168020@codespeak.net> Author: arigo Date: Mon Sep 21 18:11:04 2009 New Revision: 67830 Added: pypy/branch/remove-plfbid/ - copied from r67829, pypy/trunk/ Log: A branch in which we try to remove PrepareLoopFromBridgeIsDisabled. From afa at codespeak.net Mon Sep 21 19:29:21 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Mon, 21 Sep 2009 19:29:21 +0200 (CEST) Subject: [pypy-svn] r67831 - in pypy/trunk/pypy/translator/c/gcc: . test Message-ID: <20090921172921.CCBBB168016@codespeak.net> Author: afa Date: Mon Sep 21 19:29:21 2009 New Revision: 67831 Modified: pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Log: Work around the call to _alloca() inserted on Windows for large functions. Modified: pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/test/test_asmgcroot.py Mon Sep 21 19:29:21 2009 @@ -89,6 +89,23 @@ f.writelines(lines) f.close() + def test_large_function(self): + class A(object): + def __init__(self): + self.x = 0 + d = dict(A=A) + exec ("def g(a):\n" + + " a.x += 1\n" * 1000 + + " return A()\n" + ) in d + g = d['g'] + def f(): + a = A() + g(a) + return a.x + c_fn = self.getcompiled(f) + assert c_fn() == 1000 + class TestAsmGCRootWithSemiSpaceGC(AbstractTestAsmGCRoot, test_newgc.TestSemiSpaceGC): Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Mon Sep 21 19:29:21 2009 @@ -782,6 +782,14 @@ target = match.group(1) if target in FUNCTIONS_NOT_RETURNING: return InsnStop() + if sys.platform == 'win32' and target == '__alloca': + # in functions with large stack requirements, windows + # needs a call to _alloca(), to turn reserved pages + # into committed memory. + # With mingw32 gcc at least, %esp is not used before + # this call. So we don't bother to compute the exact + # stack effect. + return [InsnCannotFollowEsp()] if target in self.labels: lineoffset = self.labels[target].lineno - self.currentlineno if lineoffset >= 0: From arigo at codespeak.net Mon Sep 21 19:36:14 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Sep 2009 19:36:14 +0200 (CEST) Subject: [pypy-svn] r67832 - in pypy/branch/remove-plfbid/pypy/jit/metainterp: . test Message-ID: <20090921173614.BE922168016@codespeak.net> Author: arigo Date: Mon Sep 21 19:36:14 2009 New Revision: 67832 Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_send.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_tl.py Log: (pedronis, arigo) Really kill PrepareLoopFromBridgeIsDisabled, and replace it with a working (if inefficient) solution instead. Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py Mon Sep 21 19:36:14 2009 @@ -365,10 +365,10 @@ new_loop) # store the new_loop in compiled_merge_points too # XXX it's probably useless to do so when optimizing - glob = metainterp_sd.globaldata - greenargs = glob.unpack_greenkey(greenkey) - old_loops = glob.compiled_merge_points.setdefault(greenargs, []) - old_loops.append(new_loop) + #glob = metainterp_sd.globaldata + #greenargs = glob.unpack_greenkey(greenkey) + #old_loops = glob.compiled_merge_points.setdefault(greenargs, []) + #old_loops.append(new_loop) def compile_fresh_bridge(metainterp, old_loops, resumekey): @@ -388,7 +388,7 @@ except InvalidLoop: assert 0, "InvalidLoop in optimize_bridge?" return None - # Did it work? If not, prepare_loop_from_bridge() will probably be used. + # Did it work? if target_loop is not None: # Yes, we managed to create a bridge. Dispatch to resumekey to # know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr) @@ -407,49 +407,3 @@ descr = target_loop.finishdescr new_op = ResOperation(rop.FAIL, op.args, None, descr=descr) new_loop.operations[-1] = new_op - - -def prepare_loop_from_bridge(metainterp, resumekey): - # To handle this case, we prepend to the history the unoptimized - # operations coming from the loop, in order to make a (fake) complete - # unoptimized trace. (Then we will just compile this loop normally.) - raise PrepareLoopFromBridgeIsDisabled - if not we_are_translated(): - log.info("completing the bridge into a stand-alone loop") - else: - debug_print("completing the bridge into a stand-alone loop") - operations = metainterp.history.operations - metainterp.history.operations = [] - assert isinstance(resumekey, ResumeGuardDescr) - append_full_operations(metainterp.history, - resumekey.history, - resumekey.history_guard_index) - metainterp.history.operations.extend(operations) - -def append_full_operations(history, sourcehistory, guard_index): - prev = sourcehistory.source_link - if isinstance(prev, History): - append_full_operations(history, prev, sourcehistory.source_guard_index) - history.operations.extend(sourcehistory.operations[:guard_index]) - op = inverse_guard(sourcehistory.operations[guard_index]) - history.operations.append(op) - -def inverse_guard(guard_op): - suboperations = guard_op.suboperations - assert guard_op.is_guard() - if guard_op.opnum == rop.GUARD_TRUE: - guard_op = ResOperation(rop.GUARD_FALSE, guard_op.args, None) - elif guard_op.opnum == rop.GUARD_FALSE: - guard_op = ResOperation(rop.GUARD_TRUE, guard_op.args, None) - else: - # XXX other guards have no inverse so far - raise InverseTheOtherGuardsPlease(guard_op) - # - guard_op.suboperations = suboperations - return guard_op - -class InverseTheOtherGuardsPlease(Exception): - pass - -class PrepareLoopFromBridgeIsDisabled(Exception): - pass Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py Mon Sep 21 19:36:14 2009 @@ -802,17 +802,19 @@ @arguments("orgpc") def opimpl_jit_merge_point(self, pc): - if self.metainterp.is_blackholing(): - self.blackhole_reached_merge_point(self.env) - return True - else: + if not self.metainterp.is_blackholing(): self.generate_merge_point(pc, self.env) if DEBUG > 0: self.debug_merge_point() if self.metainterp.seen_can_enter_jit: self.metainterp.seen_can_enter_jit = False - self.metainterp.reached_can_enter_jit(self.env) - return False + try: + self.metainterp.reached_can_enter_jit(self.env) + except GiveUp: + self.metainterp.switch_to_blackhole() + if self.metainterp.is_blackholing(): + self.blackhole_reached_merge_point(self.env) + return True def debug_merge_point(self): # debugging: produce a DEBUG_MERGE_POINT operation @@ -1287,18 +1289,21 @@ op.pc = self.framestack[-1].pc op.name = self.framestack[-1].jitcode.name + def switch_to_blackhole(self): + self.history = None # start blackholing + if not we_are_translated(): + self.staticdata.stats.aborted_count += 1 + history.log.event('ABORTING TRACING') + elif DEBUG: + debug_print('~~~ ABORTING TRACING') + self.staticdata.profiler.end_tracing() + self.staticdata.profiler.start_blackhole() + def switch_to_blackhole_if_trace_too_long(self): if not self.is_blackholing(): warmrunnerstate = self.staticdata.state if len(self.history.operations) > warmrunnerstate.trace_limit: - self.history = None # start blackholing - if not we_are_translated(): - self.staticdata.stats.aborted_count += 1 - history.log.event('ABORTING TRACING') - elif DEBUG: - debug_print('~~~ ABORTING TRACING') - self.staticdata.profiler.end_tracing() - self.staticdata.profiler.start_blackhole() + self.switch_to_blackhole() def _interpret(self): # Execute the frames forward until we raise a DoneWithThisFrame, @@ -1425,16 +1430,7 @@ else: assert start == 0 if self.extra_rebuild_operations >= 0: - # The history only starts at a bridge, not at the - # full loop header. Complete it as a full loop by - # inserting a copy of the operations from the old - # loop branch before the guard that failed. - start = self.extra_rebuild_operations - assert start >= 0 - # clean up, but without shifting the end of the list - for i in range(start): - self.history.operations[i] = None - compile.prepare_loop_from_bridge(self, self.resumekey) + raise GiveUp loop = self.compile(original_boxes, live_arg_boxes, start) if loop is not None: raise GenerateMergePoint(live_arg_boxes, loop) @@ -1443,7 +1439,7 @@ # exactly its old list of operations... # xxx maybe we could patch history.operations with # Nones after calling self.compile() instead of - # before... + # before... xxx maybe we should just raise GiveUp del self.history.operations[:] self.history.operations.extend(oldops) @@ -1605,9 +1601,7 @@ else: self.history = history.History(self.cpu) extra = len(suboperations) - 1 - assert extra >= 0 - for i in range(extra): - self.history.operations.append(suboperations[i]) + assert extra == 0 # for now self.extra_rebuild_operations = extra if must_compile: self.staticdata.profiler.start_tracing() @@ -1814,3 +1808,6 @@ assert target_loop is not None self.argboxes = args self.target_loop = target_loop + +class GiveUp(Exception): + pass Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_send.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_send.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_send.py Mon Sep 21 19:36:14 2009 @@ -374,6 +374,35 @@ self.check_loops(new_with_vtable=0) self.check_loop_count(2) + def test_behavior_change_after_a_while(self): + myjitdriver = JitDriver(greens = [], reds = ['x', 'y']) + class Base: + def __init__(self, value): + self.value = value + class Int1(Base): + pass + class Int2(Base): + pass + cases = [False, True, True, True, True]*40 + def f(y): + x = Int1(0) + while y > 0: + myjitdriver.can_enter_jit(x=x, y=y) + myjitdriver.jit_merge_point(x=x, y=y) + y -= 1 + value = x.value + 1 + if cases[y]: + x = Int1(value) + else: + x = Int2(value) + return x.value + res = self.meta_interp(f, [len(cases)]) + assert res == 200 + # for now, we really expect only 1 loop. This is known to be kind + # of wrong. XXX later... + self.check_loop_count(2) # 1 loop + 1 bridge + self.check_tree_loop_count(2) # 1 loop + 1 entry bridge (argh) + def test_three_cases(self): class Node: def __init__(self, x): Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_tl.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_tl.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_tl.py Mon Sep 21 19:36:14 2009 @@ -133,7 +133,7 @@ PUSH 1 ADD PICK 0 - PUSH 3 + PUSH 5 LE BR_COND inside PUSH 1 From arigo at codespeak.net Mon Sep 21 19:41:48 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Sep 2009 19:41:48 +0200 (CEST) Subject: [pypy-svn] r67833 - pypy/branch/remove-plfbid/pypy Message-ID: <20090921174148.94F15168016@codespeak.net> Author: arigo Date: Mon Sep 21 19:41:48 2009 New Revision: 67833 Modified: pypy/branch/remove-plfbid/pypy/testrunner_cfg.py Log: (pedronis, arigo) Add support for an env variable, PYPYCHERRYPICK, passed from buildbot's builders to select specific directories to run test in. Modified: pypy/branch/remove-plfbid/pypy/testrunner_cfg.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/testrunner_cfg.py (original) +++ pypy/branch/remove-plfbid/pypy/testrunner_cfg.py Mon Sep 21 19:41:48 2009 @@ -1,4 +1,5 @@ # nightly test configuration for the paraller runner +import os def collect_one_testdir(testdirs, reldir, tests): if (reldir.startswith('translator/c/') or @@ -10,4 +11,7 @@ else: testdirs.append(reldir) - + +_cherrypick = os.getenv('PYPYCHERRYPICK', '') +if _cherrypick: + cherrypick = _cherrypick.split(':') From arigo at codespeak.net Mon Sep 21 19:49:42 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Sep 2009 19:49:42 +0200 (CEST) Subject: [pypy-svn] r67834 - pypy/build/bot2/pypybuildbot Message-ID: <20090921174942.B931A16801B@codespeak.net> Author: arigo Date: Mon Sep 21 19:49:42 2009 New Revision: 67834 Modified: pypy/build/bot2/pypybuildbot/master.py Log: Random tweaks: hide the obscure "rebuild" button in the pages describing a particular build, and disable pinging. Modified: pypy/build/bot2/pypybuildbot/master.py ============================================================================== --- pypy/build/bot2/pypybuildbot/master.py (original) +++ pypy/build/bot2/pypybuildbot/master.py Mon Sep 21 19:49:42 2009 @@ -13,6 +13,23 @@ server.Site = LoggingSite # So I did. + +# The button Resubmit Build is quite confusing, so disable it +from buildbot.status.web.build import StatusResourceBuild +StatusResourceBuild_init = StatusResourceBuild.__init__ +def my_init(self, build_status, build_control, builder_control): + StatusResourceBuild_init(self, build_status, build_control, None) +StatusResourceBuild.__init__ = my_init +# Disabled. + +# Disable pinging, as it seems to deadlock the client +from buildbot.status.web.builder import StatusResourceBuilder +def my_ping(self, req): + raise Exception("pinging is disabled, as it seems to deadlock clients") +StatusResourceBuilder.ping = my_ping +# Disabled. + + status = WebStatus(httpPortNumber, allowForce=True) # pypy test summary page From arigo at codespeak.net Mon Sep 21 19:50:37 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Sep 2009 19:50:37 +0200 (CEST) Subject: [pypy-svn] r67835 - pypy/build/bot2/pypybuildbot Message-ID: <20090921175037.05ADD168003@codespeak.net> Author: arigo Date: Mon Sep 21 19:50:37 2009 New Revision: 67835 Modified: pypy/build/bot2/pypybuildbot/builds.py pypy/build/bot2/pypybuildbot/master.py Log: (pedronis, arigo) Add a "jit-only" tests builder. Modified: pypy/build/bot2/pypybuildbot/builds.py ============================================================================== --- pypy/build/bot2/pypybuildbot/builds.py (original) +++ pypy/build/bot2/pypybuildbot/builds.py Mon Sep 21 19:50:37 2009 @@ -91,6 +91,7 @@ def __init__(self, *a, **kw): platform = kw.pop('platform', 'linux') + cherrypick = kw.pop('cherrypick', '') factory.BuildFactory.__init__(self, *a, **kw) setup_steps(platform, self) @@ -104,7 +105,8 @@ "--root=pypy", "--timeout=10800"], logfiles={'pytestLog': 'testrun.log'}, timeout = 4000, - env={"PYTHONPATH": ['.']})) + env={"PYTHONPATH": ['.'], + "PYPYCHERRYPICK": cherrypick})) class PyPyTranslatedLibPythonTestFactory(factory.BuildFactory): Modified: pypy/build/bot2/pypybuildbot/master.py ============================================================================== --- pypy/build/bot2/pypybuildbot/master.py (original) +++ pypy/build/bot2/pypybuildbot/master.py Mon Sep 21 19:50:37 2009 @@ -44,6 +44,8 @@ pypyOwnTestFactory = pypybuilds.PyPyOwnTestFactory() pypyOwnTestFactoryWin = pypybuilds.PyPyOwnTestFactory(platform="win32") +pypyJitOnlyOwnTestFactory = pypybuilds.PyPyOwnTestFactory(cherrypick="jit") + pypyTranslatedLibPythonTestFactory = pypybuilds.PyPyTranslatedLibPythonTestFactory() pypyTranslatedLibPythonTestFactoryWin = pypybuilds.PyPyTranslatedLibPythonTestFactory(platform="win32") pypyTranslatedLibPythonMaemoTestFactory = pypybuilds.PyPyTranslatedScratchboxTestFactory() @@ -61,7 +63,8 @@ APPLVLLINUX32 = "pypy-c-app-level-linux-x86-32" STACKLESSAPPLVLLINUX32 = "pypy-c-stackless-app-level-linux-x86-32" CPYFREEBSD64 = 'pypy-c-lib-python-freebsd-7-x86-64' -JITLINUX32 = "pypy-c-jit-lib-python-linux-x86-32" +JITCPYLINUX32 = "pypy-c-jit-lib-python-linux-x86-32" +JITONLYLINUX32 = "jitonly-own-linux-x86-32" BuildmasterConfig = { 'slavePortnum': slavePortnum, @@ -69,7 +72,7 @@ 'change_source': [], 'schedulers': [ Nightly("nightly", [LINUX32, CPYLINUX32, APPLVLLINUX32, CPYWIN32, - STACKLESSAPPLVLLINUX32, JITLINUX32], + STACKLESSAPPLVLLINUX32, JITCPYLINUX32], hour=4, minute=45), ], 'status': [status], @@ -127,12 +130,18 @@ 'factory' : pypyTranslatedLibPythonTestFactory, "category": 'other' }, - {"name" : JITLINUX32, + {"name" : JITCPYLINUX32, "slavenames": ["bigdogvm1"], - 'builddir' : JITLINUX32, + 'builddir' : JITCPYLINUX32, 'factory' : pypyJITTranslatedTestFactory, 'category' : 'lib-python', - } + }, + {"name": JITONLYLINUX32, + "slavenames": ["wyvern"], + "builddir": JITONLYLINUX32, + "factory": pypyJitOnlyOwnTestFactory, + "category": 'own' + }, ], 'buildbotURL': 'http://codespeak.net:%d/'%(httpPortNumber), From antocuni at codespeak.net Tue Sep 22 10:19:09 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 22 Sep 2009 10:19:09 +0200 (CEST) Subject: [pypy-svn] r67836 - pypy/trunk/pypy/jit/backend/cli/test Message-ID: <20090922081909.41953318136@codespeak.net> Author: antocuni Date: Tue Sep 22 10:19:08 2009 New Revision: 67836 Modified: pypy/trunk/pypy/jit/backend/cli/test/test_zrpy_send.py Log: xfail these two tests for now Modified: pypy/trunk/pypy/jit/backend/cli/test/test_zrpy_send.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/test/test_zrpy_send.py (original) +++ pypy/trunk/pypy/jit/backend/cli/test/test_zrpy_send.py Tue Sep 22 10:19:08 2009 @@ -10,3 +10,8 @@ def test_recursive_call_to_portal_from_blackhole(self): py.test.skip('string return values are not supported') + test_oosend_guard_failure = py.test.mark.xfail( + test_send.TestOOtype.test_oosend_guard_failure.im_func) + + test_oosend_guard_failure_2 = py.test.mark.xfail( + test_send.TestOOtype.test_oosend_guard_failure_2.im_func) From arigo at codespeak.net Tue Sep 22 11:06:15 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Sep 2009 11:06:15 +0200 (CEST) Subject: [pypy-svn] r67837 - in pypy/trunk/pypy: jit/backend/x86 translator/c/gcc Message-ID: <20090922090615.ED45E318136@codespeak.net> Author: arigo Date: Tue Sep 22 11:06:15 2009 New Revision: 67837 Added: pypy/trunk/pypy/jit/backend/x86/valgrind.py Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py pypy/trunk/pypy/jit/backend/x86/codebuf.py pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Log: Support for running pypy-c-jit under valgrind. Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py Tue Sep 22 11:06:15 2009 @@ -139,8 +139,9 @@ newaddr = self.assemble(tree, guard_op.suboperations, guard_op) # patch the jump from original guard addr = guard_op._x86_addr - mc = codebuf.InMemoryCodeBuilder(addr, addr + 128) + mc = codebuf.InMemoryCodeBuilder(addr, addr + 4) mc.write(packimm32(newaddr - addr - 4)) + mc.valgrind_invalidated() mc.done() def assemble(self, tree, operations, guard_op): @@ -176,9 +177,9 @@ if not we_are_translated(): # for the benefit of tests guard_op._x86_bridge_stack_depth = stack_depth - mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) - + mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 8) mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) + mc.valgrind_invalidated() mc.done() if we_are_translated(): self._regalloc = None # else keep it around for debugging Modified: pypy/trunk/pypy/jit/backend/x86/codebuf.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/codebuf.py (original) +++ pypy/trunk/pypy/jit/backend/x86/codebuf.py Tue Sep 22 11:06:15 2009 @@ -61,6 +61,11 @@ if machine_code_dumper.enabled: machine_code_dumper.dump(self, 'LOG', self._pos, msg) + def valgrind_invalidated(self): + # mark the range of the InMemoryCodeBuilder as invalidated for Valgrind + from pypy.jit.backend.x86 import valgrind + valgrind.discard_translations(self._data, self._size) + BINARYFN = lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed) Added: pypy/trunk/pypy/jit/backend/x86/valgrind.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/jit/backend/x86/valgrind.py Tue Sep 22 11:06:15 2009 @@ -0,0 +1,29 @@ +""" +Support for valgrind: tell it when we patch code in-place. +""" + +from pypy.rpython.tool import rffi_platform +from pypy.rpython.lltypesystem import lltype, llmemory, rffi +from pypy.translator.tool.cbuild import ExternalCompilationInfo +from pypy.rlib.objectmodel import we_are_translated + + +eci = ExternalCompilationInfo(includes = ['valgrind/valgrind.h']) + +try: + rffi_platform.verify_eci(eci) +except rffi_platform.CompilationError: + VALGRIND_DISCARD_TRANSLATIONS = None +else: + VALGRIND_DISCARD_TRANSLATIONS = rffi.llexternal( + "VALGRIND_DISCARD_TRANSLATIONS", + [llmemory.Address, lltype.Signed], + lltype.Void, + compilation_info=eci, + _nowrapper=True) + +# ____________________________________________________________ + +def discard_translations(data, size): + if we_are_translated() and VALGRIND_DISCARD_TRANSLATIONS is not None: + VALGRIND_DISCARD_TRANSLATIONS(llmemory.cast_ptr_to_adr(data), size) Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Tue Sep 22 11:06:15 2009 @@ -774,6 +774,16 @@ visit_jo = conditional_jump visit_jno = conditional_jump + def visit_xchgl(self, line): + # only support the format used in VALGRIND_DISCARD_TRANSLATIONS + # which is to use a marker no-op "xchgl %ebx, %ebx" + match = r_binaryinsn.match(line) + source = match.group(1) + target = match.group(2) + if source == target: + return [] + raise UnrecognizedOperation(line) + def visit_call(self, line): match = r_unaryinsn.match(line) if match is None: From pedronis at codespeak.net Tue Sep 22 11:11:15 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 22 Sep 2009 11:11:15 +0200 (CEST) Subject: [pypy-svn] r67838 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090922091115.86202318136@codespeak.net> Author: pedronis Date: Tue Sep 22 11:11:14 2009 New Revision: 67838 Modified: pypy/trunk/pypy/jit/metainterp/test/test_tl.py Log: (micke, pedronis) this test doesn't loop at all so it is a bit useless as a jit test Modified: pypy/trunk/pypy/jit/metainterp/test/test_tl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_tl.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_tl.py Tue Sep 22 11:11:14 2009 @@ -6,32 +6,6 @@ class ToyLanguageTests: - def test_tiny1(self): - myjitdriver = JitDriver(greens = ['s', 'pc'], - reds = ['y', 'acc']) - - def ll_plus_minus(s, x, y): - acc = x - pc = 0 - while pc < len(s): - myjitdriver.can_enter_jit(y=y, pc=pc, acc=acc, s=s) - myjitdriver.jit_merge_point(y=y, pc=pc, acc=acc, s=s) - op = s[pc] - if op == '+': - acc += y - elif op == '-': - acc -= y - pc += 1 - return acc - - codes = ["++++++++++", "+-++---+-++-"] - def main(n, x, y): - code = codes[n] - return ll_plus_minus(code, x, y) - - res = self.meta_interp(main, [0, 100, 2]) - assert res == 120 - def test_tlr(self): from pypy.jit.tl.tlr import interpret, SQUARE From pedronis at codespeak.net Tue Sep 22 12:52:56 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 22 Sep 2009 12:52:56 +0200 (CEST) Subject: [pypy-svn] r67839 - in pypy/trunk/pypy/jit: backend backend/cli backend/test backend/x86 metainterp metainterp/test Message-ID: <20090922105256.B9767498425@codespeak.net> Author: pedronis Date: Tue Sep 22 12:52:55 2009 New Revision: 67839 Added: pypy/trunk/pypy/jit/metainterp/logger.py (props changed) - copied unchanged from r67836, pypy/trunk/pypy/jit/backend/logger.py pypy/trunk/pypy/jit/metainterp/test/test_logger.py (contents, props changed) - copied, changed from r67836, pypy/trunk/pypy/jit/backend/test/test_logger.py Removed: pypy/trunk/pypy/jit/backend/logger.py pypy/trunk/pypy/jit/backend/test/test_logger.py Modified: pypy/trunk/pypy/jit/backend/cli/method.py pypy/trunk/pypy/jit/backend/cli/runner.py pypy/trunk/pypy/jit/backend/x86/assembler.py pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/oparser.py pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py Log: (micke, pedronis) move the logging of optimized loops and bridges to the frontend in compile, this also means that these logs will keep their debug_merge_points - move the logger to metainterp - change opparse not to have the default shared cache anymore, more trouble than convenience, have a per namespace cache instead Modified: pypy/trunk/pypy/jit/backend/cli/method.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/method.py (original) +++ pypy/trunk/pypy/jit/backend/cli/method.py Tue Sep 22 12:52:55 2009 @@ -151,9 +151,6 @@ self.av_ZeroDivisionError = None # ---- - cpu.logger.create_log() - cpu.logger.log_loop(loop) - # ---- self.box2type = {} if self.nocast: self.compute_types() Modified: pypy/trunk/pypy/jit/backend/cli/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/runner.py (original) +++ pypy/trunk/pypy/jit/backend/cli/runner.py Tue Sep 22 12:52:55 2009 @@ -8,7 +8,6 @@ from pypy.jit.metainterp import executor from pypy.jit.metainterp.resoperation import rop, opname from pypy.jit.backend import model -from pypy.jit.backend.logger import Logger from pypy.jit.backend.llgraph.runner import KeyManager from pypy.translator.cli import dotnet from pypy.translator.cli.dotnet import CLR @@ -45,7 +44,6 @@ self.failing_ops = [] # index --> op self.ll_ovf_exc = self._get_prebuilt_exc(OverflowError) self.ll_zero_exc = self._get_prebuilt_exc(ZeroDivisionError) - self.logger = Logger(self.ts) def _get_prebuilt_exc(self, cls): if self.rtyper is None: Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py Tue Sep 22 12:52:55 2009 @@ -6,7 +6,6 @@ from pypy.rpython.lltypesystem.rclass import OBJECT from pypy.rpython.lltypesystem.lloperation import llop from pypy.tool.uid import fixid -from pypy.jit.backend.logger import Logger from pypy.jit.backend.x86.regalloc import (RegAlloc, WORD, REGS, TempBox, lower_byte, stack_pos) from pypy.rlib.objectmodel import we_are_translated, specialize @@ -77,7 +76,6 @@ self.malloc_array_func_addr = 0 self.malloc_str_func_addr = 0 self.malloc_unicode_func_addr = 0 - self.logger = Logger(cpu.ts) self.fail_boxes_int = lltype.malloc(lltype.GcArray(lltype.Signed), MAX_FAIL_BOXES, zero=True) self.fail_boxes_ptr = lltype.malloc(lltype.GcArray(llmemory.GCREF), @@ -97,7 +95,6 @@ self.fail_box_ptr_addr = rffi.cast(lltype.Signed, lltype.direct_arrayitems(self.fail_boxes_ptr)) - self.logger.create_log() # the address of the function called by 'new' gc_ll_descr = self.cpu.gc_ll_descr gc_ll_descr.initialize() @@ -158,11 +155,9 @@ adr_lea = 0 if guard_op is None: inputargs = tree.inputargs - self.logger.log_loop(tree) regalloc.walk_operations(tree) else: inputargs = regalloc.inputargs - self.logger.log_operations(inputargs, guard_op.suboperations, {}) mc = self.mc._mc adr_lea = mc.tell() mc.LEA(esp, fixedsize_ebp_ofs(0)) Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Tue Sep 22 12:52:55 2009 @@ -117,20 +117,22 @@ debug_print("reusing old loop") return old_loop history.source_link = loop - send_loop_to_backend(metainterp, loop, None, "loop") - metainterp.staticdata.stats.loops.append(loop) + send_loop_to_backend(metainterp, loop, None, "loop", loop) + metainterp_sd.stats.loops.append(loop) old_loops.append(loop) return loop -def send_loop_to_backend(metainterp, loop, guard_op, type): +def send_loop_to_backend(metainterp, loop, guard_op, type, loop_to_log): for box in loop.inputargs: assert isinstance(box, Box) - metainterp.staticdata.profiler.start_backend() + metainterp_sd = metainterp.staticdata + metainterp_sd.options.logger_ops.log_loop(loop_to_log) + metainterp_sd.profiler.start_backend() metainterp.cpu.compile_operations(loop, guard_op) - metainterp.staticdata.profiler.end_backend() + metainterp_sd.profiler.end_backend() if not we_are_translated(): if type != "entry bridge": - metainterp.staticdata.stats.compiled_count += 1 + metainterp_sd.stats.compiled_count += 1 else: loop._ignore_during_counting = True log.info("compiled new " + type) @@ -320,7 +322,7 @@ guard_op = self.get_guard_op() guard_op.suboperations = new_loop.operations send_loop_to_backend(metainterp, source_loop, self.get_guard_op(), - "bridge") + "bridge", new_loop) def find_source_loop(self): # Find the TreeLoop object that contains this guard operation. @@ -358,7 +360,8 @@ new_loop.greenkey = greenkey new_loop.inputargs = redkey new_loop.specnodes = [prebuiltNotSpecNode] * len(redkey) - send_loop_to_backend(metainterp, new_loop, None, "entry bridge") + send_loop_to_backend(metainterp, new_loop, None, "entry bridge", + new_loop) metainterp_sd.stats.loops.append(new_loop) # send the new_loop to warmspot.py, to be called directly the next time metainterp_sd.state.attach_unoptimized_bridge_from_interp(greenkey, Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Tue Sep 22 12:52:55 2009 @@ -9,7 +9,7 @@ from pypy.jit.metainterp.history import Const, ConstInt, Box from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import codewriter, executor -from pypy.jit.backend.logger import Logger +from pypy.jit.metainterp.logger import Logger from pypy.jit.metainterp.jitprof import EmptyProfiler, BLACKHOLED_OPS from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS from pypy.rlib.rarithmetic import intmask @@ -978,6 +978,7 @@ self.stats = stats self.options = options options.logger_noopt = Logger(cpu.ts) + options.logger_ops = Logger(cpu.ts) RESULT = portal_graph.getreturnvar().concretetype self.result_type = history.getkind(RESULT) @@ -1025,6 +1026,7 @@ self.profiler.initialized = True self.globaldata.initialized = True self.options.logger_noopt.create_log('.noopt') + self.options.logger_ops.create_log('.ops') def _setup_class_sizes(self): class_sizes = {} Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/oparser.py Tue Sep 22 12:52:55 2009 @@ -11,9 +11,6 @@ from pypy.rpython.ootypesystem import ootype from pypy.rpython.annlowlevel import llstr -_cache = {} -_default_namespace = {'lltype': {}, 'ootype': {}} - class ParseError(Exception): pass @@ -60,10 +57,11 @@ self.boxkinds = boxkinds or {} self.jumps = [] self.jump_targets = jump_targets + self._cache = namespace.setdefault('_CACHE_', {}) def box_for_var(self, elem): try: - return _cache[self.type_system, elem] + return self._cache[self.type_system, elem] except KeyError: pass if elem.startswith('i'): @@ -82,7 +80,7 @@ break else: raise ParseError("Unknown variable type: %s" % elem) - _cache[self.type_system, elem] = box + self._cache[self.type_system, elem] = box box._str = elem return box @@ -264,7 +262,7 @@ def parse(descr, cpu=None, namespace=None, type_system='lltype', boxkinds=None, jump_targets=None): if namespace is None: - namespace = _default_namespace[type_system] + namespace = {} return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_targets).parse() def _box_counter_more_than(s): Copied: pypy/trunk/pypy/jit/metainterp/test/test_logger.py (from r67836, pypy/trunk/pypy/jit/backend/test/test_logger.py) ============================================================================== --- pypy/trunk/pypy/jit/backend/test/test_logger.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_logger.py Tue Sep 22 12:52:55 2009 @@ -1,6 +1,6 @@ from pypy.jit.metainterp.test.oparser import parse -from pypy.jit.backend import logger +from pypy.jit.metainterp import logger from pypy.jit.metainterp.typesystem import llhelper from StringIO import StringIO from pypy.jit.metainterp.test.test_optimizeopt import equaloplists @@ -25,7 +25,7 @@ class TestLogger(object): ts = llhelper - def reparse(self, inp, namespace=None): + def reparse(self, inp, namespace={}): """ parse loop once, then log it and parse again, return both """ Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py Tue Sep 22 12:52:55 2009 @@ -48,9 +48,11 @@ fail(i2) jump(i1) """ - loop1 = parse(ops) - loop2 = parse(ops) - loop3 = parse(ops.replace("i2 = int_add", "i2 = int_sub")) + namespace = {} + loop1 = parse(ops, namespace=namespace) + loop2 = parse(ops, namespace=namespace) + loop3 = parse(ops.replace("i2 = int_add", "i2 = int_sub"), + namespace=namespace) assert equaloplists(loop1.operations, loop2.operations) py.test.raises(AssertionError, "equaloplists(loop1.operations, loop3.operations)") From afa at codespeak.net Tue Sep 22 14:40:20 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Tue, 22 Sep 2009 14:40:20 +0200 (CEST) Subject: [pypy-svn] r67840 - in pypy/trunk/pypy/translator/c/gcc: . test Message-ID: <20090922124020.E45FF318136@codespeak.net> Author: afa Date: Tue Sep 22 14:40:20 2009 New Revision: 67840 Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Log: More tweaks in trackgcroot for the mingw32 compiler: - the table-based switches table may appear in a .rdata section, inside the function code - the jump address is stored in a registry, set by the instruction just above. If the jump pattern is more complex, no instruction will appear to jump to the missed labels, and trackgcroot will fail. Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py Tue Sep 22 14:40:20 2009 @@ -105,7 +105,52 @@ assert parts[4] == (False, lines[13:18]) assert parts[5] == (True, lines[18:20]) assert parts[6] == (False, lines[20:]) - + +def test_find_functions_mingw32(): + source = """\ +\t.text +\t.globl _pypy_g_funccall_valuestack__AccessDirect_None +_pypy_g_funccall_valuestack__AccessDirect_None: +\t$pushl %ebp +\t$movl %esp, %ebp +\t$subl $40, %esp +L410: +\t$movl $10, %eax +\t$movl %eax, -12(%ebp) +\t$movl -4(%ebp), %eax +\t$movl L9341(%eax), %eax +\t$jmp *%eax +\t$.section .rdata,"dr" +\t$.align 4 +L9341: +\t$.long L9331 +\t$.long L9332 +\t$.long L9333 +\t$.long L9334 +\t$.long L9335 +\t$.text +L9331: +L9332: +L9333: +L9334: +L9335: +\t$movl -12(%ebp), %eax +/APP +\t$/* GCROOT %eax */ +/NO_APP +\tcall\t_someFunction +\t$leave +\t$ret +""" + lines = source.splitlines(True) + parts = list(GcRootTracker(format='mingw32').find_functions(iter(lines))) + assert len(parts) == 2 + assert parts[0] == (False, lines[:2]) + assert parts[1] == (True, lines[2:]) + lines = parts[1][1] + tracker = FunctionGcRootTracker(lines, format='mingw32') + tracker.computegcmaptable(verbose=sys.maxint) + def test_computegcmaptable(): tests = [] for format in ('elf', 'darwin'): Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Tue Sep 22 14:40:20 2009 @@ -219,7 +219,24 @@ if functionlines: yield in_function, functionlines - _find_functions_mingw32 = _find_functions_darwin + def _find_functions_mingw32(self, iterlines): + functionlines = [] + in_text = False + in_function = False + for n, line in enumerate(iterlines): + if r_textstart.match(line): + assert not in_text, "unexpected repeated .text start: %d" % n + in_text = True + elif r_sectionstart.match(line): + in_text = False + elif in_text and r_functionstart_darwin.match(line): + yield in_function, functionlines + functionlines = [] + in_function = True + functionlines.append(line) + + if functionlines: + yield in_function, functionlines def process(self, iterlines, newfile, entrypoint='main', filename='?'): if self.format in ('darwin', 'mingw32'): @@ -717,12 +734,27 @@ return InsnRet() def visit_jmp(self, line): + tablelabel = None match = r_jmp_switch.match(line) if match: # this is a jmp *Label(%index), used for table-based switches. # Assume that the table is just a list of lines looking like # .long LABEL or .long 0, ending in a .text or .section .text.hot. tablelabel = match.group(1) + elif r_unaryinsn_star.match(line): + # maybe a jmp similar to the above, but stored in a + # registry: + # movl L9341(%eax), %eax + # jmp *%eax + operand = r_unaryinsn_star.match(line).group(1)[1:] + prev_line = self.lines[self.currentlineno-1] + match = r_insn.match(prev_line) + binaryinsn = r_binaryinsn.match(prev_line) + if (match and binaryinsn and + match.group(1) == 'movl' and binaryinsn.group(2) == operand + and '(' in binaryinsn.group(1)): + tablelabel = binaryinsn.group(1).split('(')[0] + if tablelabel: tablelin = self.labels[tablelabel].lineno + 1 while not r_jmptable_end.match(self.lines[tablelin]): match = r_jmptable_item.match(self.lines[tablelin]) From afa at codespeak.net Tue Sep 22 15:25:29 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Tue, 22 Sep 2009 15:25:29 +0200 (CEST) Subject: [pypy-svn] r67841 - pypy/trunk/pypy/translator/c/gcc/test Message-ID: <20090922132529.276A5318137@codespeak.net> Author: afa Date: Tue Sep 22 15:25:28 2009 New Revision: 67841 Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py Log: Fix the mess in assembler code. Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py Tue Sep 22 15:25:28 2009 @@ -111,36 +111,36 @@ \t.text \t.globl _pypy_g_funccall_valuestack__AccessDirect_None _pypy_g_funccall_valuestack__AccessDirect_None: -\t$pushl %ebp -\t$movl %esp, %ebp -\t$subl $40, %esp +\tpushl %ebp +\tmovl %esp, %ebp +\tsubl $40, %esp L410: -\t$movl $10, %eax -\t$movl %eax, -12(%ebp) -\t$movl -4(%ebp), %eax -\t$movl L9341(%eax), %eax -\t$jmp *%eax -\t$.section .rdata,"dr" -\t$.align 4 +\tmovl $10, %eax +\tmovl %eax, -12(%ebp) +\tmovl -4(%ebp), %eax +\tmovl L9341(%eax), %eax +\tjmp *%eax +\t.section .rdata,"dr" +\t.align 4 L9341: -\t$.long L9331 -\t$.long L9332 -\t$.long L9333 -\t$.long L9334 -\t$.long L9335 -\t$.text +\t.long\tL9331 +\t.long\tL9332 +\t.long\tL9333 +\t.long\tL9334 +\t.long\tL9335 +\t.text L9331: L9332: L9333: L9334: L9335: -\t$movl -12(%ebp), %eax +\tmovl -12(%ebp), %eax /APP -\t$/* GCROOT %eax */ +\t/* GCROOT %eax */ /NO_APP \tcall\t_someFunction -\t$leave -\t$ret +\tleave +\tret """ lines = source.splitlines(True) parts = list(GcRootTracker(format='mingw32').find_functions(iter(lines))) From afa at codespeak.net Tue Sep 22 15:37:24 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Tue, 22 Sep 2009 15:37:24 +0200 (CEST) Subject: [pypy-svn] r67842 - in pypy/trunk/pypy/translator/c/gcc: . test Message-ID: <20090922133724.64646318136@codespeak.net> Author: afa Date: Tue Sep 22 15:37:23 2009 New Revision: 67842 Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Log: Another change for mingw32 which generates statements like leal 2(%esp), %esp Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py Tue Sep 22 15:37:23 2009 @@ -151,6 +151,33 @@ tracker = FunctionGcRootTracker(lines, format='mingw32') tracker.computegcmaptable(verbose=sys.maxint) +def test_leal_esp(): + # "leal 2(%esp), %esp" is equivalent to "addl $2, %esp" + source = """\ +\t.text +\t.globl _someFunction +_someFunction: +\tpushl %ebp +\tmovl %esp, %ebp +\tsubl $40, %esp +\tmovl $10, -4(%ebp) +\tcmpb $0, -26(%ebp) +\tje L7816 +\tleal 2(%esp), %esp +\tjmp L7817 +L7816: +\taddl $2, %esp +L7817: +\tmovl -4(%ebp), %eax +\t/* GCROOT %eax */ +\tcall\t_someFunction +""" + lines = source.splitlines(True) + parts = list(GcRootTracker(format='mingw32').find_functions(iter(lines))) + lines = parts[1][1] + tracker = FunctionGcRootTracker(lines, format='mingw32') + tracker.computegcmaptable(verbose=sys.maxint) + def test_computegcmaptable(): tests = [] for format in ('elf', 'darwin'): Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Tue Sep 22 15:37:23 2009 @@ -664,20 +664,21 @@ match = r_binaryinsn.match(line) target = match.group(2) if target == '%esp': - # only for leal -12(%ebp), %esp in function epilogues source = match.group(1) match = r_localvar_ebp.match(source) - if not match: - framesize = None # strange instruction - else: + # leal -12(%ebp), %esp in function epilogues + if match: if not self.uses_frame_pointer: raise UnrecognizedOperation('epilogue without prologue') ofs_from_ebp = int(match.group(1) or '0') assert ofs_from_ebp <= 0 framesize = 4 - ofs_from_ebp - return InsnEpilogue(framesize) - else: - return self.binary_insn(line) + return InsnEpilogue(framesize) + match = r_localvar_esp.match(source) + # leal 12(%esp), %esp + if match: + return InsnStackAdjust(int(match.group(1))) + return self.binary_insn(line) def insns_for_copy(self, source, target): if source == '%esp' or target == '%esp': From antocuni at codespeak.net Tue Sep 22 16:15:38 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 22 Sep 2009 16:15:38 +0200 (CEST) Subject: [pypy-svn] r67843 - in pypy/trunk/pypy/rpython/ootypesystem: . test Message-ID: <20090922141538.7077F318136@codespeak.net> Author: antocuni Date: Tue Sep 22 16:15:37 2009 New Revision: 67843 Modified: pypy/trunk/pypy/rpython/ootypesystem/ootype.py pypy/trunk/pypy/rpython/ootypesystem/test/test_oodict.py pypy/trunk/pypy/rpython/ootypesystem/test/test_oolist.py Log: make ootype.{Array,List,Dict}(None) behaving exactly like ForwardReferences: in particular, don't crash if you try to compare them, but compare by identity. Modified: pypy/trunk/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/ootype.py Tue Sep 22 16:15:37 2009 @@ -583,7 +583,7 @@ if not isinstance(other, List): return False if self.ITEM is None or other.ITEM is None: - raise TypeError("Can't compare uninitialized List type.") + return False # behave like a ForwardReference, i.e. compare by identity return BuiltinADTType.__eq__(self, other) def __ne__(self, other): @@ -664,7 +664,7 @@ if not isinstance(other, Array): return False if self.ITEM is None or other.ITEM is None: - raise TypeError("Can't compare uninitialized List type.") + return False # behave like a ForwardReference, i.e. compare by identity return BuiltinADTType.__eq__(self, other) def __ne__(self, other): @@ -768,7 +768,7 @@ if not isinstance(other, Dict): return False if not self._is_initialized() or not other._is_initialized(): - raise TypeError("Can't compare uninitialized Dict type.") + return False # behave like a ForwardReference, i.e. compare by identity return BuiltinADTType.__eq__(self, other) def __ne__(self, other): Modified: pypy/trunk/pypy/rpython/ootypesystem/test/test_oodict.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/test/test_oodict.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/test/test_oodict.py Tue Sep 22 16:15:37 2009 @@ -36,8 +36,8 @@ DT = Dict() DT2 = Dict(Signed, Float) assert DT != Signed - py.test.raises(TypeError, "DT == DT2") - py.test.raises(TypeError, "DT2 == DT") + assert DT != DT2 + assert DT2 != DT py.test.raises(TypeError, hash, DT) setDictTypes(DT, Signed, Float) assert DT == DT2 Modified: pypy/trunk/pypy/rpython/ootypesystem/test/test_oolist.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/test/test_oolist.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/test/test_oolist.py Tue Sep 22 16:15:37 2009 @@ -64,8 +64,8 @@ LT = List() LT2 = List(Signed) assert LT != Signed - py.test.raises(TypeError, "LT == LT2") - py.test.raises(TypeError, "LT2 == LT") + assert LT != LT2 + assert LT2 != LT py.test.raises(TypeError, hash, LT) setItemType(LT, Signed) assert LT == LT2 From pedronis at codespeak.net Tue Sep 22 16:24:58 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 22 Sep 2009 16:24:58 +0200 (CEST) Subject: [pypy-svn] r67844 - in pypy/branch/remove-plfbid/pypy/jit: backend backend/llgraph backend/test backend/x86 metainterp Message-ID: <20090922142458.ECDE4318136@codespeak.net> Author: pedronis Date: Tue Sep 22 16:24:57 2009 New Revision: 67844 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py pypy/branch/remove-plfbid/pypy/jit/backend/model.py pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py Log: (arigo, pedronis) WIP - start redefining the backend interface - start removing the need to keep unoptimized loops around Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py Tue Sep 22 16:24:57 2009 @@ -103,7 +103,14 @@ size = size.ofs llimpl.set_class_size(self.memo_cast, vtable, size) - def compile_operations(self, loop, bridge=None): + def compile_loop(self, loop): + self._compile_operations(loop) + return loop._compiled_version + + def compile_bridge(self, guard_op): + self._compile_operations(guard_op._ll_origloop) + + def _compile_operations(self, loop): """In a real assembler backend, this should assemble the given list of operations. Here we just generate a similar CompiledLoop instance. The code here is RPython, whereas the code in llimpl @@ -123,13 +130,13 @@ var2index[box] = llimpl.compile_start_float_var(c) else: raise Exception("box is: %r" % (box,)) - self._compile_branch(c, loop.operations, var2index) + self._compile_branch(c, loop, loop.operations, var2index) # We must redirect code jumping to the old loop so that it goes # to the new loop. if prev_c: llimpl.compile_redirect_code(prev_c, c) - def _compile_branch(self, c, operations, var2index): + def _compile_branch(self, c, origloop, operations, var2index): for op in operations: llimpl.compile_add(c, op.opnum) descr = op.descr @@ -153,8 +160,10 @@ raise Exception("%s args contain: %r" % (op.getopname(), x)) if op.is_guard(): + op._ll_origloop = origloop c2 = llimpl.compile_suboperations(c) - self._compile_branch(c2, op.suboperations, var2index.copy()) + self._compile_branch(c2, origloop, op.suboperations, + var2index.copy()) x = op.result if x is not None: if isinstance(x, history.BoxInt): @@ -174,13 +183,13 @@ llimpl.compile_add_fail(c, len(self.fail_ops)) self.fail_ops.append(op) - def execute_operations(self, loop): + def execute_token(self, compiled_version): """Calls the assembler generated for the given loop. Returns the ResOperation that failed, of type rop.FAIL. """ frame = llimpl.new_frame(self.memo_cast, self.is_oo) # setup the frame - llimpl.frame_clear(frame, loop._compiled_version) + llimpl.frame_clear(frame, compiled_version) # run the loop fail_index = llimpl.frame_execute(frame) # we hit a FAIL operation. Modified: pypy/branch/remove-plfbid/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/model.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/model.py Tue Sep 22 16:24:57 2009 @@ -8,12 +8,17 @@ """Called once by the front-end when the program starts.""" pass - def compile_operations(self, loop): - """Assemble the given list of operations.""" + def compile_loop(self, loop): + """Assemble the given loop. + Return an opaque token to be consumed by execute_token""" raise NotImplementedError - def execute_operations(self, loop): - """Calls the assembler generated for the given loop. + def compile_bridge(self, guard_op): # xxx unhappy + """Assemble the bridge""" + raise NotImplementedError + + def execute_token(self, executable_token): + """Execute the generated code referenced by the executable_token Returns the ResOperation that failed, of type rop.FAIL. Use set_future_value_xxx() before, and get_latest_value_xxx() after. """ Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py Tue Sep 22 16:24:57 2009 @@ -16,8 +16,9 @@ class Runner(object): def execute_operation(self, opname, valueboxes, result_type, descr=None): - loop = self.get_compiled_single_operation(opname, result_type, - valueboxes, descr) + loop = self._get_single_operation_loop(opname, result_type, + valueboxes, descr) + executable_token = self.cpu.compile_loop(loop) j = 0 for box in valueboxes: if isinstance(box, BoxInt): @@ -31,7 +32,7 @@ j += 1 else: assert isinstance(box, Const) - res = self.cpu.execute_operations(loop) + res = self.cpu.execute_token(executable_token) if res is loop.operations[-1]: self.guard_failed = False else: @@ -47,8 +48,8 @@ else: assert False - def get_compiled_single_operation(self, opnum, result_type, valueboxes, - descr): + def _get_single_operation_loop(self, opnum, result_type, valueboxes, + descr): if result_type == 'void': result = None elif result_type == 'int': @@ -76,12 +77,90 @@ if isinstance(box, Box): assert box not in loop.inputargs, "repeated box!" loop.inputargs.append(box) - self.cpu.compile_operations(loop) return loop - class BaseBackendTest(Runner): - + + def test_compile_linear_loop(self): + loop = TreeLoop('single op') + i0 = BoxInt() + i1 = BoxInt() + loop.operations = [ + ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), + ResOperation(rop.FAIL, [i1], None) + ] + loop.inputargs = [i0] + executable_token = self.cpu.compile_loop(loop) + self.cpu.set_future_value_int(0, 2) + fail_op = self.cpu.execute_token(executable_token) + assert fail_op is loop.operations[-1] # xxx unhappy + res = self.cpu.get_latest_value_int(0) + assert res == 3 + + def test_compile_loop(self): + loop = TreeLoop('single op') + i0 = BoxInt() + i1 = BoxInt() + i2 = BoxInt() + loop.operations = [ + ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), + ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), + ResOperation(rop.GUARD_TRUE, [i2], None), + ResOperation(rop.JUMP, [i1], None), + ] + loop.inputargs = [i0] + loop.operations[2].suboperations = [ + ResOperation(rop.FAIL, [i1], None) + ] + loop.operations[-1].jump_target = loop + + executable_token = self.cpu.compile_loop(loop) + self.cpu.set_future_value_int(0, 2) + fail_op = self.cpu.execute_token(executable_token) + assert fail_op is loop.operations[2].suboperations[-1] # xxx unhappy + res = self.cpu.get_latest_value_int(0) + assert res == 10 + + def test_compile_bridge(self): + loop = TreeLoop('single op') + i0 = BoxInt() + i1 = BoxInt() + i2 = BoxInt() + loop.operations = [ + ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), + ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), + ResOperation(rop.GUARD_TRUE, [i2], None), + ResOperation(rop.JUMP, [i1], None), + ] + loop.inputargs = [i0] + loop.operations[2].suboperations = [ + ResOperation(rop.FAIL, [i1], None) + ] + loop.operations[-1].jump_target = loop + executable_token = self.cpu.compile_loop(loop) + + i3 = BoxInt() + bridge = [ + ResOperation(rop.INT_LE, [i1, ConstInt(19)], i3), + ResOperation(rop.GUARD_TRUE, [i3], None), + ResOperation(rop.JUMP, [i1], None), + ] + bridge[1].suboperations = [ + ResOperation(rop.FAIL, [i1], None) + ] + bridge[-1].jump_target = loop + + # xxx unhappy + guard_op = loop.operations[2] + guard_op.suboperations = bridge + self.cpu.compile_bridge(guard_op) + + self.cpu.set_future_value_int(0, 2) + fail_op = self.cpu.execute_token(executable_token) + assert fail_op is bridge[1].suboperations[-1] # xxx unhappy + res = self.cpu.get_latest_value_int(0) + assert res == 20 + def test_do_call(self): cpu = self.cpu # @@ -269,13 +348,13 @@ loop = TreeLoop('name') loop.operations = ops loop.inputargs = [v1, v2] - self.cpu.compile_operations(loop) + executable_token = self.cpu.compile_loop(loop) for x, y, z in testcases: assert not self.cpu.get_exception() assert not self.cpu.get_exc_value() self.cpu.set_future_value_int(0, x) self.cpu.set_future_value_int(1, y) - op = self.cpu.execute_operations(loop) + op = self.cpu.execute_token(executable_token) if (z == boom) ^ reversed: assert op is ops[1].suboperations[0] else: @@ -909,14 +988,14 @@ exc_tp = xtp exc_ptr = xptr loop = parse(ops, self.cpu, namespace=locals()) - self.cpu.compile_operations(loop) + executable_token = self.cpu.compile_loop(loop) self.cpu.set_future_value_int(0, 1) - self.cpu.execute_operations(loop) + self.cpu.execute_token(executable_token) assert self.cpu.get_latest_value_int(0) == 0 assert self.cpu.get_latest_value_ref(1) == xptr self.cpu.clear_exception() self.cpu.set_future_value_int(0, 0) - self.cpu.execute_operations(loop) + self.cpu.execute_token(executable_token) assert self.cpu.get_latest_value_int(0) == 1 self.cpu.clear_exception() @@ -932,9 +1011,9 @@ exc_tp = ytp exc_ptr = yptr loop = parse(ops, self.cpu, namespace=locals()) - self.cpu.compile_operations(loop) + executable_token = self.cpu.compile_loop(loop) self.cpu.set_future_value_int(0, 1) - self.cpu.execute_operations(loop) + self.cpu.execute_token(executable_token) assert self.cpu.get_latest_value_int(0) == 1 self.cpu.clear_exception() @@ -948,13 +1027,13 @@ fail(0) ''' loop = parse(ops, self.cpu, namespace=locals()) - self.cpu.compile_operations(loop) + executable_token = self.cpu.compile_loop(loop) self.cpu.set_future_value_int(0, 1) - self.cpu.execute_operations(loop) + self.cpu.execute_token(executable_token) assert self.cpu.get_latest_value_int(0) == 1 self.cpu.clear_exception() self.cpu.set_future_value_int(0, 0) - self.cpu.execute_operations(loop) + self.cpu.execute_token(executable_token) assert self.cpu.get_latest_value_int(0) == 0 self.cpu.clear_exception() Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py Tue Sep 22 16:24:57 2009 @@ -159,12 +159,12 @@ #print >>s, ' loop.operations[%d].suboperations = [' % i #print >>s, ' ResOperation(rop.FAIL, [%s], None)]' % ( # ', '.join([names[v] for v in op.args])) - print >>s, ' cpu.compile_operations(loop)' + print >>s, ' executable_token = cpu.compile_loop(loop)' if hasattr(self.loop, 'inputargs'): for i, v in enumerate(self.loop.inputargs): print >>s, ' cpu.set_future_value_int(%d, %d)' % (i, v.value) - print >>s, ' op = cpu.execute_operations(loop)' + print >>s, ' op = cpu.execute_token(executable_token)' if self.should_fail_by is None: for i, v in enumerate(self.loop.operations[-1].args): print >>s, ' assert cpu.get_latest_value_int(%d) == %d' % ( @@ -404,8 +404,8 @@ builder = builder_factory(cpu, loop, startvars[:]) self.generate_ops(builder, r, loop, startvars) self.builder = builder - cpu.compile_operations(loop) self.loop = loop + self.executable_token = cpu.compile_loop(loop) def generate_ops(self, builder, r, loop, startvars): block_length = demo_conftest.option.block_length @@ -458,7 +458,7 @@ for i, v in enumerate(self.values): cpu.set_future_value_int(i, v) - op = cpu.execute_operations(self.loop) + op = cpu.execute_token(self.executable_token) assert op is self.should_fail_by for i, v in enumerate(op.args): value = cpu.get_latest_value_int(i) @@ -510,7 +510,7 @@ args = [x.clonebox() for x in subset] jump_target = RandomLoop(self.builder.cpu, self.builder.fork, r, args) - self.cpu.compile_operations(jump_target.loop) + self.cpu.compile_loop(jump_target.loop) jump_op = ResOperation(rop.JUMP, subset, None) jump_op.jump_target = jump_target.loop self.should_fail_by = jump_target.should_fail_by @@ -519,13 +519,13 @@ guard_op.suboperations[-1] = jump_op else: self.guard_op.suboperations[0].args.extend(subset) - self.builder.cpu.compile_operations(self.loop, guard_op) + self.builder.cpu.compile_bridge(guard_op) if self.guard_op.is_guard_exception(): # exception clearing self.guard_op.suboperations.insert(-1, exc_handling( self.guard_op)) self.guard_op.suboperations[-1] = jump_op - self.builder.cpu.compile_operations(self.loop, self.guard_op) + self.builder.cpu.compile_bridge(self.guard_op) dont_compile = True self.guard_op = jump_target.guard_op self.prebuilt_ptr_consts += jump_target.prebuilt_ptr_consts @@ -533,7 +533,7 @@ if r.random() < .05: return False if not dont_compile: - self.builder.cpu.compile_operations(self.loop, guard_op) + self.builder.cpu.compile_bridge(guard_op) return True def check_random_function(cpu, BuilderClass, r, num=None, max=None): Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py Tue Sep 22 16:24:57 2009 @@ -148,7 +148,6 @@ # a 'jump' can either close a loop, or end a bridge to some # previously-compiled code. self._compute_longest_fail_op(operations) - self.tree = tree self.make_sure_mc_exists() newpos = self.mc.tell() regalloc = RegAlloc(self, tree, self.cpu.translate_support_code, Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py Tue Sep 22 16:24:57 2009 @@ -71,7 +71,6 @@ inpargs = [arg for arg in guard_op._fail_op.args if isinstance(arg, Box)] self._compute_vars_longevity(inpargs, guard_op.suboperations) - self.inputargs = inpargs self.position = -1 self._update_bindings(locs, inpargs) self.current_stack_depth = guard_op._x86_current_stack_depth Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py Tue Sep 22 16:24:57 2009 @@ -247,14 +247,16 @@ oohelper.loops_exit_frame_with_exception_ref = [_loop] del _loop +class ResumeDescr(AbstractDescr): + def __init__(self, original_greenkey): + self.original_greenkey = original_greenkey -class ResumeGuardDescr(AbstractDescr): +class ResumeGuardDescr(ResumeDescr): counter = 0 - def __init__(self, history, history_guard_index): - self.history = history - assert history_guard_index >= 0 - self.history_guard_index = history_guard_index + def __init__(self, original_greenkey, guard_op): + ResumeDescr.__init__(self, original_greenkey) + self.guard_op = guard_op # this class also gets attributes stored by ResumeDataBuilder.finish() def handle_fail_op(self, metainterp_sd, fail_op): @@ -304,7 +306,7 @@ assert False def get_guard_op(self): - guard_op = self.history.operations[self.history_guard_index] + guard_op = self.guard_op assert guard_op.is_guard() if guard_op.optimized is not None: # should always be the case, return guard_op.optimized # except if not optimizing at all @@ -329,20 +331,11 @@ source_loop = source_loop.source_link return source_loop - def find_toplevel_history(self): - # Find the History that describes the start of the loop containing this - # guard operation. - history = self.history - prevhistory = history.source_link - while isinstance(prevhistory, History): - history = prevhistory - prevhistory = history.source_link - return history - -class ResumeFromInterpDescr(AbstractDescr): - def __init__(self, original_boxes): - self.original_boxes = original_boxes +class ResumeFromInterpDescr(ResumeDescr): + def __init__(self, original_greenkey, redkey): + ResumeDescr.__init__(self, original_greenkey) + self.redkey = redkey def compile_and_attach(self, metainterp, new_loop): # We managed to create a bridge going from the interpreter @@ -350,14 +343,11 @@ # a loop at all but ends in a jump to the target loop. It starts # with completely unoptimized arguments, as in the interpreter. metainterp_sd = metainterp.staticdata - num_green_args = metainterp_sd.num_green_args - greenkey = self.original_boxes[:num_green_args] - redkey = self.original_boxes[num_green_args:] metainterp.history.source_link = new_loop metainterp.history.inputargs = redkey - new_loop.greenkey = greenkey - new_loop.inputargs = redkey - new_loop.specnodes = [prebuiltNotSpecNode] * len(redkey) + new_loop.greenkey = self.original_greenkey + new_loop.inputargs = self.redkey + new_loop.specnodes = [prebuiltNotSpecNode] * len(self.redkey) send_loop_to_backend(metainterp, new_loop, None, "entry bridge") metainterp_sd.stats.loops.append(new_loop) # send the new_loop to warmspot.py, to be called directly the next time Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py Tue Sep 22 16:24:57 2009 @@ -920,8 +920,10 @@ else: moreargs = list(extraargs) guard_op = metainterp.history.record(opnum, moreargs, None) - resumedescr = compile.ResumeGuardDescr( - metainterp.history, len(metainterp.history.operations)-1) + + original_greenkey = self.resumekey.original_greenkey + resumedescr = compile.ResumeGuardDescr(original_greenkey, guard_op) + liveboxes = resumebuilder.finish(resumedescr) self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count op = history.ResOperation(rop.FAIL, liveboxes, None, descr=resumedescr) @@ -1345,7 +1347,11 @@ log('Switching from interpreter to compiler') original_boxes = self.initialize_state_from_start(*args) self.current_merge_points = [(original_boxes, 0)] - self.resumekey = compile.ResumeFromInterpDescr(original_boxes) + num_green_args = self.staticdata.num_green_args + original_greenkey = original_boxes[:num_green_args] + redkey = original_boxes[num_green_args:] + self.resumekey = compile.ResumeFromInterpDescr(original_greenkey, + redkey) self.extra_rebuild_operations = -1 self.seen_can_enter_jit = False try: @@ -1358,11 +1364,9 @@ from pypy.jit.metainterp.warmspot import ContinueRunningNormallyBase resumedescr = self.initialize_state_from_guard_failure(exec_result) assert isinstance(key, compile.ResumeGuardDescr) - top_history = key.find_toplevel_history() - source_loop = top_history.source_link - assert isinstance(source_loop, history.TreeLoop) - original_boxes = source_loop.greenkey + top_history.inputargs - self.current_merge_points = [(original_boxes, 0)] + original_greenkey = key.original_greenkey + # notice that here we just put the greenkey + self.current_merge_points = [(original_greenkey, 0)] # xxx self.resumekey = key self.seen_can_enter_jit = False guard_op = key.get_guard_op() From pedronis at codespeak.net Tue Sep 22 17:21:54 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 22 Sep 2009 17:21:54 +0200 (CEST) Subject: [pypy-svn] r67845 - pypy/branch/remove-plfbid/pypy/jit/metainterp Message-ID: <20090922152154.9DE01498425@codespeak.net> Author: pedronis Date: Tue Sep 22 17:21:54 2009 New Revision: 67845 Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py Log: (arigo, pedronis) - fix the frontend, less storing of the old loops but still issues e.g. with stats - some failures related to the llgraph backend always recompiling everything Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py Tue Sep 22 17:21:54 2009 @@ -116,18 +116,20 @@ if we_are_translated() and DEBUG > 0: debug_print("reusing old loop") return old_loop - history.source_link = loop send_loop_to_backend(metainterp, loop, None, "loop") - metainterp.staticdata.stats.loops.append(loop) old_loops.append(loop) return loop def send_loop_to_backend(metainterp, loop, guard_op, type): - for box in loop.inputargs: - assert isinstance(box, Box) metainterp.staticdata.profiler.start_backend() - metainterp.cpu.compile_operations(loop, guard_op) + if guard_op is None: + executable_token = metainterp.cpu.compile_loop(loop) + loop.executable_token = executable_token # xxx unhappy + else: + metainterp.cpu.compile_bridge(guard_op) metainterp.staticdata.profiler.end_backend() + if loop is not None: + metainterp.staticdata.stats.loops.append(loop) if not we_are_translated(): if type != "entry bridge": metainterp.staticdata.stats.compiled_count += 1 @@ -315,22 +317,11 @@ def compile_and_attach(self, metainterp, new_loop): # We managed to create a bridge. Attach the new operations - # to the existing source_loop and recompile the whole thing. - source_loop = self.find_source_loop() - metainterp.history.source_link = self.history - metainterp.history.source_guard_index = self.history_guard_index + # to the corrsponding guard_op and compile from there + # xxx unhappy guard_op = self.get_guard_op() guard_op.suboperations = new_loop.operations - send_loop_to_backend(metainterp, source_loop, self.get_guard_op(), - "bridge") - - def find_source_loop(self): - # Find the TreeLoop object that contains this guard operation. - source_loop = self.history.source_link - while not isinstance(source_loop, TreeLoop): - source_loop = source_loop.source_link - return source_loop - + send_loop_to_backend(metainterp, None, guard_op, "bridge") class ResumeFromInterpDescr(ResumeDescr): def __init__(self, original_greenkey, redkey): @@ -343,16 +334,15 @@ # a loop at all but ends in a jump to the target loop. It starts # with completely unoptimized arguments, as in the interpreter. metainterp_sd = metainterp.staticdata - metainterp.history.source_link = new_loop - metainterp.history.inputargs = redkey + metainterp.history.inputargs = self.redkey new_loop.greenkey = self.original_greenkey new_loop.inputargs = self.redkey new_loop.specnodes = [prebuiltNotSpecNode] * len(self.redkey) send_loop_to_backend(metainterp, new_loop, None, "entry bridge") - metainterp_sd.stats.loops.append(new_loop) # send the new_loop to warmspot.py, to be called directly the next time - metainterp_sd.state.attach_unoptimized_bridge_from_interp(greenkey, - new_loop) + metainterp_sd.state.attach_unoptimized_bridge_from_interp( + self.original_greenkey, + new_loop) # store the new_loop in compiled_merge_points too # XXX it's probably useless to do so when optimizing #glob = metainterp_sd.globaldata Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py Tue Sep 22 17:21:54 2009 @@ -921,7 +921,7 @@ moreargs = list(extraargs) guard_op = metainterp.history.record(opnum, moreargs, None) - original_greenkey = self.resumekey.original_greenkey + original_greenkey = metainterp.resumekey.original_greenkey resumedescr = compile.ResumeGuardDescr(original_greenkey, guard_op) liveboxes = resumebuilder.finish(resumedescr) @@ -1352,7 +1352,6 @@ redkey = original_boxes[num_green_args:] self.resumekey = compile.ResumeFromInterpDescr(original_greenkey, redkey) - self.extra_rebuild_operations = -1 self.seen_can_enter_jit = False try: self.interpret() @@ -1366,7 +1365,9 @@ assert isinstance(key, compile.ResumeGuardDescr) original_greenkey = key.original_greenkey # notice that here we just put the greenkey - self.current_merge_points = [(original_greenkey, 0)] # xxx + # use -1 to mark that we will have to give up + # because we cannot reconstruct the beginning of the proper loop + self.current_merge_points = [(original_greenkey, -1)] self.resumekey = key self.seen_can_enter_jit = False guard_op = key.get_guard_op() @@ -1416,7 +1417,7 @@ for j in range(len(self.current_merge_points)-1, -1, -1): original_boxes, start = self.current_merge_points[j] - assert len(original_boxes) == len(live_arg_boxes) + assert len(original_boxes) == len(live_arg_boxes) or start < 0 for i in range(self.staticdata.num_green_args): box1 = original_boxes[i] box2 = live_arg_boxes[i] @@ -1425,16 +1426,11 @@ break else: # Found! Compile it as a loop. + if start < 0: + # we cannot reconstruct the beginning of the proper loop + raise GiveUp + oldops = self.history.operations[:] - if j > 0: - # clean up, but without shifting the end of the list - # (that would make 'history_guard_index' invalid) - for i in range(start): - self.history.operations[i] = None - else: - assert start == 0 - if self.extra_rebuild_operations >= 0: - raise GiveUp loop = self.compile(original_boxes, live_arg_boxes, start) if loop is not None: raise GenerateMergePoint(live_arg_boxes, loop) @@ -1599,15 +1595,8 @@ if must_compile: guard_op = resumedescr.get_guard_op() suboperations = guard_op.suboperations - if suboperations[-1] is not guard_failure: - must_compile = False - log("ignoring old version of the guard") - else: - self.history = history.History(self.cpu) - extra = len(suboperations) - 1 - assert extra == 0 # for now - self.extra_rebuild_operations = extra - if must_compile: + assert suboperations[-1] is guard_failure + self.history = history.History(self.cpu) self.staticdata.profiler.start_tracing() else: self.staticdata.profiler.start_blackhole() Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py Tue Sep 22 17:21:54 2009 @@ -841,7 +841,9 @@ # ---------- execute assembler ---------- while True: # until interrupted by an exception metainterp_sd.profiler.start_running() - fail_op = metainterp_sd.cpu.execute_operations(loop) + # xxx unhappy + executable_token = loop.executable_token + fail_op = metainterp_sd.cpu.execute_token(executable_token) metainterp_sd.profiler.end_running() loop = fail_op.descr.handle_fail_op(metainterp_sd, fail_op) maybe_compile_and_run._dont_inline_ = True From pedronis at codespeak.net Tue Sep 22 17:56:00 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 22 Sep 2009 17:56:00 +0200 (CEST) Subject: [pypy-svn] r67846 - in pypy/branch/remove-plfbid/pypy/jit: backend/test metainterp/test Message-ID: <20090922155600.D9DE616801F@codespeak.net> Author: pedronis Date: Tue Sep 22 17:55:59 2009 New Revision: 67846 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py Log: (arigo, pedronis) a test and a goal test Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py Tue Sep 22 17:55:59 2009 @@ -121,6 +121,30 @@ res = self.cpu.get_latest_value_int(0) assert res == 10 + def test_backends_dont_keep_loops_alive(self): + import weakref, gc + loop = TreeLoop('single op') + i0 = BoxInt() + i1 = BoxInt() + i2 = BoxInt() + loop.operations = [ + ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), + ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), + ResOperation(rop.GUARD_TRUE, [i2], None), + ResOperation(rop.JUMP, [i1], None), + ] + loop.inputargs = [i0] + loop.operations[2].suboperations = [ + ResOperation(rop.FAIL, [i1], None) + ] + loop.operations[-1].jump_target = loop + + executable_token = self.cpu.compile_loop(loop) + wr = weakref.ref(loop) + del loop + gc.collect() + assert not wr() + def test_compile_bridge(self): loop = TreeLoop('single op') i0 = BoxInt() Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py Tue Sep 22 17:55:59 2009 @@ -177,12 +177,6 @@ res = self.interp_operations(f, [40, 2]) assert res == 42 - def test_basic_mp(self): - def f(x, y): - return x + y - res = self.interp_operations(f, [40, 2]) - assert res == 42 - def test_basic_inst(self): class A: pass @@ -238,6 +232,36 @@ found += 1 assert found == 1 + @py.test.mark.xfail + def test_loops_are_transient(self): + import gc, weakref + myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res']) + def f(x, y): + res = 0 + while y > 0: + myjitdriver.can_enter_jit(x=x, y=y, res=res) + myjitdriver.jit_merge_point(x=x, y=y, res=res) + res += x + if y%2: + res *= 2 + y -= 1 + return res + wr_loops = [] + old_init = history.TreeLoop.__init__.im_func + try: + def track_init(self, name): + old_init(self, name) + wr_loops.append(weakref.ref(self)) + history.TreeLoop.__init__ = track_init + res = self.meta_interp(f, [6, 15], no_stats=True) + finally: + history.TreeLoop.__init__ = old_init + + assert res == f(6, 15) + gc.collect() + + assert not [wr for wr in wr_loops if wr()] + def test_string(self): def f(n): bytecode = 'adlfkj' + chr(n) From afa at codespeak.net Tue Sep 22 19:05:30 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Tue, 22 Sep 2009 19:05:30 +0200 (CEST) Subject: [pypy-svn] r67847 - pypy/trunk/pypy/translator/c/gcc Message-ID: <20090922170530.661B0168016@codespeak.net> Author: afa Date: Tue Sep 22 19:05:30 2009 New Revision: 67847 Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Log: "call __assert" always fails, of course. Update the list of non-returning functions. This fixes the last error when translating on Windows: translator/goal/translate.py -Ojit --cc=mingw32 --gc=hybrid --gcrootfinder=asmgcc Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Tue Sep 22 19:05:30 2009 @@ -1037,13 +1037,21 @@ self.framesize = framesize -FUNCTIONS_NOT_RETURNING = { - 'abort': None, - '_exit': None, - '__assert_fail': None, - '___assert_rtn': None, - 'L___assert_rtn$stub': None - } +if sys.platform != 'win32': + FUNCTIONS_NOT_RETURNING = { + 'abort': None, + '_exit': None, + '__assert_fail': None, + '___assert_rtn': None, + 'L___assert_rtn$stub': None + } +else: + FUNCTIONS_NOT_RETURNING = { + '_abort': None, + '__exit': None, + '__assert': None, + '__wassert': None, + } CALLEE_SAVE_REGISTERS_NOEBP = ['%ebx', '%esi', '%edi'] CALLEE_SAVE_REGISTERS = CALLEE_SAVE_REGISTERS_NOEBP + ['%ebp'] From pedronis at codespeak.net Tue Sep 22 19:31:56 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 22 Sep 2009 19:31:56 +0200 (CEST) Subject: [pypy-svn] r67848 - in pypy/branch/remove-plfbid/pypy/jit/metainterp: . test Message-ID: <20090922173156.5E7BB318136@codespeak.net> Author: pedronis Date: Tue Sep 22 19:31:55 2009 New Revision: 67848 Removed: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_debug.py Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py pypy/branch/remove-plfbid/pypy/jit/metainterp/dump.py pypy/branch/remove-plfbid/pypy/jit/metainterp/executor.py pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py Log: (arigo, pedronis) WIP more refactoring in progress not to keep loops around at all Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py Tue Sep 22 19:31:55 2009 @@ -14,38 +14,44 @@ from pypy.jit.metainterp.optimizeutil import InvalidLoop from pypy.rlib.debug import debug_print -def compile_new_loop(metainterp, old_loops, greenkey, start=0): +class LoopToken(object): + + def __init__(self, specnodes, executable_token): + self.specnodes = specnodes + self.executable_token = executable_token + +def compile_new_loop(metainterp, old_loop_tokens, greenkey, start=0): """Try to compile a new loop by closing the current history back to the first operation. """ if we_are_translated(): - return compile_fresh_loop(metainterp, old_loops, greenkey, start) + return compile_fresh_loop(metainterp, old_loop_tokens, greenkey, start) else: - return _compile_new_loop_1(metainterp, old_loops, greenkey, start) + return _compile_new_loop_1(metainterp, old_loop_tokens, greenkey, start) -def compile_new_bridge(metainterp, old_loops, resumekey): +def compile_new_bridge(metainterp, old_loop_tokens, resumekey): """Try to compile a new bridge leading from the beginning of the history to some existing place. """ if we_are_translated(): - return compile_fresh_bridge(metainterp, old_loops, resumekey) + return compile_fresh_bridge(metainterp, old_loop_tokens, resumekey) else: - return _compile_new_bridge_1(metainterp, old_loops, resumekey) + return _compile_new_bridge_1(metainterp, old_loop_tokens, resumekey) class BridgeInProgress(Exception): pass # the following is not translatable -def _compile_new_loop_1(metainterp, old_loops, greenkey, start): - old_loops_1 = old_loops[:] +def _compile_new_loop_1(metainterp, old_loop_tokens, greenkey, start): + old_loop_tokens_1 = old_loop_tokens[:] try: - loop = compile_fresh_loop(metainterp, old_loops, greenkey, start) + loop = compile_fresh_loop(metainterp, old_loop_tokens, greenkey, start) except Exception, exc: show_loop(metainterp, error=exc) raise else: - if loop in old_loops_1: + if loop in old_loop_tokens_1: log.info("reusing loop at %r" % (loop,)) else: show_loop(metainterp, loop) @@ -53,9 +59,9 @@ loop.check_consistency() return loop -def _compile_new_bridge_1(metainterp, old_loops, resumekey): +def _compile_new_bridge_1(metainterp, old_loop_tokens, resumekey): try: - target_loop = compile_fresh_bridge(metainterp, old_loops, + target_loop = compile_fresh_bridge(metainterp, old_loop_tokens, resumekey) except Exception, exc: show_loop(metainterp, error=exc) @@ -83,15 +89,12 @@ metainterp.staticdata.stats.view(errmsg=errmsg, extraloops=extraloops) def create_empty_loop(metainterp): - if we_are_translated(): - name = 'Loop' - else: - name = 'Loop #%d' % len(metainterp.staticdata.stats.loops) + name = metainterp.staticdata.stats.name_for_new_loop() return TreeLoop(name) # ____________________________________________________________ -def compile_fresh_loop(metainterp, old_loops, greenkey, start): +def compile_fresh_loop(metainterp, old_loop_tokens, greenkey, start): from pypy.jit.metainterp.pyjitpl import DEBUG history = metainterp.history @@ -108,7 +111,7 @@ metainterp_sd = metainterp.staticdata try: old_loop = metainterp_sd.state.optimize_loop(metainterp_sd.options, - old_loops, loop, + old_loop_tokens, loop, metainterp.cpu) except InvalidLoop: return None @@ -117,7 +120,7 @@ debug_print("reusing old loop") return old_loop send_loop_to_backend(metainterp, loop, None, "loop") - old_loops.append(loop) + old_loop_tokens.append(loop) return loop def send_loop_to_backend(metainterp, loop, guard_op, type): @@ -129,10 +132,10 @@ metainterp.cpu.compile_bridge(guard_op) metainterp.staticdata.profiler.end_backend() if loop is not None: - metainterp.staticdata.stats.loops.append(loop) + metainterp.staticdata.stats.add_new_loop(loop) if not we_are_translated(): if type != "entry bridge": - metainterp.staticdata.stats.compiled_count += 1 + metainterp.staticdata.stats.compiled() else: loop._ignore_during_counting = True log.info("compiled new " + type) @@ -200,54 +203,38 @@ done_with_this_frame_descr_float = DoneWithThisFrameDescrFloat() exit_frame_with_exception_descr_ref = ExitFrameWithExceptionDescrRef() -class TerminatingLoop(TreeLoop): - pass prebuiltNotSpecNode = NotSpecNode() -# pseudo-loops to make the life of optimize.py easier -_loop = TerminatingLoop('done_with_this_frame_int') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxInt()] -_loop.finishdescr = done_with_this_frame_descr_int -loops_done_with_this_frame_int = [_loop] - -_loop = TerminatingLoop('done_with_this_frame_ref') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxPtr()] -_loop.finishdescr = done_with_this_frame_descr_ref -llhelper.loops_done_with_this_frame_ref = [_loop] - -_loop = TerminatingLoop('done_with_this_frame_ref') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxObj()] -_loop.finishdescr = done_with_this_frame_descr_ref -oohelper.loops_done_with_this_frame_ref = [_loop] - -_loop = TerminatingLoop('done_with_this_frame_float') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxFloat()] -_loop.finishdescr = done_with_this_frame_descr_float -loops_done_with_this_frame_float = [_loop] - -_loop = TerminatingLoop('done_with_this_frame_void') -_loop.specnodes = [] -_loop.inputargs = [] -_loop.finishdescr = done_with_this_frame_descr_void -loops_done_with_this_frame_void = [_loop] - -_loop = TerminatingLoop('exit_frame_with_exception_ref') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxPtr()] -_loop.finishdescr = exit_frame_with_exception_descr_ref -llhelper.loops_exit_frame_with_exception_ref = [_loop] - -_loop = TerminatingLoop('exit_frame_with_exception_ref') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxObj()] -_loop.finishdescr = exit_frame_with_exception_descr_ref -oohelper.loops_exit_frame_with_exception_ref = [_loop] -del _loop +class TerminatingLoopToken(LoopToken): + def __init__(self, nargs, finishdescr): + LoopToken.__init__(self, [prebuiltNotSpecNode]*nargs, None) + self.finishdescr = finishdescr + +# pseudo loop tokens to make the life of optimize.py easier +loop_tokens_done_with_this_frame_int = [ + TerminatingLoopToken(1, done_with_this_frame_descr_int) + ] +# xxx they are the same now +llhelper.loop_tokens_done_with_this_frame_ref = [ + TerminatingLoopToken(1, done_with_this_frame_descr_ref) + ] +oohelper.loop_tokens_done_with_this_frame_ref = [ + TerminatingLoopToken(1, done_with_this_frame_descr_ref) + ] +loop_tokens_done_with_this_frame_float = [ + TerminatingLoopToken(1, done_with_this_frame_descr_float) + ] +loop_tokens_done_with_this_frame_void = [ + TerminatingLoopToken(0, done_with_this_frame_descr_void) + ] +# xxx they are the same now +llhelper.loop_tokens_exit_frame_with_exception_ref = [ + TerminatingLoopToken(1, exit_frame_with_exception_descr_ref) + ] +oohelper.loop_tokens_exit_frame_with_exception_ref = [ + TerminatingLoopToken(1, exit_frame_with_exception_descr_ref) + ] class ResumeDescr(AbstractDescr): def __init__(self, original_greenkey): @@ -343,27 +330,22 @@ metainterp_sd.state.attach_unoptimized_bridge_from_interp( self.original_greenkey, new_loop) - # store the new_loop in compiled_merge_points too - # XXX it's probably useless to do so when optimizing - #glob = metainterp_sd.globaldata - #greenargs = glob.unpack_greenkey(greenkey) - #old_loops = glob.compiled_merge_points.setdefault(greenargs, []) - #old_loops.append(new_loop) -def compile_fresh_bridge(metainterp, old_loops, resumekey): +def compile_fresh_bridge(metainterp, old_loop_tokens, resumekey): # The history contains new operations to attach as the code for the # failure of 'resumekey.guard_op'. # # Attempt to use optimize_bridge(). This may return None in case - # it does not work -- i.e. none of the existing old_loops match. + # it does not work -- i.e. none of the existing old_loop_tokens match. new_loop = create_empty_loop(metainterp) new_loop.operations = metainterp.history.operations metainterp_sd = metainterp.staticdata options = metainterp_sd.options try: target_loop = metainterp_sd.state.optimize_bridge(options, - old_loops, new_loop, + old_loop_tokens, + new_loop, metainterp.cpu) except InvalidLoop: assert 0, "InvalidLoop in optimize_bridge?" Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/dump.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/dump.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/dump.py Tue Sep 22 19:31:55 2009 @@ -130,26 +130,3 @@ if src.pc != len(jitcode.code): print >> file, 'WARNING: the pc column is bogus! fix dump.py!' - -def dump_call_history(call_history, outfile=None): - if outfile is None: - outfile = sys.stderr - indent = 0 - for ev, code, args in call_history: - if ev == 'enter': - if args is not None: - args_s = [repr(a) for a in args] - else: - args_s = [] - print >>outfile, "%s%s(%s)" % (" "*indent, code.name, ', '.join(args_s)) - indent += 2 - elif ev == 'call': - args_s = [repr(a) for a in args] - print >>outfile, "%sCALL %r(%s)" % (" "*indent, code, ', '.join(args_s)) - elif ev.startswith('leave'): - indent -= 2 - elif ev == 'guard_failure': - break - else: - raise NotImplementedError(ev) - Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/executor.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/executor.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/executor.py Tue Sep 22 19:31:55 2009 @@ -245,7 +245,7 @@ def do_debug_merge_point(cpu, box1): from pypy.jit.metainterp.warmspot import get_stats loc = box1._get_str() - get_stats().locations.append(loc) + get_stats().add_merge_point_location(loc) # ____________________________________________________________ Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py Tue Sep 22 19:31:55 2009 @@ -769,6 +769,29 @@ # ____________________________________________________________ +class NoStats(object): + + def set_history(self, history): + pass + + def aborted(self): + pass + + def entered(self): + pass + + def compiled(self): + pass + + def add_merge_point_location(self, loc): + pass + + def name_for_new_loop(self): + return 'Loop' + + def add_new_loop(self, loop): + pass + class Stats(object): """For tests.""" @@ -780,6 +803,29 @@ self.loops = [] self.locations = [] + def set_history(self, history): + self.history = history + + def aborted(self): + self.aborted_count += 1 + + def entered(self): + self.enter_count += 1 + + def compiled(self): + self.compiled_count += 1 + + def add_merge_point_location(self, loc): + self.locations.append(loc) + + def name_for_new_loop(self): + return 'Loop #%d' % len(self.loops) + + def add_new_loop(self, loop): + self.loops.append(loop) + + # test read interface + def get_all_loops(self): return self.loops Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py Tue Sep 22 19:31:55 2009 @@ -30,12 +30,13 @@ "steps": 1, "detailed": 2} -def log(msg): +def log(msg, event_kind='info'): if not we_are_translated(): - history.log.info(msg) + getattr(history.log, event_kind)(msg) elif DEBUG: debug_print(msg) + class arguments(object): def __init__(self, *argtypes): self.argtypes = argtypes @@ -873,8 +874,6 @@ check_args(*argboxes) self.pc = 0 self.env = argboxes - if not we_are_translated(): - self.metainterp._debug_history[-1][-1] = argboxes def setup_resume_at_op(self, pc, exception_target, env): if not we_are_translated(): @@ -960,11 +959,6 @@ descr=descr) if resbox is not None: self.make_result_box(resbox) - if not we_are_translated(): - # this assumes that execute_varargs() is only used for calls, - # which is the case so far - self.metainterp._debug_history.append(['call', - argboxes[0], argboxes[1:]]) if exc: return self.metainterp.handle_exception() return False @@ -1069,7 +1063,6 @@ class MetaInterpGlobalData(object): def __init__(self, staticdata): - self._debug_history = [] self.initialized = False # state = staticdata.state @@ -1090,8 +1083,6 @@ def __init__(self, staticdata): self.staticdata = staticdata self.cpu = staticdata.cpu - if not we_are_translated(): - self._debug_history = staticdata.globaldata._debug_history def is_blackholing(self): return self.history is None @@ -1103,8 +1094,6 @@ return "" def newframe(self, jitcode): - if not we_are_translated(): - self._debug_history.append(['enter', jitcode, None]) if jitcode is self.staticdata.portal_code: self.in_recursion += 1 f = MIFrame(self, jitcode) @@ -1119,8 +1108,6 @@ def finishframe(self, resultbox): frame = self.popframe() - if not we_are_translated(): - self._debug_history.append(['leave', frame.jitcode, None]) if self.framestack: if resultbox is not None: self.framestack[-1].make_result_box(resultbox) @@ -1159,8 +1146,6 @@ frame.exception_box = exceptionbox frame.exc_value_box = excvaluebox return True - if not we_are_translated(): - self._debug_history.append(['leave_exc', frame.jitcode, None]) self.popframe() if not self.is_blackholing(): self.compile_exit_frame_with_exception(excvaluebox) @@ -1199,8 +1184,7 @@ def create_empty_history(self): warmrunnerstate = self.staticdata.state self.history = history.History(self.cpu) - if self.staticdata.stats is not None: - self.staticdata.stats.history = self.history + self.staticdata.stats.set_history(self.history) def _all_constants(self, *boxes): if len(boxes) == 0: @@ -1293,11 +1277,8 @@ def switch_to_blackhole(self): self.history = None # start blackholing - if not we_are_translated(): - self.staticdata.stats.aborted_count += 1 - history.log.event('ABORTING TRACING') - elif DEBUG: - debug_print('~~~ ABORTING TRACING') + self.staticdata.stats.aborted() + log('~~~ ABORTING TRACING', event_kind='event') self.staticdata.profiler.end_tracing() self.staticdata.profiler.start_blackhole() @@ -1310,11 +1291,8 @@ def _interpret(self): # Execute the frames forward until we raise a DoneWithThisFrame, # a ContinueRunningNormally, or a GenerateMergePoint exception. - if not we_are_translated(): - history.log.event('ENTER' + self.blackholing_text()) - self.staticdata.stats.enter_count += 1 - elif DEBUG: - debug_print('~~~ ENTER', self.blackholing_text()) + self.staticdata.stats.entered() + log('~~~ ENTER' + self.blackholing_text(), event_kind='event') try: while True: self.framestack[-1].run_one_step() @@ -1326,10 +1304,7 @@ self.staticdata.profiler.end_blackhole() else: self.staticdata.profiler.end_tracing() - if not we_are_translated(): - history.log.event('LEAVE' + self.blackholing_text()) - elif DEBUG: - debug_print('~~~ LEAVE', self.blackholing_text()) + log('~~~ LEAVE' + self.blackholing_text(), event_kind='event') def interpret(self): if we_are_translated(): @@ -1431,9 +1406,8 @@ raise GiveUp oldops = self.history.operations[:] - loop = self.compile(original_boxes, live_arg_boxes, start) - if loop is not None: - raise GenerateMergePoint(live_arg_boxes, loop) + # raises in case it works -- which is the common case + self.compile(original_boxes, live_arg_boxes, start) # creation of the loop was cancelled! Patch # history.operations so that it contains again # exactly its old list of operations... @@ -1448,13 +1422,13 @@ self.current_merge_points.append((live_arg_boxes, start)) def designate_target_loop(self, gmp): - loop = gmp.target_loop + loop_token = gmp.target_loop_token num_green_args = self.staticdata.num_green_args - residual_args = self.get_residual_args(loop, + residual_args = self.get_residual_args(loop_token.specnodes, gmp.argboxes[num_green_args:]) history.set_future_values(self.cpu, residual_args) self.clean_up_history() - return loop + return loop_token.executable_token def clean_up_history(self): # Clear the BoxPtrs used in self.history, at the end. The @@ -1497,12 +1471,12 @@ greenkey = original_boxes[:num_green_args] glob = self.staticdata.globaldata greenargs = glob.unpack_greenkey(greenkey) - old_loops = glob.compiled_merge_points.setdefault(greenargs, []) + old_loop_tokens = glob.compiled_merge_points.setdefault(greenargs, []) self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None) - loop = compile.compile_new_loop(self, old_loops, greenkey, start) - if not we_are_translated() and loop is not None: - loop._call_history = self._debug_history - return loop + loop_token = compile.compile_new_loop(self, old_loop_tokens, + greenkey, start) + if loop_token is not None: # raise if it *worked* correctly + raise GenerateMergePoint(live_arg_boxes, loop_token) def compile_bridge(self, live_arg_boxes): num_green_args = self.staticdata.num_green_args @@ -1510,14 +1484,14 @@ glob = self.staticdata.globaldata greenargs = glob.unpack_greenkey(greenkey) try: - old_loops = glob.compiled_merge_points[greenargs] + old_loop_tokens = glob.compiled_merge_points[greenargs] except KeyError: return self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None) - target_loop = compile.compile_new_bridge(self, old_loops, - self.resumekey) - if target_loop is not None: # raise if it *worked* correctly - raise GenerateMergePoint(live_arg_boxes, target_loop) + target_loop_token = compile.compile_new_bridge(self, old_loop_tokens, + self.resumekey) + if target_loop_token is not None: # raise if it *worked* correctly + raise GenerateMergePoint(live_arg_boxes, target_loop_token) self.history.operations.pop() # remove the JUMP def compile_done_with_this_frame(self, exitbox): @@ -1527,37 +1501,39 @@ if sd.result_type == 'void': assert exitbox is None exits = [] - loops = compile.loops_done_with_this_frame_void + loop_tokens = compile.loop_tokens_done_with_this_frame_void elif sd.result_type == 'int': exits = [exitbox] - loops = compile.loops_done_with_this_frame_int + loop_tokens = compile.loop_tokens_done_with_this_frame_int elif sd.result_type == 'ref': exits = [exitbox] - loops = sd.cpu.ts.loops_done_with_this_frame_ref + loop_tokens = sd.cpu.ts.loop_tokens_done_with_this_frame_ref elif sd.result_type == 'float': exits = [exitbox] - loops = compile.loops_done_with_this_frame_float + loop_tokens = compile.loop_tokens_done_with_this_frame_float else: assert False self.history.record(rop.JUMP, exits, None) - target_loop = compile.compile_new_bridge(self, loops, self.resumekey) - assert target_loop is loops[0] + target_loop_token = compile.compile_new_bridge(self, loop_tokens, + self.resumekey) + assert target_loop_token is loop_tokens[0] def compile_exit_frame_with_exception(self, valuebox): self.gen_store_back_in_virtualizable() # temporarily put a JUMP to a pseudo-loop self.history.record(rop.JUMP, [valuebox], None) - loops = self.cpu.ts.loops_exit_frame_with_exception_ref - target_loop = compile.compile_new_bridge(self, loops, self.resumekey) - assert target_loop is loops[0] + loop_tokens = self.cpu.ts.loop_tokens_exit_frame_with_exception_ref + target_loop_token = compile.compile_new_bridge(self, loop_tokens, + self.resumekey) + assert target_loop_token is loop_tokens[0] - def get_residual_args(self, loop, args): - if loop.specnodes is None: # it is None only for tests + def get_residual_args(self, specnodes, args): + if specnodes is None: # it is None only for tests return args - assert len(loop.specnodes) == len(args) + assert len(specnodes) == len(args) expanded_args = [] - for i in range(len(loop.specnodes)): - specnode = loop.specnodes[i] + for i in range(len(specnodes)): + specnode = specnodes[i] specnode.extract_runtime_data(self.cpu, args[i], expanded_args) return expanded_args @@ -1683,8 +1659,6 @@ return False def rebuild_state_after_failure(self, resumedescr, newboxes): - if not we_are_translated(): - self._debug_history.append(['guard_failure', None, None]) vinfo = self.staticdata.virtualizable_info resumereader = resume.ResumeDataReader(resumedescr, newboxes, self) self.framestack = [] @@ -1797,10 +1771,10 @@ class GenerateMergePoint(Exception): - def __init__(self, args, target_loop): - assert target_loop is not None + def __init__(self, args, target_loop_token): + assert target_loop_token is not None self.argboxes = args - self.target_loop = target_loop + self.target_loop_token = target_loop_token class GiveUp(Exception): pass Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py Tue Sep 22 19:31:55 2009 @@ -232,7 +232,7 @@ found += 1 assert found == 1 - @py.test.mark.xfail + #@py.test.mark.xfail def test_loops_are_transient(self): import gc, weakref myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res']) Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py Tue Sep 22 19:31:55 2009 @@ -41,6 +41,7 @@ translate_support_code=True, listops=True, profile=profile, + no_stats = True, **kwds) warmrunnerdesc.state.set_param_inlining(inline) warmrunnerdesc.finish() @@ -226,10 +227,14 @@ really_remove_asserts=True) def build_meta_interp(self, CPUClass, translate_support_code=False, - view="auto", profile=None, **kwds): + view="auto", profile=None, no_stats=False, **kwds): assert CPUClass is not None opt = history.Options(**kwds) - self.stats = history.Stats() + if no_stats: + stats = history.NoStats() + else: + stats = history.Stats() + self.stats = stats if translate_support_code: self.annhelper = MixLevelHelperAnnotator(self.translator.rtyper) annhelper = self.annhelper @@ -690,8 +695,8 @@ # class MachineCodeEntryPoint(object): next = None # linked list - def __init__(self, bridge, *greenargs): - self.bridge = bridge + def __init__(self, entry_executable_token, *greenargs): + self.entry_executable_token = entry_executable_token i = 0 for name in green_args_names: setattr(self, 'green_' + name, greenargs[i]) @@ -819,7 +824,7 @@ return metainterp = MetaInterp(metainterp_sd) try: - loop = metainterp.compile_and_run_once(*args) + executable_token = metainterp.compile_and_run_once(*args) except warmrunnerdesc.ContinueRunningNormally: # the trace got too long, reset the counter self.mccounters[argshash] = 0 @@ -831,21 +836,23 @@ cell = self.mcentrypoints[argshash] if not cell.equalkey(*greenargs): # hash collision - loop = self.handle_hash_collision(cell, argshash, *args) - if loop is None: + executable_token = self.handle_hash_collision(cell, + argshash, + *args) + if executable_token is None: return else: # get the assembler and fill in the boxes cell.set_future_values(*args[num_green_args:]) - loop = cell.bridge + executable_token = cell.entry_executable_token # ---------- execute assembler ---------- while True: # until interrupted by an exception metainterp_sd.profiler.start_running() # xxx unhappy - executable_token = loop.executable_token fail_op = metainterp_sd.cpu.execute_token(executable_token) metainterp_sd.profiler.end_running() - loop = fail_op.descr.handle_fail_op(metainterp_sd, fail_op) + executable_token = fail_op.descr.handle_fail_op(metainterp_sd, + fail_op) maybe_compile_and_run._dont_inline_ = True def handle_hash_collision(self, firstcell, argshash, *args): @@ -860,7 +867,7 @@ nextcell.next = firstcell self.mcentrypoints[argshash] = nextcell nextcell.set_future_values(*args[num_green_args:]) - return nextcell.bridge + return nextcell.entry_executable_token cell = nextcell # not found at all, do profiling counter = self.mccounters[argshash] @@ -918,9 +925,10 @@ def reset_counter_from_failure(self, key): key.counter = 0 - def attach_unoptimized_bridge_from_interp(self, greenkey, bridge): + def attach_unoptimized_bridge_from_interp(self, greenkey, + entry_executable_token): greenargs = self.unwrap_greenkey(greenkey) - newcell = MachineCodeEntryPoint(bridge, *greenargs) + newcell = MachineCodeEntryPoint(entry_executable_token, *greenargs) argshash = self.getkeyhash(*greenargs) & self.hashtablemask oldcell = self.mcentrypoints[argshash] newcell.next = oldcell # link From pedronis at codespeak.net Wed Sep 23 11:41:16 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 23 Sep 2009 11:41:16 +0200 (CEST) Subject: [pypy-svn] r67849 - in pypy/trunk/pypy/translator/c/gcc: . test Message-ID: <20090923094116.709AF168021@codespeak.net> Author: pedronis Date: Wed Sep 23 11:41:15 2009 New Revision: 67849 Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Log: revert r67842, it broke the build on Linux Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py Wed Sep 23 11:41:15 2009 @@ -151,33 +151,6 @@ tracker = FunctionGcRootTracker(lines, format='mingw32') tracker.computegcmaptable(verbose=sys.maxint) -def test_leal_esp(): - # "leal 2(%esp), %esp" is equivalent to "addl $2, %esp" - source = """\ -\t.text -\t.globl _someFunction -_someFunction: -\tpushl %ebp -\tmovl %esp, %ebp -\tsubl $40, %esp -\tmovl $10, -4(%ebp) -\tcmpb $0, -26(%ebp) -\tje L7816 -\tleal 2(%esp), %esp -\tjmp L7817 -L7816: -\taddl $2, %esp -L7817: -\tmovl -4(%ebp), %eax -\t/* GCROOT %eax */ -\tcall\t_someFunction -""" - lines = source.splitlines(True) - parts = list(GcRootTracker(format='mingw32').find_functions(iter(lines))) - lines = parts[1][1] - tracker = FunctionGcRootTracker(lines, format='mingw32') - tracker.computegcmaptable(verbose=sys.maxint) - def test_computegcmaptable(): tests = [] for format in ('elf', 'darwin'): Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Wed Sep 23 11:41:15 2009 @@ -664,21 +664,20 @@ match = r_binaryinsn.match(line) target = match.group(2) if target == '%esp': + # only for leal -12(%ebp), %esp in function epilogues source = match.group(1) match = r_localvar_ebp.match(source) - # leal -12(%ebp), %esp in function epilogues - if match: + if not match: + framesize = None # strange instruction + else: if not self.uses_frame_pointer: raise UnrecognizedOperation('epilogue without prologue') ofs_from_ebp = int(match.group(1) or '0') assert ofs_from_ebp <= 0 framesize = 4 - ofs_from_ebp - return InsnEpilogue(framesize) - match = r_localvar_esp.match(source) - # leal 12(%esp), %esp - if match: - return InsnStackAdjust(int(match.group(1))) - return self.binary_insn(line) + return InsnEpilogue(framesize) + else: + return self.binary_insn(line) def insns_for_copy(self, source, target): if source == '%esp' or target == '%esp': From antocuni at codespeak.net Wed Sep 23 13:54:50 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 23 Sep 2009 13:54:50 +0200 (CEST) Subject: [pypy-svn] r67850 - pypy/trunk/pypy/jit/backend/cli Message-ID: <20090923115450.280D1168020@codespeak.net> Author: antocuni Date: Wed Sep 23 13:54:49 2009 New Revision: 67850 Modified: pypy/trunk/pypy/jit/backend/cli/runner.py Log: rpython fix Modified: pypy/trunk/pypy/jit/backend/cli/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/runner.py (original) +++ pypy/trunk/pypy/jit/backend/cli/runner.py Wed Sep 23 13:54:49 2009 @@ -175,6 +175,7 @@ return BoxObj(ootype.cast_to_object(res)) def do_instanceof(self, instancebox, typedescr): + assert isinstance(typedescr, TypeDescr) return typedescr.instanceof(instancebox) def do_getfield_gc(self, instancebox, fielddescr): From pedronis at codespeak.net Wed Sep 23 15:09:24 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 23 Sep 2009 15:09:24 +0200 (CEST) Subject: [pypy-svn] r67851 - in pypy/branch/remove-plfbid/pypy/jit: backend/llgraph backend/test metainterp metainterp/test Message-ID: <20090923130924.75597168020@codespeak.net> Author: pedronis Date: Wed Sep 23 15:09:23 2009 New Revision: 67851 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/llimpl.py pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py pypy/branch/remove-plfbid/pypy/jit/metainterp/optimize.py pypy/branch/remove-plfbid/pypy/jit/metainterp/optimizeopt.py pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_oparser.py Log: (arigo, pedronis) we don't keep loop around anymore, just loop tokens Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/llimpl.py Wed Sep 23 15:09:23 2009 @@ -363,16 +363,15 @@ op.subloop = CompiledLoop() return _to_opaque(op.subloop) -def compile_redirect_code(old_loop, new_loop): +def compile_redirect_fail(old_loop, new_loop): old_loop = _from_opaque(old_loop) new_loop = _from_opaque(new_loop) - # we patch the old_loop so that it starts with a JUMP to the new_loop - # (but only if we can reasonably -- if new arguments grew, it is not) - if len(old_loop.inputargs) == len(new_loop.inputargs): - op = Operation(rop.JUMP) - op.args = old_loop.inputargs - op.jump_target = new_loop - old_loop.operations[0] = op + assert len(old_loop.operations) == 1 + assert old_loop.operations[-1].opnum == rop.FAIL + op = Operation(rop.JUMP) + op.args = old_loop.operations[-1].args + op.jump_target = new_loop + old_loop.operations[0] = op # ------------------------------ @@ -1356,7 +1355,7 @@ setannotation(compile_add_jump_target, annmodel.s_None) setannotation(compile_add_fail, annmodel.s_None) setannotation(compile_suboperations, s_CompiledLoop) -setannotation(compile_redirect_code, annmodel.s_None) +setannotation(compile_redirect_fail, annmodel.s_None) setannotation(new_frame, s_Frame) setannotation(frame_clear, annmodel.s_None) Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py Wed Sep 23 15:09:23 2009 @@ -104,23 +104,22 @@ llimpl.set_class_size(self.memo_cast, vtable, size) def compile_loop(self, loop): - self._compile_operations(loop) - return loop._compiled_version + return self._compile_operations(loop.inputargs, loop.operations) def compile_bridge(self, guard_op): - self._compile_operations(guard_op._ll_origloop) + inputargs = guard_op._fail_op.args # xxx unhappy + c = self._compile_operations(inputargs, guard_op.suboperations) + llimpl.compile_redirect_fail(guard_op._compiled_fail, c) - def _compile_operations(self, loop): + def _compile_operations(self, inputargs, operations): """In a real assembler backend, this should assemble the given list of operations. Here we just generate a similar CompiledLoop instance. The code here is RPython, whereas the code in llimpl is not. """ c = llimpl.compile_start() - prev_c = loop._compiled_version - loop._compiled_version = c var2index = {} - for box in loop.inputargs: + for box in inputargs: if isinstance(box, history.BoxInt): var2index[box] = llimpl.compile_start_int_var(c) elif isinstance(box, self.ts.BoxRef): @@ -130,13 +129,10 @@ var2index[box] = llimpl.compile_start_float_var(c) else: raise Exception("box is: %r" % (box,)) - self._compile_branch(c, loop, loop.operations, var2index) - # We must redirect code jumping to the old loop so that it goes - # to the new loop. - if prev_c: - llimpl.compile_redirect_code(prev_c, c) + self._compile_branch(c, operations, var2index) + return c - def _compile_branch(self, c, origloop, operations, var2index): + def _compile_branch(self, c, operations, var2index): for op in operations: llimpl.compile_add(c, op.opnum) descr = op.descr @@ -160,10 +156,13 @@ raise Exception("%s args contain: %r" % (op.getopname(), x)) if op.is_guard(): - op._ll_origloop = origloop c2 = llimpl.compile_suboperations(c) - self._compile_branch(c2, origloop, op.suboperations, - var2index.copy()) + suboperations = op.suboperations + assert len(suboperations) == 1 + assert suboperations[0].opnum == rop.FAIL + op._fail_op = suboperations[0] # xxx unhappy + op._compiled_fail = c2 + self._compile_branch(c2, op.suboperations, var2index.copy()) x = op.result if x is not None: if isinstance(x, history.BoxInt): @@ -178,7 +177,12 @@ op = operations[-1] assert op.is_final() if op.opnum == rop.JUMP: - llimpl.compile_add_jump_target(c, op.jump_target._compiled_version) + target = op.jump_target + if target is None: + target = c + else: + target = target.executable_token + llimpl.compile_add_jump_target(c, target) elif op.opnum == rop.FAIL: llimpl.compile_add_fail(c, len(self.fail_ops)) self.fail_ops.append(op) Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py Wed Sep 23 15:09:23 2009 @@ -1,6 +1,7 @@ import py, sys, random -from pypy.jit.metainterp.history import (BoxInt, Box, BoxPtr, TreeLoop, +from pypy.jit.metainterp.history import (BoxInt, Box, BoxPtr, + TreeLoop, LoopToken, ConstInt, ConstPtr, BoxObj, Const, ConstObj, BoxFloat, ConstFloat) from pypy.jit.metainterp.resoperation import ResOperation, rop @@ -112,7 +113,7 @@ loop.operations[2].suboperations = [ ResOperation(rop.FAIL, [i1], None) ] - loop.operations[-1].jump_target = loop + loop.operations[-1].jump_target = None executable_token = self.cpu.compile_loop(loop) self.cpu.set_future_value_int(0, 2) @@ -137,7 +138,7 @@ loop.operations[2].suboperations = [ ResOperation(rop.FAIL, [i1], None) ] - loop.operations[-1].jump_target = loop + loop.operations[-1].jump_target = None executable_token = self.cpu.compile_loop(loop) wr = weakref.ref(loop) @@ -160,8 +161,10 @@ loop.operations[2].suboperations = [ ResOperation(rop.FAIL, [i1], None) ] - loop.operations[-1].jump_target = loop + loop.operations[-1].jump_target = None executable_token = self.cpu.compile_loop(loop) + loop_token = LoopToken() + loop_token.executable_token = executable_token i3 = BoxInt() bridge = [ @@ -171,8 +174,8 @@ ] bridge[1].suboperations = [ ResOperation(rop.FAIL, [i1], None) - ] - bridge[-1].jump_target = loop + ] + bridge[-1].jump_target = loop_token # xxx unhappy guard_op = loop.operations[2] Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py Wed Sep 23 15:09:23 2009 @@ -5,7 +5,7 @@ from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import TreeLoop, log, Box, History +from pypy.jit.metainterp.history import TreeLoop, log, Box, History, LoopToken from pypy.jit.metainterp.history import AbstractDescr, BoxInt, BoxPtr, BoxObj,\ BoxFloat, Const from pypy.jit.metainterp import history @@ -14,65 +14,6 @@ from pypy.jit.metainterp.optimizeutil import InvalidLoop from pypy.rlib.debug import debug_print -class LoopToken(object): - - def __init__(self, specnodes, executable_token): - self.specnodes = specnodes - self.executable_token = executable_token - -def compile_new_loop(metainterp, old_loop_tokens, greenkey, start=0): - """Try to compile a new loop by closing the current history back - to the first operation. - """ - if we_are_translated(): - return compile_fresh_loop(metainterp, old_loop_tokens, greenkey, start) - else: - return _compile_new_loop_1(metainterp, old_loop_tokens, greenkey, start) - -def compile_new_bridge(metainterp, old_loop_tokens, resumekey): - """Try to compile a new bridge leading from the beginning of the history - to some existing place. - """ - if we_are_translated(): - return compile_fresh_bridge(metainterp, old_loop_tokens, resumekey) - else: - return _compile_new_bridge_1(metainterp, old_loop_tokens, resumekey) - -class BridgeInProgress(Exception): - pass - - -# the following is not translatable -def _compile_new_loop_1(metainterp, old_loop_tokens, greenkey, start): - old_loop_tokens_1 = old_loop_tokens[:] - try: - loop = compile_fresh_loop(metainterp, old_loop_tokens, greenkey, start) - except Exception, exc: - show_loop(metainterp, error=exc) - raise - else: - if loop in old_loop_tokens_1: - log.info("reusing loop at %r" % (loop,)) - else: - show_loop(metainterp, loop) - if loop is not None: - loop.check_consistency() - return loop - -def _compile_new_bridge_1(metainterp, old_loop_tokens, resumekey): - try: - target_loop = compile_fresh_bridge(metainterp, old_loop_tokens, - resumekey) - except Exception, exc: - show_loop(metainterp, error=exc) - raise - else: - if target_loop is not None: - show_loop(metainterp, target_loop) - if target_loop is not None and type(target_loop) is not TerminatingLoop: - target_loop.check_consistency() - return target_loop - def show_loop(metainterp, loop=None, error=None): # debugging if option.view or option.viewloops: @@ -94,7 +35,10 @@ # ____________________________________________________________ -def compile_fresh_loop(metainterp, old_loop_tokens, greenkey, start): +def compile_new_loop(metainterp, old_loop_tokens, greenkey, start): + """Try to compile a new loop by closing the current history back + to the first operation. + """ from pypy.jit.metainterp.pyjitpl import DEBUG history = metainterp.history @@ -107,32 +51,32 @@ loop.operations = history.operations[start:] else: loop.operations = history.operations - loop.operations[-1].jump_target = loop + loop.operations[-1].jump_target = None metainterp_sd = metainterp.staticdata try: - old_loop = metainterp_sd.state.optimize_loop(metainterp_sd.options, - old_loop_tokens, loop, - metainterp.cpu) + old_loop_token = metainterp_sd.state.optimize_loop( + metainterp_sd.options, old_loop_tokens, loop, metainterp.cpu) except InvalidLoop: return None - if old_loop is not None: - if we_are_translated() and DEBUG > 0: + if old_loop_token is not None: + if DEBUG > 0: debug_print("reusing old loop") - return old_loop - send_loop_to_backend(metainterp, loop, None, "loop") - old_loop_tokens.append(loop) - return loop + return old_loop_token + executable_token = send_loop_to_backend(metainterp, loop, "loop") + loop_token = LoopToken() + loop_token.specnodes = loop.specnodes + loop_token.executable_token = executable_token + old_loop_tokens.append(loop_token) + return loop_token -def send_loop_to_backend(metainterp, loop, guard_op, type): +def send_loop_to_backend(metainterp, loop, type): metainterp.staticdata.profiler.start_backend() - if guard_op is None: - executable_token = metainterp.cpu.compile_loop(loop) - loop.executable_token = executable_token # xxx unhappy - else: - metainterp.cpu.compile_bridge(guard_op) + if not we_are_translated(): + show_loop(metainterp, loop) + loop.check_consistency() + executable_token = metainterp.cpu.compile_loop(loop) metainterp.staticdata.profiler.end_backend() - if loop is not None: - metainterp.staticdata.stats.add_new_loop(loop) + metainterp.staticdata.stats.add_new_loop(loop) if not we_are_translated(): if type != "entry bridge": metainterp.staticdata.stats.compiled() @@ -143,6 +87,23 @@ from pypy.jit.metainterp.pyjitpl import DEBUG if DEBUG > 0: debug_print("compiled new " + type) + return executable_token + +def send_bridge_to_backend(metainterp, guard_op): + metainterp.staticdata.profiler.start_backend() + if not we_are_translated(): + show_loop(metainterp) + #TreeLoop.check_consistency_of(xxx unhappy, guard_op.suboperations) + pass + metainterp.cpu.compile_bridge(guard_op) + metainterp.staticdata.profiler.end_backend() + if not we_are_translated(): + metainterp.staticdata.stats.compiled() + log.info("compiled new bridge") + else: + from pypy.jit.metainterp.pyjitpl import DEBUG + if DEBUG > 0: + debug_print("compiled new bridge") # ____________________________________________________________ @@ -208,7 +169,7 @@ class TerminatingLoopToken(LoopToken): def __init__(self, nargs, finishdescr): - LoopToken.__init__(self, [prebuiltNotSpecNode]*nargs, None) + self.specnodes = [prebuiltNotSpecNode]*nargs self.finishdescr = finishdescr # pseudo loop tokens to make the life of optimize.py easier @@ -308,7 +269,7 @@ # xxx unhappy guard_op = self.get_guard_op() guard_op.suboperations = new_loop.operations - send_loop_to_backend(metainterp, None, guard_op, "bridge") + send_bridge_to_backend(metainterp, guard_op) class ResumeFromInterpDescr(ResumeDescr): def __init__(self, original_greenkey, redkey): @@ -324,15 +285,18 @@ metainterp.history.inputargs = self.redkey new_loop.greenkey = self.original_greenkey new_loop.inputargs = self.redkey - new_loop.specnodes = [prebuiltNotSpecNode] * len(self.redkey) - send_loop_to_backend(metainterp, new_loop, None, "entry bridge") + executable_token = send_loop_to_backend(metainterp, new_loop, + "entry bridge") # send the new_loop to warmspot.py, to be called directly the next time metainterp_sd.state.attach_unoptimized_bridge_from_interp( self.original_greenkey, - new_loop) + executable_token) -def compile_fresh_bridge(metainterp, old_loop_tokens, resumekey): +def compile_new_bridge(metainterp, old_loop_tokens, resumekey): + """Try to compile a new bridge leading from the beginning of the history + to some existing place. + """ # The history contains new operations to attach as the code for the # failure of 'resumekey.guard_op'. # @@ -343,7 +307,7 @@ metainterp_sd = metainterp.staticdata options = metainterp_sd.options try: - target_loop = metainterp_sd.state.optimize_bridge(options, + target_loop_token = metainterp_sd.state.optimize_bridge(options, old_loop_tokens, new_loop, metainterp.cpu) @@ -351,21 +315,22 @@ assert 0, "InvalidLoop in optimize_bridge?" return None # Did it work? - if target_loop is not None: + if target_loop_token is not None: # Yes, we managed to create a bridge. Dispatch to resumekey to # know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr) - prepare_last_operation(new_loop, target_loop) + prepare_last_operation(new_loop, target_loop_token) resumekey.compile_and_attach(metainterp, new_loop) - return target_loop + return target_loop_token -def prepare_last_operation(new_loop, target_loop): +def prepare_last_operation(new_loop, target_loop_token): op = new_loop.operations[-1] - if not isinstance(target_loop, TerminatingLoop): + if not isinstance(target_loop_token, TerminatingLoopToken): # normal case - op.jump_target = target_loop + op.jump_target = target_loop_token else: - # The target_loop is a pseudo-loop, e.g. done_with_this_frame. + # The target_loop_token is a pseudo loop token, + # e.g. loop_tokens_done_with_this_frame_void[0] # Replace the operation with the real operation we want, i.e. a FAIL. - descr = target_loop.finishdescr + descr = target_loop_token.finishdescr new_op = ResOperation(rop.FAIL, op.args, None, descr=descr) new_loop.operations[-1] = new_op Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py Wed Sep 23 15:09:23 2009 @@ -662,6 +662,11 @@ class Base(object): """Common base class for TreeLoop and History.""" +class LoopToken(object): + """loop token""" + # specnodes + # executable_token + class TreeLoop(Base): inputargs = None specnodes = None @@ -701,14 +706,19 @@ def check_consistency(self): # for testing "NOT_RPYTHON" - for box in self.inputargs: + self.check_consistency_of(self.inputargs, self.operations) + + @staticmethod + def check_consistency_of(inputargs, operations): + for box in inputargs: assert isinstance(box, Box), "Loop.inputargs contains %r" % (box,) - seen = dict.fromkeys(self.inputargs) - assert len(seen) == len(self.inputargs), ( + seen = dict.fromkeys(inputargs) + assert len(seen) == len(inputargs), ( "duplicate Box in the Loop.inputargs") - self.check_consistency_of_branch(self.operations, seen) - - def check_consistency_of_branch(self, operations, seen): + TreeLoop.check_consistency_of_branch(operations, seen) + + @staticmethod + def check_consistency_of_branch(operations, seen): "NOT_RPYTHON" for op in operations: for box in op.args: @@ -716,7 +726,8 @@ assert box in seen assert (op.suboperations is not None) == op.is_guard() if op.is_guard(): - self.check_consistency_of_branch(op.suboperations, seen.copy()) + TreeLoop.check_consistency_of_branch(op.suboperations, + seen.copy()) box = op.result if box is not None: assert isinstance(box, Box) @@ -724,7 +735,9 @@ seen[box] = True assert operations[-1].is_final() if operations[-1].opnum == rop.JUMP: - assert isinstance(operations[-1].jump_target, TreeLoop) + target = operations[-1].jump_target + if target is not None: + assert isinstance(target, LoopToken) def dump(self): # RPython-friendly Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/optimize.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/optimize.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/optimize.py Wed Sep 23 15:09:23 2009 @@ -4,19 +4,19 @@ from pypy.jit.metainterp.optimizeopt import optimize_loop_1 from pypy.jit.metainterp.specnode import equals_specnodes -def optimize_loop(options, old_loops, loop, cpu): +def optimize_loop(options, old_loop_tokens, loop, cpu): if not options.specialize: # for tests only - if old_loops: - return old_loops[0] + if old_loop_tokens: + return old_loop_tokens[0] else: return None if options.logger_noopt is not None: options.logger_noopt.log_loop(loop) finder = PerfectSpecializationFinder(cpu) finder.find_nodes_loop(loop) - for old_loop in old_loops: - if equals_specnodes(old_loop.specnodes, loop.specnodes): - return old_loop + for old_loop_token in old_loop_tokens: + if equals_specnodes(old_loop_token.specnodes, loop.specnodes): + return old_loop_token optimize_loop_1(cpu, loop) return None @@ -25,18 +25,18 @@ from pypy.jit.metainterp.optimizefindnode import BridgeSpecializationFinder from pypy.jit.metainterp.optimizeopt import optimize_bridge_1 -def optimize_bridge(options, old_loops, bridge, cpu): +def optimize_bridge(options, old_loop_tokens, bridge, cpu): if not options.specialize: # for tests only - return old_loops[0] + return old_loop_tokens[0] if options.logger_noopt is not None: options.logger_noopt.log_loop(bridge) finder = BridgeSpecializationFinder(cpu) finder.find_nodes_bridge(bridge) - for old_loop in old_loops: - if finder.bridge_matches(old_loop.specnodes): - bridge.operations[-1].jump_target = old_loop + for old_loop_token in old_loop_tokens: + if finder.bridge_matches(old_loop_token.specnodes): + bridge.operations[-1].jump_target = old_loop_token optimize_bridge_1(cpu, bridge) - return old_loop + return old_loop_token return None # ____________________________________________________________ Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/optimizeopt.py Wed Sep 23 15:09:23 2009 @@ -564,7 +564,11 @@ def optimize_JUMP(self, op): orgop = self.loop.operations[-1] exitargs = [] - specnodes = orgop.jump_target.specnodes + target = orgop.jump_target + if target is None: + specnodes = self.loop.specnodes + else: + specnodes = target.specnodes assert len(op.args) == len(specnodes) for i in range(len(specnodes)): value = self.getvalue(op.args[i]) Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py Wed Sep 23 15:09:23 2009 @@ -918,11 +918,9 @@ moreargs = [box] + extraargs else: moreargs = list(extraargs) - guard_op = metainterp.history.record(opnum, moreargs, None) - + guard_op = metainterp.history.record(opnum, moreargs, None) original_greenkey = metainterp.resumekey.original_greenkey resumedescr = compile.ResumeGuardDescr(original_greenkey, guard_op) - liveboxes = resumebuilder.finish(resumedescr) self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count op = history.ResOperation(rop.FAIL, liveboxes, None, descr=resumedescr) Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py Wed Sep 23 15:09:23 2009 @@ -223,11 +223,9 @@ raise ParseError("Wrong number of jump targets") if self.jump_targets is None: for jump in self.jumps: - jump.jump_target = loop + jump.jump_target = None else: for jump, jump_target in zip(self.jumps, self.jump_targets): - if jump_target == 'self': - jump_target = loop jump.jump_target = jump_target loop.operations = ops loop.inputargs = inpargs Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py Wed Sep 23 15:09:23 2009 @@ -232,7 +232,6 @@ found += 1 assert found == 1 - #@py.test.mark.xfail def test_loops_are_transient(self): import gc, weakref myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res']) Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_oparser.py Wed Sep 23 15:09:23 2009 @@ -118,7 +118,7 @@ jump() ''' loop = parse(x) - assert loop.operations[0].jump_target is loop + assert loop.operations[0].jump_target is None def test_jump_target_other(): x = ''' @@ -137,8 +137,8 @@ jump() ''' obj = object() - loop = parse(x, jump_targets=[obj, 'self']) - assert loop.operations[-1].jump_target is loop + loop = parse(x, jump_targets=[obj, None]) + assert loop.operations[-1].jump_target is None assert loop.operations[0].suboperations[0].jump_target is obj def test_debug_merge_point(): From antocuni at codespeak.net Wed Sep 23 15:15:52 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 23 Sep 2009 15:15:52 +0200 (CEST) Subject: [pypy-svn] r67852 - pypy/trunk/pypy/jit/tl Message-ID: <20090923131552.44AF3168020@codespeak.net> Author: antocuni Date: Wed Sep 23 15:15:51 2009 New Revision: 67852 Modified: pypy/trunk/pypy/jit/tl/pypyjit_child.py Log: - kill outdated comment - factor out common code between lltype and ootype, thus enabling inlining also for ootype Modified: pypy/trunk/pypy/jit/tl/pypyjit_child.py ============================================================================== --- pypy/trunk/pypy/jit/tl/pypyjit_child.py (original) +++ pypy/trunk/pypy/jit/tl/pypyjit_child.py Wed Sep 23 15:15:51 2009 @@ -4,25 +4,6 @@ from pypy.module.pypyjit.policy import PyPyJitPolicy from pypy.rlib.jit import OPTIMIZER_FULL -# Current output: http://paste.pocoo.org/show/106540/ -# -# Some optimizations missing: -# -# - remove the useless 'ec' argument (p1 and p115 in the trace) -# -# - the guards have very long 'liveboxes' lists containing mostly -# Consts -- make sure that these Consts are not stored, or else -# remove them entirely - -# Some optimizations that might help under different circumstances: -# -# - figure out who calls W_TypeObject.is_heaptype(), leading to -# the "int_and 512" (lines 48, 147, 154) -# -# - improve the optimization: e.g. ooisnull followed by oononnull -# on the same variable -# - def run_child(glob, loc): import sys, pdb @@ -34,26 +15,25 @@ return lltype.nullptr(T) interp.heap.malloc_nonmovable = returns_null # XXX - print 'warmspot.jittify_and_run() started...' from pypy.jit.backend.llgraph.runner import LLtypeCPU LLtypeCPU.supports_floats = False # for now - policy = PyPyJitPolicy(interp.typer.annotator.translator) - option.view = True - warmspot.jittify_and_run(interp, graph, [], policy=policy, - listops=True, CPUClass=LLtypeCPU, - backendopt=True, inline=True, - optimizer=OPTIMIZER_FULL) + apply_jit(interp, graph, LLtypeCPU) def run_child_ootype(glob, loc): import sys, pdb interp = loc['interp'] graph = loc['graph'] + from pypy.jit.backend.llgraph.runner import OOtypeCPU + apply_jit(interp, graph, OOtypeCPU) + +def apply_jit(interp, graph, CPUClass): print 'warmspot.jittify_and_run() started...' - from pypy.jit.backend.llgraph.runner import OOtypeCPU policy = PyPyJitPolicy(interp.typer.annotator.translator) option.view = True warmspot.jittify_and_run(interp, graph, [], policy=policy, - listops=True, CPUClass=OOtypeCPU, - backendopt=True) + listops=True, CPUClass=CPUClass, + backendopt=True, inline=True, + optimizer=OPTIMIZER_FULL) + From pedronis at codespeak.net Wed Sep 23 15:23:40 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 23 Sep 2009 15:23:40 +0200 (CEST) Subject: [pypy-svn] r67853 - in pypy/branch/remove-plfbid/pypy/jit/backend: llsupport llsupport/test test Message-ID: <20090923132340.CD458168020@codespeak.net> Author: pedronis Date: Wed Sep 23 15:23:40 2009 New Revision: 67853 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/test/test_runner.py pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py Log: (arigo, pedronis) more fixes Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py Wed Sep 23 15:23:40 2009 @@ -206,7 +206,7 @@ loop = TreeLoop('call') loop.inputargs = args loop.operations = operations - cpu.compile_operations(loop) + cpu.compile_loop(loop) self.call_loop = loop return loop Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/test/test_runner.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/test/test_runner.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/test/test_runner.py Wed Sep 23 15:23:40 2009 @@ -7,7 +7,7 @@ pass class MyLLCPU(AbstractLLCPU): - def compile_operations(self, loop, guard_op=None): + def compile_loop(self, loop): py.test.skip("llsupport test: cannot compile operations") Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py Wed Sep 23 15:23:40 2009 @@ -2,7 +2,7 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT from pypy.rpython.lltypesystem import llmemory from pypy.jit.backend.test import conftest as demo_conftest -from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt +from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt, LoopToken from pypy.jit.metainterp.history import BoxPtr, ConstPtr, ConstAddr from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.executor import execute_nonspec @@ -510,9 +510,10 @@ args = [x.clonebox() for x in subset] jump_target = RandomLoop(self.builder.cpu, self.builder.fork, r, args) - self.cpu.compile_loop(jump_target.loop) + executable_token = self.cpu.compile_loop(jump_target.loop) jump_op = ResOperation(rop.JUMP, subset, None) - jump_op.jump_target = jump_target.loop + jump_op.jump_target = LoopToken() + jump_op.jump_target.executable_token = executable_token self.should_fail_by = jump_target.should_fail_by self.expected = jump_target.expected if self.guard_op is None: From afa at codespeak.net Wed Sep 23 19:49:37 2009 From: afa at codespeak.net (afa at codespeak.net) Date: Wed, 23 Sep 2009 19:49:37 +0200 (CEST) Subject: [pypy-svn] r67858 - in pypy/trunk/pypy/translator/c/gcc: . test Message-ID: <20090923174937.81620168015@codespeak.net> Author: afa Date: Wed Sep 23 19:49:36 2009 New Revision: 67858 Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Log: Revert this change which breaks translation on Linux. I need to better understand the difference between a real jump and a tail-call. Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py Wed Sep 23 19:49:36 2009 @@ -105,52 +105,7 @@ assert parts[4] == (False, lines[13:18]) assert parts[5] == (True, lines[18:20]) assert parts[6] == (False, lines[20:]) - -def test_find_functions_mingw32(): - source = """\ -\t.text -\t.globl _pypy_g_funccall_valuestack__AccessDirect_None -_pypy_g_funccall_valuestack__AccessDirect_None: -\tpushl %ebp -\tmovl %esp, %ebp -\tsubl $40, %esp -L410: -\tmovl $10, %eax -\tmovl %eax, -12(%ebp) -\tmovl -4(%ebp), %eax -\tmovl L9341(%eax), %eax -\tjmp *%eax -\t.section .rdata,"dr" -\t.align 4 -L9341: -\t.long\tL9331 -\t.long\tL9332 -\t.long\tL9333 -\t.long\tL9334 -\t.long\tL9335 -\t.text -L9331: -L9332: -L9333: -L9334: -L9335: -\tmovl -12(%ebp), %eax -/APP -\t/* GCROOT %eax */ -/NO_APP -\tcall\t_someFunction -\tleave -\tret -""" - lines = source.splitlines(True) - parts = list(GcRootTracker(format='mingw32').find_functions(iter(lines))) - assert len(parts) == 2 - assert parts[0] == (False, lines[:2]) - assert parts[1] == (True, lines[2:]) - lines = parts[1][1] - tracker = FunctionGcRootTracker(lines, format='mingw32') - tracker.computegcmaptable(verbose=sys.maxint) - + def test_computegcmaptable(): tests = [] for format in ('elf', 'darwin'): Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py ============================================================================== --- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original) +++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Wed Sep 23 19:49:36 2009 @@ -219,24 +219,7 @@ if functionlines: yield in_function, functionlines - def _find_functions_mingw32(self, iterlines): - functionlines = [] - in_text = False - in_function = False - for n, line in enumerate(iterlines): - if r_textstart.match(line): - assert not in_text, "unexpected repeated .text start: %d" % n - in_text = True - elif r_sectionstart.match(line): - in_text = False - elif in_text and r_functionstart_darwin.match(line): - yield in_function, functionlines - functionlines = [] - in_function = True - functionlines.append(line) - - if functionlines: - yield in_function, functionlines + _find_functions_mingw32 = _find_functions_darwin def process(self, iterlines, newfile, entrypoint='main', filename='?'): if self.format in ('darwin', 'mingw32'): @@ -734,27 +717,12 @@ return InsnRet() def visit_jmp(self, line): - tablelabel = None match = r_jmp_switch.match(line) if match: # this is a jmp *Label(%index), used for table-based switches. # Assume that the table is just a list of lines looking like # .long LABEL or .long 0, ending in a .text or .section .text.hot. tablelabel = match.group(1) - elif r_unaryinsn_star.match(line): - # maybe a jmp similar to the above, but stored in a - # registry: - # movl L9341(%eax), %eax - # jmp *%eax - operand = r_unaryinsn_star.match(line).group(1)[1:] - prev_line = self.lines[self.currentlineno-1] - match = r_insn.match(prev_line) - binaryinsn = r_binaryinsn.match(prev_line) - if (match and binaryinsn and - match.group(1) == 'movl' and binaryinsn.group(2) == operand - and '(' in binaryinsn.group(1)): - tablelabel = binaryinsn.group(1).split('(')[0] - if tablelabel: tablelin = self.labels[tablelabel].lineno + 1 while not r_jmptable_end.match(self.lines[tablelin]): match = r_jmptable_item.match(self.lines[tablelin]) From pedronis at codespeak.net Wed Sep 23 20:24:09 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 23 Sep 2009 20:24:09 +0200 (CEST) Subject: [pypy-svn] r67859 - in pypy/branch/remove-plfbid/pypy/jit: backend backend/llgraph backend/llsupport backend/llsupport/test backend/test metainterp metainterp/test Message-ID: <20090923182409.CD121168021@codespeak.net> Author: pedronis Date: Wed Sep 23 20:24:08 2009 New Revision: 67859 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/llimpl.py pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/llmodel.py pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/test/test_runner.py pypy/branch/remove-plfbid/pypy/jit/backend/model.py pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py pypy/branch/remove-plfbid/pypy/jit/backend/test/test_ll_random.py pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py pypy/branch/remove-plfbid/pypy/jit/metainterp/graphpage.py pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py pypy/branch/remove-plfbid/pypy/jit/metainterp/resoperation.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_oparser.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_optimizeopt.py pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py Log: (arigo, pedronis) getting somewhere in terms of a saner backend interface Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/llimpl.py Wed Sep 23 20:24:08 2009 @@ -353,7 +353,6 @@ def compile_add_fail(loop, fail_index): loop = _from_opaque(loop) op = loop.operations[-1] - assert op.opnum == rop.FAIL op.fail_index = fail_index def compile_suboperations(loop): @@ -440,6 +439,13 @@ ', '.join(map(str, args)),)) self.fail_args = args return op.fail_index + elif op.opnum == rop.FINISH: + if self.verbose: + log.trace('finished: %s' % ( + ', '.join(map(str, args)),)) + self.fail_args = args + return op.fail_index + else: assert 0, "unknown final operation %d" % (op.opnum,) Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py Wed Sep 23 20:24:08 2009 @@ -85,7 +85,7 @@ self.stats.exec_jumps = 0 self.stats.exec_conditional_jumps = 0 self.memo_cast = llimpl.new_memo_cast() - self.fail_ops = [] + self.fail_descrs = [] llimpl._stats = self.stats llimpl._llinterp = LLInterpreter(self.rtyper) if translate_support_code: @@ -103,15 +103,11 @@ size = size.ofs llimpl.set_class_size(self.memo_cast, vtable, size) - def compile_loop(self, loop): - return self._compile_operations(loop.inputargs, loop.operations) + def compile_bridge(self, faildescr, inputargs, operations): + c = self.compile_loop(inputargs, operations) + llimpl.compile_redirect_fail(faildescr._compiled_fail, c) - def compile_bridge(self, guard_op): - inputargs = guard_op._fail_op.args # xxx unhappy - c = self._compile_operations(inputargs, guard_op.suboperations) - llimpl.compile_redirect_fail(guard_op._compiled_fail, c) - - def _compile_operations(self, inputargs, operations): + def compile_loop(self, inputargs, operations): """In a real assembler backend, this should assemble the given list of operations. Here we just generate a similar CompiledLoop instance. The code here is RPython, whereas the code in llimpl @@ -160,8 +156,6 @@ suboperations = op.suboperations assert len(suboperations) == 1 assert suboperations[0].opnum == rop.FAIL - op._fail_op = suboperations[0] # xxx unhappy - op._compiled_fail = c2 self._compile_branch(c2, op.suboperations, var2index.copy()) x = op.result if x is not None: @@ -184,8 +178,18 @@ target = target.executable_token llimpl.compile_add_jump_target(c, target) elif op.opnum == rop.FAIL: - llimpl.compile_add_fail(c, len(self.fail_ops)) - self.fail_ops.append(op) + faildescr = op.descr + assert isinstance(faildescr, history.AbstractFailDescr) + faildescr._compiled_fail = c + llimpl.compile_add_fail(c, len(self.fail_descrs)) + self.fail_descrs.append(faildescr) + elif op.opnum == rop.FINISH: + llimpl.compile_add_fail(c, len(self.fail_descrs)) + faildescr = op.descr + assert isinstance(faildescr, history.AbstractFailDescr) + self.fail_descrs.append(faildescr) + else: + assert False, "unknown operation" def execute_token(self, compiled_version): """Calls the assembler generated for the given loop. @@ -198,7 +202,7 @@ fail_index = llimpl.frame_execute(frame) # we hit a FAIL operation. self.latest_frame = frame - return self.fail_ops[fail_index] + return self.fail_descrs[fail_index] def set_future_value_int(self, index, intvalue): llimpl.set_future_value_int(index, intvalue) Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py Wed Sep 23 20:24:08 2009 @@ -1,7 +1,7 @@ from pypy.rpython.lltypesystem import lltype from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr -from pypy.jit.metainterp.history import TreeLoop +from pypy.jit.metainterp.history import AbstractFailDescr from pypy.jit.metainterp.resoperation import ResOperation, rop # The point of the class organization in this file is to make instances @@ -165,7 +165,7 @@ class BaseCallDescr(AbstractDescr): _clsname = '' - call_loop = None + executable_token = None arg_classes = '' # <-- annotation hack def __init__(self, arg_classes): @@ -185,9 +185,9 @@ def get_result_size(self, translate_support_code): raise NotImplementedError - def get_loop_for_call(self, cpu): - if self.call_loop is not None: - return self.call_loop + def get_token_for_call(self, cpu): + if self.executable_token is not None: + return self.executable_token args = [BoxInt()] + self.instantiate_arg_classes() if self.get_result_size(cpu.translate_support_code) == 0: result = None @@ -201,14 +201,13 @@ operations = [ ResOperation(rop.CALL, args, result, self), ResOperation(rop.GUARD_NO_EXCEPTION, [], None), - ResOperation(rop.FAIL, result_list, None)] - operations[1].suboperations = [ResOperation(rop.FAIL, [], None)] - loop = TreeLoop('call') - loop.inputargs = args - loop.operations = operations - cpu.compile_loop(loop) - self.call_loop = loop - return loop + ResOperation(rop.FAIL, result_list, None, + descr=AbstractFailDescr())] + operations[1].suboperations = [ResOperation(rop.FAIL, [], None, + descr=AbstractFailDescr())] + executable_token = cpu.compile_loop(args, operations) + self.executable_token = executable_token + return executable_token def repr_of_descr(self): return '<%s>' % self._clsname Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/llmodel.py Wed Sep 23 20:24:08 2009 @@ -420,9 +420,9 @@ if not we_are_translated(): assert (list(calldescr.arg_classes) == [arg.type for arg in args[1:]]) - loop = calldescr.get_loop_for_call(self) + executable_token = calldescr.get_token_for_call(self) set_future_values(self, args) - self.execute_operations(loop) + self.execute_token(executable_token) # Note: if an exception is set, the rest of the code does a bit of # nonsense but nothing wrong (the return value should be ignored) if calldescr.returns_a_pointer(): Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/test/test_runner.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/test/test_runner.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/test/test_runner.py Wed Sep 23 20:24:08 2009 @@ -7,7 +7,7 @@ pass class MyLLCPU(AbstractLLCPU): - def compile_loop(self, loop): + def compile_loop(self, inputargs, operations): py.test.skip("llsupport test: cannot compile operations") Modified: pypy/branch/remove-plfbid/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/model.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/model.py Wed Sep 23 20:24:08 2009 @@ -8,12 +8,12 @@ """Called once by the front-end when the program starts.""" pass - def compile_loop(self, loop): + def compile_loop(self, inputargs, operations): """Assemble the given loop. Return an opaque token to be consumed by execute_token""" raise NotImplementedError - def compile_bridge(self, guard_op): # xxx unhappy + def compile_bridge(self, faildescr, inputargs, operations): """Assemble the bridge""" raise NotImplementedError Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py Wed Sep 23 20:24:08 2009 @@ -1,7 +1,8 @@ import py, sys, random -from pypy.jit.metainterp.history import (BoxInt, Box, BoxPtr, - TreeLoop, LoopToken, +from pypy.jit.metainterp.history import (AbstractDescr, AbstractFailDescr, + BoxInt, Box, BoxPtr, + LoopToken, ConstInt, ConstPtr, BoxObj, Const, ConstObj, BoxFloat, ConstFloat) from pypy.jit.metainterp.resoperation import ResOperation, rop @@ -14,12 +15,16 @@ from pypy.rpython.annlowlevel import llhelper from pypy.rpython.llinterp import LLException +FailDescr = AbstractFailDescr + class Runner(object): def execute_operation(self, opname, valueboxes, result_type, descr=None): - loop = self._get_single_operation_loop(opname, result_type, - valueboxes, descr) - executable_token = self.cpu.compile_loop(loop) + inputargs, operations = self._get_single_operation_list(opname, + result_type, + valueboxes, + descr) + executable_token = self.cpu.compile_loop(inputargs, operations) j = 0 for box in valueboxes: if isinstance(box, BoxInt): @@ -34,7 +39,7 @@ else: assert isinstance(box, Const) res = self.cpu.execute_token(executable_token) - if res is loop.operations[-1]: + if res is operations[-1].descr: self.guard_failed = False else: self.guard_failed = True @@ -49,7 +54,7 @@ else: assert False - def _get_single_operation_loop(self, opnum, result_type, valueboxes, + def _get_single_operation_list(self, opnum, result_type, valueboxes, descr): if result_type == 'void': result = None @@ -66,128 +71,159 @@ else: results = [result] operations = [ResOperation(opnum, valueboxes, result), - ResOperation(rop.FAIL, results, None)] + ResOperation(rop.FAIL, results, None, + descr=FailDescr())] operations[0].descr = descr if operations[0].is_guard(): operations[0].suboperations = [ResOperation(rop.FAIL, - [ConstInt(-13)], None)] - loop = TreeLoop('single op') - loop.operations = operations - loop.inputargs = [] + [ConstInt(-13)], None, + descr=FailDescr())] + inputargs = [] for box in valueboxes: if isinstance(box, Box): - assert box not in loop.inputargs, "repeated box!" - loop.inputargs.append(box) - return loop + assert box not in inputargs, "repeated box!" + inputargs.append(box) + return inputargs, operations class BaseBackendTest(Runner): def test_compile_linear_loop(self): - loop = TreeLoop('single op') i0 = BoxInt() i1 = BoxInt() - loop.operations = [ + faildescr = FailDescr() + operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), - ResOperation(rop.FAIL, [i1], None) + ResOperation(rop.FAIL, [i1], None, descr=faildescr) ] - loop.inputargs = [i0] - executable_token = self.cpu.compile_loop(loop) + inputargs = [i0] + executable_token = self.cpu.compile_loop(inputargs, operations) self.cpu.set_future_value_int(0, 2) - fail_op = self.cpu.execute_token(executable_token) - assert fail_op is loop.operations[-1] # xxx unhappy + fail = self.cpu.execute_token(executable_token) + assert fail is faildescr res = self.cpu.get_latest_value_int(0) assert res == 3 def test_compile_loop(self): - loop = TreeLoop('single op') i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() - loop.operations = [ + faildescr = FailDescr() + operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.GUARD_TRUE, [i2], None), ResOperation(rop.JUMP, [i1], None), ] - loop.inputargs = [i0] - loop.operations[2].suboperations = [ - ResOperation(rop.FAIL, [i1], None) + inputargs = [i0] + operations[2].suboperations = [ + ResOperation(rop.FAIL, [i1], None, descr=faildescr) ] - loop.operations[-1].jump_target = None + operations[-1].jump_target = None - executable_token = self.cpu.compile_loop(loop) + executable_token = self.cpu.compile_loop(inputargs, operations) self.cpu.set_future_value_int(0, 2) - fail_op = self.cpu.execute_token(executable_token) - assert fail_op is loop.operations[2].suboperations[-1] # xxx unhappy + fail = self.cpu.execute_token(executable_token) + assert fail is faildescr res = self.cpu.get_latest_value_int(0) assert res == 10 def test_backends_dont_keep_loops_alive(self): import weakref, gc - loop = TreeLoop('single op') i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() - loop.operations = [ + faildescr = FailDescr() + operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.GUARD_TRUE, [i2], None), ResOperation(rop.JUMP, [i1], None), ] - loop.inputargs = [i0] - loop.operations[2].suboperations = [ - ResOperation(rop.FAIL, [i1], None) + inputargs = [i0] + operations[2].suboperations = [ + ResOperation(rop.FAIL, [i1], None, descr=faildescr) ] - loop.operations[-1].jump_target = None - - executable_token = self.cpu.compile_loop(loop) - wr = weakref.ref(loop) - del loop + operations[-1].jump_target = None + wr_i1 = weakref.ref(i1) + wr_guard = weakref.ref(operations[2]) + wr_fail = weakref.ref(operations[2].suboperations[0]) + executable_token = self.cpu.compile_loop(inputargs, operations) + del i0, i1, i2 + del inputargs + del operations gc.collect() - assert not wr() + assert not wr_i1() and not wr_guard() and not wr_fail() def test_compile_bridge(self): - loop = TreeLoop('single op') i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() - loop.operations = [ + faildescr1 = FailDescr() + faildescr2 = FailDescr() + operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.GUARD_TRUE, [i2], None), ResOperation(rop.JUMP, [i1], None), ] - loop.inputargs = [i0] - loop.operations[2].suboperations = [ - ResOperation(rop.FAIL, [i1], None) + inputargs = [i0] + operations[2].suboperations = [ + ResOperation(rop.FAIL, [i1], None, descr=faildescr1) ] - loop.operations[-1].jump_target = None - executable_token = self.cpu.compile_loop(loop) + operations[-1].jump_target = None + executable_token = self.cpu.compile_loop(inputargs, operations) loop_token = LoopToken() loop_token.executable_token = executable_token + i1b = BoxInt() i3 = BoxInt() bridge = [ - ResOperation(rop.INT_LE, [i1, ConstInt(19)], i3), + ResOperation(rop.INT_LE, [i1b, ConstInt(19)], i3), ResOperation(rop.GUARD_TRUE, [i3], None), - ResOperation(rop.JUMP, [i1], None), + ResOperation(rop.JUMP, [i1b], None), ] bridge[1].suboperations = [ - ResOperation(rop.FAIL, [i1], None) + ResOperation(rop.FAIL, [i1b], None, descr=faildescr2) ] bridge[-1].jump_target = loop_token - # xxx unhappy - guard_op = loop.operations[2] - guard_op.suboperations = bridge - self.cpu.compile_bridge(guard_op) + self.cpu.compile_bridge(faildescr1, [i1b], bridge) self.cpu.set_future_value_int(0, 2) - fail_op = self.cpu.execute_token(executable_token) - assert fail_op is bridge[1].suboperations[-1] # xxx unhappy + fail = self.cpu.execute_token(executable_token) + assert fail is faildescr2 res = self.cpu.get_latest_value_int(0) assert res == 20 - + + def test_finish(self): + i0 = BoxInt() + faildescr = AbstractDescr() # to check that is not touched + operations = [ + ResOperation(rop.FINISH, [i0], None, descr=faildescr) + ] + executable_token = self.cpu.compile_loop([i0], operations) + self.cpu.set_future_value_int(0, 99) + fail = self.cpu.execute_token(executable_token) + assert fail is faildescr + res = self.cpu.get_latest_value_int(0) + assert res == 99 + + operations = [ + ResOperation(rop.FINISH, [ConstInt(42)], None, descr=faildescr) + ] + executable_token = self.cpu.compile_loop([], operations) + fail = self.cpu.execute_token(executable_token) + assert fail is faildescr + res = self.cpu.get_latest_value_int(0) + assert res == 42 + + operations = [ + ResOperation(rop.FINISH, [], None, descr=faildescr) + ] + executable_token = self.cpu.compile_loop([], operations) + fail = self.cpu.execute_token(executable_token) + assert fail is faildescr + def test_do_call(self): cpu = self.cpu # @@ -360,32 +396,31 @@ ops = [ ResOperation(opnum, [v1, v2], v_res), ResOperation(rop.GUARD_NO_OVERFLOW, [], None), - ResOperation(rop.FAIL, [v_res], None), + ResOperation(rop.FAIL, [v_res], None, descr=FailDescr()), ] - ops[1].suboperations = [ResOperation(rop.FAIL, [], None)] + ops[1].suboperations = [ResOperation(rop.FAIL, [], None, + descr=FailDescr())] else: v_exc = self.cpu.ts.BoxRef() ops = [ ResOperation(opnum, [v1, v2], v_res), ResOperation(rop.GUARD_OVERFLOW, [], None), - ResOperation(rop.FAIL, [], None), + ResOperation(rop.FAIL, [], None, descr=FailDescr()), ] - ops[1].suboperations = [ResOperation(rop.FAIL, [v_res], None)] + ops[1].suboperations = [ResOperation(rop.FAIL, [v_res], None, + descr=FailDescr())] # - loop = TreeLoop('name') - loop.operations = ops - loop.inputargs = [v1, v2] - executable_token = self.cpu.compile_loop(loop) + executable_token = self.cpu.compile_loop([v1, v2], ops) for x, y, z in testcases: assert not self.cpu.get_exception() assert not self.cpu.get_exc_value() self.cpu.set_future_value_int(0, x) self.cpu.set_future_value_int(1, y) - op = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(executable_token) if (z == boom) ^ reversed: - assert op is ops[1].suboperations[0] + assert fail is ops[1].suboperations[0].descr else: - assert op is ops[-1] + assert fail is ops[-1].descr if z != boom: assert self.cpu.get_latest_value_int(0) == z assert not self.cpu.get_exception() @@ -1015,7 +1050,8 @@ exc_tp = xtp exc_ptr = xptr loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop) + executable_token = self.cpu.compile_loop(loop.inputargs, + loop.operations) self.cpu.set_future_value_int(0, 1) self.cpu.execute_token(executable_token) assert self.cpu.get_latest_value_int(0) == 0 @@ -1038,7 +1074,8 @@ exc_tp = ytp exc_ptr = yptr loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop) + executable_token = self.cpu.compile_loop(loop.inputargs, + loop.operations) self.cpu.set_future_value_int(0, 1) self.cpu.execute_token(executable_token) assert self.cpu.get_latest_value_int(0) == 1 @@ -1054,7 +1091,8 @@ fail(0) ''' loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop) + executable_token = self.cpu.compile_loop(loop.inputargs, + loop.operations) self.cpu.set_future_value_int(0, 1) self.cpu.execute_token(executable_token) assert self.cpu.get_latest_value_int(0) == 1 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/test_ll_random.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/test_ll_random.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/test_ll_random.py Wed Sep 23 20:24:08 2009 @@ -1,6 +1,7 @@ import py from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rffi, rstr from pypy.jit.backend.test import test_random +from pypy.jit.backend.test.test_random import FailDescr from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.history import ConstInt, ConstPtr, ConstAddr, BoxPtr,\ BoxInt @@ -449,7 +450,8 @@ descr = builder.cpu.calldescrof(TP, TP.ARGS, TP.RESULT) self.put(builder, args, descr) op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None) - op.suboperations = [ResOperation(rop.FAIL, fail_subset, None)] + op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, + descr=FailDescr())] builder.loop.operations.append(op) # 5. Non raising-call and GUARD_EXCEPTION @@ -471,7 +473,8 @@ exc_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr()) subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None)] + op.suboperations = [ResOperation(rop.FAIL, subset, None, + descr=FailDescr())] op._exc_box = None builder.should_fail_by = op.suboperations[0] builder.guard_op = op @@ -493,7 +496,8 @@ assert builder.cpu.get_exception() builder.cpu.clear_exception() op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr()) - op.suboperations = [ResOperation(rop.FAIL, fail_subset, None)] + op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, + descr=FailDescr())] builder.loop.operations.append(op) # 4. raising call and guard_no_exception @@ -512,7 +516,8 @@ op = ResOperation(rop.GUARD_NO_EXCEPTION, [], BoxPtr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None)] + op.suboperations = [ResOperation(rop.FAIL, subset, None, + descr=FailDescr())] builder.should_fail_by = op.suboperations[0] builder.guard_op = op builder.loop.operations.append(op) @@ -538,7 +543,8 @@ op = ResOperation(rop.GUARD_EXCEPTION, [other_box], BoxPtr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None)] + op.suboperations = [ResOperation(rop.FAIL, subset, None, + descr=FailDescr())] builder.should_fail_by = op.suboperations[0] builder.guard_op = op builder.loop.operations.append(op) Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py Wed Sep 23 20:24:08 2009 @@ -2,12 +2,15 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT from pypy.rpython.lltypesystem import llmemory from pypy.jit.backend.test import conftest as demo_conftest -from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt, LoopToken +from pypy.jit.metainterp.history import AbstractFailDescr, TreeLoop +from pypy.jit.metainterp.history import BoxInt, ConstInt, LoopToken from pypy.jit.metainterp.history import BoxPtr, ConstPtr, ConstAddr from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.executor import execute_nonspec from pypy.jit.metainterp.resoperation import opname +FailDescr = AbstractFailDescr + class PleaseRewriteMe(Exception): pass @@ -139,11 +142,10 @@ print_loop_prebuilt(self.loop.operations) # print >>s, ' cpu = CPU(None, None)' - print >>s, " loop = TreeLoop('test')" if hasattr(self.loop, 'inputargs'): - print >>s, ' loop.inputargs = [%s]' % ( + print >>s, ' inputargs = [%s]' % ( ', '.join([names[v] for v in self.loop.inputargs])) - print >>s, ' loop.operations = [' + print >>s, ' operations = [' for op in self.loop.operations: self.process_operation(s, op, names, subops) print >>s, ' ]' @@ -156,10 +158,10 @@ # continue # XXX #[op] = op.suboperations #assert op.opnum == rop.FAIL - #print >>s, ' loop.operations[%d].suboperations = [' % i + #print >>s, ' operations[%d].suboperations = [' % i #print >>s, ' ResOperation(rop.FAIL, [%s], None)]' % ( # ', '.join([names[v] for v in op.args])) - print >>s, ' executable_token = cpu.compile_loop(loop)' + print >>s, ' executable_token = cpu.compile_loop(inputargs, operations)' if hasattr(self.loop, 'inputargs'): for i, v in enumerate(self.loop.inputargs): print >>s, ' cpu.set_future_value_int(%d, %d)' % (i, @@ -246,7 +248,8 @@ builder.intvars[:] = original_intvars else: op = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) - op.suboperations = [ResOperation(rop.FAIL, fail_subset, None)] + op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, + descr=FailDescr())] builder.loop.operations.append(op) class BinaryOvfOperation(AbstractOvfOperation, BinaryOperation): @@ -264,7 +267,8 @@ op, passing = self.gen_guard(builder, r) builder.loop.operations.append(op) subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None)] + op.suboperations = [ResOperation(rop.FAIL, subset, None, + descr=FailDescr())] if not passing: builder.should_fail_by = op.suboperations[0] builder.guard_op = op @@ -405,7 +409,8 @@ self.generate_ops(builder, r, loop, startvars) self.builder = builder self.loop = loop - self.executable_token = cpu.compile_loop(loop) + self.executable_token = cpu.compile_loop(loop.inputargs, + loop.operations) def generate_ops(self, builder, r, loop, startvars): block_length = demo_conftest.option.block_length @@ -426,7 +431,8 @@ if v not in used_later: endvars.append(v) r.shuffle(endvars) - loop.operations.append(ResOperation(rop.FAIL, endvars, None)) + loop.operations.append(ResOperation(rop.FAIL, endvars, None, + descr=FailDescr())) if builder.should_fail_by: self.should_fail_by = builder.should_fail_by self.guard_op = builder.guard_op @@ -458,9 +464,9 @@ for i, v in enumerate(self.values): cpu.set_future_value_int(i, v) - op = cpu.execute_token(self.executable_token) - assert op is self.should_fail_by - for i, v in enumerate(op.args): + fail = cpu.execute_token(self.executable_token) + assert fail is self.should_fail_by.descr + for i, v in enumerate(self.should_fail_by.args): value = cpu.get_latest_value_int(i) assert value == self.expected[v], ( "Got %d, expected %d for value #%d" % (value, @@ -485,13 +491,16 @@ else: op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box], BoxPtr()) - op.suboperations = [ResOperation(rop.FAIL, [], None)] + op.suboperations = [ResOperation(rop.FAIL, [], None, + descr=FailDescr())] return op if self.dont_generate_more: return False r = self.r guard_op = self.guard_op + fail_args = guard_op.suboperations[-1].args + fail_descr = guard_op.suboperations[-1].descr guard_op.suboperations = [] op = self.should_fail_by if not op.args: @@ -508,17 +517,20 @@ if len(subset) == 0: return False args = [x.clonebox() for x in subset] - jump_target = RandomLoop(self.builder.cpu, self.builder.fork, + rl = RandomLoop(self.builder.cpu, self.builder.fork, r, args) - executable_token = self.cpu.compile_loop(jump_target.loop) + executable_token = self.cpu.compile_loop(rl.loop.inputargs, + rl.loop.operations) jump_op = ResOperation(rop.JUMP, subset, None) jump_op.jump_target = LoopToken() jump_op.jump_target.executable_token = executable_token - self.should_fail_by = jump_target.should_fail_by - self.expected = jump_target.expected + self.should_fail_by = rl.should_fail_by + self.expected = rl.expected if self.guard_op is None: guard_op.suboperations[-1] = jump_op else: + print "fix me, I'm a mess" + return False # XXX fix me self.guard_op.suboperations[0].args.extend(subset) self.builder.cpu.compile_bridge(guard_op) if self.guard_op.is_guard_exception(): @@ -528,13 +540,14 @@ self.guard_op.suboperations[-1] = jump_op self.builder.cpu.compile_bridge(self.guard_op) dont_compile = True - self.guard_op = jump_target.guard_op - self.prebuilt_ptr_consts += jump_target.prebuilt_ptr_consts + self.guard_op = rl.guard_op + self.prebuilt_ptr_consts += rl.prebuilt_ptr_consts self.dont_generate_more = True if r.random() < .05: return False if not dont_compile: - self.builder.cpu.compile_bridge(guard_op) + self.builder.cpu.compile_bridge(fail_descr, fail_args, + guard_op.suboperations) # xxx insane return True def check_random_function(cpu, BuilderClass, r, num=None, max=None): Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py Wed Sep 23 20:24:08 2009 @@ -6,8 +6,8 @@ from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.history import TreeLoop, log, Box, History, LoopToken -from pypy.jit.metainterp.history import AbstractDescr, BoxInt, BoxPtr, BoxObj,\ - BoxFloat, Const +from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt +from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const from pypy.jit.metainterp import history from pypy.jit.metainterp.specnode import NotSpecNode from pypy.jit.metainterp.typesystem import llhelper, oohelper @@ -23,7 +23,7 @@ errmsg += ': ' + str(error) else: errmsg = None - if loop is None or type(loop) is TerminatingLoop: + if loop is None: # or type(loop) is TerminatingLoop: extraloops = [] else: extraloops = [loop] @@ -66,6 +66,8 @@ loop_token = LoopToken() loop_token.specnodes = loop.specnodes loop_token.executable_token = executable_token + if not we_are_translated(): + loop.token = loop_token old_loop_tokens.append(loop_token) return loop_token @@ -74,7 +76,8 @@ if not we_are_translated(): show_loop(metainterp, loop) loop.check_consistency() - executable_token = metainterp.cpu.compile_loop(loop) + executable_token = metainterp.cpu.compile_loop(loop.inputargs, + loop.operations) metainterp.staticdata.profiler.end_backend() metainterp.staticdata.stats.add_new_loop(loop) if not we_are_translated(): @@ -89,13 +92,13 @@ debug_print("compiled new " + type) return executable_token -def send_bridge_to_backend(metainterp, guard_op): +def send_bridge_to_backend(metainterp, faildescr, inputargs, operations): metainterp.staticdata.profiler.start_backend() if not we_are_translated(): show_loop(metainterp) - #TreeLoop.check_consistency_of(xxx unhappy, guard_op.suboperations) + TreeLoop.check_consistency_of(inputargs, operations) pass - metainterp.cpu.compile_bridge(guard_op) + metainterp.cpu.compile_bridge(faildescr, inputargs, operations) metainterp.staticdata.profiler.end_backend() if not we_are_translated(): metainterp.staticdata.stats.compiled() @@ -107,55 +110,34 @@ # ____________________________________________________________ -class DoneWithThisFrameDescrVoid(AbstractDescr): - def handle_fail_op(self, metainterp_sd, fail_op): +class DoneWithThisFrameDescrVoid(AbstractFailDescr): + def handle_fail(self, metainterp_sd): assert metainterp_sd.result_type == 'void' raise metainterp_sd.DoneWithThisFrameVoid() -class DoneWithThisFrameDescrInt(AbstractDescr): - def handle_fail_op(self, metainterp_sd, fail_op): +class DoneWithThisFrameDescrInt(AbstractFailDescr): + def handle_fail(self, metainterp_sd): assert metainterp_sd.result_type == 'int' - resultbox = fail_op.args[0] - if isinstance(resultbox, BoxInt): - result = metainterp_sd.cpu.get_latest_value_int(0) - else: - assert isinstance(resultbox, history.Const) - result = resultbox.getint() + result = metainterp_sd.cpu.get_latest_value_int(0) raise metainterp_sd.DoneWithThisFrameInt(result) -class DoneWithThisFrameDescrRef(AbstractDescr): - def handle_fail_op(self, metainterp_sd, fail_op): +class DoneWithThisFrameDescrRef(AbstractFailDescr): + def handle_fail(self, metainterp_sd): assert metainterp_sd.result_type == 'ref' - resultbox = fail_op.args[0] cpu = metainterp_sd.cpu - if isinstance(resultbox, cpu.ts.BoxRef): - result = cpu.get_latest_value_ref(0) - else: - assert isinstance(resultbox, history.Const) - result = resultbox.getref_base() + result = cpu.get_latest_value_ref(0) raise metainterp_sd.DoneWithThisFrameRef(cpu, result) -class DoneWithThisFrameDescrFloat(AbstractDescr): - def handle_fail_op(self, metainterp_sd, fail_op): +class DoneWithThisFrameDescrFloat(AbstractFailDescr): + def handle_fail(self, metainterp_sd): assert metainterp_sd.result_type == 'float' - resultbox = fail_op.args[0] - if isinstance(resultbox, BoxFloat): - result = metainterp_sd.cpu.get_latest_value_float(0) - else: - assert isinstance(resultbox, history.Const) - result = resultbox.getfloat() + result = metainterp_sd.cpu.get_latest_value_float(0) raise metainterp_sd.DoneWithThisFrameFloat(result) -class ExitFrameWithExceptionDescrRef(AbstractDescr): - def handle_fail_op(self, metainterp_sd, fail_op): - assert len(fail_op.args) == 1 - valuebox = fail_op.args[0] +class ExitFrameWithExceptionDescrRef(AbstractFailDescr): + def handle_fail(self, metainterp_sd): cpu = metainterp_sd.cpu - if isinstance(valuebox, cpu.ts.BoxRef): - value = cpu.get_latest_value_ref(0) - else: - assert isinstance(valuebox, history.Const) - value = valuebox.getref_base() + value = cpu.get_latest_value_ref(0) raise metainterp_sd.ExitFrameWithExceptionRef(cpu, value) done_with_this_frame_descr_void = DoneWithThisFrameDescrVoid() @@ -168,6 +150,8 @@ prebuiltNotSpecNode = NotSpecNode() class TerminatingLoopToken(LoopToken): + terminating = True + def __init__(self, nargs, finishdescr): self.specnodes = [prebuiltNotSpecNode]*nargs self.finishdescr = finishdescr @@ -176,11 +160,7 @@ loop_tokens_done_with_this_frame_int = [ TerminatingLoopToken(1, done_with_this_frame_descr_int) ] -# xxx they are the same now -llhelper.loop_tokens_done_with_this_frame_ref = [ - TerminatingLoopToken(1, done_with_this_frame_descr_ref) - ] -oohelper.loop_tokens_done_with_this_frame_ref = [ +loop_tokens_done_with_this_frame_ref = [ TerminatingLoopToken(1, done_with_this_frame_descr_ref) ] loop_tokens_done_with_this_frame_float = [ @@ -189,15 +169,11 @@ loop_tokens_done_with_this_frame_void = [ TerminatingLoopToken(0, done_with_this_frame_descr_void) ] -# xxx they are the same now -llhelper.loop_tokens_exit_frame_with_exception_ref = [ - TerminatingLoopToken(1, exit_frame_with_exception_descr_ref) - ] -oohelper.loop_tokens_exit_frame_with_exception_ref = [ +loop_tokens_exit_frame_with_exception_ref = [ TerminatingLoopToken(1, exit_frame_with_exception_descr_ref) ] -class ResumeDescr(AbstractDescr): +class ResumeDescr(AbstractFailDescr): def __init__(self, original_greenkey): self.original_greenkey = original_greenkey @@ -209,9 +185,10 @@ self.guard_op = guard_op # this class also gets attributes stored by ResumeDataBuilder.finish() - def handle_fail_op(self, metainterp_sd, fail_op): + def handle_fail(self, metainterp_sd): from pypy.jit.metainterp.pyjitpl import MetaInterp metainterp = MetaInterp(metainterp_sd) + fail_op = self.get_guard_op().suboperations[-1] # xxx unhappy patch = self.patch_boxes_temporarily(metainterp_sd, fail_op) try: return metainterp.handle_guard_failure(fail_op, self) @@ -268,8 +245,10 @@ # to the corrsponding guard_op and compile from there # xxx unhappy guard_op = self.get_guard_op() - guard_op.suboperations = new_loop.operations - send_bridge_to_backend(metainterp, guard_op) + fail_args = guard_op.suboperations[-1].args + if not we_are_translated(): + guard_op._debug_suboperations = new_loop.operations + send_bridge_to_backend(metainterp, self, fail_args, new_loop.operations) class ResumeFromInterpDescr(ResumeDescr): def __init__(self, original_greenkey, redkey): @@ -332,5 +311,5 @@ # e.g. loop_tokens_done_with_this_frame_void[0] # Replace the operation with the real operation we want, i.e. a FAIL. descr = target_loop_token.finishdescr - new_op = ResOperation(rop.FAIL, op.args, None, descr=descr) + new_op = ResOperation(rop.FINISH, op.args, None, descr=descr) new_loop.operations[-1] = new_op Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/graphpage.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/graphpage.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/graphpage.py Wed Sep 23 20:24:08 2009 @@ -4,8 +4,6 @@ from pypy.jit.metainterp.history import Box from pypy.jit.metainterp.resoperation import rop -SHOW_FAILS = False - class SubGraph: def __init__(self, suboperations): self.suboperations = suboperations @@ -15,24 +13,17 @@ return None def display_loops(loops, errmsg=None, highlight_loops=()): - graphs = [(loop, loop in highlight_loops) for loop in loops] + graphs = [(loop, loop in highlight_loops) for loop in loops] for graph, highlight in graphs: for op in graph.get_operations(): if is_interesting_guard(op): - graphs.append((SubGraph(op.suboperations), highlight)) + graphs.append((SubGraph(op._debug_suboperations), + highlight)) graphpage = ResOpGraphPage(graphs, errmsg) graphpage.display() def is_interesting_guard(op): - if not op.is_guard(): - return False - if SHOW_FAILS: - return True - if len(op.suboperations) > 1: - return True - if op.suboperations[0].opnum == rop.FAIL: - return False - return True + return hasattr(op, '_debug_suboperations') class ResOpGraphPage(GraphPage): @@ -40,6 +31,10 @@ def compute(self, graphs, errmsg=None): resopgen = ResOpGen() for graph, highlight in graphs: + if hasattr(graph, 'token'): + resopgen.jumps_to_graphs[graph.token] = graph + + for graph, highlight in graphs: resopgen.add_graph(graph, highlight) if errmsg: resopgen.set_errmsg(errmsg) @@ -57,6 +52,7 @@ self.block_starters = {} # {graphindex: {set-of-operation-indices}} self.all_operations = {} self.errmsg = None + self.jumps_to_graphs = {} def op_name(self, graphindex, opindex): return 'g%dop%d' % (graphindex, opindex) @@ -159,7 +155,7 @@ op = operations[opindex] lines.append(repr(op)) if is_interesting_guard(op): - tgt = op.suboperations[0] + tgt = op._debug_suboperations[0] tgt_g, tgt_i = self.all_operations[tgt] self.genedge((graphindex, opstartindex), (tgt_g, tgt_i), @@ -171,12 +167,19 @@ self.genedge((graphindex, opstartindex), (graphindex, opindex)) break - tgt = getattr(op, 'jump_target', None) - if tgt is not None and tgt in self.graphs: - tgt_g = self.graphs.index(tgt) - self.genedge((graphindex, opstartindex), - (tgt_g, 0), - weight="0") + if op.opnum == rop.JUMP: + tgt = op.jump_target + tgt_g = -1 + if tgt is None: + tgt_g = graphindex + else: + tgt = self.jumps_to_graphs.get(tgt) + if tgt is not None: + tgt_g = self.graphs.index(tgt) + if tgt_g != -1: + self.genedge((graphindex, opstartindex), + (tgt_g, 0), + weight="0") lines.append("") label = "\\l".join(lines) kwds = {} Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py Wed Sep 23 20:24:08 2009 @@ -126,6 +126,9 @@ def repr_of_descr(self): return '%r' % (self,) +class AbstractFailDescr(AbstractDescr): + pass + class AbstractMethDescr(AbstractDescr): # the base class of the result of cpu.methdescrof() jitcodes = None @@ -664,6 +667,7 @@ class LoopToken(object): """loop token""" + terminating = False # see TerminatingLoopToken in compile.py # specnodes # executable_token @@ -726,8 +730,11 @@ assert box in seen assert (op.suboperations is not None) == op.is_guard() if op.is_guard(): - TreeLoop.check_consistency_of_branch(op.suboperations, - seen.copy()) + if hasattr(op, '_debug_suboperations'): + ops = op._debug_suboperations + else: + ops = op.suboperations + TreeLoop.check_consistency_of_branch(ops, seen.copy()) box = op.result if box is not None: assert isinstance(box, Box) @@ -759,12 +766,19 @@ return '<%s>' % (self.name,) def _list_all_operations(result, operations, omit_fails=True): - if omit_fails and operations[-1].opnum == rop.FAIL: + if omit_fails and operations[-1].opnum in (rop.FAIL, rop.FINISH): + # xxx obscure return result.extend(operations) for op in operations: if op.is_guard(): - _list_all_operations(result, op.suboperations, omit_fails) + if hasattr(op, '_debug_suboperations'): + ops = op._debug_suboperations + else: + if omit_fails: + continue + ops = op.suboperations + _list_all_operations(result, ops, omit_fails) # ____________________________________________________________ @@ -884,7 +898,7 @@ def view(self, errmsg=None, extraloops=[]): from pypy.jit.metainterp.graphpage import display_loops - loops = self.get_all_loops() + loops = self.get_all_loops()[:] for loop in extraloops: if loop in loops: loops.remove(loop) Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py Wed Sep 23 20:24:08 2009 @@ -1505,7 +1505,7 @@ loop_tokens = compile.loop_tokens_done_with_this_frame_int elif sd.result_type == 'ref': exits = [exitbox] - loop_tokens = sd.cpu.ts.loop_tokens_done_with_this_frame_ref + loop_tokens = compile.loop_tokens_done_with_this_frame_ref elif sd.result_type == 'float': exits = [exitbox] loop_tokens = compile.loop_tokens_done_with_this_frame_float @@ -1520,7 +1520,7 @@ self.gen_store_back_in_virtualizable() # temporarily put a JUMP to a pseudo-loop self.history.record(rop.JUMP, [valuebox], None) - loop_tokens = self.cpu.ts.loop_tokens_exit_frame_with_exception_ref + loop_tokens = compile.loop_tokens_exit_frame_with_exception_ref target_loop_token = compile.compile_new_bridge(self, loop_tokens, self.resumekey) assert target_loop_token is loop_tokens[0] Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/resoperation.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/resoperation.py Wed Sep 23 20:24:08 2009 @@ -106,6 +106,7 @@ '_FINAL_FIRST', 'JUMP', 'FAIL', + 'FINISH', '_FINAL_LAST', '_GUARD_FIRST', Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py Wed Sep 23 20:24:08 2009 @@ -4,7 +4,7 @@ """ from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ - ConstAddr, ConstObj, ConstPtr, Box + ConstAddr, ConstObj, ConstPtr, Box, AbstractFailDescr from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.typesystem import llhelper from pypy.rpython.lltypesystem import lltype, llmemory @@ -21,6 +21,9 @@ class Boxes(object): pass +FailDescr = AbstractFailDescr + + class ExtendedTreeLoop(TreeLoop): def getboxes(self): @@ -51,7 +54,7 @@ getattr(boxes, name).value = value class OpParser(object): - def __init__(self, descr, cpu, namespace, type_system, boxkinds, jump_targets): + def __init__(self, descr, cpu, namespace, type_system, boxkinds, jump_targets, invent_fail_descrs=True): self.descr = descr self.vars = {} self.cpu = cpu @@ -60,6 +63,7 @@ self.boxkinds = boxkinds or {} self.jumps = [] self.jump_targets = jump_targets + self.invent_fail_descrs = invent_fail_descrs def box_for_var(self, elem): try: @@ -144,30 +148,32 @@ endnum = line.rfind(')') if endnum == -1: raise ParseError("invalid line: %s" % line) - argspec = line[num + 1:endnum] - if not argspec.strip(): - return opnum, [], None - if opname == 'debug_merge_point': - allargs = [argspec] - else: - allargs = argspec.split(",") args = [] descr = None - poss_descr = allargs[-1].strip() - if poss_descr.startswith('descr='): - if poss_descr.startswith('descr=<'): - descr = None + argspec = line[num + 1:endnum] + if argspec.strip(): + if opname == 'debug_merge_point': + allargs = [argspec] else: - descr = self.consts[poss_descr[len('descr='):]] - allargs = allargs[:-1] - for arg in allargs: - arg = arg.strip() - try: - args.append(self.getvar(arg)) - except KeyError: - raise ParseError("Unknown var: %s" % arg) - if hasattr(descr, '_oparser_uses_descr'): - descr._oparser_uses_descr(self, args) + allargs = argspec.split(",") + + poss_descr = allargs[-1].strip() + if poss_descr.startswith('descr='): + if poss_descr.startswith('descr=<'): + descr = None + else: + descr = self.consts[poss_descr[len('descr='):]] + allargs = allargs[:-1] + for arg in allargs: + arg = arg.strip() + try: + args.append(self.getvar(arg)) + except KeyError: + raise ParseError("Unknown var: %s" % arg) + if hasattr(descr, '_oparser_uses_descr'): + descr._oparser_uses_descr(self, args) + if opnum == rop.FAIL and descr is None and self.invent_fail_descrs: + descr = FailDescr() return opnum, args, descr def parse_result_op(self, line): @@ -260,10 +266,14 @@ return base_indent, inpargs def parse(descr, cpu=None, namespace=None, type_system='lltype', - boxkinds=None, jump_targets=None): + boxkinds=None, jump_targets=None, invent_fail_descrs=True): if namespace is None: namespace = _default_namespace[type_system] - return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_targets).parse() + return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_targets, invent_fail_descrs).parse() + +def pure_parse(*args, **kwds): + kwds['invent_fail_descrs'] = False + return parse(*args, **kwds) def _box_counter_more_than(s): if s.isdigit(): Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_oparser.py Wed Sep 23 20:24:08 2009 @@ -18,6 +18,7 @@ assert [op.opnum for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, rop.FAIL] assert len(loop.inputargs) == 2 + assert loop.operations[-1].descr def test_const_ptr_subops(): x = """ @@ -30,6 +31,7 @@ loop = parse(x, None, locals()) assert len(loop.operations) == 1 assert len(loop.operations[0].suboperations) == 1 + assert loop.operations[0].suboperations[-1].descr def test_descr(): class Xyz(AbstractDescr): Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_optimizefindnode.py Wed Sep 23 20:24:08 2009 @@ -16,8 +16,7 @@ from pypy.jit.metainterp.specnode import VirtualArraySpecNode from pypy.jit.metainterp.specnode import VirtualStructSpecNode from pypy.jit.metainterp.specnode import ConstantSpecNode -from pypy.jit.metainterp.test.oparser import parse - +from pypy.jit.metainterp.test.oparser import pure_parse as parse def test_sort_descrs(): class PseudoDescr(AbstractDescr): Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_optimizeopt.py Wed Sep 23 20:24:08 2009 @@ -11,7 +11,8 @@ from pypy.jit.metainterp.history import AbstractDescr, ConstInt from pypy.jit.metainterp import resume, executor, compile from pypy.jit.metainterp.resoperation import rop, opname -from pypy.jit.metainterp.test.oparser import parse +from pypy.jit.metainterp.test.oparser import pure_parse as parse + # ____________________________________________________________ Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py Wed Sep 23 20:24:08 2009 @@ -848,11 +848,10 @@ # ---------- execute assembler ---------- while True: # until interrupted by an exception metainterp_sd.profiler.start_running() - # xxx unhappy - fail_op = metainterp_sd.cpu.execute_token(executable_token) + fail_descr = metainterp_sd.cpu.execute_token(executable_token) metainterp_sd.profiler.end_running() - executable_token = fail_op.descr.handle_fail_op(metainterp_sd, - fail_op) + executable_token = fail_descr.handle_fail(metainterp_sd) + maybe_compile_and_run._dont_inline_ = True def handle_hash_collision(self, firstcell, argshash, *args): From pedronis at codespeak.net Thu Sep 24 11:16:16 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 24 Sep 2009 11:16:16 +0200 (CEST) Subject: [pypy-svn] r67861 - in pypy/trunk/pypy/jit/backend/llvm: . test Message-ID: <20090924091616.CD70E168023@codespeak.net> Author: pedronis Date: Thu Sep 24 11:16:15 2009 New Revision: 67861 Added: pypy/trunk/pypy/jit/backend/llvm/test/conftest.py (props changed) - copied unchanged from r67860, pypy/trunk/pypy/jit/backend/llvm/conftest.py Removed: pypy/trunk/pypy/jit/backend/llvm/conftest.py Log: (micke, pedronis) fix the nightly run by moving the conftest so that py.test doesn't explode (confusing) From pedronis at codespeak.net Thu Sep 24 11:40:53 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 24 Sep 2009 11:40:53 +0200 (CEST) Subject: [pypy-svn] r67862 - in pypy/branch/remove-plfbid/pypy/jit: backend/llgraph backend/llsupport backend/test metainterp metainterp/test Message-ID: <20090924094053.85D3E16801B@codespeak.net> Author: pedronis Date: Thu Sep 24 11:40:52 2009 New Revision: 67862 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py pypy/branch/remove-plfbid/pypy/jit/backend/test/test_ll_random.py pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py Log: (micke, pedronis) test_finish was failing, fix it by clarifying a bit more the role of AbstractFailDescr and introducing a convenience BasicFailDescr Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/runner.py Thu Sep 24 11:40:52 2009 @@ -186,7 +186,7 @@ elif op.opnum == rop.FINISH: llimpl.compile_add_fail(c, len(self.fail_descrs)) faildescr = op.descr - assert isinstance(faildescr, history.AbstractFailDescr) + assert isinstance(faildescr, history.AbstractFailDescr) self.fail_descrs.append(faildescr) else: assert False, "unknown operation" Modified: pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/descr.py Thu Sep 24 11:40:52 2009 @@ -1,7 +1,7 @@ from pypy.rpython.lltypesystem import lltype from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr -from pypy.jit.metainterp.history import AbstractFailDescr +from pypy.jit.metainterp.history import BasicFailDescr from pypy.jit.metainterp.resoperation import ResOperation, rop # The point of the class organization in this file is to make instances @@ -202,9 +202,9 @@ ResOperation(rop.CALL, args, result, self), ResOperation(rop.GUARD_NO_EXCEPTION, [], None), ResOperation(rop.FAIL, result_list, None, - descr=AbstractFailDescr())] + descr=BasicFailDescr())] operations[1].suboperations = [ResOperation(rop.FAIL, [], None, - descr=AbstractFailDescr())] + descr=BasicFailDescr())] executable_token = cpu.compile_loop(args, operations) self.executable_token = executable_token return executable_token Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py Thu Sep 24 11:40:52 2009 @@ -1,9 +1,11 @@ import py, sys, random -from pypy.jit.metainterp.history import (AbstractDescr, AbstractFailDescr, +from pypy.jit.metainterp.history import (AbstractFailDescr, + BasicFailDescr, BoxInt, Box, BoxPtr, LoopToken, - ConstInt, ConstPtr, BoxObj, Const, + ConstInt, ConstPtr, + BoxObj, Const, ConstObj, BoxFloat, ConstFloat) from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.typesystem import deref @@ -15,8 +17,6 @@ from pypy.rpython.annlowlevel import llhelper from pypy.rpython.llinterp import LLException -FailDescr = AbstractFailDescr - class Runner(object): def execute_operation(self, opname, valueboxes, result_type, descr=None): @@ -72,12 +72,12 @@ results = [result] operations = [ResOperation(opnum, valueboxes, result), ResOperation(rop.FAIL, results, None, - descr=FailDescr())] + descr=BasicFailDescr())] operations[0].descr = descr if operations[0].is_guard(): operations[0].suboperations = [ResOperation(rop.FAIL, [ConstInt(-13)], None, - descr=FailDescr())] + descr=BasicFailDescr())] inputargs = [] for box in valueboxes: if isinstance(box, Box): @@ -90,7 +90,7 @@ def test_compile_linear_loop(self): i0 = BoxInt() i1 = BoxInt() - faildescr = FailDescr() + faildescr = BasicFailDescr() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.FAIL, [i1], None, descr=faildescr) @@ -107,7 +107,7 @@ i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() - faildescr = FailDescr() + faildescr = BasicFailDescr() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), @@ -132,7 +132,7 @@ i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() - faildescr = FailDescr() + faildescr = BasicFailDescr() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), @@ -158,8 +158,8 @@ i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() - faildescr1 = FailDescr() - faildescr2 = FailDescr() + faildescr1 = BasicFailDescr() + faildescr2 = BasicFailDescr() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), @@ -197,7 +197,7 @@ def test_finish(self): i0 = BoxInt() - faildescr = AbstractDescr() # to check that is not touched + faildescr = AbstractFailDescr() # to check that is not touched operations = [ ResOperation(rop.FINISH, [i0], None, descr=faildescr) ] @@ -396,19 +396,19 @@ ops = [ ResOperation(opnum, [v1, v2], v_res), ResOperation(rop.GUARD_NO_OVERFLOW, [], None), - ResOperation(rop.FAIL, [v_res], None, descr=FailDescr()), + ResOperation(rop.FAIL, [v_res], None, descr=BasicFailDescr()), ] ops[1].suboperations = [ResOperation(rop.FAIL, [], None, - descr=FailDescr())] + descr=BasicFailDescr())] else: v_exc = self.cpu.ts.BoxRef() ops = [ ResOperation(opnum, [v1, v2], v_res), ResOperation(rop.GUARD_OVERFLOW, [], None), - ResOperation(rop.FAIL, [], None, descr=FailDescr()), + ResOperation(rop.FAIL, [], None, descr=BasicFailDescr()), ] ops[1].suboperations = [ResOperation(rop.FAIL, [v_res], None, - descr=FailDescr())] + descr=BasicFailDescr())] # executable_token = self.cpu.compile_loop([v1, v2], ops) for x, y, z in testcases: Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/test_ll_random.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/test_ll_random.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/test_ll_random.py Thu Sep 24 11:40:52 2009 @@ -1,10 +1,10 @@ import py from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rffi, rstr from pypy.jit.backend.test import test_random -from pypy.jit.backend.test.test_random import FailDescr from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import ConstInt, ConstPtr, ConstAddr, BoxPtr,\ - BoxInt +from pypy.jit.metainterp.history import BasicFailDescr +from pypy.jit.metainterp.history import ConstInt, ConstPtr +from pypy.jit.metainterp.history import ConstAddr, BoxPtr, BoxInt from pypy.rpython.annlowlevel import llhelper from pypy.rlib.rarithmetic import intmask from pypy.rpython.llinterp import LLException @@ -451,7 +451,7 @@ self.put(builder, args, descr) op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None) op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, - descr=FailDescr())] + descr=BasicFailDescr())] builder.loop.operations.append(op) # 5. Non raising-call and GUARD_EXCEPTION @@ -474,7 +474,7 @@ op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr()) subset = builder.subset_of_intvars(r) op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=FailDescr())] + descr=BasicFailDescr())] op._exc_box = None builder.should_fail_by = op.suboperations[0] builder.guard_op = op @@ -497,7 +497,7 @@ builder.cpu.clear_exception() op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr()) op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, - descr=FailDescr())] + descr=BasicFailDescr())] builder.loop.operations.append(op) # 4. raising call and guard_no_exception @@ -517,7 +517,7 @@ op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) subset = builder.subset_of_intvars(r) op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=FailDescr())] + descr=BasicFailDescr())] builder.should_fail_by = op.suboperations[0] builder.guard_op = op builder.loop.operations.append(op) @@ -544,7 +544,7 @@ op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) subset = builder.subset_of_intvars(r) op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=FailDescr())] + descr=BasicFailDescr())] builder.should_fail_by = op.suboperations[0] builder.guard_op = op builder.loop.operations.append(op) Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py Thu Sep 24 11:40:52 2009 @@ -2,15 +2,13 @@ from pypy.rlib.rarithmetic import intmask, LONG_BIT from pypy.rpython.lltypesystem import llmemory from pypy.jit.backend.test import conftest as demo_conftest -from pypy.jit.metainterp.history import AbstractFailDescr, TreeLoop +from pypy.jit.metainterp.history import BasicFailDescr, TreeLoop from pypy.jit.metainterp.history import BoxInt, ConstInt, LoopToken from pypy.jit.metainterp.history import BoxPtr, ConstPtr, ConstAddr from pypy.jit.metainterp.resoperation import ResOperation, rop from pypy.jit.metainterp.executor import execute_nonspec from pypy.jit.metainterp.resoperation import opname -FailDescr = AbstractFailDescr - class PleaseRewriteMe(Exception): pass @@ -249,7 +247,7 @@ else: op = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, - descr=FailDescr())] + descr=BasicFailDescr())] builder.loop.operations.append(op) class BinaryOvfOperation(AbstractOvfOperation, BinaryOperation): @@ -268,7 +266,7 @@ builder.loop.operations.append(op) subset = builder.subset_of_intvars(r) op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=FailDescr())] + descr=BasicFailDescr())] if not passing: builder.should_fail_by = op.suboperations[0] builder.guard_op = op @@ -432,7 +430,7 @@ endvars.append(v) r.shuffle(endvars) loop.operations.append(ResOperation(rop.FAIL, endvars, None, - descr=FailDescr())) + descr=BasicFailDescr())) if builder.should_fail_by: self.should_fail_by = builder.should_fail_by self.guard_op = builder.guard_op @@ -492,7 +490,7 @@ op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box], BoxPtr()) op.suboperations = [ResOperation(rop.FAIL, [], None, - descr=FailDescr())] + descr=BasicFailDescr())] return op if self.dont_generate_more: Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py Thu Sep 24 11:40:52 2009 @@ -127,6 +127,9 @@ return '%r' % (self,) class AbstractFailDescr(AbstractDescr): + __slots__ = () + +class BasicFailDescr(AbstractFailDescr): pass class AbstractMethDescr(AbstractDescr): Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py Thu Sep 24 11:40:52 2009 @@ -4,7 +4,7 @@ """ from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ - ConstAddr, ConstObj, ConstPtr, Box, AbstractFailDescr + ConstAddr, ConstObj, ConstPtr, Box, BasicFailDescr from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.typesystem import llhelper from pypy.rpython.lltypesystem import lltype, llmemory @@ -21,9 +21,6 @@ class Boxes(object): pass -FailDescr = AbstractFailDescr - - class ExtendedTreeLoop(TreeLoop): def getboxes(self): @@ -173,7 +170,7 @@ if hasattr(descr, '_oparser_uses_descr'): descr._oparser_uses_descr(self, args) if opnum == rop.FAIL and descr is None and self.invent_fail_descrs: - descr = FailDescr() + descr = BasicFailDescr() return opnum, args, descr def parse_result_op(self, line): From fijal at codespeak.net Thu Sep 24 14:19:16 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 24 Sep 2009 14:19:16 +0200 (CEST) Subject: [pypy-svn] r67863 - pypy/branch/experiment-less-resumeinfo Message-ID: <20090924121916.F299C16801E@codespeak.net> Author: fijal Date: Thu Sep 24 14:19:16 2009 New Revision: 67863 Added: pypy/branch/experiment-less-resumeinfo/ - copied from r67862, pypy/trunk/ Log: A branch to experiment with sharing of resumedata From antocuni at codespeak.net Thu Sep 24 14:21:41 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 24 Sep 2009 14:21:41 +0200 (CEST) Subject: [pypy-svn] r67864 - pypy/trunk/pypy/jit/backend/cli Message-ID: <20090924122141.01A9116801E@codespeak.net> Author: antocuni Date: Thu Sep 24 14:21:41 2009 New Revision: 67864 Modified: pypy/trunk/pypy/jit/backend/cli/runner.py Log: display the name of the methods in the logs Modified: pypy/trunk/pypy/jit/backend/cli/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/cli/runner.py (original) +++ pypy/trunk/pypy/jit/backend/cli/runner.py Thu Sep 24 14:21:41 2009 @@ -409,6 +409,8 @@ def get_call_opcode(self): return OpCodes.Callvirt + def repr_of_descr(self): + return "'%s'" % self.methname class StringMethDescr(MethDescr): From fijal at codespeak.net Thu Sep 24 16:31:23 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 24 Sep 2009 16:31:23 +0200 (CEST) Subject: [pypy-svn] r67866 - pypy/branch/experiment-less-resumeinfo/pypy/jit/backend Message-ID: <20090924143123.6B195168022@codespeak.net> Author: fijal Date: Thu Sep 24 16:31:22 2009 New Revision: 67866 Added: pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/loopviewer.py (contents, props changed) Log: Resurrect loopviewer, because carl wants it. A fix that shows all pointers as null ptrs, but at least displays stuff. Added: pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/loopviewer.py ============================================================================== --- (empty file) +++ pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/loopviewer.py Thu Sep 24 16:31:22 2009 @@ -0,0 +1,34 @@ +#!/usr/bin/env python +""" Usage: loopviewer.py [loopnum] loopfile +""" + +import py +import sys +from pypy.jit.metainterp.test.oparser import parse +from pypy.jit.metainterp.history import ConstInt +from pypy.rpython.lltypesystem import llmemory, lltype + +class AllDict(dict): + def __getitem__(self, item): + return lltype.nullptr(llmemory.GCREF.TO) + +alldict = AllDict() + +def main(loopnum, loopfile): + data = py.path.local(loopfile).read() + loops = [i for i in data.split("[") if i] + inp = "[" + loops[loopnum] + loop = parse(inp, namespace=alldict) + loop.show() + +if __name__ == '__main__': + if len(sys.argv) == 2: + loopnum = -1 + loopfile = sys.argv[1] + elif len(sys.argv) == 3: + loopnum = int(sys.argv[1]) + loopfile = sys.argv[2] + else: + print __doc__ + sys.exit(1) + main(loopnum, loopfile) From cfbolz at codespeak.net Thu Sep 24 16:35:43 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 24 Sep 2009 16:35:43 +0200 (CEST) Subject: [pypy-svn] r67867 - pypy/trunk/pypy/jit/backend Message-ID: <20090924143543.D501B168022@codespeak.net> Author: cfbolz Date: Thu Sep 24 16:35:43 2009 New Revision: 67867 Added: pypy/trunk/pypy/jit/backend/loopviewer.py - copied unchanged from r67866, pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/loopviewer.py Log: copy loopviewer from maciej's branch From antocuni at codespeak.net Thu Sep 24 17:11:56 2009 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 24 Sep 2009 17:11:56 +0200 (CEST) Subject: [pypy-svn] r67868 - pypy/trunk/pypy/rpython/ootypesystem Message-ID: <20090924151156.C585E168027@codespeak.net> Author: antocuni Date: Thu Sep 24 17:11:56 2009 New Revision: 67868 Modified: pypy/trunk/pypy/rpython/ootypesystem/rpbc.py Log: make MultipleFrozenPBC immutable on ootype too Modified: pypy/trunk/pypy/rpython/ootypesystem/rpbc.py ============================================================================== --- pypy/trunk/pypy/rpython/ootypesystem/rpbc.py (original) +++ pypy/trunk/pypy/rpython/ootypesystem/rpbc.py Thu Sep 24 17:11:56 2009 @@ -182,7 +182,7 @@ def __init__(self, rtyper, access_set): self.rtyper = rtyper self.access_set = access_set - self.lowleveltype = ootype.Instance('pbc', PBCROOT) + self.lowleveltype = ootype.Instance('pbc', PBCROOT, _hints={'immutable': True}) self.pbc_cache = {} def _setup_repr(self): From pedronis at codespeak.net Thu Sep 24 17:35:31 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 24 Sep 2009 17:35:31 +0200 (CEST) Subject: [pypy-svn] r67869 - in pypy/branch/remove-plfbid/pypy/jit/backend: test x86 Message-ID: <20090924153531.3E3A916801F@codespeak.net> Author: pedronis Date: Thu Sep 24 17:35:30 2009 New Revision: 67869 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/runner.py Log: (micke, pedronis) WIP fixing the x86 backend, loops work, bridges mostly there Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py Thu Sep 24 17:35:30 2009 @@ -99,9 +99,9 @@ executable_token = self.cpu.compile_loop(inputargs, operations) self.cpu.set_future_value_int(0, 2) fail = self.cpu.execute_token(executable_token) - assert fail is faildescr res = self.cpu.get_latest_value_int(0) - assert res == 3 + assert res == 3 + assert fail is faildescr def test_compile_loop(self): i0 = BoxInt() @@ -129,6 +129,7 @@ def test_backends_dont_keep_loops_alive(self): import weakref, gc + self.cpu.dont_keepalive_stuff = True i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py Thu Sep 24 17:35:30 2009 @@ -63,6 +63,10 @@ if name.upper() == name: setattr(MachineCodeBlockWrapper, name, _new_method(name)) +class ExecutableToken386(object): + _x86_compiled = 0 + _x86_bootstrap_code = 0 + _x86_stack_depth = 0 class Assembler386(object): mc = None @@ -132,18 +136,36 @@ assert max_so_far < MAX_FAIL_BOXES return max_so_far - def assemble_loop(self, loop): - self.assemble(loop, loop.operations, None) + def assemble_loop(self, inputargs, operations): + self._compute_longest_fail_op(operations) + self.make_sure_mc_exists() + regalloc = RegAlloc(self, self.cpu.translate_support_code) + self._regalloc = regalloc + executable_token = regalloc.walk_operations(inputargs, operations) + self.mc.done() + self.mc2.done() + # possibly align, e.g. for Mac OS X + if we_are_translated() or self.cpu.dont_keepalive_stuff: + self._regalloc = None # else keep it around for debugging + return executable_token - def assemble_from_guard(self, tree, guard_op): - newaddr = self.assemble(tree, guard_op.suboperations, guard_op) + def assemble_bridge(self, faildescr, inputargs, operations): + self._compute_longest_fail_op(operations) + self.make_sure_mc_exists() + regalloc = RegAlloc(self, self.cpu.translate_support_code) + self._regalloc = regalloc + bridgeaddr = regalloc.walk_bridge(faildescr,inputargs, operations) + self.mc.done() + self.mc2.done() + if we_are_translated() or self.cpu.dont_keepalive_stuff: + self._regalloc = None # else keep it around for debugging # patch the jump from original guard - addr = guard_op._x86_addr + addr = faildescr._x86_addr mc = codebuf.InMemoryCodeBuilder(addr, addr + 128) - mc.write(packimm32(newaddr - addr - 4)) + mc.write(packimm32(bridgeddr - addr - 4)) mc.done() - def assemble(self, tree, operations, guard_op): + def xassemble(self, tree, operations, guard_op): # the last operation can be 'jump', 'return' or 'guard_pause'; # a 'jump' can either close a loop, or end a bridge to some # previously-compiled code. @@ -156,11 +178,9 @@ adr_lea = 0 if guard_op is None: inputargs = tree.inputargs - self.logger.log_loop(tree) regalloc.walk_operations(tree) else: inputargs = regalloc.inputargs - self.logger.log_operations(inputargs, guard_op.suboperations, {}) mc = self.mc._mc adr_lea = mc.tell() mc.LEA(esp, fixedsize_ebp_ofs(0)) @@ -183,7 +203,7 @@ self._regalloc = None # else keep it around for debugging return newpos - def assemble_bootstrap_code(self, jumpaddr, arglocs, args, framesize): + def assemble_bootstrap_code(self, jumpaddr, arglocs, argtypes, framesize): self.make_sure_mc_exists() addr = self.mc.tell() self.mc.PUSH(ebp) @@ -197,7 +217,7 @@ for i in range(len(arglocs)): loc = arglocs[i] if not isinstance(loc, REG): - if args[i].type == REF: + if argtypes[i] == REF: # This uses XCHG to put zeroes in fail_boxes_ptr after # reading them self.mc.XOR(ecx, ecx) @@ -210,7 +230,7 @@ for i in range(len(arglocs)): loc = arglocs[i] if isinstance(loc, REG): - if args[i].type == REF: + if argtypes[i] == REF: # This uses XCHG to put zeroes in fail_boxes_ptr after # reading them self.mc.XOR(loc, loc) @@ -253,15 +273,28 @@ genop_discard_list[op.opnum](self, op, arglocs) def regalloc_perform_with_guard(self, op, guard_op, faillocs, - arglocs, resloc): - addr = self.implement_guard_recovery(guard_op, faillocs) - genop_guard_list[op.opnum](self, op, guard_op, addr, arglocs, - resloc) - - def regalloc_perform_guard(self, op, faillocs, arglocs, resloc): - addr = self.implement_guard_recovery(op, faillocs) - genop_guard_list[op.opnum](self, op, None, addr, arglocs, - resloc) + arglocs, resloc, current_stack_depth): + fail_op = guard_op.suboperations[0] + faildescr = fail_op.descr + faildescr._x86_current_stack_depth = current_stack_depth + failargs = fail_op.args + guard_opnum = guard_op.opnum + failaddr = self.implement_guard_recovery(guard_opnum, + faildescr, failargs, + faillocs) + if op is None: + dispatch_opnum = guard_opnum + else: + dispatch_opnum = op.opnum + addr = genop_guard_list[dispatch_opnum](self, op, guard_opnum, + failaddr, arglocs, + resloc) + faildescr._x86_addr = addr + + def regalloc_perform_guard(self, guard_op, faillocs, arglocs, resloc, + current_stack_depth): + self.regalloc_perform_with_guard(None, guard_op, faillocs, arglocs, + resloc, current_stack_depth) def load_effective_addr(self, sizereg, baseofs, scale, result): self.mc.LEA(result, addr_add(imm(0), sizereg, baseofs, scale)) @@ -289,23 +322,23 @@ return genop_cmp def _cmpop_guard(cond, rev_cond, false_cond, false_rev_cond): - def genop_cmp_guard(self, op, guard_op, addr, arglocs, result_loc): + def genop_cmp_guard(self, op, guard_opnum, addr, arglocs, result_loc): if isinstance(op.args[0], Const): self.mc.CMP(arglocs[1], arglocs[0]) - if guard_op.opnum == rop.GUARD_FALSE: + if guard_opnum == rop.GUARD_FALSE: name = 'J' + rev_cond - self.implement_guard(addr, guard_op, getattr(self.mc, name)) + return self.implement_guard(addr, getattr(self.mc, name)) else: name = 'J' + false_rev_cond - self.implement_guard(addr, guard_op, getattr(self.mc, name)) + return self.implement_guard(addr, getattr(self.mc, name)) else: self.mc.CMP(arglocs[0], arglocs[1]) - if guard_op.opnum == rop.GUARD_FALSE: - self.implement_guard(addr, guard_op, - getattr(self.mc, 'J' + cond)) + if guard_opnum == rop.GUARD_FALSE: + name = 'J' + cond + return self.implement_guard(addr, getattr(self.mc, name)) else: name = 'J' + false_cond - self.implement_guard(addr, guard_op, getattr(self.mc, name)) + return self.implement_guard(addr, getattr(self.mc, name)) return genop_cmp_guard def align_stack_for_call(self, nargs): @@ -389,22 +422,21 @@ loc2 = cl self.mc.SHR(loc, loc2) - def genop_guard_oononnull(self, op, guard_op, addr, arglocs, resloc): + def genop_guard_oononnull(self, op, guard_opnum, addr, arglocs, resloc): loc = arglocs[0] self.mc.TEST(loc, loc) - if guard_op.opnum == rop.GUARD_TRUE: - self.implement_guard(addr, guard_op, self.mc.JZ) + if guard_opnum == rop.GUARD_TRUE: + return self.implement_guard(addr, self.mc.JZ) else: - self.implement_guard(addr, guard_op, self.mc.JNZ) + return self.implement_guard(addr, self.mc.JNZ) - def genop_guard_ooisnull(self, op, guard_op, addr, arglocs, resloc): + def genop_guard_ooisnull(self, op, guard_opnum, addr, arglocs, resloc): loc = arglocs[0] self.mc.TEST(loc, loc) - if guard_op.opnum == rop.GUARD_TRUE: - self.implement_guard(addr, guard_op, self.mc.JNZ) + if guard_opnum == rop.GUARD_TRUE: + return self.implement_guard(addr, self.mc.JNZ) else: - self.implement_guard(addr, guard_op, self.mc.JZ) - + return self.implement_guard(addr, self.mc.JZ) genop_guard_int_is_true = genop_guard_oononnull @@ -573,72 +605,98 @@ else: assert 0, itemsize - def make_merge_point(self, tree, locs): + def make_merge_point(self, argtypes, locs): + executable_token = ExecutableToken386() pos = self.mc.tell() - tree._x86_compiled = pos + executable_token.argtypes = argtypes + executable_token.arglocs = locs + executable_token._x86_compiled = pos + return executable_token + + def _get_executable_token(self, loop_token, cur_executable_token): + if loop_token is not None: + return loop_token.executable_token + return cur_executable_token + + def extract_merge_point(self, loop_token, cur_executable_token): + executable_token = self._get_executable_token(loop_token, + cur_executable_token) + return executable_token.arglocs + + def closing_jump(self, loop_token, cur_executable_token): + executable_token = self._get_executable_token(loop_token, + cur_executable_token) + # xxx delicate + cur_executable_token._x86_stack_depth = executable_token._x86_stack_depth + self.mc.JMP(rel32(executable_token._x86_compiled)) + + def close_back(self, executable_token, stack_depth): + prev_stack_depth = executable_token._x86_stack_depth + executable_token._x86_stack_depth = max(prev_stack_depth, stack_depth) - def genop_discard_jump(self, op, locs): - self.mc.JMP(rel32(op.jump_target._x86_compiled)) + #def genop_discard_jump(self, op, locs): + # self.mc.JMP(rel32(op.jump_target._x86_compiled)) - def genop_guard_guard_true(self, op, ign_1, addr, locs, ign_2): + def genop_guard_guard_true(self, ign_1, guard_opnum, addr, locs, ign_2): loc = locs[0] self.mc.TEST(loc, loc) - self.implement_guard(addr, op, self.mc.JZ) + return self.implement_guard(addr, self.mc.JZ) - def genop_guard_guard_no_exception(self, op, ign_1, addr, locs, ign_2): + def genop_guard_guard_no_exception(self, ign_1, guard_opnum, addr, + locs, ign_2): self.mc.CMP(heap(self.cpu.pos_exception()), imm(0)) - self.implement_guard(addr, op, self.mc.JNZ) + return self.implement_guard(addr, self.mc.JNZ) - def genop_guard_guard_exception(self, op, ign_1, addr, locs, resloc): + def genop_guard_guard_exception(self, ign_1, guard_opnum, addr, + locs, resloc): loc = locs[0] loc1 = locs[1] self.mc.MOV(loc1, heap(self.cpu.pos_exception())) self.mc.CMP(loc1, loc) - self.implement_guard(addr, op, self.mc.JNE) + addr = self.implement_guard(addr, self.mc.JNE) if resloc is not None: self.mc.MOV(resloc, heap(self.cpu.pos_exc_value())) self.mc.MOV(heap(self.cpu.pos_exception()), imm(0)) self.mc.MOV(heap(self.cpu.pos_exc_value()), imm(0)) + return addr - def genop_guard_guard_no_overflow(self, op, ign_1, addr, locs, resloc): - self.implement_guard(addr, op, self.mc.JO) - - def genop_guard_guard_overflow(self, op, ign_1, addr, locs, resloc): - self.implement_guard(addr, op, self.mc.JNO) + def genop_guard_guard_no_overflow(self, ign_1, guard_opnum, addr, + locs, resloc): + return self.implement_guard(addr, self.mc.JO) + + def genop_guard_guard_overflow(self, ign_1, guard_opnum, addr, + locs, resloc): + return self.implement_guard(addr, self.mc.JNO) - def genop_guard_guard_false(self, op, ign_1, addr, locs, ign_2): + def genop_guard_guard_false(self, ign_1, guard_opnum, addr, locs, ign_2): loc = locs[0] self.mc.TEST(loc, loc) - self.implement_guard(addr, op, self.mc.JNZ) + return self.implement_guard(addr, self.mc.JNZ) - def genop_guard_guard_value(self, op, ign_1, addr, locs, ign_2): + def genop_guard_guard_value(self, ign_1, guard_opnum, addr, locs, ign_2): self.mc.CMP(locs[0], locs[1]) - self.implement_guard(addr, op, self.mc.JNE) + return self.implement_guard(addr, self.mc.JNE) - def genop_guard_guard_class(self, op, ign_1, addr, locs, ign_2): + def genop_guard_guard_class(self, ign_1, guard_opnum, addr, locs, ign_2): offset = self.cpu.vtable_offset self.mc.CMP(mem(locs[0], offset), locs[1]) - self.implement_guard(addr, op, self.mc.JNE) + return self.implement_guard(addr, self.mc.JNE) - def implement_guard_recovery(self, guard_op, fail_locs): + def implement_guard_recovery(self, guard_opnum, faildescr, failargs, + fail_locs): addr = self.mc2.tell() - exc = (guard_op.opnum == rop.GUARD_EXCEPTION or - guard_op.opnum == rop.GUARD_NO_EXCEPTION) - guard_op._x86_faillocs = fail_locs - # XXX horrible hack that allows us to preserve order - # of inputargs to bridge - guard_op._fail_op = guard_op.suboperations[0] - self.generate_failure(self.mc2, guard_op.suboperations[0], fail_locs, - exc) + exc = (guard_opnum == rop.GUARD_EXCEPTION or + guard_opnum == rop.GUARD_NO_EXCEPTION) + faildescr._x86_faillocs = fail_locs + self.generate_failure(self.mc2, faildescr, failargs, fail_locs, exc) return addr - def generate_failure(self, mc, op, locs, exc): - assert op.opnum == rop.FAIL + def generate_failure(self, mc, faildescr, failargs, locs, exc): pos = mc.tell() for i in range(len(locs)): loc = locs[i] if isinstance(loc, REG): - if op.args[i].type == REF: + if failargs[i].type == REF: base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr @@ -646,7 +704,7 @@ for i in range(len(locs)): loc = locs[i] if not isinstance(loc, REG): - if op.args[i].type == REF: + if failargs[i].type == REF: base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr @@ -669,7 +727,7 @@ # don't break the following code sequence! mc = mc._mc mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD)) - guard_index = self.cpu.make_guard_index(op) + guard_index = self.cpu.make_guard_index(faildescr) mc.MOV(eax, imm(guard_index)) mc.POP(edi) mc.POP(esi) @@ -677,10 +735,10 @@ mc.POP(ebp) mc.RET() - @specialize.arg(3) - def implement_guard(self, addr, guard_op, emit_jump): + @specialize.arg(2) + def implement_guard(self, addr, emit_jump): emit_jump(rel32(addr)) - guard_op._x86_addr = self.mc.tell() - 4 + return self.mc.tell() - 4 def genop_call(self, op, arglocs, resloc): sizeloc = arglocs[0] Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py Thu Sep 24 17:35:30 2009 @@ -53,10 +53,58 @@ raise AssertionError class RegAlloc(object): - max_stack_depth = 0 exc = False - - def __init__(self, assembler, tree, translate_support_code=False, + + def __init__(self, assembler, translate_support_code=False): + # variables that have place in register + self.assembler = assembler + self.translate_support_code = translate_support_code + self.reg_bindings = newcheckdict() + self.stack_bindings = newcheckdict() + self.position = -1 + + def walk_operations(self, inputargs, operations): + cpu = self.assembler.cpu + cpu.gc_ll_descr.rewrite_assembler(cpu, operations) + self._compute_vars_longevity(inputargs, operations) + # compute longevity of variables + jump = operations[-1] + loop_consts = self._compute_loop_consts(inputargs, jump) + self.loop_consts = loop_consts + self.current_stack_depth = 0 + self.free_regs = REGS[:] + self.executable_token = self._process_inputargs(inputargs) + stack_depth = self._walk_operations(operations) + self.assembler.close_back(self.executable_token, stack_depth) + return self.executable_token + + def walk_bridge(self, faildescr, inputargs, operations): + cpu = self.assembler.cpu + locs = faildescr._x86_faillocs + cpu.gc_ll_descr.rewrite_assembler(cpu, operations) + self._compute_vars_longevity(inputargs, operations) + self.loop_consts = {} + self._update_bindings(locs, inputargs) + self.current_stack_depth = faildescr._x86_current_stack_depth + self.executable_token = None + # xxx + mc = self.assembler.mc._mc + adr_lea = mc.tell() + mc.LEA(esp, fixedsize_ebp_ofs(0)) + stack_depth = self._walk_operations(operations) + + # xxx + if not we_are_translated(): + # for the benefit of tests + faildescr._x86_bridge_stack_depth = stack_depth + + RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words + mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) + mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) + mc.done() + return adr_lea # start address + + def x__init__(self, assembler, tree, translate_support_code=False, guard_op=None): # variables that have place in register self.assembler = assembler @@ -108,7 +156,7 @@ self._check_invariants() def _compute_loop_consts(self, inputargs, jump): - if jump.opnum != rop.JUMP or jump.jump_target is not self.tree: + if jump.opnum != rop.JUMP or jump.jump_target is not None: loop_consts = {} else: loop_consts = {} @@ -148,22 +196,36 @@ self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) self.assembler.regalloc_perform(op, arglocs, result_loc) - def perform_with_guard(self, op, guard_op, locs, arglocs, result_loc): - guard_op._x86_current_stack_depth = self.current_stack_depth + def locs_for_fail(self, guard_op): + assert len(guard_op.suboperations) == 1 + fail_op = guard_op.suboperations[0] + assert fail_op.opnum == rop.FAIL + return [self.loc(v) for v in fail_op.args] + + def perform_with_guard(self, op, guard_op, arglocs, result_loc): + faillocs = self.locs_for_fail(guard_op) + self.position += 1 if not we_are_translated(): self.assembler.dump('%s <- %s(%s) [GUARDED]' % (result_loc, op, arglocs)) - self.assembler.regalloc_perform_with_guard(op, guard_op, locs, - arglocs, result_loc) + self.assembler.regalloc_perform_with_guard(op, guard_op, faillocs, + arglocs, result_loc, + self.current_stack_depth) + self.eventually_free_var(op.result) + self.eventually_free_vars(guard_op.suboperations[0].args) - def perform_guard(self, op, locs, arglocs, result_loc): - op._x86_current_stack_depth = self.current_stack_depth + def perform_guard(self, guard_op, arglocs, result_loc): + faillocs = self.locs_for_fail(guard_op) if not we_are_translated(): if result_loc is not None: - self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) + self.assembler.dump('%s <- %s(%s)' % (result_loc, guard_op, + arglocs)) else: - self.assembler.dump('%s(%s)' % (op, arglocs)) - self.assembler.regalloc_perform_guard(op, locs, arglocs, result_loc) + self.assembler.dump('%s(%s)' % (guard_op, arglocs)) + self.assembler.regalloc_perform_guard(guard_op, faillocs, arglocs, + result_loc, + self.current_stack_depth) + self.eventually_free_vars(guard_op.suboperations[0].args) def PerformDiscard(self, op, arglocs): if not we_are_translated(): @@ -184,13 +246,13 @@ return False return True - def walk_operations(self, tree): - # first pass - walk along the operations in order to find - # load/store places - self.position = -1 - operations = tree.operations - self.process_inputargs(tree) - self._walk_operations(operations) +## def walk_operations(self, tree): +## # first pass - walk along the operations in order to find +## # load/store places +## self.position = -1 +## operations = tree.operations +## self.process_inputargs(tree) +## self._walk_operations(operations) #def walk_guard_ops(self, inputargs, operations, exc): # self.exc = exc @@ -201,7 +263,7 @@ def _walk_operations(self, operations): i = 0 - self.operations = operations + #self.operations = operations while i < len(operations): op = operations[i] self.position = i @@ -218,9 +280,7 @@ self._check_invariants() i += 1 assert not self.reg_bindings - jmp = operations[-1] - self.max_stack_depth = max(self.current_stack_depth, - self.max_stack_depth) + return self.current_stack_depth def _compute_vars_longevity(self, inputargs, operations): # compute a dictionary that maps variables to index in @@ -490,21 +550,18 @@ loc = self.reg_bindings[result_v] return loc - def locs_for_fail(self, guard_op): - assert len(guard_op.suboperations) == 1 - return [self.loc(v) for v in guard_op.suboperations[0].args] - - def process_inputargs(self, tree): + def _process_inputargs(self, inputargs): # XXX we can sort out here by longevity if we need something # more optimal - inputargs = tree.inputargs locs = [None] * len(inputargs) # Don't use REGS[0] for passing arguments around a loop. # Must be kept in sync with consider_jump(). tmpreg = self.free_regs.pop(0) assert tmpreg == REGS[0] + argtypes = [] for i in range(len(inputargs)): arg = inputargs[i] + argtypes.append(arg.type) assert not isinstance(arg, Const) reg = None if arg not in self.loop_consts and self.longevity[arg][1] > -1: @@ -517,16 +574,15 @@ # otherwise we have it saved on stack, so no worry self.free_regs.insert(0, tmpreg) assert tmpreg not in locs - tree.arglocs = locs - self.assembler.make_merge_point(tree, locs) + # xxx think + executable_token = self.assembler.make_merge_point(argtypes, locs) self.eventually_free_vars(inputargs) + return executable_token def _consider_guard(self, op, ignored): loc = self.make_sure_var_in_reg(op.args[0], []) - locs = self.locs_for_fail(op) - self.perform_guard(op, locs, [loc], None) + self.perform_guard(op, [loc], None) self.eventually_free_var(op.args[0]) - self.eventually_free_vars(op.suboperations[0].args) consider_guard_true = _consider_guard consider_guard_false = _consider_guard @@ -534,13 +590,12 @@ def consider_fail(self, op, ignored): # make sure all vars are on stack locs = [self.loc(arg) for arg in op.args] - self.assembler.generate_failure(self.assembler.mc, op, locs, self.exc) + self.assembler.generate_failure(self.assembler.mc, op.descr, op.args, + locs, self.exc) self.eventually_free_vars(op.args) def consider_guard_no_exception(self, op, ignored): - faillocs = self.locs_for_fail(op) - self.perform_guard(op, faillocs, [], None) - self.eventually_free_vars(op.suboperations[0].args) + self.perform_guard(op, [], None) def consider_guard_exception(self, op, ignored): loc = self.make_sure_var_in_reg(op.args[0], []) @@ -551,9 +606,7 @@ resloc = self.force_allocate_reg(op.result, op.args + [box]) else: resloc = None - faillocs = self.locs_for_fail(op) - self.perform_guard(op, faillocs, [loc, loc1], resloc) - self.eventually_free_vars(op.suboperations[0].args) + self.perform_guard(op, [loc, loc1], resloc) self.eventually_free_vars(op.args) self.eventually_free_var(box) @@ -563,18 +616,14 @@ def consider_guard_value(self, op, ignored): x = self.make_sure_var_in_reg(op.args[0], []) y = self.loc(op.args[1]) - faillocs = self.locs_for_fail(op) - self.perform_guard(op, faillocs, [x, y], None) - self.eventually_free_vars(op.suboperations[0].args) + self.perform_guard(op, [x, y], None) self.eventually_free_vars(op.args) def consider_guard_class(self, op, ignored): assert isinstance(op.args[0], Box) x = self.make_sure_var_in_reg(op.args[0], []) y = self.loc(op.args[1]) - faillocs = self.locs_for_fail(op) - self.perform_guard(op, faillocs, [x, y], None) - self.eventually_free_vars(op.suboperations[0].args) + self.perform_guard(op, [x, y], None) self.eventually_free_vars(op.args) def _consider_binop_part(self, op, ignored): @@ -653,11 +702,7 @@ need_lower_byte=True) self.Perform(op, arglocs, loc) else: - faillocs = self.locs_for_fail(guard_op) - self.position += 1 - self.perform_with_guard(op, guard_op, faillocs, arglocs, None) - self.eventually_free_var(op.result) - self.eventually_free_vars(guard_op.suboperations[0].args) + self.perform_with_guard(op, guard_op, arglocs, None) consider_int_lt = _consider_compop consider_int_gt = _consider_compop @@ -877,11 +922,7 @@ if guard_op is not None: argloc = self.make_sure_var_in_reg(op.args[0], []) self.eventually_free_var(op.args[0]) - faillocs = self.locs_for_fail(guard_op) - self.position += 1 - self.perform_with_guard(op, guard_op, faillocs, [argloc], None) - self.eventually_free_var(op.result) - self.eventually_free_vars(guard_op.suboperations[0].args) + self.perform_with_guard(op, guard_op, [argloc], None) else: argloc = self.loc(op.args[0]) self.eventually_free_var(op.args[0]) @@ -927,19 +968,19 @@ consider_unicodegetitem = consider_strgetitem def consider_jump(self, op, ignored): - loop = op.jump_target + assembler = self.assembler + arglocs = assembler.extract_merge_point(op.jump_target, + self.executable_token) # compute 'tmploc' to be REGS[0] by spilling what is there box = TempBox() tmploc = self.force_allocate_reg(box, [], selected_reg=REGS[0]) src_locations = [self.loc(arg) for arg in op.args] - dst_locations = loop.arglocs + dst_locations = arglocs assert tmploc not in dst_locations - remap_stack_layout(self.assembler, src_locations, - dst_locations, tmploc) + remap_stack_layout(assembler, src_locations, dst_locations, tmploc) self.eventually_free_var(box) self.eventually_free_vars(op.args) - self.max_stack_depth = op.jump_target._x86_stack_depth - self.PerformDiscard(op, []) + assembler.closing_jump(op.jump_target, self.executable_token) def consider_debug_merge_point(self, op, ignored): pass Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/runner.py Thu Sep 24 17:35:30 2009 @@ -8,14 +8,12 @@ from pypy.jit.backend.x86.assembler import Assembler386, MAX_FAIL_BOXES from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU -history.TreeLoop._x86_compiled = 0 -history.TreeLoop._x86_bootstrap_code = 0 -history.TreeLoop._x86_stack_depth = 0 class CPU386(AbstractLLCPU): debug = True BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) + dont_keepalive_stuff = False # for tests def __init__(self, rtyper, stats, translate_support_code=False, gcdescr=None): @@ -35,34 +33,31 @@ def setup_once(self): pass - def compile_operations(self, tree, guard_op=None): - if guard_op is not None: - self.assembler.assemble_from_guard(tree, guard_op) - else: - self.assembler.assemble_loop(tree) + def compile_loop(self, inputargs, operations): + return self.assembler.assemble_loop(inputargs, operations) + + def compile_bridge(self, faildescr, inputargs, operations): + self.assembler.assemble_bridge(faildescr, inputargs, operations) + + def execute_token(self, executable_token): + func = self.get_bootstrap_code(executable_token) + guard_index = self.execute_call(func) + op = self._guard_list[guard_index] # xxx + return op - def get_bootstrap_code(self, loop): - addr = loop._x86_bootstrap_code + def get_bootstrap_code(self, executable_token): + addr = executable_token._x86_bootstrap_code if not addr: - arglocs = loop.arglocs - addr = self.assembler.assemble_bootstrap_code(loop._x86_compiled, - arglocs, - loop.inputargs, - loop._x86_stack_depth) - loop._x86_bootstrap_code = addr + arglocs = executable_token.arglocs + addr = self.assembler.assemble_bootstrap_code( + executable_token._x86_compiled, + arglocs, + executable_token.argtypes, + executable_token._x86_stack_depth) + executable_token._x86_bootstrap_code = addr func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr) return func - def execute_operations(self, loop, verbose=False): - assert isinstance(verbose, bool) - func = self.get_bootstrap_code(loop) - guard_index = self.execute_call(loop, func, verbose) - op = self._guard_list[guard_index] - if verbose: - print "Leaving at: %d" % self.assembler.fail_boxes_int[ - len(op.args)] - return op - def set_future_value_int(self, index, intvalue): assert index < MAX_FAIL_BOXES, "overflow!" self.assembler.fail_boxes_int[index] = intvalue @@ -81,7 +76,7 @@ llmemory.GCREF.TO) return ptrvalue - def execute_call(self, loop, func, verbose): + def execute_call(self, func): # help flow objspace prev_interpreter = None if not self.translate_support_code: @@ -89,8 +84,6 @@ LLInterpreter.current_interpreter = self.debug_ll_interpreter res = 0 try: - if verbose: - print "Entering: %d" % rffi.cast(lltype.Signed, func) #llop.debug_print(lltype.Void, ">>>> Entering", # rffi.cast(lltype.Signed, func)) res = func() From cfbolz at codespeak.net Thu Sep 24 17:50:18 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 24 Sep 2009 17:50:18 +0200 (CEST) Subject: [pypy-svn] r67870 - pypy/extradoc/sprintinfo/ddorf2009 Message-ID: <20090924155018.865DC16801F@codespeak.net> Author: cfbolz Date: Thu Sep 24 17:50:17 2009 New Revision: 67870 Modified: pypy/extradoc/sprintinfo/ddorf2009/announce.txt Log: another umlaut bug Modified: pypy/extradoc/sprintinfo/ddorf2009/announce.txt ============================================================================== --- pypy/extradoc/sprintinfo/ddorf2009/announce.txt (original) +++ pypy/extradoc/sprintinfo/ddorf2009/announce.txt Thu Sep 24 17:50:17 2009 @@ -1,4 +1,4 @@ -D??sseldorf PyPy sprint November 6 - November 13 2009 +D?sseldorf PyPy sprint November 6 - November 13 2009 ===================================================== The next PyPy sprint will be held in the Computer Science department of From cfbolz at codespeak.net Thu Sep 24 18:27:42 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 24 Sep 2009 18:27:42 +0200 (CEST) Subject: [pypy-svn] r67871 - pypy/extradoc/sprintinfo/ddorf2009 Message-ID: <20090924162742.42F7D16800B@codespeak.net> Author: cfbolz Date: Thu Sep 24 18:27:41 2009 New Revision: 67871 Modified: pypy/extradoc/sprintinfo/ddorf2009/announce.txt Log: reflow to 72 chars Modified: pypy/extradoc/sprintinfo/ddorf2009/announce.txt ============================================================================== --- pypy/extradoc/sprintinfo/ddorf2009/announce.txt (original) +++ pypy/extradoc/sprintinfo/ddorf2009/announce.txt Thu Sep 24 18:27:41 2009 @@ -3,30 +3,31 @@ The next PyPy sprint will be held in the Computer Science department of Heinrich-Heine Universit?t D?sseldorf from the 6th to the 13th of -November 2009. This is a fully public sprint, everyone is welcome to join us. +November 2009. This is a fully public sprint, everyone is welcome to +join us. Topics and goals ---------------- -At the sprint we intend to work on the JIT generator in PyPy and on applying -it to PyPy Python interpreter. +At the sprint we intend to work on the JIT generator in PyPy and on +applying it to PyPy Python interpreter. -The precise work that will be done is not fixed, as we don't know in which -state the JIT will be in November. However, possible areas of work might -include: +The precise work that will be done is not fixed, as we don't know in +which state the JIT will be in November. However, possible areas of +work might include: - tweaking the interpreter/objspace to be more JIT-friendly, e.g. instance implementation code, call code - if there is interest starting non x86-32 JIT backends -- trying out existing software to find features where the optimizations of the - JIT could be improved +- trying out existing software to find features where the optimizations + of the JIT could be improved - improving our benchmarking infrastructure We will give special priority to topics that "non-core" people find interesting (as long as they are somehow JIT-related). -For an introduction of how our JIT-generation process works, please refer to -our blog: +For an introduction of how our JIT-generation process works, please +refer to our blog: http://morepypy.blogspot.com/2009/03/jit-bit-of-look-inside.html @@ -38,19 +39,19 @@ -------- The sprint will take place in a seminar room of the computer science -department. It is in the building 25.12 of the university campus. For travel -instructions see +department. It is in the building 25.12 of the university campus. For +travel instructions see http://stups.cs.uni-duesseldorf.de/anreise/esbahn.php Registration ------------ -If you'd like to come, please subscribe to the `pypy-sprint mailing list`_ -and drop a note about your interests and post any questions. More -organisational information will be send to that list. We'll keep -a list of `people`_ which we'll update (which you can do so yourself -if you have codespeak commit rights). +If you'd like to come, please subscribe to the `pypy-sprint mailing +list`_ and drop a note about your interests and post any questions. +More organisational information will be send to that list. We'll keep a +list of `people`_ which we'll update (which you can do so yourself if +you have codespeak commit rights). .. _`pypy-sprint mailing list`: http://codespeak.net/mailman/listinfo/pypy-sprint .. _`people`: http://codespeak.net/pypy/extradoc/sprintinfo/ddorf2009/people.txt From pedronis at codespeak.net Fri Sep 25 10:19:39 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 25 Sep 2009 10:19:39 +0200 (CEST) Subject: [pypy-svn] r67872 - pypy/branch/remove-plfbid/pypy/jit/backend/x86 Message-ID: <20090925081939.73AB4168021@codespeak.net> Author: pedronis Date: Fri Sep 25 10:19:38 2009 New Revision: 67872 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py Log: bridges work again, finish op and cleanup next Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py Fri Sep 25 10:19:38 2009 @@ -141,67 +141,90 @@ self.make_sure_mc_exists() regalloc = RegAlloc(self, self.cpu.translate_support_code) self._regalloc = regalloc - executable_token = regalloc.walk_operations(inputargs, operations) + regalloc.walk_operations(inputargs, operations) self.mc.done() self.mc2.done() - # possibly align, e.g. for Mac OS X if we_are_translated() or self.cpu.dont_keepalive_stuff: self._regalloc = None # else keep it around for debugging + stack_depth = regalloc.current_stack_depth + jump_target = regalloc.jump_target + if jump_target is not None: + target_stack_depth = jump_target.executable_token._x86_stack_depth + stack_depth = max(stack_depth, target_stack_depth) + executable_token = regalloc.executable_token + # possibly align, e.g. for Mac OS X + executable_token._x86_stack_depth = stack_depth return executable_token def assemble_bridge(self, faildescr, inputargs, operations): self._compute_longest_fail_op(operations) self.make_sure_mc_exists() regalloc = RegAlloc(self, self.cpu.translate_support_code) - self._regalloc = regalloc - bridgeaddr = regalloc.walk_bridge(faildescr,inputargs, operations) + self._regalloc = regalloc + # stack adjustment LEA + mc = self.mc._mc + adr_bridge = mc.tell() + mc.LEA(esp, fixedsize_ebp_ofs(0)) + regalloc.walk_bridge(faildescr, inputargs, operations) self.mc.done() self.mc2.done() if we_are_translated() or self.cpu.dont_keepalive_stuff: self._regalloc = None # else keep it around for debugging + stack_depth = regalloc.current_stack_depth + jump_target = regalloc.jump_target + assert jump_target + target_stack_depth = jump_target.executable_token._x86_stack_depth + stack_depth = max(stack_depth, target_stack_depth) + # patch stack adjustment LEA + if not we_are_translated(): + # for the benefit of tests + faildescr._x86_bridge_stack_depth = stack_depth + mc = codebuf.InMemoryCodeBuilder(adr_bridge, adr_bridge + 128) + mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) + mc.done() # patch the jump from original guard addr = faildescr._x86_addr mc = codebuf.InMemoryCodeBuilder(addr, addr + 128) - mc.write(packimm32(bridgeddr - addr - 4)) + mc.write(packimm32(adr_bridge - addr - 4)) mc.done() - def xassemble(self, tree, operations, guard_op): - # the last operation can be 'jump', 'return' or 'guard_pause'; - # a 'jump' can either close a loop, or end a bridge to some - # previously-compiled code. - self._compute_longest_fail_op(operations) - self.make_sure_mc_exists() - newpos = self.mc.tell() - regalloc = RegAlloc(self, tree, self.cpu.translate_support_code, - guard_op) - self._regalloc = regalloc - adr_lea = 0 - if guard_op is None: - inputargs = tree.inputargs - regalloc.walk_operations(tree) - else: - inputargs = regalloc.inputargs - mc = self.mc._mc - adr_lea = mc.tell() - mc.LEA(esp, fixedsize_ebp_ofs(0)) - regalloc._walk_operations(operations) - stack_depth = regalloc.max_stack_depth - self.mc.done() - self.mc2.done() - # possibly align, e.g. for Mac OS X - if guard_op is None: - tree._x86_stack_depth = stack_depth - else: - if not we_are_translated(): - # for the benefit of tests - guard_op._x86_bridge_stack_depth = stack_depth - mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) +## def assemble(self, tree, operations, guard_op): +## # the last operation can be 'jump', 'return' or 'guard_pause'; +## # a 'jump' can either close a loop, or end a bridge to some +## # previously-compiled code. +## self._compute_longest_fail_op(operations) +## self.make_sure_mc_exists() +## newpos = self.mc.tell() +## regalloc = RegAlloc(self, tree, self.cpu.translate_support_code, +## guard_op) +## self._regalloc = regalloc +## adr_lea = 0 +## if guard_op is None: +## inputargs = tree.inputargs +## regalloc.walk_operations(tree) +## else: +## inputargs = regalloc.inputargs +## mc = self.mc._mc +## adr_lea = mc.tell() +## mc.LEA(esp, fixedsize_ebp_ofs(0)) +## regalloc._walk_operations(operations) +## stack_depth = regalloc.max_stack_depth +## self.mc.done() +## self.mc2.done() +## # possibly align, e.g. for Mac OS X +## if guard_op is None: +## tree._x86_stack_depth = stack_depth +## else: +## if not we_are_translated(): +## # for the benefit of tests +## guard_op._x86_bridge_stack_depth = stack_depth +## mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) - mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) - mc.done() - if we_are_translated(): - self._regalloc = None # else keep it around for debugging - return newpos +## mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) +## mc.done() +## if we_are_translated(): +## self._regalloc = None # else keep it around for debugging +## return newpos def assemble_bootstrap_code(self, jumpaddr, arglocs, argtypes, framesize): self.make_sure_mc_exists() @@ -626,14 +649,8 @@ def closing_jump(self, loop_token, cur_executable_token): executable_token = self._get_executable_token(loop_token, cur_executable_token) - # xxx delicate - cur_executable_token._x86_stack_depth = executable_token._x86_stack_depth self.mc.JMP(rel32(executable_token._x86_compiled)) - def close_back(self, executable_token, stack_depth): - prev_stack_depth = executable_token._x86_stack_depth - executable_token._x86_stack_depth = max(prev_stack_depth, stack_depth) - #def genop_discard_jump(self, op, locs): # self.mc.JMP(rel32(op.jump_target._x86_compiled)) Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py Fri Sep 25 10:19:38 2009 @@ -63,75 +63,102 @@ self.stack_bindings = newcheckdict() self.position = -1 + # to be read/used by the assembler too + self.executable_token = None + self.current_stack_depth = 0 + self.jump_target = None + def walk_operations(self, inputargs, operations): cpu = self.assembler.cpu cpu.gc_ll_descr.rewrite_assembler(cpu, operations) - self._compute_vars_longevity(inputargs, operations) # compute longevity of variables + self._compute_vars_longevity(inputargs, operations) jump = operations[-1] loop_consts = self._compute_loop_consts(inputargs, jump) self.loop_consts = loop_consts self.current_stack_depth = 0 self.free_regs = REGS[:] self.executable_token = self._process_inputargs(inputargs) - stack_depth = self._walk_operations(operations) - self.assembler.close_back(self.executable_token, stack_depth) - return self.executable_token + self._walk_operations(operations) def walk_bridge(self, faildescr, inputargs, operations): cpu = self.assembler.cpu locs = faildescr._x86_faillocs cpu.gc_ll_descr.rewrite_assembler(cpu, operations) + # compute longevity of variables self._compute_vars_longevity(inputargs, operations) self.loop_consts = {} self._update_bindings(locs, inputargs) self.current_stack_depth = faildescr._x86_current_stack_depth - self.executable_token = None - # xxx - mc = self.assembler.mc._mc - adr_lea = mc.tell() - mc.LEA(esp, fixedsize_ebp_ofs(0)) - stack_depth = self._walk_operations(operations) + self._walk_operations(operations) + +## def x__init__(self, assembler, tree, translate_support_code=False, +## guard_op=None): +## # variables that have place in register +## self.assembler = assembler +## self.translate_support_code = translate_support_code +## cpu = self.assembler.cpu +## self.reg_bindings = newcheckdict() +## self.stack_bindings = newcheckdict() +## self.tree = tree +## if guard_op is not None: +## locs = guard_op._x86_faillocs +## cpu.gc_ll_descr.rewrite_assembler(cpu, guard_op.suboperations) +## inpargs = [arg for arg in guard_op._fail_op.args if +## isinstance(arg, Box)] +## self._compute_vars_longevity(inpargs, guard_op.suboperations) +## self.position = -1 +## self._update_bindings(locs, inpargs) +## self.current_stack_depth = guard_op._x86_current_stack_depth +## self.loop_consts = {} +## else: +## cpu.gc_ll_descr.rewrite_assembler(cpu, tree.operations) +## self._compute_vars_longevity(tree.inputargs, tree.operations) +## # compute longevity of variables +## jump = tree.operations[-1] +## loop_consts = self._compute_loop_consts(tree.inputargs, jump) +## self.loop_consts = loop_consts +## self.current_stack_depth = 0 +## self.free_regs = REGS[:] - # xxx - if not we_are_translated(): - # for the benefit of tests - faildescr._x86_bridge_stack_depth = stack_depth + def _process_inputargs(self, inputargs): + # XXX we can sort out here by longevity if we need something + # more optimal + locs = [None] * len(inputargs) + # Don't use REGS[0] for passing arguments around a loop. + # Must be kept in sync with consider_jump(). + tmpreg = self.free_regs.pop(0) + assert tmpreg == REGS[0] + argtypes = [] + for i in range(len(inputargs)): + arg = inputargs[i] + argtypes.append(arg.type) + assert not isinstance(arg, Const) + reg = None + if arg not in self.loop_consts and self.longevity[arg][1] > -1: + reg = self.try_allocate_reg(arg) + if reg: + locs[i] = reg + else: + loc = self.stack_loc(arg) + locs[i] = loc + # otherwise we have it saved on stack, so no worry + self.free_regs.insert(0, tmpreg) + assert tmpreg not in locs + # xxx think + executable_token = self.assembler.make_merge_point(argtypes, locs) + self.eventually_free_vars(inputargs) + return executable_token - RET_BP = 5 # ret ip + bp + bx + esi + edi = 5 words - mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) - mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) - mc.done() - return adr_lea # start address - - def x__init__(self, assembler, tree, translate_support_code=False, - guard_op=None): - # variables that have place in register - self.assembler = assembler - self.translate_support_code = translate_support_code - cpu = self.assembler.cpu - self.reg_bindings = newcheckdict() - self.stack_bindings = newcheckdict() - self.tree = tree - if guard_op is not None: - locs = guard_op._x86_faillocs - cpu.gc_ll_descr.rewrite_assembler(cpu, guard_op.suboperations) - inpargs = [arg for arg in guard_op._fail_op.args if - isinstance(arg, Box)] - self._compute_vars_longevity(inpargs, guard_op.suboperations) - self.position = -1 - self._update_bindings(locs, inpargs) - self.current_stack_depth = guard_op._x86_current_stack_depth - self.loop_consts = {} - else: - cpu.gc_ll_descr.rewrite_assembler(cpu, tree.operations) - self._compute_vars_longevity(tree.inputargs, tree.operations) - # compute longevity of variables - jump = tree.operations[-1] - loop_consts = self._compute_loop_consts(tree.inputargs, jump) - self.loop_consts = loop_consts - self.current_stack_depth = 0 - self.free_regs = REGS[:] + def _compute_loop_consts(self, inputargs, jump): + if jump.opnum != rop.JUMP or jump.jump_target is not None: + loop_consts = {} + else: + loop_consts = {} + for i in range(len(inputargs)): + if inputargs[i] is jump.args[i]: + loop_consts[inputargs[i]] = i + return loop_consts def _update_bindings(self, locs, args): newlocs = [] @@ -155,16 +182,6 @@ self.free_regs.append(reg) self._check_invariants() - def _compute_loop_consts(self, inputargs, jump): - if jump.opnum != rop.JUMP or jump.jump_target is not None: - loop_consts = {} - else: - loop_consts = {} - for i in range(len(inputargs)): - if inputargs[i] is jump.args[i]: - loop_consts[inputargs[i]] = i - return loop_consts - def _check_invariants(self): if not we_are_translated(): # make sure no duplicates @@ -280,7 +297,6 @@ self._check_invariants() i += 1 assert not self.reg_bindings - return self.current_stack_depth def _compute_vars_longevity(self, inputargs, operations): # compute a dictionary that maps variables to index in @@ -550,35 +566,6 @@ loc = self.reg_bindings[result_v] return loc - def _process_inputargs(self, inputargs): - # XXX we can sort out here by longevity if we need something - # more optimal - locs = [None] * len(inputargs) - # Don't use REGS[0] for passing arguments around a loop. - # Must be kept in sync with consider_jump(). - tmpreg = self.free_regs.pop(0) - assert tmpreg == REGS[0] - argtypes = [] - for i in range(len(inputargs)): - arg = inputargs[i] - argtypes.append(arg.type) - assert not isinstance(arg, Const) - reg = None - if arg not in self.loop_consts and self.longevity[arg][1] > -1: - reg = self.try_allocate_reg(arg) - if reg: - locs[i] = reg - else: - loc = self.stack_loc(arg) - locs[i] = loc - # otherwise we have it saved on stack, so no worry - self.free_regs.insert(0, tmpreg) - assert tmpreg not in locs - # xxx think - executable_token = self.assembler.make_merge_point(argtypes, locs) - self.eventually_free_vars(inputargs) - return executable_token - def _consider_guard(self, op, ignored): loc = self.make_sure_var_in_reg(op.args[0], []) self.perform_guard(op, [loc], None) @@ -969,7 +956,9 @@ def consider_jump(self, op, ignored): assembler = self.assembler - arglocs = assembler.extract_merge_point(op.jump_target, + assert self.jump_target is None + self.jump_target = op.jump_target + arglocs = assembler.extract_merge_point(self.jump_target, self.executable_token) # compute 'tmploc' to be REGS[0] by spilling what is there box = TempBox() From pedronis at codespeak.net Fri Sep 25 10:23:55 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 25 Sep 2009 10:23:55 +0200 (CEST) Subject: [pypy-svn] r67873 - pypy/branch/remove-plfbid/pypy/jit/backend/x86 Message-ID: <20090925082355.5E8A8168021@codespeak.net> Author: pedronis Date: Fri Sep 25 10:23:54 2009 New Revision: 67873 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py Log: fix for test_ll_random Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py Fri Sep 25 10:23:54 2009 @@ -172,9 +172,9 @@ self._regalloc = None # else keep it around for debugging stack_depth = regalloc.current_stack_depth jump_target = regalloc.jump_target - assert jump_target - target_stack_depth = jump_target.executable_token._x86_stack_depth - stack_depth = max(stack_depth, target_stack_depth) + if jump_target is not None: + target_stack_depth = jump_target.executable_token._x86_stack_depth + stack_depth = max(stack_depth, target_stack_depth) # patch stack adjustment LEA if not we_are_translated(): # for the benefit of tests From pedronis at codespeak.net Fri Sep 25 11:37:43 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 25 Sep 2009 11:37:43 +0200 (CEST) Subject: [pypy-svn] r67874 - in pypy/branch/remove-plfbid/pypy/jit/backend/x86: . test Message-ID: <20090925093743.57409168021@codespeak.net> Author: pedronis Date: Fri Sep 25 11:37:42 2009 New Revision: 67874 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_gc_integration.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_recompilation.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc2.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_runner.py Log: (arigo, pedronis) more tests pass again Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py Fri Sep 25 11:37:42 2009 @@ -56,12 +56,14 @@ exc = False def __init__(self, assembler, translate_support_code=False): + assert isinstance(translate_support_code, bool) # variables that have place in register self.assembler = assembler self.translate_support_code = translate_support_code self.reg_bindings = newcheckdict() self.stack_bindings = newcheckdict() self.position = -1 + self.longevity = None # to be read/used by the assembler too self.executable_token = None @@ -575,12 +577,13 @@ consider_guard_false = _consider_guard def consider_fail(self, op, ignored): - # make sure all vars are on stack locs = [self.loc(arg) for arg in op.args] self.assembler.generate_failure(self.assembler.mc, op.descr, op.args, locs, self.exc) self.eventually_free_vars(op.args) + consider_finish = consider_fail # for now + def consider_guard_no_exception(self, op, ignored): self.perform_guard(op, [], None) Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_gc_integration.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_gc_integration.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_gc_integration.py Fri Sep 25 11:37:42 2009 @@ -16,7 +16,7 @@ from pypy.jit.backend.x86.ri386 import * from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList, GcPtrFieldDescr -from pypy.jit.backend.x86.test.test_regalloc import DummyTree, MockAssembler +from pypy.jit.backend.x86.test.test_regalloc import MockAssembler from pypy.jit.backend.x86.test.test_regalloc import fill_regs, BaseTestRegalloc class MockGcRootMap(object): @@ -55,14 +55,13 @@ def test_mark_gc_roots(self): cpu = CPU(None, None) - regalloc = RegAlloc(MockAssembler(cpu, MockGcDescr(False)), DummyTree()) + regalloc = RegAlloc(MockAssembler(cpu, MockGcDescr(False))) cpu = regalloc.assembler.cpu boxes = fill_regs(regalloc, cls=BoxPtr) TP = lltype.FuncType([], lltype.Signed) calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) regalloc._check_invariants() - for box in boxes: - regalloc.longevity[box] = (0, 1) + regalloc.longevity = dict.fromkeys(boxes, (0, 1)) box = boxes[0] regalloc.position = 0 regalloc.consider_call(ResOperation(rop.CALL, [box], BoxInt(), @@ -114,25 +113,6 @@ self.interpret(ops, []) assert not self.getptr(0, lltype.Ptr(self.S)) - def test_rewrite_constptr_bridge(self): - ops = ''' - [i0] - guard_true(i0) - fail(1) - fail(0) - ''' - loop = self.interpret(ops, [0]) - assert self.getint(0) == 1 - bridge_ops = ''' - [i0] - p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) - fail(p1) - ''' - self.attach_bridge(bridge_ops, loop, loop.operations[0]) - self.cpu.set_future_value_int(0, 0) - self.cpu.execute_operations(loop) - not self.getptr(0, lltype.Ptr(self.S)) - def test_bug_0(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_recompilation.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_recompilation.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_recompilation.py Fri Sep 25 11:37:42 2009 @@ -19,10 +19,10 @@ i3 = int_add(i1, 1) fail(i3) ''' - bridge = self.attach_bridge(ops, loop, loop.operations[-2]) + bridge = self.attach_bridge(ops, loop, -2) self.cpu.set_future_value_int(0, 0) - op = self.cpu.execute_operations(loop) - assert op is bridge.operations[-1] + fail = self.run(loop) + assert fail is bridge.operations[-1].descr assert self.getint(0) == 21 def test_compile_bridge_deeper(self): @@ -35,7 +35,7 @@ jump(i1) ''' loop = self.interpret(ops, [0]) - previous = loop._x86_stack_depth + previous = loop.executable_token._x86_stack_depth assert self.getint(0) == 20 ops = ''' [i1] @@ -48,12 +48,13 @@ i9 = int_add(i8, 1) fail(i3, i4, i5, i6, i7, i8, i9) ''' - bridge = self.attach_bridge(ops, loop, loop.operations[-2]) - new = loop.operations[2]._x86_bridge_stack_depth + bridge = self.attach_bridge(ops, loop, -2) + fail_op = loop._loop.operations[2].suboperations[0] + new = fail_op.descr._x86_bridge_stack_depth assert new > previous self.cpu.set_future_value_int(0, 0) - op = self.cpu.execute_operations(loop) - assert op is bridge.operations[-1] + fail = self.run(loop) + assert fail is bridge.operations[-1].descr assert self.getint(0) == 21 assert self.getint(1) == 22 assert self.getint(2) == 23 @@ -78,11 +79,10 @@ [i3] jump(i3, 1, 2, 3, 4, 5, 6, 7) ''' - bridge = self.attach_bridge(ops, other_loop, other_loop.operations[0], - jump_targets=[loop]) + bridge = self.attach_bridge(ops, other_loop, 0, jump_targets=[loop]) self.cpu.set_future_value_int(0, 1) - op = self.cpu.execute_operations(other_loop) - assert op is loop.operations[2].suboperations[0] + fail = self.run(other_loop) + assert fail is loop._loop.operations[2].suboperations[0].descr def test_bridge_jumps_to_self_deeper(self): loop = self.interpret(''' @@ -109,14 +109,14 @@ i11 = int_add(i12, i6) jump(i3, i12, i11, i10, i6, i7) ''' - guard_op = loop.operations[3] - bridge = self.attach_bridge(ops, loop, guard_op, - jump_targets=[loop]) - assert guard_op._x86_bridge_stack_depth > loop._x86_stack_depth + bridge = self.attach_bridge(ops, loop, 3, jump_targets=[loop]) + fail_op = loop._loop.operations[3].suboperations[0] + loop_stack_depth = loop.executable_token._x86_stack_depth + assert fail_op.descr._x86_bridge_stack_depth > loop_stack_depth self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) self.cpu.set_future_value_int(2, 0) - self.cpu.execute_operations(loop) + self.run(loop) assert self.getint(0) == 1 assert self.getint(1) == 20 @@ -138,12 +138,11 @@ [i3] jump(i3, 0, 1) ''' - bridge = self.attach_bridge(ops, loop, loop.operations[2], - jump_targets=[loop]) + bridge = self.attach_bridge(ops, loop, 2, jump_targets=[loop]) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) self.cpu.set_future_value_int(2, 0) - self.cpu.execute_operations(loop) + self.run(loop) assert self.getint(0) == 1 assert self.getint(1) == 20 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc.py Fri Sep 25 11:37:42 2009 @@ -4,7 +4,7 @@ import py from pypy.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ - BoxPtr, ConstPtr, TreeLoop + BoxPtr, ConstPtr, LoopToken from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.backend.llsupport.descr import GcCache from pypy.jit.backend.x86.runner import CPU @@ -15,11 +15,6 @@ from pypy.rpython.lltypesystem import rclass, rstr from pypy.jit.backend.x86.ri386 import * - -class DummyTree(object): - operations = [ResOperation(rop.FAIL, [], None)] - inputargs = [] - class MockGcDescr(GcCache): def get_funcptr_for_new(self): return 123 @@ -78,7 +73,7 @@ class TestRegallocDirect(object): def test_make_sure_var_in_reg(self): - regalloc = RegAlloc(MockAssembler(), DummyTree()) + regalloc = RegAlloc(MockAssembler()) boxes = fill_regs(regalloc) box = boxes[-1] oldloc = regalloc.loc(box) @@ -87,17 +82,17 @@ regalloc._check_invariants() def test_make_sure_var_in_reg_need_lower_byte(self): - regalloc = RegAlloc(MockAssembler(), DummyTree()) + regalloc = RegAlloc(MockAssembler()) box = BoxInt() regalloc.reg_bindings[box] = edi - regalloc.free_regs.remove(edi) + regalloc.free_regs = [eax, ecx, edx, ebx, esi] loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True) assert loc is not edi and loc is not esi assert len(regalloc.assembler.loads) == 1 regalloc._check_invariants() def test_make_sure_var_in_reg_need_lower_byte_no_free_reg(self): - regalloc = RegAllocForTests(MockAssembler(), DummyTree()) + regalloc = RegAllocForTests(MockAssembler()) box = BoxInt() regalloc.reg_bindings = {BoxInt(): eax, BoxInt(): ebx, BoxInt(): ecx, BoxInt(): edx, box:edi} @@ -109,7 +104,8 @@ regalloc._check_invariants() def test_make_sure_var_in_reg_mem(self): - regalloc = RegAlloc(MockAssembler(), DummyTree()) + regalloc = RegAlloc(MockAssembler()) + regalloc.free_regs = REGS[:] box = BoxInt() regalloc.stack_loc(box) loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True) @@ -119,13 +115,12 @@ def test_registers_around_call(self): cpu = CPU(None, None) - regalloc = RegAlloc(MockAssembler(cpu), DummyTree()) + regalloc = RegAlloc(MockAssembler(cpu)) boxes = fill_regs(regalloc) TP = lltype.FuncType([], lltype.Void) calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) regalloc._check_invariants() - for box in boxes: - regalloc.longevity[box] = (0, 1) + regalloc.longevity = dict.fromkeys(boxes, (0, 1)) box = boxes[0] regalloc.position = 0 regalloc.consider_call(ResOperation(rop.CALL, [box], None, calldescr), @@ -135,11 +130,11 @@ def test_registers_around_newstr(self): cpu = CPU(None, None) - regalloc = RegAllocForTests(MockAssembler(cpu), DummyTree()) + regalloc = RegAllocForTests(MockAssembler(cpu)) boxes = fill_regs(regalloc) regalloc._check_invariants() - for box in boxes: - regalloc.longevity[box] = (0, 1) + regalloc.longevity = dict.fromkeys(boxes, (0, 1)) + box = boxes[-1] regalloc.position = 0 resbox = BoxInt() regalloc.longevity[resbox] = (1, 1) @@ -148,7 +143,7 @@ regalloc._check_invariants() def test_move_away_does_not_spill(self): - regalloc = RegAlloc(MockAssembler(), DummyTree()) + regalloc = RegAlloc(MockAssembler()) regalloc.position = 0 resbox = BoxInt() box = BoxInt() @@ -187,7 +182,8 @@ def interpret(self, ops, args, jump_targets=None, run=True): loop = self.parse(ops, jump_targets=jump_targets) - self.cpu.compile_operations(loop) + executable_token = self.cpu.compile_loop(loop.inputargs, + loop.operations) for i, arg in enumerate(args): if isinstance(arg, int): self.cpu.set_future_value_int(i, arg) @@ -196,8 +192,11 @@ llgcref = lltype.cast_opaque_ptr(llmemory.GCREF, arg) self.cpu.set_future_value_ref(i, llgcref) if run: - self.cpu.execute_operations(loop) - return loop + self.cpu.execute_token(executable_token) + loop_token = LoopToken() + loop_token.executable_token = executable_token + loop_token._loop = loop + return loop_token def getint(self, index): return self.cpu.get_latest_value_int(index) @@ -210,13 +209,16 @@ gcref = self.cpu.get_latest_value_ref(index) return lltype.cast_opaque_ptr(T, gcref) - def attach_bridge(self, ops, loop, guard_op, **kwds): + def attach_bridge(self, ops, loop_token, guard_op_index, **kwds): + guard_op = loop_token._loop.operations[guard_op_index] assert guard_op.is_guard() bridge = self.parse(ops, **kwds) - guard_op.suboperations = bridge.operations - self.cpu.compile_operations(loop, guard_op) + faildescr = guard_op.suboperations[0].descr + self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations) return bridge + def run(self, loop_token): + return self.cpu.execute_token(loop_token.executable_token) class TestRegallocSimple(BaseTestRegalloc): def test_simple_loop(self): @@ -256,10 +258,9 @@ [i4] jump(i4, i4, i4, i4) ''' - bridge = self.attach_bridge(bridge_ops, loop2, loop2.operations[4], - jump_targets=[loop]) + bridge = self.attach_bridge(bridge_ops, loop2, 4, jump_targets=[loop]) self.cpu.set_future_value_int(0, 0) - self.cpu.execute_operations(loop2) + self.run(loop2) assert self.getint(0) == 31 assert self.getint(1) == 30 assert self.getint(2) == 30 @@ -297,9 +298,9 @@ ''' loop = self.interpret(ops, [0]) assert self.getint(0) == 1 - bridge = self.attach_bridge(bridge_ops, loop, loop.operations[1]) + bridge = self.attach_bridge(bridge_ops, loop, 1) self.cpu.set_future_value_int(0, 0) - self.cpu.execute_operations(loop) + self.run(loop) assert self.getint(0) == 1 def test_inputarg_unused(self): @@ -326,10 +327,10 @@ loop = self.interpret(ops, [0, 10]) assert self.getint(0) == 0 assert self.getint(1) == 10 - bridge = self.attach_bridge(bridge_ops, loop, loop.operations[0]) + bridge = self.attach_bridge(bridge_ops, loop, 0) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 10) - self.cpu.execute_operations(loop) + self.run(loop) assert self.getint(0) == 0 assert self.getint(1) == 10 @@ -346,10 +347,10 @@ [i0, i1] fail(1, 2) ''' - self.attach_bridge(bridge_ops, loop, loop.operations[0]) + self.attach_bridge(bridge_ops, loop, 0) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 1) - self.cpu.execute_operations(loop) + self.run(loop) def test_spill_for_constant(self): ops = ''' @@ -467,10 +468,10 @@ call(ConstClass(raising_fptr), 0, descr=raising_calldescr) fail(i0, i1, i2, i3, i4, i5, i6, i7, i8) ''' - self.attach_bridge(bridge_ops, loop, loop.operations[0]) + self.attach_bridge(bridge_ops, loop, 0) for i in range(9): self.cpu.set_future_value_int(i, i) - self.cpu.execute_operations(loop) + self.run(loop) assert self.getints(9) == range(9) class TestRegallocCompOps(BaseTestRegalloc): Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc2.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc2.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc2.py Fri Sep 25 11:37:42 2009 @@ -1,6 +1,6 @@ import py from pypy.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ - BoxPtr, ConstPtr, TreeLoop + BoxPtr, ConstPtr from pypy.jit.metainterp.resoperation import rop from pypy.jit.backend.x86.runner import CPU @@ -9,18 +9,17 @@ v2 = BoxInt() v3 = BoxInt() v4 = BoxInt() - loop = TreeLoop('test') - loop.inputargs = [v1] - loop.operations = [ + inputargs = [v1] + operations = [ ResOperation(rop.INT_ADD, [v1, v1], v2), ResOperation(rop.INT_INVERT, [v2], v3), ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4), ResOperation(rop.FAIL, [v4, v3], None), ] cpu = CPU(None, None) - cpu.compile_operations(loop) + executable_token = cpu.compile_loop(inputargs, operations) cpu.set_future_value_int(0, 9) - cpu.execute_operations(loop) + cpu.execute_token(executable_token) assert cpu.get_latest_value_int(0) == (9 >> 3) assert cpu.get_latest_value_int(1) == (~18) @@ -30,9 +29,8 @@ v3 = BoxInt() v4 = BoxInt() tmp5 = BoxInt() - loop = TreeLoop('test') - loop.inputargs = [v1] - loop.operations = [ + inputargs = [v1] + operations = [ ResOperation(rop.INT_MUL, [v1, v1], v2), ResOperation(rop.INT_MUL, [v2, v1], v3), ResOperation(rop.INT_IS_TRUE, [v2], tmp5), @@ -40,9 +38,9 @@ ResOperation(rop.FAIL, [v4, v3, tmp5], None), ] cpu = CPU(None, None) - cpu.compile_operations(loop) + executable_token = cpu.compile_loop(inputargs, operations) cpu.set_future_value_int(0, -10) - cpu.execute_operations(loop) + cpu.execute_token(executable_token) assert cpu.get_latest_value_int(0) == 0 assert cpu.get_latest_value_int(1) == -1000 assert cpu.get_latest_value_int(2) == 1 @@ -94,9 +92,8 @@ tmp44 = BoxInt() tmp45 = BoxInt() tmp46 = BoxInt() - loop = TreeLoop('test') - loop.inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - loop.operations = [ + inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] + operations = [ ResOperation(rop.UINT_GT, [v3, ConstInt(-48)], v11), ResOperation(rop.INT_XOR, [v8, v1], v12), ResOperation(rop.INT_GT, [v6, ConstInt(-9)], v13), @@ -136,7 +133,7 @@ ResOperation(rop.FAIL, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None), ] cpu = CPU(None, None) - cpu.compile_operations(loop) + executable_token = cpu.compile_loop(inputargs, operations) cpu.set_future_value_int(0, -13) cpu.set_future_value_int(1, 10) cpu.set_future_value_int(2, 10) @@ -147,7 +144,7 @@ cpu.set_future_value_int(7, 46) cpu.set_future_value_int(8, -12) cpu.set_future_value_int(9, 26) - cpu.execute_operations(loop) + cpu.execute_token(executable_token) assert cpu.get_latest_value_int(0) == 0 assert cpu.get_latest_value_int(1) == 0 assert cpu.get_latest_value_int(2) == 0 @@ -209,9 +206,8 @@ tmp43 = BoxInt() tmp44 = BoxInt() tmp45 = BoxInt() - loop = TreeLoop('test') - loop.inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - loop.operations = [ + inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] + operations = [ ResOperation(rop.UINT_LT, [v6, ConstInt(0)], v11), ResOperation(rop.INT_AND, [v3, ConstInt(31)], tmp41), ResOperation(rop.INT_RSHIFT, [v3, tmp41], v12), @@ -250,7 +246,7 @@ ResOperation(rop.FAIL, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None), ] cpu = CPU(None, None) - cpu.compile_operations(loop) + executable_token = cpu.compile_loop(inputargs, operations) cpu.set_future_value_int(0, 17) cpu.set_future_value_int(1, -20) cpu.set_future_value_int(2, -6) @@ -261,7 +257,7 @@ cpu.set_future_value_int(7, 9) cpu.set_future_value_int(8, 49) cpu.set_future_value_int(9, 8) - cpu.execute_operations(loop) + cpu.execute_token(executable_token) assert cpu.get_latest_value_int(0) == 0 assert cpu.get_latest_value_int(1) == 8 assert cpu.get_latest_value_int(2) == 1 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_runner.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_runner.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_runner.py Fri Sep 25 11:37:42 2009 @@ -1,8 +1,8 @@ import py from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr, rclass -from pypy.jit.metainterp.history import ResOperation, TreeLoop +from pypy.jit.metainterp.history import ResOperation from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr, - Box) + Box, BasicFailDescr) from pypy.jit.backend.x86.runner import CPU from pypy.jit.backend.x86.regalloc import WORD from pypy.jit.backend.llsupport import symbolic @@ -80,15 +80,13 @@ ResOperation(rop.GUARD_FALSE, [u], None), ResOperation(rop.JUMP, [z, t], None), ] - loop = TreeLoop('loop') - loop.operations = operations - loop.inputargs = [x, y] - operations[-1].jump_target = loop - operations[-2].suboperations = [ResOperation(rop.FAIL, [t, z], None)] - cpu.compile_operations(loop) + operations[-1].jump_target = None + operations[-2].suboperations = [ResOperation(rop.FAIL, [t, z], None, + descr=BasicFailDescr())] + executable_token = cpu.compile_loop([x, y], operations) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 10) - res = self.cpu.execute_operations(loop) + res = self.cpu.execute_token(executable_token) assert self.cpu.get_latest_value_int(0) == 0 assert self.cpu.get_latest_value_int(1) == 55 @@ -324,16 +322,15 @@ ResOperation(guard, [f], None), ResOperation(rop.FAIL, [ConstInt(0)], None), ] - ops[1].suboperations = [ResOperation(rop.FAIL, [ConstInt(1)], None)] - loop = TreeLoop('name') - loop.operations = ops - loop.inputargs = [b] - self.cpu.compile_operations(loop) + ops[1].suboperations = [ResOperation(rop.FAIL, + [ConstInt(1)], None, + descr=BasicFailDescr())] + executable_token = self.cpu.compile_loop([b], ops) if op == rop.INT_IS_TRUE: self.cpu.set_future_value_int(0, b.value) else: self.cpu.set_future_value_ref(0, b.value) - r = self.cpu.execute_operations(loop) + r = self.cpu.execute_token(executable_token) result = self.cpu.get_latest_value_int(0) if guard == rop.GUARD_FALSE: assert result == execute(self.cpu, op, None, b).value @@ -369,14 +366,14 @@ ResOperation(guard, [res], None), ResOperation(rop.FAIL, [ConstInt(0)], None), ] - ops[1].suboperations = [ResOperation(rop.FAIL, [ConstInt(1)], None)] - loop = TreeLoop('name') - loop.operations = ops - loop.inputargs = [i for i in (a, b) if isinstance(i, Box)] - self.cpu.compile_operations(loop) - for i, box in enumerate(loop.inputargs): + ops[1].suboperations = [ResOperation(rop.FAIL, + [ConstInt(1)], None, + descr=BasicFailDescr())] + inputargs = [i for i in (a, b) if isinstance(i, Box)] + executable_token = self.cpu.compile_loop(inputargs, ops) + for i, box in enumerate(inputargs): self.cpu.set_future_value_int(i, box.value) - r = self.cpu.execute_operations(loop) + r = self.cpu.execute_token(executable_token) result = self.cpu.get_latest_value_int(0) expected = execute(self.cpu, op, None, a, b).value if guard == rop.GUARD_FALSE: @@ -400,14 +397,12 @@ next_v = BoxInt() ops.append(ResOperation(rop.INT_ADD, [v, ConstInt(1)], next_v)) v = next_v - ops.append(ResOperation(rop.FAIL, [v], None)) - loop = TreeLoop('name') - loop.operations = ops - loop.inputargs = [base_v] - self.cpu.compile_operations(loop) + ops.append(ResOperation(rop.FAIL, [v], None, + descr=BasicFailDescr())) + executable_token = self.cpu.compile_loop([base_v], ops) assert self.cpu.assembler.mc != old_mc # overflowed self.cpu.set_future_value_int(0, base_v.value) - op = self.cpu.execute_operations(loop) + self.cpu.execute_token(executable_token) assert self.cpu.get_latest_value_int(0) == 1024 finally: MachineCodeBlockWrapper.MC_SIZE = orig_size From fijal at codespeak.net Fri Sep 25 13:55:22 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 25 Sep 2009 13:55:22 +0200 (CEST) Subject: [pypy-svn] r67875 - pypy/branch/remove-plfbid/pypy/jit/backend/test Message-ID: <20090925115522.E1F90168023@codespeak.net> Author: fijal Date: Fri Sep 25 13:55:22 2009 New Revision: 67875 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py Log: Fix the "fix me, I'm a mess", hence providing bridges for test_random Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py Fri Sep 25 13:55:22 2009 @@ -512,6 +512,7 @@ dont_compile = False if r.random() < 0.1: subset = bridge_builder.subset_of_intvars(r) + subset = [i for i in subset if i in fail_args] if len(subset) == 0: return False args = [x.clonebox() for x in subset] @@ -524,19 +525,21 @@ jump_op.jump_target.executable_token = executable_token self.should_fail_by = rl.should_fail_by self.expected = rl.expected + assert len(rl.loop.inputargs) == len(args) if self.guard_op is None: guard_op.suboperations[-1] = jump_op else: - print "fix me, I'm a mess" - return False # XXX fix me - self.guard_op.suboperations[0].args.extend(subset) - self.builder.cpu.compile_bridge(guard_op) + args = self.guard_op.suboperations[-1].args + fail_args + self.guard_op.suboperations[-1].args = args + self.builder.cpu.compile_bridge(fail_descr, fail_args, + guard_op.suboperations) + fail_descr_2 = self.guard_op.suboperations[0].descr + ops = [] if self.guard_op.is_guard_exception(): # exception clearing - self.guard_op.suboperations.insert(-1, exc_handling( - self.guard_op)) - self.guard_op.suboperations[-1] = jump_op - self.builder.cpu.compile_bridge(self.guard_op) + ops = [exc_handling(self.guard_op)] + ops.append(jump_op) + self.builder.cpu.compile_bridge(fail_descr_2, args, ops) dont_compile = True self.guard_op = rl.guard_op self.prebuilt_ptr_consts += rl.prebuilt_ptr_consts From fijal at codespeak.net Fri Sep 25 15:04:07 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 25 Sep 2009 15:04:07 +0200 (CEST) Subject: [pypy-svn] r67876 - in pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp: . test Message-ID: <20090925130407.09CAC168022@codespeak.net> Author: fijal Date: Fri Sep 25 15:04:06 2009 New Revision: 67876 Modified: pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/history.py pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/optimizeopt.py pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/pyjitpl.py pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_basic.py pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_exception.py pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_optimizeopt.py Log: Check in intermediate-changes, so they stay somewhere else than my own wc. Does not work so far Modified: pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/history.py (original) +++ pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/history.py Fri Sep 25 15:04:06 2009 @@ -761,9 +761,12 @@ self.cpu = cpu self.inputargs = None self.operations = [] + self.no_sideeffects_since_last_check = False def record(self, opnum, argboxes, resbox, descr=None): op = ResOperation(opnum, argboxes, resbox, descr) self.operations.append(op) + if not op.has_no_side_effect(): + self.no_sideeffects_since_last_check = False return op # ____________________________________________________________ Modified: pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/optimizeopt.py Fri Sep 25 15:04:06 2009 @@ -346,6 +346,8 @@ class Optimizer(object): + no_side_effects_since_last_set = False + def __init__(self, cpu, loop): self.cpu = cpu self.loop = loop @@ -493,11 +495,18 @@ op.args[i] = box if op.is_guard(): self.clone_guard(op, op1) - elif op.can_raise(): - self.exception_might_have_happened = True + else: + if not op.has_no_side_effect(): + self.no_side_effects_since_last_set = False + if op.can_raise(): + self.exception_might_have_happened = True self.newoperations.append(op) def clone_guard(self, op2, op1): + if self.no_side_effects_since_last_set: + op2.suboperations = self.last_guard.suboperations + op1.optimized = op2 + return assert len(op1.suboperations) == 1 op_fail = op1.suboperations[0] assert op_fail.opnum == rop.FAIL @@ -529,6 +538,8 @@ op_fail.args = newboxes op2.suboperations = op1.suboperations op1.optimized = op2 + self.no_side_effects_since_last_set = True + self.last_guard = op2 def clean_fields_of_values(self, descr=None): if descr is None: Modified: pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/pyjitpl.py Fri Sep 25 15:04:06 2009 @@ -910,20 +910,29 @@ return saved_pc = self.pc self.pc = pc - resumebuilder = resume.ResumeDataBuilder.make(metainterp.framestack) - if metainterp.staticdata.virtualizable_info is not None: - resumebuilder.generate_boxes(metainterp.virtualizable_boxes) + if metainterp.history.no_sideeffects_since_last_check: + resumebuilder = None + else: + resumebuilder = resume.ResumeDataBuilder.make(metainterp.framestack) + if metainterp.staticdata.virtualizable_info is not None: + resumebuilder.generate_boxes(metainterp.virtualizable_boxes) if box is not None: moreargs = [box] + extraargs else: moreargs = list(extraargs) guard_op = metainterp.history.record(opnum, moreargs, None) - resumedescr = compile.ResumeGuardDescr( - metainterp.history, len(metainterp.history.operations)-1) - liveboxes = resumebuilder.finish(resumedescr) - self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count - op = history.ResOperation(rop.FAIL, liveboxes, None, descr=resumedescr) - guard_op.suboperations = [op] + metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count + if resumebuilder is not None: + resumedescr = compile.ResumeGuardDescr( + metainterp.history, len(metainterp.history.operations)-1) + liveboxes = resumebuilder.finish(resumedescr) + op = history.ResOperation(rop.FAIL, liveboxes, None, descr=resumedescr) + guard_op.suboperations = [op] + metainterp.last_guard_op = guard_op + else: + guard_op.suboperations = metainterp.last_guard_op.suboperations + # guard ops has no reasonable side effects + #metainterp.history.no_sideeffects_since_last_check = True metainterp.attach_debug_info(guard_op) self.pc = saved_pc return guard_op @@ -1601,6 +1610,8 @@ if must_compile: guard_op = resumedescr.get_guard_op() suboperations = guard_op.suboperations + import pdb + pdb.set_trace() if suboperations[-1] is not guard_failure: must_compile = False log("ignoring old version of the guard") Modified: pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_basic.py Fri Sep 25 15:04:06 2009 @@ -886,6 +886,9 @@ class TestOOtype(BasicTests, OOJitMixin): + def setup_class(cls): + py.test.skip("!!!") + def test_oohash(self): def f(): s = ootype.oostring(5, -1) Modified: pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_exception.py ============================================================================== --- pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_exception.py (original) +++ pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_exception.py Fri Sep 25 15:04:06 2009 @@ -59,8 +59,8 @@ res = self.meta_interp(f, [20], policy=StopAtXPolicy(check)) assert res == f(20) - res = self.meta_interp(f, [21], policy=StopAtXPolicy(check)) - assert res == f(21) + #res = self.meta_interp(f, [21], policy=StopAtXPolicy(check)) + #assert res == f(21) def test_bridge_from_guard_no_exception(self): myjitdriver = JitDriver(greens = [], reds = ['n']) Modified: pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/experiment-less-resumeinfo/pypy/jit/metainterp/test/test_optimizeopt.py Fri Sep 25 15:04:06 2009 @@ -121,6 +121,7 @@ # expected = self.parse(optops) self.assert_equal(loop, expected) + return loop def test_simple(self): ops = """ @@ -1647,6 +1648,28 @@ where p7v is a node_vtable, valuedescr=iv ''') + def test_sharing_of_resumedata(self): + ops = """ + [i0, i1, i2] + guard_true(i0) + fail(i0, i1, i2) + i3 = int_add(i1, i2) + guard_true(i1) + fail(i2, i1, i0) + jump(i0, i1, i2) + """ + expected = """ + [i0, i1, i2] + guard_true(i0) + fail(i0, i1, i2) + i3 = int_add(i1, i2) + guard_true(i1) + fail(i0, i1, i2) + jump(1, 1, i2) + """ + loop = self.optimize_loop(ops, "Not, Not, Not", expected) + assert (loop.operations[0].suboperations is + loop.operations[2].suboperations) class TestLLtype(BaseTestOptimizeOpt, LLtypeMixin): pass From fijal at codespeak.net Fri Sep 25 15:04:45 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 25 Sep 2009 15:04:45 +0200 (CEST) Subject: [pypy-svn] r67877 - pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/llgraph Message-ID: <20090925130445.CE238168022@codespeak.net> Author: fijal Date: Fri Sep 25 15:04:44 2009 New Revision: 67877 Modified: pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/llgraph/llimpl.py pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/llgraph/runner.py Log: This also belongs to 67876 Modified: pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/llgraph/llimpl.py Fri Sep 25 15:04:44 2009 @@ -439,6 +439,9 @@ if self.verbose: log.trace('failed: %s' % ( ', '.join(map(str, args)),)) + print op.fail_index + import pdb + pdb.set_trace() self.fail_args = args return op.fail_index else: Modified: pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/experiment-less-resumeinfo/pypy/jit/backend/llgraph/runner.py Fri Sep 25 15:04:44 2009 @@ -86,6 +86,7 @@ self.stats.exec_conditional_jumps = 0 self.memo_cast = llimpl.new_memo_cast() self.fail_ops = [] + self.fail_memo = {} llimpl._stats = self.stats llimpl._llinterp = LLInterpreter(self.rtyper) if translate_support_code: @@ -171,8 +172,12 @@ if op.opnum == rop.JUMP: llimpl.compile_add_jump_target(c, op.jump_target._compiled_version) elif op.opnum == rop.FAIL: - llimpl.compile_add_fail(c, len(self.fail_ops)) - self.fail_ops.append(op) + num = self.fail_memo.get(op, -1) + if num == -1: + num = len(self.fail_ops) + self.fail_memo[op] = num + self.fail_ops.append(op) + llimpl.compile_add_fail(c, num) def execute_operations(self, loop): """Calls the assembler generated for the given loop. From pedronis at codespeak.net Fri Sep 25 15:07:45 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 25 Sep 2009 15:07:45 +0200 (CEST) Subject: [pypy-svn] r67878 - in pypy/branch/remove-plfbid/pypy/jit: backend/test backend/x86 backend/x86/test metainterp Message-ID: <20090925130745.DDCC1168020@codespeak.net> Author: pedronis Date: Fri Sep 25 15:07:44 2009 New Revision: 67878 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/runner.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc2.py pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_runner.py pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py Log: (arigo, pedronis) "final" cleanups Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py Fri Sep 25 15:07:44 2009 @@ -198,7 +198,10 @@ def test_finish(self): i0 = BoxInt() - faildescr = AbstractFailDescr() # to check that is not touched + class UntouchableFailDescr(AbstractFailDescr): + def __setattr__(self, name, value): + py.test.fail("finish descrs should not be touched") + faildescr = UntouchableFailDescr() # to check that is not touched operations = [ ResOperation(rop.FINISH, [i0], None, descr=faildescr) ] Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py Fri Sep 25 15:07:44 2009 @@ -2,6 +2,7 @@ import ctypes from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.history import Const, Box, BoxPtr, REF +from pypy.jit.metainterp.history import AbstractFailDescr from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory from pypy.rpython.lltypesystem.rclass import OBJECT from pypy.rpython.lltypesystem.lloperation import llop @@ -64,9 +65,10 @@ setattr(MachineCodeBlockWrapper, name, _new_method(name)) class ExecutableToken386(object): - _x86_compiled = 0 + _x86_loop_code = 0 _x86_bootstrap_code = 0 _x86_stack_depth = 0 + _x86_arglocs = None class Assembler386(object): mc = None @@ -125,47 +127,45 @@ self.mc = MachineCodeBlockWrapper() self.mc2 = MachineCodeBlockWrapper() - def _compute_longest_fail_op(self, ops): - max_so_far = 0 - for op in ops: - if op.opnum == rop.FAIL: - max_so_far = max(max_so_far, len(op.args)) - if op.is_guard(): - max_so_far = max(max_so_far, self._compute_longest_fail_op( - op.suboperations)) - assert max_so_far < MAX_FAIL_BOXES - return max_so_far - def assemble_loop(self, inputargs, operations): - self._compute_longest_fail_op(operations) self.make_sure_mc_exists() regalloc = RegAlloc(self, self.cpu.translate_support_code) - self._regalloc = regalloc - regalloc.walk_operations(inputargs, operations) - self.mc.done() - self.mc2.done() - if we_are_translated() or self.cpu.dont_keepalive_stuff: - self._regalloc = None # else keep it around for debugging - stack_depth = regalloc.current_stack_depth - jump_target = regalloc.jump_target - if jump_target is not None: - target_stack_depth = jump_target.executable_token._x86_stack_depth - stack_depth = max(stack_depth, target_stack_depth) - executable_token = regalloc.executable_token - # possibly align, e.g. for Mac OS X + arglocs = regalloc.prepare_loop(inputargs, operations) + executable_token = ExecutableToken386() + executable_token._x86_arglocs = arglocs + executable_token._x86_bootstrap_code = self.mc.tell() + adr_stackadjust = self._assemble_bootstrap_code(inputargs, arglocs) + executable_token._x86_loop_code = self.mc.tell() + self._executable_token = executable_token + stack_depth = self._assemble(regalloc, operations) + self._executable_token = None + self._patch_stackadjust(adr_stackadjust, stack_depth) executable_token._x86_stack_depth = stack_depth return executable_token def assemble_bridge(self, faildescr, inputargs, operations): - self._compute_longest_fail_op(operations) self.make_sure_mc_exists() regalloc = RegAlloc(self, self.cpu.translate_support_code) + arglocs = faildescr._x86_faillocs + fail_stack_depth = faildescr._x86_current_stack_depth + regalloc.prepare_bridge(fail_stack_depth, inputargs, arglocs, + operations) + adr_bridge = self.mc.tell() + adr_stackadjust = self._patchable_stackadjust() + stack_depth = self._assemble(regalloc, operations) + self._patch_stackadjust(adr_stackadjust, stack_depth) + if not we_are_translated(): + # for the benefit of tests + faildescr._x86_bridge_stack_depth = stack_depth + # patch the jump from original guard + adr_jump_offset = faildescr._x86_adr_jump_offset + mc = codebuf.InMemoryCodeBuilder(adr_jump_offset, adr_jump_offset + 4) + mc.write(packimm32(adr_bridge - adr_jump_offset - 4)) + mc.done() + + def _assemble(self, regalloc, operations): self._regalloc = regalloc - # stack adjustment LEA - mc = self.mc._mc - adr_bridge = mc.tell() - mc.LEA(esp, fixedsize_ebp_ofs(0)) - regalloc.walk_bridge(faildescr, inputargs, operations) + regalloc.walk_operations(operations) self.mc.done() self.mc2.done() if we_are_translated() or self.cpu.dont_keepalive_stuff: @@ -175,60 +175,21 @@ if jump_target is not None: target_stack_depth = jump_target.executable_token._x86_stack_depth stack_depth = max(stack_depth, target_stack_depth) + return stack_depth + + def _patchable_stackadjust(self): + # stack adjustment LEA + self.mc.LEA(esp, fixedsize_ebp_ofs(0)) + return self.mc.tell() - 4 + + def _patch_stackadjust(self, adr_lea, stack_depth): # patch stack adjustment LEA - if not we_are_translated(): - # for the benefit of tests - faildescr._x86_bridge_stack_depth = stack_depth - mc = codebuf.InMemoryCodeBuilder(adr_bridge, adr_bridge + 128) - mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) - mc.done() - # patch the jump from original guard - addr = faildescr._x86_addr - mc = codebuf.InMemoryCodeBuilder(addr, addr + 128) - mc.write(packimm32(adr_bridge - addr - 4)) + # possibly align, e.g. for Mac OS X + mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 4) + mc.write(packimm32(-(stack_depth + RET_BP - 2) * WORD)) mc.done() -## def assemble(self, tree, operations, guard_op): -## # the last operation can be 'jump', 'return' or 'guard_pause'; -## # a 'jump' can either close a loop, or end a bridge to some -## # previously-compiled code. -## self._compute_longest_fail_op(operations) -## self.make_sure_mc_exists() -## newpos = self.mc.tell() -## regalloc = RegAlloc(self, tree, self.cpu.translate_support_code, -## guard_op) -## self._regalloc = regalloc -## adr_lea = 0 -## if guard_op is None: -## inputargs = tree.inputargs -## regalloc.walk_operations(tree) -## else: -## inputargs = regalloc.inputargs -## mc = self.mc._mc -## adr_lea = mc.tell() -## mc.LEA(esp, fixedsize_ebp_ofs(0)) -## regalloc._walk_operations(operations) -## stack_depth = regalloc.max_stack_depth -## self.mc.done() -## self.mc2.done() -## # possibly align, e.g. for Mac OS X -## if guard_op is None: -## tree._x86_stack_depth = stack_depth -## else: -## if not we_are_translated(): -## # for the benefit of tests -## guard_op._x86_bridge_stack_depth = stack_depth -## mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 128) - -## mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) -## mc.done() -## if we_are_translated(): -## self._regalloc = None # else keep it around for debugging -## return newpos - - def assemble_bootstrap_code(self, jumpaddr, arglocs, argtypes, framesize): - self.make_sure_mc_exists() - addr = self.mc.tell() + def _assemble_bootstrap_code(self, inputargs, arglocs): self.mc.PUSH(ebp) self.mc.MOV(ebp, esp) self.mc.PUSH(ebx) @@ -236,11 +197,11 @@ self.mc.PUSH(edi) # NB. exactly 4 pushes above; if this changes, fix stack_pos(). # You must also keep _get_callshape() in sync. - self.mc.SUB(esp, imm(framesize * WORD)) + adr_stackadjust = self._patchable_stackadjust() for i in range(len(arglocs)): loc = arglocs[i] if not isinstance(loc, REG): - if argtypes[i] == REF: + if inputargs[i].type == REF: # This uses XCHG to put zeroes in fail_boxes_ptr after # reading them self.mc.XOR(ecx, ecx) @@ -253,7 +214,7 @@ for i in range(len(arglocs)): loc = arglocs[i] if isinstance(loc, REG): - if argtypes[i] == REF: + if inputargs[i].type == REF: # This uses XCHG to put zeroes in fail_boxes_ptr after # reading them self.mc.XOR(loc, loc) @@ -262,9 +223,7 @@ else: self.mc.MOV(loc, addr_add(imm(self.fail_box_int_addr), imm(i*WORD))) - self.mc.JMP(rel32(jumpaddr)) - self.mc.done() - return addr + return adr_stackadjust def dump(self, text): if not self.verbose: @@ -299,6 +258,7 @@ arglocs, resloc, current_stack_depth): fail_op = guard_op.suboperations[0] faildescr = fail_op.descr + assert isinstance(faildescr, AbstractFailDescr) faildescr._x86_current_stack_depth = current_stack_depth failargs = fail_op.args guard_opnum = guard_op.opnum @@ -309,10 +269,11 @@ dispatch_opnum = guard_opnum else: dispatch_opnum = op.opnum - addr = genop_guard_list[dispatch_opnum](self, op, guard_opnum, - failaddr, arglocs, - resloc) - faildescr._x86_addr = addr + adr_jump_offset = genop_guard_list[dispatch_opnum](self, op, + guard_opnum, + failaddr, arglocs, + resloc) + faildescr._x86_adr_jump_offset = adr_jump_offset def regalloc_perform_guard(self, guard_op, faillocs, arglocs, resloc, current_stack_depth): @@ -628,32 +589,6 @@ else: assert 0, itemsize - def make_merge_point(self, argtypes, locs): - executable_token = ExecutableToken386() - pos = self.mc.tell() - executable_token.argtypes = argtypes - executable_token.arglocs = locs - executable_token._x86_compiled = pos - return executable_token - - def _get_executable_token(self, loop_token, cur_executable_token): - if loop_token is not None: - return loop_token.executable_token - return cur_executable_token - - def extract_merge_point(self, loop_token, cur_executable_token): - executable_token = self._get_executable_token(loop_token, - cur_executable_token) - return executable_token.arglocs - - def closing_jump(self, loop_token, cur_executable_token): - executable_token = self._get_executable_token(loop_token, - cur_executable_token) - self.mc.JMP(rel32(executable_token._x86_compiled)) - - #def genop_discard_jump(self, op, locs): - # self.mc.JMP(rel32(op.jump_target._x86_compiled)) - def genop_guard_guard_true(self, ign_1, guard_opnum, addr, locs, ign_2): loc = locs[0] self.mc.TEST(loc, loc) @@ -709,6 +644,7 @@ return addr def generate_failure(self, mc, faildescr, failargs, locs, exc): + assert len(failargs) < MAX_FAIL_BOXES pos = mc.tell() for i in range(len(locs)): loc = locs[i] @@ -744,8 +680,9 @@ # don't break the following code sequence! mc = mc._mc mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD)) - guard_index = self.cpu.make_guard_index(faildescr) - mc.MOV(eax, imm(guard_index)) + assert isinstance(faildescr, AbstractFailDescr) + fail_index = self.cpu.make_fail_index(faildescr) + mc.MOV(eax, imm(fail_index)) mc.POP(edi) mc.POP(esi) mc.POP(ebx) @@ -826,6 +763,20 @@ mark = self._regalloc.get_mark_gc_roots(gcrootmap) gcrootmap.put(rffi.cast(llmemory.Address, self.mc.tell()), mark) + def _get_executable_token(self, loop_token): + if loop_token is not None: + return loop_token.executable_token + assert self._executable_token is not None + return self._executable_token + + def target_arglocs(self, loop_token): + executable_token = self._get_executable_token(loop_token) + return executable_token._x86_arglocs + + def closing_jump(self, loop_token): + executable_token = self._get_executable_token(loop_token) + self.mc.JMP(rel32(executable_token._x86_loop_code)) + genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST genop_list = [Assembler386.not_implemented_op] * rop._LAST Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py Fri Sep 25 15:07:44 2009 @@ -66,11 +66,10 @@ self.longevity = None # to be read/used by the assembler too - self.executable_token = None self.current_stack_depth = 0 self.jump_target = None - def walk_operations(self, inputargs, operations): + def prepare_loop(self, inputargs, operations): cpu = self.assembler.cpu cpu.gc_ll_descr.rewrite_assembler(cpu, operations) # compute longevity of variables @@ -80,48 +79,16 @@ self.loop_consts = loop_consts self.current_stack_depth = 0 self.free_regs = REGS[:] - self.executable_token = self._process_inputargs(inputargs) - self._walk_operations(operations) + return self._process_inputargs(inputargs) - def walk_bridge(self, faildescr, inputargs, operations): + def prepare_bridge(self, prev_stack_depth, inputargs, arglocs, operations): cpu = self.assembler.cpu - locs = faildescr._x86_faillocs cpu.gc_ll_descr.rewrite_assembler(cpu, operations) # compute longevity of variables self._compute_vars_longevity(inputargs, operations) self.loop_consts = {} - self._update_bindings(locs, inputargs) - self.current_stack_depth = faildescr._x86_current_stack_depth - self._walk_operations(operations) - -## def x__init__(self, assembler, tree, translate_support_code=False, -## guard_op=None): -## # variables that have place in register -## self.assembler = assembler -## self.translate_support_code = translate_support_code -## cpu = self.assembler.cpu -## self.reg_bindings = newcheckdict() -## self.stack_bindings = newcheckdict() -## self.tree = tree -## if guard_op is not None: -## locs = guard_op._x86_faillocs -## cpu.gc_ll_descr.rewrite_assembler(cpu, guard_op.suboperations) -## inpargs = [arg for arg in guard_op._fail_op.args if -## isinstance(arg, Box)] -## self._compute_vars_longevity(inpargs, guard_op.suboperations) -## self.position = -1 -## self._update_bindings(locs, inpargs) -## self.current_stack_depth = guard_op._x86_current_stack_depth -## self.loop_consts = {} -## else: -## cpu.gc_ll_descr.rewrite_assembler(cpu, tree.operations) -## self._compute_vars_longevity(tree.inputargs, tree.operations) -## # compute longevity of variables -## jump = tree.operations[-1] -## loop_consts = self._compute_loop_consts(tree.inputargs, jump) -## self.loop_consts = loop_consts -## self.current_stack_depth = 0 -## self.free_regs = REGS[:] + self._update_bindings(arglocs, inputargs) + self.current_stack_depth = prev_stack_depth def _process_inputargs(self, inputargs): # XXX we can sort out here by longevity if we need something @@ -131,10 +98,8 @@ # Must be kept in sync with consider_jump(). tmpreg = self.free_regs.pop(0) assert tmpreg == REGS[0] - argtypes = [] for i in range(len(inputargs)): arg = inputargs[i] - argtypes.append(arg.type) assert not isinstance(arg, Const) reg = None if arg not in self.loop_consts and self.longevity[arg][1] > -1: @@ -147,10 +112,8 @@ # otherwise we have it saved on stack, so no worry self.free_regs.insert(0, tmpreg) assert tmpreg not in locs - # xxx think - executable_token = self.assembler.make_merge_point(argtypes, locs) self.eventually_free_vars(inputargs) - return executable_token + return locs def _compute_loop_consts(self, inputargs, jump): if jump.opnum != rop.JUMP or jump.jump_target is not None: @@ -265,22 +228,7 @@ return False return True -## def walk_operations(self, tree): -## # first pass - walk along the operations in order to find -## # load/store places -## self.position = -1 -## operations = tree.operations -## self.process_inputargs(tree) -## self._walk_operations(operations) - - #def walk_guard_ops(self, inputargs, operations, exc): - # self.exc = exc - # old_regalloc = self.assembler._regalloc - # self.assembler._regalloc = self - # self._walk_operations(operations) - # self.assembler._regalloc = old_regalloc - - def _walk_operations(self, operations): + def walk_operations(self, operations): i = 0 #self.operations = operations while i < len(operations): @@ -331,33 +279,6 @@ assert isinstance(arg, Box) self.longevity = longevity -# def _compute_inpargs(self, guard): -# operations = guard.suboperations -# longevity = {} -# end = {} -# for i in range(len(operations)-1, -1, -1): -# op = operations[i] -# if op.is_guard(): -# for arg in op.suboperations[0].args: -# if isinstance(arg, Box) and arg not in end: -# end[arg] = i -# for arg in op.args: -# if isinstance(arg, Box) and arg not in end: -# end[arg] = i -# if op.result: -# if op.result in end: -# longevity[op.result] = (i, end[op.result]) -# del end[op.result] -# # otherwise this var is never ever used -# for v, e in end.items(): -# longevity[v] = (0, e) -# inputargs = end.keys() -# for arg in longevity: -# assert isinstance(arg, Box) -# for arg in inputargs: -# assert isinstance(arg, Box) -# return inputargs, longevity - def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): assert not isinstance(v, Const) if selected_reg is not None: @@ -961,8 +882,7 @@ assembler = self.assembler assert self.jump_target is None self.jump_target = op.jump_target - arglocs = assembler.extract_merge_point(self.jump_target, - self.executable_token) + arglocs = assembler.target_arglocs(self.jump_target) # compute 'tmploc' to be REGS[0] by spilling what is there box = TempBox() tmploc = self.force_allocate_reg(box, [], selected_reg=REGS[0]) @@ -972,7 +892,7 @@ remap_stack_layout(assembler, src_locations, dst_locations, tmploc) self.eventually_free_var(box) self.eventually_free_vars(op.args) - assembler.closing_jump(op.jump_target, self.executable_token) + assembler.closing_jump(self.jump_target) def consider_debug_merge_point(self, op, ignored): pass Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/runner.py Fri Sep 25 15:07:44 2009 @@ -20,7 +20,7 @@ AbstractLLCPU.__init__(self, rtyper, stats, translate_support_code, gcdescr) self._bootstrap_cache = {} - self._guard_list = [] + self._faildescr_list = [] if rtyper is not None: # for tests self.lltype2vtable = rtyper.lltype_to_vtable_mapping() @@ -39,24 +39,10 @@ def compile_bridge(self, faildescr, inputargs, operations): self.assembler.assemble_bridge(faildescr, inputargs, operations) - def execute_token(self, executable_token): - func = self.get_bootstrap_code(executable_token) - guard_index = self.execute_call(func) - op = self._guard_list[guard_index] # xxx - return op - - def get_bootstrap_code(self, executable_token): - addr = executable_token._x86_bootstrap_code - if not addr: - arglocs = executable_token.arglocs - addr = self.assembler.assemble_bootstrap_code( - executable_token._x86_compiled, - arglocs, - executable_token.argtypes, - executable_token._x86_stack_depth) - executable_token._x86_bootstrap_code = addr - func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr) - return func + def make_fail_index(self, faildescr): + index = len(self._faildescr_list) + self._faildescr_list.append(faildescr) + return index def set_future_value_int(self, index, intvalue): assert index < MAX_FAIL_BOXES, "overflow!" @@ -76,7 +62,14 @@ llmemory.GCREF.TO) return ptrvalue - def execute_call(self, func): + def execute_token(self, executable_token): + addr = executable_token._x86_bootstrap_code + func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr) + faildescr_index = self._execute_call(func) + faildescr = self._faildescr_list[faildescr_index] + return faildescr + + def _execute_call(self, func): # help flow objspace prev_interpreter = None if not self.translate_support_code: @@ -93,11 +86,6 @@ LLInterpreter.current_interpreter = prev_interpreter return res - def make_guard_index(self, guard_op): - index = len(self._guard_list) - self._guard_list.append(guard_op) - return index - @staticmethod def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc2.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc2.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_regalloc2.py Fri Sep 25 15:07:44 2009 @@ -1,6 +1,6 @@ import py from pypy.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ - BoxPtr, ConstPtr + BoxPtr, ConstPtr, BasicFailDescr from pypy.jit.metainterp.resoperation import rop from pypy.jit.backend.x86.runner import CPU @@ -14,7 +14,7 @@ ResOperation(rop.INT_ADD, [v1, v1], v2), ResOperation(rop.INT_INVERT, [v2], v3), ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4), - ResOperation(rop.FAIL, [v4, v3], None), + ResOperation(rop.FAIL, [v4, v3], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) @@ -35,7 +35,7 @@ ResOperation(rop.INT_MUL, [v2, v1], v3), ResOperation(rop.INT_IS_TRUE, [v2], tmp5), ResOperation(rop.BOOL_NOT, [tmp5], v4), - ResOperation(rop.FAIL, [v4, v3, tmp5], None), + ResOperation(rop.FAIL, [v4, v3, tmp5], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) @@ -130,7 +130,7 @@ ResOperation(rop.UINT_GT, [v33, ConstInt(-11)], v38), ResOperation(rop.INT_NEG, [v7], v39), ResOperation(rop.INT_GT, [v24, v32], v40), - ResOperation(rop.FAIL, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None), + ResOperation(rop.FAIL, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) @@ -243,7 +243,7 @@ ResOperation(rop.INT_GT, [v4, v11], v38), ResOperation(rop.INT_LT, [v27, v22], v39), ResOperation(rop.INT_NEG, [v27], v40), - ResOperation(rop.FAIL, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None), + ResOperation(rop.FAIL, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_runner.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_runner.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/test_runner.py Fri Sep 25 15:07:44 2009 @@ -320,7 +320,8 @@ ops = [ ResOperation(op, [b], f), ResOperation(guard, [f], None), - ResOperation(rop.FAIL, [ConstInt(0)], None), + ResOperation(rop.FAIL, [ConstInt(0)], None, + descr=BasicFailDescr()), ] ops[1].suboperations = [ResOperation(rop.FAIL, [ConstInt(1)], None, @@ -364,7 +365,8 @@ ops = [ ResOperation(op, [a, b], res), ResOperation(guard, [res], None), - ResOperation(rop.FAIL, [ConstInt(0)], None), + ResOperation(rop.FAIL, [ConstInt(0)], None, + descr=BasicFailDescr()), ] ops[1].suboperations = [ResOperation(rop.FAIL, [ConstInt(1)], None, Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py Fri Sep 25 15:07:44 2009 @@ -40,7 +40,6 @@ to the first operation. """ from pypy.jit.metainterp.pyjitpl import DEBUG - history = metainterp.history loop = create_empty_loop(metainterp) loop.greenkey = greenkey Modified: pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py Fri Sep 25 15:07:44 2009 @@ -119,15 +119,15 @@ class AbstractDescr(AbstractValue): __slots__ = () - def handle_fail_op(self, metainterp, fail_op): - raise NotImplementedError - def compile_and_attach(self, metainterp, new_loop): - raise NotImplementedError def repr_of_descr(self): return '%r' % (self,) class AbstractFailDescr(AbstractDescr): - __slots__ = () + + def handle_fail(self, metainterp_sd): + raise NotImplementedError + def compile_and_attach(self, metainterp, new_loop): + raise NotImplementedError class BasicFailDescr(AbstractFailDescr): pass From fijal at codespeak.net Fri Sep 25 15:07:45 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 25 Sep 2009 15:07:45 +0200 (CEST) Subject: [pypy-svn] r67879 - pypy/branch/experiment-less-resumeinfo Message-ID: <20090925130745.DB5D6168024@codespeak.net> Author: fijal Date: Fri Sep 25 15:07:45 2009 New Revision: 67879 Removed: pypy/branch/experiment-less-resumeinfo/ Log: Remove going-nowhere branch From pedronis at codespeak.net Fri Sep 25 15:23:38 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 25 Sep 2009 15:23:38 +0200 (CEST) Subject: [pypy-svn] r67880 - pypy/branch/remove-plfbid/pypy/jit/backend/test Message-ID: <20090925132338.38E01168022@codespeak.net> Author: pedronis Date: Fri Sep 25 15:23:37 2009 New Revision: 67880 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/test_logger.py Log: fix test Modified: pypy/branch/remove-plfbid/pypy/jit/backend/test/test_logger.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/test/test_logger.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/test/test_logger.py Fri Sep 25 15:23:37 2009 @@ -1,5 +1,5 @@ -from pypy.jit.metainterp.test.oparser import parse +from pypy.jit.metainterp.test.oparser import pure_parse from pypy.jit.backend import logger from pypy.jit.metainterp.typesystem import llhelper from StringIO import StringIO @@ -29,10 +29,10 @@ """ parse loop once, then log it and parse again, return both """ - loop = parse(inp, namespace=namespace) + loop = pure_parse(inp, namespace=namespace) logger = Logger(self.ts) output = logger.log_loop(loop, namespace) - oloop = parse(output, namespace=namespace) + oloop = pure_parse(output, namespace=namespace) return loop, oloop def test_simple(self): From arigo at codespeak.net Fri Sep 25 15:38:34 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 15:38:34 +0200 (CEST) Subject: [pypy-svn] r67881 - pypy/branch/remove-plfbid/pypy/jit/backend/x86 Message-ID: <20090925133834.0701D16801E@codespeak.net> Author: arigo Date: Fri Sep 25 15:38:33 2009 New Revision: 67881 Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py Log: (pedronis, arigo) Kill useless lines. Modified: pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py Fri Sep 25 15:38:33 2009 @@ -7,7 +7,6 @@ from pypy.rpython.lltypesystem.rclass import OBJECT from pypy.rpython.lltypesystem.lloperation import llop from pypy.tool.uid import fixid -from pypy.jit.backend.logger import Logger from pypy.jit.backend.x86.regalloc import (RegAlloc, WORD, REGS, TempBox, lower_byte, stack_pos) from pypy.rlib.objectmodel import we_are_translated, specialize @@ -83,7 +82,6 @@ self.malloc_array_func_addr = 0 self.malloc_str_func_addr = 0 self.malloc_unicode_func_addr = 0 - self.logger = Logger(cpu.ts) self.fail_boxes_int = lltype.malloc(lltype.GcArray(lltype.Signed), MAX_FAIL_BOXES, zero=True) self.fail_boxes_ptr = lltype.malloc(lltype.GcArray(llmemory.GCREF), @@ -103,7 +101,6 @@ self.fail_box_ptr_addr = rffi.cast(lltype.Signed, lltype.direct_arrayitems(self.fail_boxes_ptr)) - self.logger.create_log() # the address of the function called by 'new' gc_ll_descr = self.cpu.gc_ll_descr gc_ll_descr.initialize() From arigo at codespeak.net Fri Sep 25 15:49:29 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 15:49:29 +0200 (CEST) Subject: [pypy-svn] r67882 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090925134929.3036D16801D@codespeak.net> Author: arigo Date: Fri Sep 25 15:49:28 2009 New Revision: 67882 Added: pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp - copied, changed from r67880, pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/remove-plfbid/pypy/jit/metainterp/pyjitpl.py revisions 67829 to 67880: ------------------------------------------------------------------------ r67859 | pedronis | 2009-09-23 20:24:08 +0200 (Wed, 23 Sep 2009) | 3 lines (arigo, pedronis) getting somewhere in terms of a saner backend interface ------------------------------------------------------------------------ r67851 | pedronis | 2009-09-23 15:09:23 +0200 (Wed, 23 Sep 2009) | 3 lines (arigo, pedronis) we don't keep loop around anymore, just loop tokens ------------------------------------------------------------------------ r67848 | pedronis | 2009-09-22 19:31:55 +0200 (Tue, 22 Sep 2009) | 3 lines (arigo, pedronis) WIP more refactoring in progress not to keep loops around at all ------------------------------------------------------------------------ r67845 | pedronis | 2009-09-22 17:21:54 +0200 (Tue, 22 Sep 2009) | 6 lines (arigo, pedronis) - fix the frontend, less storing of the old loops but still issues e.g. with stats - some failures related to the llgraph backend always recompiling everything ------------------------------------------------------------------------ r67844 | pedronis | 2009-09-22 16:24:57 +0200 (Tue, 22 Sep 2009) | 6 lines (arigo, pedronis) WIP - start redefining the backend interface - start removing the need to keep unoptimized loops around ------------------------------------------------------------------------ r67832 | arigo | 2009-09-21 19:36:14 +0200 (Mon, 21 Sep 2009) | 4 lines (pedronis, arigo) Really kill PrepareLoopFromBridgeIsDisabled, and replace it with a working (if inefficient) solution instead. ------------------------------------------------------------------------ r67830 | arigo | 2009-09-21 18:11:04 +0200 (Mon, 21 Sep 2009) | 2 lines A branch in which we try to remove PrepareLoopFromBridgeIsDisabled. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp (from r67880, pypy/trunk/pypy/jit/metainterp/pyjitpl.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp Fri Sep 25 15:49:28 2009 @@ -30,12 +30,13 @@ "steps": 1, "detailed": 2} -def log(msg): +def log(msg, event_kind='info'): if not we_are_translated(): - history.log.info(msg) + getattr(history.log, event_kind)(msg) elif DEBUG: debug_print(msg) + class arguments(object): def __init__(self, *argtypes): self.argtypes = argtypes @@ -802,17 +803,19 @@ @arguments("orgpc") def opimpl_jit_merge_point(self, pc): - if self.metainterp.is_blackholing(): - self.blackhole_reached_merge_point(self.env) - return True - else: + if not self.metainterp.is_blackholing(): self.generate_merge_point(pc, self.env) if DEBUG > 0: self.debug_merge_point() if self.metainterp.seen_can_enter_jit: self.metainterp.seen_can_enter_jit = False - self.metainterp.reached_can_enter_jit(self.env) - return False + try: + self.metainterp.reached_can_enter_jit(self.env) + except GiveUp: + self.metainterp.switch_to_blackhole() + if self.metainterp.is_blackholing(): + self.blackhole_reached_merge_point(self.env) + return True def debug_merge_point(self): # debugging: produce a DEBUG_MERGE_POINT operation @@ -871,8 +874,6 @@ check_args(*argboxes) self.pc = 0 self.env = argboxes - if not we_are_translated(): - self.metainterp._debug_history[-1][-1] = argboxes def setup_resume_at_op(self, pc, exception_target, env): if not we_are_translated(): @@ -917,9 +918,9 @@ moreargs = [box] + extraargs else: moreargs = list(extraargs) - guard_op = metainterp.history.record(opnum, moreargs, None) - resumedescr = compile.ResumeGuardDescr( - metainterp.history, len(metainterp.history.operations)-1) + guard_op = metainterp.history.record(opnum, moreargs, None) + original_greenkey = metainterp.resumekey.original_greenkey + resumedescr = compile.ResumeGuardDescr(original_greenkey, guard_op) liveboxes = resumebuilder.finish(resumedescr) self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count op = history.ResOperation(rop.FAIL, liveboxes, None, descr=resumedescr) @@ -956,11 +957,6 @@ descr=descr) if resbox is not None: self.make_result_box(resbox) - if not we_are_translated(): - # this assumes that execute_varargs() is only used for calls, - # which is the case so far - self.metainterp._debug_history.append(['call', - argboxes[0], argboxes[1:]]) if exc: return self.metainterp.handle_exception() return False @@ -1067,7 +1063,6 @@ class MetaInterpGlobalData(object): def __init__(self, staticdata): - self._debug_history = [] self.initialized = False # state = staticdata.state @@ -1088,8 +1083,6 @@ def __init__(self, staticdata): self.staticdata = staticdata self.cpu = staticdata.cpu - if not we_are_translated(): - self._debug_history = staticdata.globaldata._debug_history def is_blackholing(self): return self.history is None @@ -1101,8 +1094,6 @@ return "" def newframe(self, jitcode): - if not we_are_translated(): - self._debug_history.append(['enter', jitcode, None]) if jitcode is self.staticdata.portal_code: self.in_recursion += 1 f = MIFrame(self, jitcode) @@ -1117,8 +1108,6 @@ def finishframe(self, resultbox): frame = self.popframe() - if not we_are_translated(): - self._debug_history.append(['leave', frame.jitcode, None]) if self.framestack: if resultbox is not None: self.framestack[-1].make_result_box(resultbox) @@ -1157,8 +1146,6 @@ frame.exception_box = exceptionbox frame.exc_value_box = excvaluebox return True - if not we_are_translated(): - self._debug_history.append(['leave_exc', frame.jitcode, None]) self.popframe() if not self.is_blackholing(): self.compile_exit_frame_with_exception(excvaluebox) @@ -1197,8 +1184,7 @@ def create_empty_history(self): warmrunnerstate = self.staticdata.state self.history = history.History(self.cpu) - if self.staticdata.stats is not None: - self.staticdata.stats.history = self.history + self.staticdata.stats.set_history(self.history) def _all_constants(self, *boxes): if len(boxes) == 0: @@ -1289,27 +1275,24 @@ op.pc = self.framestack[-1].pc op.name = self.framestack[-1].jitcode.name + def switch_to_blackhole(self): + self.history = None # start blackholing + self.staticdata.stats.aborted() + log('~~~ ABORTING TRACING', event_kind='event') + self.staticdata.profiler.end_tracing() + self.staticdata.profiler.start_blackhole() + def switch_to_blackhole_if_trace_too_long(self): if not self.is_blackholing(): warmrunnerstate = self.staticdata.state if len(self.history.operations) > warmrunnerstate.trace_limit: - self.history = None # start blackholing - if not we_are_translated(): - self.staticdata.stats.aborted_count += 1 - history.log.event('ABORTING TRACING') - elif DEBUG: - debug_print('~~~ ABORTING TRACING') - self.staticdata.profiler.end_tracing() - self.staticdata.profiler.start_blackhole() + self.switch_to_blackhole() def _interpret(self): # Execute the frames forward until we raise a DoneWithThisFrame, # a ContinueRunningNormally, or a GenerateMergePoint exception. - if not we_are_translated(): - history.log.event('ENTER' + self.blackholing_text()) - self.staticdata.stats.enter_count += 1 - elif DEBUG: - debug_print('~~~ ENTER', self.blackholing_text()) + self.staticdata.stats.entered() + log('~~~ ENTER' + self.blackholing_text(), event_kind='event') try: while True: self.framestack[-1].run_one_step() @@ -1321,10 +1304,7 @@ self.staticdata.profiler.end_blackhole() else: self.staticdata.profiler.end_tracing() - if not we_are_translated(): - history.log.event('LEAVE' + self.blackholing_text()) - elif DEBUG: - debug_print('~~~ LEAVE', self.blackholing_text()) + log('~~~ LEAVE' + self.blackholing_text(), event_kind='event') def interpret(self): if we_are_translated(): @@ -1342,8 +1322,11 @@ log('Switching from interpreter to compiler') original_boxes = self.initialize_state_from_start(*args) self.current_merge_points = [(original_boxes, 0)] - self.resumekey = compile.ResumeFromInterpDescr(original_boxes) - self.extra_rebuild_operations = -1 + num_green_args = self.staticdata.num_green_args + original_greenkey = original_boxes[:num_green_args] + redkey = original_boxes[num_green_args:] + self.resumekey = compile.ResumeFromInterpDescr(original_greenkey, + redkey) self.seen_can_enter_jit = False try: self.interpret() @@ -1355,11 +1338,11 @@ from pypy.jit.metainterp.warmspot import ContinueRunningNormallyBase resumedescr = self.initialize_state_from_guard_failure(exec_result) assert isinstance(key, compile.ResumeGuardDescr) - top_history = key.find_toplevel_history() - source_loop = top_history.source_link - assert isinstance(source_loop, history.TreeLoop) - original_boxes = source_loop.greenkey + top_history.inputargs - self.current_merge_points = [(original_boxes, 0)] + original_greenkey = key.original_greenkey + # notice that here we just put the greenkey + # use -1 to mark that we will have to give up + # because we cannot reconstruct the beginning of the proper loop + self.current_merge_points = [(original_greenkey, -1)] self.resumekey = key self.seen_can_enter_jit = False guard_op = key.get_guard_op() @@ -1409,7 +1392,7 @@ for j in range(len(self.current_merge_points)-1, -1, -1): original_boxes, start = self.current_merge_points[j] - assert len(original_boxes) == len(live_arg_boxes) + assert len(original_boxes) == len(live_arg_boxes) or start < 0 for i in range(self.staticdata.num_green_args): box1 = original_boxes[i] box2 = live_arg_boxes[i] @@ -1418,34 +1401,19 @@ break else: # Found! Compile it as a loop. + if start < 0: + # we cannot reconstruct the beginning of the proper loop + raise GiveUp + oldops = self.history.operations[:] - if j > 0: - # clean up, but without shifting the end of the list - # (that would make 'history_guard_index' invalid) - for i in range(start): - self.history.operations[i] = None - else: - assert start == 0 - if self.extra_rebuild_operations >= 0: - # The history only starts at a bridge, not at the - # full loop header. Complete it as a full loop by - # inserting a copy of the operations from the old - # loop branch before the guard that failed. - start = self.extra_rebuild_operations - assert start >= 0 - # clean up, but without shifting the end of the list - for i in range(start): - self.history.operations[i] = None - compile.prepare_loop_from_bridge(self, self.resumekey) - loop = self.compile(original_boxes, live_arg_boxes, start) - if loop is not None: - raise GenerateMergePoint(live_arg_boxes, loop) + # raises in case it works -- which is the common case + self.compile(original_boxes, live_arg_boxes, start) # creation of the loop was cancelled! Patch # history.operations so that it contains again # exactly its old list of operations... # xxx maybe we could patch history.operations with # Nones after calling self.compile() instead of - # before... + # before... xxx maybe we should just raise GiveUp del self.history.operations[:] self.history.operations.extend(oldops) @@ -1454,13 +1422,13 @@ self.current_merge_points.append((live_arg_boxes, start)) def designate_target_loop(self, gmp): - loop = gmp.target_loop + loop_token = gmp.target_loop_token num_green_args = self.staticdata.num_green_args - residual_args = self.get_residual_args(loop, + residual_args = self.get_residual_args(loop_token.specnodes, gmp.argboxes[num_green_args:]) history.set_future_values(self.cpu, residual_args) self.clean_up_history() - return loop + return loop_token.executable_token def clean_up_history(self): # Clear the BoxPtrs used in self.history, at the end. The @@ -1503,12 +1471,12 @@ greenkey = original_boxes[:num_green_args] glob = self.staticdata.globaldata greenargs = glob.unpack_greenkey(greenkey) - old_loops = glob.compiled_merge_points.setdefault(greenargs, []) + old_loop_tokens = glob.compiled_merge_points.setdefault(greenargs, []) self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None) - loop = compile.compile_new_loop(self, old_loops, greenkey, start) - if not we_are_translated() and loop is not None: - loop._call_history = self._debug_history - return loop + loop_token = compile.compile_new_loop(self, old_loop_tokens, + greenkey, start) + if loop_token is not None: # raise if it *worked* correctly + raise GenerateMergePoint(live_arg_boxes, loop_token) def compile_bridge(self, live_arg_boxes): num_green_args = self.staticdata.num_green_args @@ -1516,14 +1484,14 @@ glob = self.staticdata.globaldata greenargs = glob.unpack_greenkey(greenkey) try: - old_loops = glob.compiled_merge_points[greenargs] + old_loop_tokens = glob.compiled_merge_points[greenargs] except KeyError: return self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None) - target_loop = compile.compile_new_bridge(self, old_loops, - self.resumekey) - if target_loop is not None: # raise if it *worked* correctly - raise GenerateMergePoint(live_arg_boxes, target_loop) + target_loop_token = compile.compile_new_bridge(self, old_loop_tokens, + self.resumekey) + if target_loop_token is not None: # raise if it *worked* correctly + raise GenerateMergePoint(live_arg_boxes, target_loop_token) self.history.operations.pop() # remove the JUMP def compile_done_with_this_frame(self, exitbox): @@ -1533,37 +1501,39 @@ if sd.result_type == 'void': assert exitbox is None exits = [] - loops = compile.loops_done_with_this_frame_void + loop_tokens = compile.loop_tokens_done_with_this_frame_void elif sd.result_type == 'int': exits = [exitbox] - loops = compile.loops_done_with_this_frame_int + loop_tokens = compile.loop_tokens_done_with_this_frame_int elif sd.result_type == 'ref': exits = [exitbox] - loops = sd.cpu.ts.loops_done_with_this_frame_ref + loop_tokens = compile.loop_tokens_done_with_this_frame_ref elif sd.result_type == 'float': exits = [exitbox] - loops = compile.loops_done_with_this_frame_float + loop_tokens = compile.loop_tokens_done_with_this_frame_float else: assert False self.history.record(rop.JUMP, exits, None) - target_loop = compile.compile_new_bridge(self, loops, self.resumekey) - assert target_loop is loops[0] + target_loop_token = compile.compile_new_bridge(self, loop_tokens, + self.resumekey) + assert target_loop_token is loop_tokens[0] def compile_exit_frame_with_exception(self, valuebox): self.gen_store_back_in_virtualizable() # temporarily put a JUMP to a pseudo-loop self.history.record(rop.JUMP, [valuebox], None) - loops = self.cpu.ts.loops_exit_frame_with_exception_ref - target_loop = compile.compile_new_bridge(self, loops, self.resumekey) - assert target_loop is loops[0] + loop_tokens = compile.loop_tokens_exit_frame_with_exception_ref + target_loop_token = compile.compile_new_bridge(self, loop_tokens, + self.resumekey) + assert target_loop_token is loop_tokens[0] - def get_residual_args(self, loop, args): - if loop.specnodes is None: # it is None only for tests + def get_residual_args(self, specnodes, args): + if specnodes is None: # it is None only for tests return args - assert len(loop.specnodes) == len(args) + assert len(specnodes) == len(args) expanded_args = [] - for i in range(len(loop.specnodes)): - specnode = loop.specnodes[i] + for i in range(len(specnodes)): + specnode = specnodes[i] specnode.extract_runtime_data(self.cpu, args[i], expanded_args) return expanded_args @@ -1601,17 +1571,8 @@ if must_compile: guard_op = resumedescr.get_guard_op() suboperations = guard_op.suboperations - if suboperations[-1] is not guard_failure: - must_compile = False - log("ignoring old version of the guard") - else: - self.history = history.History(self.cpu) - extra = len(suboperations) - 1 - assert extra >= 0 - for i in range(extra): - self.history.operations.append(suboperations[i]) - self.extra_rebuild_operations = extra - if must_compile: + assert suboperations[-1] is guard_failure + self.history = history.History(self.cpu) self.staticdata.profiler.start_tracing() else: self.staticdata.profiler.start_blackhole() @@ -1698,8 +1659,6 @@ return False def rebuild_state_after_failure(self, resumedescr, newboxes): - if not we_are_translated(): - self._debug_history.append(['guard_failure', None, None]) vinfo = self.staticdata.virtualizable_info resumereader = resume.ResumeDataReader(resumedescr, newboxes, self) self.framestack = [] @@ -1812,7 +1771,10 @@ class GenerateMergePoint(Exception): - def __init__(self, args, target_loop): - assert target_loop is not None + def __init__(self, args, target_loop_token): + assert target_loop_token is not None self.argboxes = args - self.target_loop = target_loop + self.target_loop_token = target_loop_token + +class GiveUp(Exception): + pass From arigo at codespeak.net Fri Sep 25 15:49:34 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 15:49:34 +0200 (CEST) Subject: [pypy-svn] r67883 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090925134934.95D34168026@codespeak.net> Author: arigo Date: Fri Sep 25 15:49:33 2009 New Revision: 67883 Added: pypy/trunk/pypy/jit/metainterp/compile.py.merge.tmp - copied, changed from r67880, pypy/trunk/pypy/jit/metainterp/compile.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/remove-plfbid/pypy/jit/metainterp/compile.py revisions 67829 to 67880: ------------------------------------------------------------------------ r67878 | pedronis | 2009-09-25 15:07:44 +0200 (Fri, 25 Sep 2009) | 3 lines (arigo, pedronis) "final" cleanups ------------------------------------------------------------------------ r67859 | pedronis | 2009-09-23 20:24:08 +0200 (Wed, 23 Sep 2009) | 3 lines (arigo, pedronis) getting somewhere in terms of a saner backend interface ------------------------------------------------------------------------ r67851 | pedronis | 2009-09-23 15:09:23 +0200 (Wed, 23 Sep 2009) | 3 lines (arigo, pedronis) we don't keep loop around anymore, just loop tokens ------------------------------------------------------------------------ r67848 | pedronis | 2009-09-22 19:31:55 +0200 (Tue, 22 Sep 2009) | 3 lines (arigo, pedronis) WIP more refactoring in progress not to keep loops around at all ------------------------------------------------------------------------ r67845 | pedronis | 2009-09-22 17:21:54 +0200 (Tue, 22 Sep 2009) | 6 lines (arigo, pedronis) - fix the frontend, less storing of the old loops but still issues e.g. with stats - some failures related to the llgraph backend always recompiling everything ------------------------------------------------------------------------ r67844 | pedronis | 2009-09-22 16:24:57 +0200 (Tue, 22 Sep 2009) | 6 lines (arigo, pedronis) WIP - start redefining the backend interface - start removing the need to keep unoptimized loops around ------------------------------------------------------------------------ r67832 | arigo | 2009-09-21 19:36:14 +0200 (Mon, 21 Sep 2009) | 4 lines (pedronis, arigo) Really kill PrepareLoopFromBridgeIsDisabled, and replace it with a working (if inefficient) solution instead. ------------------------------------------------------------------------ r67830 | arigo | 2009-09-21 18:11:04 +0200 (Mon, 21 Sep 2009) | 2 lines A branch in which we try to remove PrepareLoopFromBridgeIsDisabled. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/compile.py.merge.tmp (from r67880, pypy/trunk/pypy/jit/metainterp/compile.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py.merge.tmp Fri Sep 25 15:49:33 2009 @@ -5,68 +5,15 @@ from pypy.conftest import option from pypy.jit.metainterp.resoperation import ResOperation, rop -from pypy.jit.metainterp.history import TreeLoop, log, Box, History -from pypy.jit.metainterp.history import AbstractDescr, BoxInt, BoxPtr, BoxObj,\ - BoxFloat, Const +from pypy.jit.metainterp.history import TreeLoop, log, Box, History, LoopToken +from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt +from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const from pypy.jit.metainterp import history from pypy.jit.metainterp.specnode import NotSpecNode from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.jit.metainterp.optimizeutil import InvalidLoop from pypy.rlib.debug import debug_print -def compile_new_loop(metainterp, old_loops, greenkey, start=0): - """Try to compile a new loop by closing the current history back - to the first operation. - """ - if we_are_translated(): - return compile_fresh_loop(metainterp, old_loops, greenkey, start) - else: - return _compile_new_loop_1(metainterp, old_loops, greenkey, start) - -def compile_new_bridge(metainterp, old_loops, resumekey): - """Try to compile a new bridge leading from the beginning of the history - to some existing place. - """ - if we_are_translated(): - return compile_fresh_bridge(metainterp, old_loops, resumekey) - else: - return _compile_new_bridge_1(metainterp, old_loops, resumekey) - -class BridgeInProgress(Exception): - pass - - -# the following is not translatable -def _compile_new_loop_1(metainterp, old_loops, greenkey, start): - old_loops_1 = old_loops[:] - try: - loop = compile_fresh_loop(metainterp, old_loops, greenkey, start) - except Exception, exc: - show_loop(metainterp, error=exc) - raise - else: - if loop in old_loops_1: - log.info("reusing loop at %r" % (loop,)) - else: - show_loop(metainterp, loop) - if loop is not None: - loop.check_consistency() - return loop - -def _compile_new_bridge_1(metainterp, old_loops, resumekey): - try: - target_loop = compile_fresh_bridge(metainterp, old_loops, - resumekey) - except Exception, exc: - show_loop(metainterp, error=exc) - raise - else: - if target_loop is not None: - show_loop(metainterp, target_loop) - if target_loop is not None and type(target_loop) is not TerminatingLoop: - target_loop.check_consistency() - return target_loop - def show_loop(metainterp, loop=None, error=None): # debugging if option.view or option.viewloops: @@ -76,24 +23,23 @@ errmsg += ': ' + str(error) else: errmsg = None - if loop is None or type(loop) is TerminatingLoop: + if loop is None: # or type(loop) is TerminatingLoop: extraloops = [] else: extraloops = [loop] metainterp.staticdata.stats.view(errmsg=errmsg, extraloops=extraloops) def create_empty_loop(metainterp): - if we_are_translated(): - name = 'Loop' - else: - name = 'Loop #%d' % len(metainterp.staticdata.stats.loops) + name = metainterp.staticdata.stats.name_for_new_loop() return TreeLoop(name) # ____________________________________________________________ -def compile_fresh_loop(metainterp, old_loops, greenkey, start): +def compile_new_loop(metainterp, old_loop_tokens, greenkey, start): + """Try to compile a new loop by closing the current history back + to the first operation. + """ from pypy.jit.metainterp.pyjitpl import DEBUG - history = metainterp.history loop = create_empty_loop(metainterp) loop.greenkey = greenkey @@ -104,35 +50,38 @@ loop.operations = history.operations[start:] else: loop.operations = history.operations - loop.operations[-1].jump_target = loop + loop.operations[-1].jump_target = None metainterp_sd = metainterp.staticdata try: - old_loop = metainterp_sd.state.optimize_loop(metainterp_sd.options, - old_loops, loop, - metainterp.cpu) + old_loop_token = metainterp_sd.state.optimize_loop( + metainterp_sd.options, old_loop_tokens, loop, metainterp.cpu) except InvalidLoop: return None - if old_loop is not None: - if we_are_translated() and DEBUG > 0: + if old_loop_token is not None: + if DEBUG > 0: debug_print("reusing old loop") - return old_loop - history.source_link = loop - send_loop_to_backend(metainterp, loop, None, "loop", loop) - metainterp_sd.stats.loops.append(loop) - old_loops.append(loop) - return loop + return old_loop_token + executable_token = send_loop_to_backend(metainterp, loop, "loop") + loop_token = LoopToken() + loop_token.specnodes = loop.specnodes + loop_token.executable_token = executable_token + if not we_are_translated(): + loop.token = loop_token + old_loop_tokens.append(loop_token) + return loop_token -def send_loop_to_backend(metainterp, loop, guard_op, type, loop_to_log): - for box in loop.inputargs: - assert isinstance(box, Box) - metainterp_sd = metainterp.staticdata - metainterp_sd.options.logger_ops.log_loop(loop_to_log) - metainterp_sd.profiler.start_backend() - metainterp.cpu.compile_operations(loop, guard_op) - metainterp_sd.profiler.end_backend() +def send_loop_to_backend(metainterp, loop, type): + metainterp.staticdata.profiler.start_backend() + if not we_are_translated(): + show_loop(metainterp, loop) + loop.check_consistency() + executable_token = metainterp.cpu.compile_loop(loop.inputargs, + loop.operations) + metainterp.staticdata.profiler.end_backend() + metainterp.staticdata.stats.add_new_loop(loop) if not we_are_translated(): if type != "entry bridge": - metainterp_sd.stats.compiled_count += 1 + metainterp.staticdata.stats.compiled() else: loop._ignore_during_counting = True log.info("compiled new " + type) @@ -140,58 +89,54 @@ from pypy.jit.metainterp.pyjitpl import DEBUG if DEBUG > 0: debug_print("compiled new " + type) + return executable_token + +def send_bridge_to_backend(metainterp, faildescr, inputargs, operations): + metainterp.staticdata.profiler.start_backend() + if not we_are_translated(): + show_loop(metainterp) + TreeLoop.check_consistency_of(inputargs, operations) + pass + metainterp.cpu.compile_bridge(faildescr, inputargs, operations) + metainterp.staticdata.profiler.end_backend() + if not we_are_translated(): + metainterp.staticdata.stats.compiled() + log.info("compiled new bridge") + else: + from pypy.jit.metainterp.pyjitpl import DEBUG + if DEBUG > 0: + debug_print("compiled new bridge") # ____________________________________________________________ -class DoneWithThisFrameDescrVoid(AbstractDescr): - def handle_fail_op(self, metainterp_sd, fail_op): +class DoneWithThisFrameDescrVoid(AbstractFailDescr): + def handle_fail(self, metainterp_sd): assert metainterp_sd.result_type == 'void' raise metainterp_sd.DoneWithThisFrameVoid() -class DoneWithThisFrameDescrInt(AbstractDescr): - def handle_fail_op(self, metainterp_sd, fail_op): +class DoneWithThisFrameDescrInt(AbstractFailDescr): + def handle_fail(self, metainterp_sd): assert metainterp_sd.result_type == 'int' - resultbox = fail_op.args[0] - if isinstance(resultbox, BoxInt): - result = metainterp_sd.cpu.get_latest_value_int(0) - else: - assert isinstance(resultbox, history.Const) - result = resultbox.getint() + result = metainterp_sd.cpu.get_latest_value_int(0) raise metainterp_sd.DoneWithThisFrameInt(result) -class DoneWithThisFrameDescrRef(AbstractDescr): - def handle_fail_op(self, metainterp_sd, fail_op): +class DoneWithThisFrameDescrRef(AbstractFailDescr): + def handle_fail(self, metainterp_sd): assert metainterp_sd.result_type == 'ref' - resultbox = fail_op.args[0] cpu = metainterp_sd.cpu - if isinstance(resultbox, cpu.ts.BoxRef): - result = cpu.get_latest_value_ref(0) - else: - assert isinstance(resultbox, history.Const) - result = resultbox.getref_base() + result = cpu.get_latest_value_ref(0) raise metainterp_sd.DoneWithThisFrameRef(cpu, result) -class DoneWithThisFrameDescrFloat(AbstractDescr): - def handle_fail_op(self, metainterp_sd, fail_op): +class DoneWithThisFrameDescrFloat(AbstractFailDescr): + def handle_fail(self, metainterp_sd): assert metainterp_sd.result_type == 'float' - resultbox = fail_op.args[0] - if isinstance(resultbox, BoxFloat): - result = metainterp_sd.cpu.get_latest_value_float(0) - else: - assert isinstance(resultbox, history.Const) - result = resultbox.getfloat() + result = metainterp_sd.cpu.get_latest_value_float(0) raise metainterp_sd.DoneWithThisFrameFloat(result) -class ExitFrameWithExceptionDescrRef(AbstractDescr): - def handle_fail_op(self, metainterp_sd, fail_op): - assert len(fail_op.args) == 1 - valuebox = fail_op.args[0] +class ExitFrameWithExceptionDescrRef(AbstractFailDescr): + def handle_fail(self, metainterp_sd): cpu = metainterp_sd.cpu - if isinstance(valuebox, cpu.ts.BoxRef): - value = cpu.get_latest_value_ref(0) - else: - assert isinstance(valuebox, history.Const) - value = valuebox.getref_base() + value = cpu.get_latest_value_ref(0) raise metainterp_sd.ExitFrameWithExceptionRef(cpu, value) done_with_this_frame_descr_void = DoneWithThisFrameDescrVoid() @@ -200,68 +145,49 @@ done_with_this_frame_descr_float = DoneWithThisFrameDescrFloat() exit_frame_with_exception_descr_ref = ExitFrameWithExceptionDescrRef() -class TerminatingLoop(TreeLoop): - pass prebuiltNotSpecNode = NotSpecNode() -# pseudo-loops to make the life of optimize.py easier -_loop = TerminatingLoop('done_with_this_frame_int') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxInt()] -_loop.finishdescr = done_with_this_frame_descr_int -loops_done_with_this_frame_int = [_loop] - -_loop = TerminatingLoop('done_with_this_frame_ref') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxPtr()] -_loop.finishdescr = done_with_this_frame_descr_ref -llhelper.loops_done_with_this_frame_ref = [_loop] - -_loop = TerminatingLoop('done_with_this_frame_ref') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxObj()] -_loop.finishdescr = done_with_this_frame_descr_ref -oohelper.loops_done_with_this_frame_ref = [_loop] - -_loop = TerminatingLoop('done_with_this_frame_float') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxFloat()] -_loop.finishdescr = done_with_this_frame_descr_float -loops_done_with_this_frame_float = [_loop] - -_loop = TerminatingLoop('done_with_this_frame_void') -_loop.specnodes = [] -_loop.inputargs = [] -_loop.finishdescr = done_with_this_frame_descr_void -loops_done_with_this_frame_void = [_loop] - -_loop = TerminatingLoop('exit_frame_with_exception_ref') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxPtr()] -_loop.finishdescr = exit_frame_with_exception_descr_ref -llhelper.loops_exit_frame_with_exception_ref = [_loop] - -_loop = TerminatingLoop('exit_frame_with_exception_ref') -_loop.specnodes = [prebuiltNotSpecNode] -_loop.inputargs = [BoxObj()] -_loop.finishdescr = exit_frame_with_exception_descr_ref -oohelper.loops_exit_frame_with_exception_ref = [_loop] -del _loop - +class TerminatingLoopToken(LoopToken): + terminating = True + + def __init__(self, nargs, finishdescr): + self.specnodes = [prebuiltNotSpecNode]*nargs + self.finishdescr = finishdescr + +# pseudo loop tokens to make the life of optimize.py easier +loop_tokens_done_with_this_frame_int = [ + TerminatingLoopToken(1, done_with_this_frame_descr_int) + ] +loop_tokens_done_with_this_frame_ref = [ + TerminatingLoopToken(1, done_with_this_frame_descr_ref) + ] +loop_tokens_done_with_this_frame_float = [ + TerminatingLoopToken(1, done_with_this_frame_descr_float) + ] +loop_tokens_done_with_this_frame_void = [ + TerminatingLoopToken(0, done_with_this_frame_descr_void) + ] +loop_tokens_exit_frame_with_exception_ref = [ + TerminatingLoopToken(1, exit_frame_with_exception_descr_ref) + ] + +class ResumeDescr(AbstractFailDescr): + def __init__(self, original_greenkey): + self.original_greenkey = original_greenkey -class ResumeGuardDescr(AbstractDescr): +class ResumeGuardDescr(ResumeDescr): counter = 0 - def __init__(self, history, history_guard_index): - self.history = history - assert history_guard_index >= 0 - self.history_guard_index = history_guard_index + def __init__(self, original_greenkey, guard_op): + ResumeDescr.__init__(self, original_greenkey) + self.guard_op = guard_op # this class also gets attributes stored by ResumeDataBuilder.finish() - def handle_fail_op(self, metainterp_sd, fail_op): + def handle_fail(self, metainterp_sd): from pypy.jit.metainterp.pyjitpl import MetaInterp metainterp = MetaInterp(metainterp_sd) + fail_op = self.get_guard_op().suboperations[-1] # xxx unhappy patch = self.patch_boxes_temporarily(metainterp_sd, fail_op) try: return metainterp.handle_guard_failure(fail_op, self) @@ -306,7 +232,7 @@ assert False def get_guard_op(self): - guard_op = self.history.operations[self.history_guard_index] + guard_op = self.guard_op assert guard_op.is_guard() if guard_op.optimized is not None: # should always be the case, return guard_op.optimized # except if not optimizing at all @@ -315,36 +241,18 @@ def compile_and_attach(self, metainterp, new_loop): # We managed to create a bridge. Attach the new operations - # to the existing source_loop and recompile the whole thing. - source_loop = self.find_source_loop() - metainterp.history.source_link = self.history - metainterp.history.source_guard_index = self.history_guard_index + # to the corrsponding guard_op and compile from there + # xxx unhappy guard_op = self.get_guard_op() - guard_op.suboperations = new_loop.operations - send_loop_to_backend(metainterp, source_loop, self.get_guard_op(), - "bridge", new_loop) - - def find_source_loop(self): - # Find the TreeLoop object that contains this guard operation. - source_loop = self.history.source_link - while not isinstance(source_loop, TreeLoop): - source_loop = source_loop.source_link - return source_loop - - def find_toplevel_history(self): - # Find the History that describes the start of the loop containing this - # guard operation. - history = self.history - prevhistory = history.source_link - while isinstance(prevhistory, History): - history = prevhistory - prevhistory = history.source_link - return history - - -class ResumeFromInterpDescr(AbstractDescr): - def __init__(self, original_boxes): - self.original_boxes = original_boxes + fail_args = guard_op.suboperations[-1].args + if not we_are_translated(): + guard_op._debug_suboperations = new_loop.operations + send_bridge_to_backend(metainterp, self, fail_args, new_loop.operations) + +class ResumeFromInterpDescr(ResumeDescr): + def __init__(self, original_greenkey, redkey): + ResumeDescr.__init__(self, original_greenkey) + self.redkey = redkey def compile_and_attach(self, metainterp, new_loop): # We managed to create a bridge going from the interpreter @@ -352,107 +260,55 @@ # a loop at all but ends in a jump to the target loop. It starts # with completely unoptimized arguments, as in the interpreter. metainterp_sd = metainterp.staticdata - num_green_args = metainterp_sd.num_green_args - greenkey = self.original_boxes[:num_green_args] - redkey = self.original_boxes[num_green_args:] - metainterp.history.source_link = new_loop - metainterp.history.inputargs = redkey - new_loop.greenkey = greenkey - new_loop.inputargs = redkey - new_loop.specnodes = [prebuiltNotSpecNode] * len(redkey) - send_loop_to_backend(metainterp, new_loop, None, "entry bridge", - new_loop) - metainterp_sd.stats.loops.append(new_loop) + metainterp.history.inputargs = self.redkey + new_loop.greenkey = self.original_greenkey + new_loop.inputargs = self.redkey + executable_token = send_loop_to_backend(metainterp, new_loop, + "entry bridge") # send the new_loop to warmspot.py, to be called directly the next time - metainterp_sd.state.attach_unoptimized_bridge_from_interp(greenkey, - new_loop) - # store the new_loop in compiled_merge_points too - # XXX it's probably useless to do so when optimizing - glob = metainterp_sd.globaldata - greenargs = glob.unpack_greenkey(greenkey) - old_loops = glob.compiled_merge_points.setdefault(greenargs, []) - old_loops.append(new_loop) + metainterp_sd.state.attach_unoptimized_bridge_from_interp( + self.original_greenkey, + executable_token) -def compile_fresh_bridge(metainterp, old_loops, resumekey): +def compile_new_bridge(metainterp, old_loop_tokens, resumekey): + """Try to compile a new bridge leading from the beginning of the history + to some existing place. + """ # The history contains new operations to attach as the code for the # failure of 'resumekey.guard_op'. # # Attempt to use optimize_bridge(). This may return None in case - # it does not work -- i.e. none of the existing old_loops match. + # it does not work -- i.e. none of the existing old_loop_tokens match. new_loop = create_empty_loop(metainterp) new_loop.operations = metainterp.history.operations metainterp_sd = metainterp.staticdata options = metainterp_sd.options try: - target_loop = metainterp_sd.state.optimize_bridge(options, - old_loops, new_loop, + target_loop_token = metainterp_sd.state.optimize_bridge(options, + old_loop_tokens, + new_loop, metainterp.cpu) except InvalidLoop: assert 0, "InvalidLoop in optimize_bridge?" return None - # Did it work? If not, prepare_loop_from_bridge() will probably be used. - if target_loop is not None: + # Did it work? + if target_loop_token is not None: # Yes, we managed to create a bridge. Dispatch to resumekey to # know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr) - prepare_last_operation(new_loop, target_loop) + prepare_last_operation(new_loop, target_loop_token) resumekey.compile_and_attach(metainterp, new_loop) - return target_loop + return target_loop_token -def prepare_last_operation(new_loop, target_loop): +def prepare_last_operation(new_loop, target_loop_token): op = new_loop.operations[-1] - if not isinstance(target_loop, TerminatingLoop): + if not isinstance(target_loop_token, TerminatingLoopToken): # normal case - op.jump_target = target_loop + op.jump_target = target_loop_token else: - # The target_loop is a pseudo-loop, e.g. done_with_this_frame. + # The target_loop_token is a pseudo loop token, + # e.g. loop_tokens_done_with_this_frame_void[0] # Replace the operation with the real operation we want, i.e. a FAIL. - descr = target_loop.finishdescr - new_op = ResOperation(rop.FAIL, op.args, None, descr=descr) + descr = target_loop_token.finishdescr + new_op = ResOperation(rop.FINISH, op.args, None, descr=descr) new_loop.operations[-1] = new_op - - -def prepare_loop_from_bridge(metainterp, resumekey): - # To handle this case, we prepend to the history the unoptimized - # operations coming from the loop, in order to make a (fake) complete - # unoptimized trace. (Then we will just compile this loop normally.) - raise PrepareLoopFromBridgeIsDisabled - if not we_are_translated(): - log.info("completing the bridge into a stand-alone loop") - else: - debug_print("completing the bridge into a stand-alone loop") - operations = metainterp.history.operations - metainterp.history.operations = [] - assert isinstance(resumekey, ResumeGuardDescr) - append_full_operations(metainterp.history, - resumekey.history, - resumekey.history_guard_index) - metainterp.history.operations.extend(operations) - -def append_full_operations(history, sourcehistory, guard_index): - prev = sourcehistory.source_link - if isinstance(prev, History): - append_full_operations(history, prev, sourcehistory.source_guard_index) - history.operations.extend(sourcehistory.operations[:guard_index]) - op = inverse_guard(sourcehistory.operations[guard_index]) - history.operations.append(op) - -def inverse_guard(guard_op): - suboperations = guard_op.suboperations - assert guard_op.is_guard() - if guard_op.opnum == rop.GUARD_TRUE: - guard_op = ResOperation(rop.GUARD_FALSE, guard_op.args, None) - elif guard_op.opnum == rop.GUARD_FALSE: - guard_op = ResOperation(rop.GUARD_TRUE, guard_op.args, None) - else: - # XXX other guards have no inverse so far - raise InverseTheOtherGuardsPlease(guard_op) - # - guard_op.suboperations = suboperations - return guard_op - -class InverseTheOtherGuardsPlease(Exception): - pass - -class PrepareLoopFromBridgeIsDisabled(Exception): - pass From arigo at codespeak.net Fri Sep 25 15:49:38 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 15:49:38 +0200 (CEST) Subject: [pypy-svn] r67884 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090925134938.C5DBA168027@codespeak.net> Author: arigo Date: Fri Sep 25 15:49:37 2009 New Revision: 67884 Added: pypy/trunk/pypy/jit/backend/x86/assembler.py.merge.tmp - copied, changed from r67880, pypy/trunk/pypy/jit/backend/x86/assembler.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/remove-plfbid/pypy/jit/backend/x86/assembler.py revisions 67829 to 67880: ------------------------------------------------------------------------ r67878 | pedronis | 2009-09-25 15:07:44 +0200 (Fri, 25 Sep 2009) | 3 lines (arigo, pedronis) "final" cleanups ------------------------------------------------------------------------ r67873 | pedronis | 2009-09-25 10:23:54 +0200 (Fri, 25 Sep 2009) | 1 line fix for test_ll_random ------------------------------------------------------------------------ r67872 | pedronis | 2009-09-25 10:19:38 +0200 (Fri, 25 Sep 2009) | 1 line bridges work again, finish op and cleanup next ------------------------------------------------------------------------ r67869 | pedronis | 2009-09-24 17:35:30 +0200 (Thu, 24 Sep 2009) | 3 lines (micke, pedronis) WIP fixing the x86 backend, loops work, bridges mostly there ------------------------------------------------------------------------ r67844 | pedronis | 2009-09-22 16:24:57 +0200 (Tue, 22 Sep 2009) | 6 lines (arigo, pedronis) WIP - start redefining the backend interface - start removing the need to keep unoptimized loops around ------------------------------------------------------------------------ r67830 | arigo | 2009-09-21 18:11:04 +0200 (Mon, 21 Sep 2009) | 2 lines A branch in which we try to remove PrepareLoopFromBridgeIsDisabled. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/backend/x86/assembler.py.merge.tmp (from r67880, pypy/trunk/pypy/jit/backend/x86/assembler.py) ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py.merge.tmp Fri Sep 25 15:49:37 2009 @@ -2,6 +2,7 @@ import ctypes from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.history import Const, Box, BoxPtr, REF +from pypy.jit.metainterp.history import AbstractFailDescr from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory from pypy.rpython.lltypesystem.rclass import OBJECT from pypy.rpython.lltypesystem.lloperation import llop @@ -62,6 +63,11 @@ if name.upper() == name: setattr(MachineCodeBlockWrapper, name, _new_method(name)) +class ExecutableToken386(object): + _x86_loop_code = 0 + _x86_bootstrap_code = 0 + _x86_stack_depth = 0 + _x86_arglocs = None class Assembler386(object): mc = None @@ -118,71 +124,70 @@ self.mc = MachineCodeBlockWrapper() self.mc2 = MachineCodeBlockWrapper() - def _compute_longest_fail_op(self, ops): - max_so_far = 0 - for op in ops: - if op.opnum == rop.FAIL: - max_so_far = max(max_so_far, len(op.args)) - if op.is_guard(): - max_so_far = max(max_so_far, self._compute_longest_fail_op( - op.suboperations)) - assert max_so_far < MAX_FAIL_BOXES - return max_so_far - - def assemble_loop(self, loop): - self.assemble(loop, loop.operations, None) + def assemble_loop(self, inputargs, operations): + self.make_sure_mc_exists() + regalloc = RegAlloc(self, self.cpu.translate_support_code) + arglocs = regalloc.prepare_loop(inputargs, operations) + executable_token = ExecutableToken386() + executable_token._x86_arglocs = arglocs + executable_token._x86_bootstrap_code = self.mc.tell() + adr_stackadjust = self._assemble_bootstrap_code(inputargs, arglocs) + executable_token._x86_loop_code = self.mc.tell() + self._executable_token = executable_token + stack_depth = self._assemble(regalloc, operations) + self._executable_token = None + self._patch_stackadjust(adr_stackadjust, stack_depth) + executable_token._x86_stack_depth = stack_depth + return executable_token - def assemble_from_guard(self, tree, guard_op): - newaddr = self.assemble(tree, guard_op.suboperations, guard_op) + def assemble_bridge(self, faildescr, inputargs, operations): + self.make_sure_mc_exists() + regalloc = RegAlloc(self, self.cpu.translate_support_code) + arglocs = faildescr._x86_faillocs + fail_stack_depth = faildescr._x86_current_stack_depth + regalloc.prepare_bridge(fail_stack_depth, inputargs, arglocs, + operations) + adr_bridge = self.mc.tell() + adr_stackadjust = self._patchable_stackadjust() + stack_depth = self._assemble(regalloc, operations) + self._patch_stackadjust(adr_stackadjust, stack_depth) + if not we_are_translated(): + # for the benefit of tests + faildescr._x86_bridge_stack_depth = stack_depth # patch the jump from original guard - addr = guard_op._x86_addr - mc = codebuf.InMemoryCodeBuilder(addr, addr + 4) - mc.write(packimm32(newaddr - addr - 4)) + adr_jump_offset = faildescr._x86_adr_jump_offset + mc = codebuf.InMemoryCodeBuilder(adr_jump_offset, adr_jump_offset + 4) + mc.write(packimm32(adr_bridge - adr_jump_offset - 4)) mc.valgrind_invalidated() mc.done() - def assemble(self, tree, operations, guard_op): - # the last operation can be 'jump', 'return' or 'guard_pause'; - # a 'jump' can either close a loop, or end a bridge to some - # previously-compiled code. - self._compute_longest_fail_op(operations) - self.tree = tree - self.make_sure_mc_exists() - newpos = self.mc.tell() - regalloc = RegAlloc(self, tree, self.cpu.translate_support_code, - guard_op) + def _assemble(self, regalloc, operations): self._regalloc = regalloc - adr_lea = 0 - if guard_op is None: - inputargs = tree.inputargs - regalloc.walk_operations(tree) - else: - inputargs = regalloc.inputargs - mc = self.mc._mc - adr_lea = mc.tell() - mc.LEA(esp, fixedsize_ebp_ofs(0)) - regalloc._walk_operations(operations) - stack_depth = regalloc.max_stack_depth + regalloc.walk_operations(operations) self.mc.done() self.mc2.done() - # possibly align, e.g. for Mac OS X - if guard_op is None: - tree._x86_stack_depth = stack_depth - else: - if not we_are_translated(): - # for the benefit of tests - guard_op._x86_bridge_stack_depth = stack_depth - mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 8) - mc.LEA(esp, fixedsize_ebp_ofs(-(stack_depth + RET_BP - 2) * WORD)) - mc.valgrind_invalidated() - mc.done() - if we_are_translated(): + if we_are_translated() or self.cpu.dont_keepalive_stuff: self._regalloc = None # else keep it around for debugging - return newpos + stack_depth = regalloc.current_stack_depth + jump_target = regalloc.jump_target + if jump_target is not None: + target_stack_depth = jump_target.executable_token._x86_stack_depth + stack_depth = max(stack_depth, target_stack_depth) + return stack_depth + + def _patchable_stackadjust(self): + # stack adjustment LEA + self.mc.LEA(esp, fixedsize_ebp_ofs(0)) + return self.mc.tell() - 4 + + def _patch_stackadjust(self, adr_lea, stack_depth): + # patch stack adjustment LEA + # possibly align, e.g. for Mac OS X + mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 4) + mc.write(packimm32(-(stack_depth + RET_BP - 2) * WORD)) + mc.done() - def assemble_bootstrap_code(self, jumpaddr, arglocs, args, framesize): - self.make_sure_mc_exists() - addr = self.mc.tell() + def _assemble_bootstrap_code(self, inputargs, arglocs): self.mc.PUSH(ebp) self.mc.MOV(ebp, esp) self.mc.PUSH(ebx) @@ -190,11 +195,11 @@ self.mc.PUSH(edi) # NB. exactly 4 pushes above; if this changes, fix stack_pos(). # You must also keep _get_callshape() in sync. - self.mc.SUB(esp, imm(framesize * WORD)) + adr_stackadjust = self._patchable_stackadjust() for i in range(len(arglocs)): loc = arglocs[i] if not isinstance(loc, REG): - if args[i].type == REF: + if inputargs[i].type == REF: # This uses XCHG to put zeroes in fail_boxes_ptr after # reading them self.mc.XOR(ecx, ecx) @@ -207,7 +212,7 @@ for i in range(len(arglocs)): loc = arglocs[i] if isinstance(loc, REG): - if args[i].type == REF: + if inputargs[i].type == REF: # This uses XCHG to put zeroes in fail_boxes_ptr after # reading them self.mc.XOR(loc, loc) @@ -216,9 +221,7 @@ else: self.mc.MOV(loc, addr_add(imm(self.fail_box_int_addr), imm(i*WORD))) - self.mc.JMP(rel32(jumpaddr)) - self.mc.done() - return addr + return adr_stackadjust def dump(self, text): if not self.verbose: @@ -250,15 +253,30 @@ genop_discard_list[op.opnum](self, op, arglocs) def regalloc_perform_with_guard(self, op, guard_op, faillocs, - arglocs, resloc): - addr = self.implement_guard_recovery(guard_op, faillocs) - genop_guard_list[op.opnum](self, op, guard_op, addr, arglocs, - resloc) - - def regalloc_perform_guard(self, op, faillocs, arglocs, resloc): - addr = self.implement_guard_recovery(op, faillocs) - genop_guard_list[op.opnum](self, op, None, addr, arglocs, - resloc) + arglocs, resloc, current_stack_depth): + fail_op = guard_op.suboperations[0] + faildescr = fail_op.descr + assert isinstance(faildescr, AbstractFailDescr) + faildescr._x86_current_stack_depth = current_stack_depth + failargs = fail_op.args + guard_opnum = guard_op.opnum + failaddr = self.implement_guard_recovery(guard_opnum, + faildescr, failargs, + faillocs) + if op is None: + dispatch_opnum = guard_opnum + else: + dispatch_opnum = op.opnum + adr_jump_offset = genop_guard_list[dispatch_opnum](self, op, + guard_opnum, + failaddr, arglocs, + resloc) + faildescr._x86_adr_jump_offset = adr_jump_offset + + def regalloc_perform_guard(self, guard_op, faillocs, arglocs, resloc, + current_stack_depth): + self.regalloc_perform_with_guard(None, guard_op, faillocs, arglocs, + resloc, current_stack_depth) def load_effective_addr(self, sizereg, baseofs, scale, result): self.mc.LEA(result, addr_add(imm(0), sizereg, baseofs, scale)) @@ -286,23 +304,23 @@ return genop_cmp def _cmpop_guard(cond, rev_cond, false_cond, false_rev_cond): - def genop_cmp_guard(self, op, guard_op, addr, arglocs, result_loc): + def genop_cmp_guard(self, op, guard_opnum, addr, arglocs, result_loc): if isinstance(op.args[0], Const): self.mc.CMP(arglocs[1], arglocs[0]) - if guard_op.opnum == rop.GUARD_FALSE: + if guard_opnum == rop.GUARD_FALSE: name = 'J' + rev_cond - self.implement_guard(addr, guard_op, getattr(self.mc, name)) + return self.implement_guard(addr, getattr(self.mc, name)) else: name = 'J' + false_rev_cond - self.implement_guard(addr, guard_op, getattr(self.mc, name)) + return self.implement_guard(addr, getattr(self.mc, name)) else: self.mc.CMP(arglocs[0], arglocs[1]) - if guard_op.opnum == rop.GUARD_FALSE: - self.implement_guard(addr, guard_op, - getattr(self.mc, 'J' + cond)) + if guard_opnum == rop.GUARD_FALSE: + name = 'J' + cond + return self.implement_guard(addr, getattr(self.mc, name)) else: name = 'J' + false_cond - self.implement_guard(addr, guard_op, getattr(self.mc, name)) + return self.implement_guard(addr, getattr(self.mc, name)) return genop_cmp_guard def align_stack_for_call(self, nargs): @@ -386,22 +404,21 @@ loc2 = cl self.mc.SHR(loc, loc2) - def genop_guard_oononnull(self, op, guard_op, addr, arglocs, resloc): + def genop_guard_oononnull(self, op, guard_opnum, addr, arglocs, resloc): loc = arglocs[0] self.mc.TEST(loc, loc) - if guard_op.opnum == rop.GUARD_TRUE: - self.implement_guard(addr, guard_op, self.mc.JZ) + if guard_opnum == rop.GUARD_TRUE: + return self.implement_guard(addr, self.mc.JZ) else: - self.implement_guard(addr, guard_op, self.mc.JNZ) + return self.implement_guard(addr, self.mc.JNZ) - def genop_guard_ooisnull(self, op, guard_op, addr, arglocs, resloc): + def genop_guard_ooisnull(self, op, guard_opnum, addr, arglocs, resloc): loc = arglocs[0] self.mc.TEST(loc, loc) - if guard_op.opnum == rop.GUARD_TRUE: - self.implement_guard(addr, guard_op, self.mc.JNZ) + if guard_opnum == rop.GUARD_TRUE: + return self.implement_guard(addr, self.mc.JNZ) else: - self.implement_guard(addr, guard_op, self.mc.JZ) - + return self.implement_guard(addr, self.mc.JZ) genop_guard_int_is_true = genop_guard_oononnull @@ -570,72 +587,67 @@ else: assert 0, itemsize - def make_merge_point(self, tree, locs): - pos = self.mc.tell() - tree._x86_compiled = pos - - def genop_discard_jump(self, op, locs): - self.mc.JMP(rel32(op.jump_target._x86_compiled)) - - def genop_guard_guard_true(self, op, ign_1, addr, locs, ign_2): + def genop_guard_guard_true(self, ign_1, guard_opnum, addr, locs, ign_2): loc = locs[0] self.mc.TEST(loc, loc) - self.implement_guard(addr, op, self.mc.JZ) + return self.implement_guard(addr, self.mc.JZ) - def genop_guard_guard_no_exception(self, op, ign_1, addr, locs, ign_2): + def genop_guard_guard_no_exception(self, ign_1, guard_opnum, addr, + locs, ign_2): self.mc.CMP(heap(self.cpu.pos_exception()), imm(0)) - self.implement_guard(addr, op, self.mc.JNZ) + return self.implement_guard(addr, self.mc.JNZ) - def genop_guard_guard_exception(self, op, ign_1, addr, locs, resloc): + def genop_guard_guard_exception(self, ign_1, guard_opnum, addr, + locs, resloc): loc = locs[0] loc1 = locs[1] self.mc.MOV(loc1, heap(self.cpu.pos_exception())) self.mc.CMP(loc1, loc) - self.implement_guard(addr, op, self.mc.JNE) + addr = self.implement_guard(addr, self.mc.JNE) if resloc is not None: self.mc.MOV(resloc, heap(self.cpu.pos_exc_value())) self.mc.MOV(heap(self.cpu.pos_exception()), imm(0)) self.mc.MOV(heap(self.cpu.pos_exc_value()), imm(0)) + return addr - def genop_guard_guard_no_overflow(self, op, ign_1, addr, locs, resloc): - self.implement_guard(addr, op, self.mc.JO) - - def genop_guard_guard_overflow(self, op, ign_1, addr, locs, resloc): - self.implement_guard(addr, op, self.mc.JNO) + def genop_guard_guard_no_overflow(self, ign_1, guard_opnum, addr, + locs, resloc): + return self.implement_guard(addr, self.mc.JO) + + def genop_guard_guard_overflow(self, ign_1, guard_opnum, addr, + locs, resloc): + return self.implement_guard(addr, self.mc.JNO) - def genop_guard_guard_false(self, op, ign_1, addr, locs, ign_2): + def genop_guard_guard_false(self, ign_1, guard_opnum, addr, locs, ign_2): loc = locs[0] self.mc.TEST(loc, loc) - self.implement_guard(addr, op, self.mc.JNZ) + return self.implement_guard(addr, self.mc.JNZ) - def genop_guard_guard_value(self, op, ign_1, addr, locs, ign_2): + def genop_guard_guard_value(self, ign_1, guard_opnum, addr, locs, ign_2): self.mc.CMP(locs[0], locs[1]) - self.implement_guard(addr, op, self.mc.JNE) + return self.implement_guard(addr, self.mc.JNE) - def genop_guard_guard_class(self, op, ign_1, addr, locs, ign_2): + def genop_guard_guard_class(self, ign_1, guard_opnum, addr, locs, ign_2): offset = self.cpu.vtable_offset self.mc.CMP(mem(locs[0], offset), locs[1]) - self.implement_guard(addr, op, self.mc.JNE) + return self.implement_guard(addr, self.mc.JNE) - def implement_guard_recovery(self, guard_op, fail_locs): + def implement_guard_recovery(self, guard_opnum, faildescr, failargs, + fail_locs): addr = self.mc2.tell() - exc = (guard_op.opnum == rop.GUARD_EXCEPTION or - guard_op.opnum == rop.GUARD_NO_EXCEPTION) - guard_op._x86_faillocs = fail_locs - # XXX horrible hack that allows us to preserve order - # of inputargs to bridge - guard_op._fail_op = guard_op.suboperations[0] - self.generate_failure(self.mc2, guard_op.suboperations[0], fail_locs, - exc) + exc = (guard_opnum == rop.GUARD_EXCEPTION or + guard_opnum == rop.GUARD_NO_EXCEPTION) + faildescr._x86_faillocs = fail_locs + self.generate_failure(self.mc2, faildescr, failargs, fail_locs, exc) return addr - def generate_failure(self, mc, op, locs, exc): - assert op.opnum == rop.FAIL + def generate_failure(self, mc, faildescr, failargs, locs, exc): + assert len(failargs) < MAX_FAIL_BOXES pos = mc.tell() for i in range(len(locs)): loc = locs[i] if isinstance(loc, REG): - if op.args[i].type == REF: + if failargs[i].type == REF: base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr @@ -643,7 +655,7 @@ for i in range(len(locs)): loc = locs[i] if not isinstance(loc, REG): - if op.args[i].type == REF: + if failargs[i].type == REF: base = self.fail_box_ptr_addr else: base = self.fail_box_int_addr @@ -666,18 +678,19 @@ # don't break the following code sequence! mc = mc._mc mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD)) - guard_index = self.cpu.make_guard_index(op) - mc.MOV(eax, imm(guard_index)) + assert isinstance(faildescr, AbstractFailDescr) + fail_index = self.cpu.make_fail_index(faildescr) + mc.MOV(eax, imm(fail_index)) mc.POP(edi) mc.POP(esi) mc.POP(ebx) mc.POP(ebp) mc.RET() - @specialize.arg(3) - def implement_guard(self, addr, guard_op, emit_jump): + @specialize.arg(2) + def implement_guard(self, addr, emit_jump): emit_jump(rel32(addr)) - guard_op._x86_addr = self.mc.tell() - 4 + return self.mc.tell() - 4 def genop_call(self, op, arglocs, resloc): sizeloc = arglocs[0] @@ -748,6 +761,20 @@ mark = self._regalloc.get_mark_gc_roots(gcrootmap) gcrootmap.put(rffi.cast(llmemory.Address, self.mc.tell()), mark) + def _get_executable_token(self, loop_token): + if loop_token is not None: + return loop_token.executable_token + assert self._executable_token is not None + return self._executable_token + + def target_arglocs(self, loop_token): + executable_token = self._get_executable_token(loop_token) + return executable_token._x86_arglocs + + def closing_jump(self, loop_token): + executable_token = self._get_executable_token(loop_token) + self.mc.JMP(rel32(executable_token._x86_loop_code)) + genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST genop_list = [Assembler386.not_implemented_op] * rop._LAST From arigo at codespeak.net Fri Sep 25 15:49:45 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 15:49:45 +0200 (CEST) Subject: [pypy-svn] r67885 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090925134945.1501C168026@codespeak.net> Author: arigo Date: Fri Sep 25 15:49:43 2009 New Revision: 67885 Added: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py.merge.tmp - copied, changed from r67880, pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_optimizeopt.py revisions 67829 to 67880: ------------------------------------------------------------------------ r67859 | pedronis | 2009-09-23 20:24:08 +0200 (Wed, 23 Sep 2009) | 3 lines (arigo, pedronis) getting somewhere in terms of a saner backend interface ------------------------------------------------------------------------ r67830 | arigo | 2009-09-21 18:11:04 +0200 (Mon, 21 Sep 2009) | 2 lines A branch in which we try to remove PrepareLoopFromBridgeIsDisabled. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py.merge.tmp (from r67880, pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py.merge.tmp Fri Sep 25 15:49:43 2009 @@ -11,7 +11,8 @@ from pypy.jit.metainterp.history import AbstractDescr, ConstInt from pypy.jit.metainterp import resume, executor, compile from pypy.jit.metainterp.resoperation import rop, opname -from pypy.jit.metainterp.test.oparser import parse +from pypy.jit.metainterp.test.oparser import pure_parse as parse + # ____________________________________________________________ From arigo at codespeak.net Fri Sep 25 15:49:47 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 15:49:47 +0200 (CEST) Subject: [pypy-svn] r67886 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090925134947.CB15F168029@codespeak.net> Author: arigo Date: Fri Sep 25 15:49:47 2009 New Revision: 67886 Added: pypy/trunk/pypy/jit/metainterp/test/oparser.py.merge.tmp - copied, changed from r67880, pypy/trunk/pypy/jit/metainterp/test/oparser.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/remove-plfbid/pypy/jit/metainterp/test/oparser.py revisions 67829 to 67880: ------------------------------------------------------------------------ r67862 | pedronis | 2009-09-24 11:40:52 +0200 (Thu, 24 Sep 2009) | 4 lines (micke, pedronis) test_finish was failing, fix it by clarifying a bit more the role of AbstractFailDescr and introducing a convenience BasicFailDescr ------------------------------------------------------------------------ r67859 | pedronis | 2009-09-23 20:24:08 +0200 (Wed, 23 Sep 2009) | 3 lines (arigo, pedronis) getting somewhere in terms of a saner backend interface ------------------------------------------------------------------------ r67851 | pedronis | 2009-09-23 15:09:23 +0200 (Wed, 23 Sep 2009) | 3 lines (arigo, pedronis) we don't keep loop around anymore, just loop tokens ------------------------------------------------------------------------ r67830 | arigo | 2009-09-21 18:11:04 +0200 (Mon, 21 Sep 2009) | 2 lines A branch in which we try to remove PrepareLoopFromBridgeIsDisabled. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/test/oparser.py.merge.tmp (from r67880, pypy/trunk/pypy/jit/metainterp/test/oparser.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/oparser.py.merge.tmp Fri Sep 25 15:49:47 2009 @@ -4,7 +4,7 @@ """ from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ - ConstAddr, ConstObj, ConstPtr, Box + ConstAddr, ConstObj, ConstPtr, Box, BasicFailDescr from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.typesystem import llhelper from pypy.rpython.lltypesystem import lltype, llmemory @@ -48,7 +48,7 @@ getattr(boxes, name).value = value class OpParser(object): - def __init__(self, descr, cpu, namespace, type_system, boxkinds, jump_targets): + def __init__(self, descr, cpu, namespace, type_system, boxkinds, jump_targets, invent_fail_descrs=True): self.descr = descr self.vars = {} self.cpu = cpu @@ -58,6 +58,7 @@ self.jumps = [] self.jump_targets = jump_targets self._cache = namespace.setdefault('_CACHE_', {}) + self.invent_fail_descrs = invent_fail_descrs def box_for_var(self, elem): try: @@ -142,30 +143,32 @@ endnum = line.rfind(')') if endnum == -1: raise ParseError("invalid line: %s" % line) - argspec = line[num + 1:endnum] - if not argspec.strip(): - return opnum, [], None - if opname == 'debug_merge_point': - allargs = [argspec] - else: - allargs = argspec.split(",") args = [] descr = None - poss_descr = allargs[-1].strip() - if poss_descr.startswith('descr='): - if poss_descr.startswith('descr=<'): - descr = None + argspec = line[num + 1:endnum] + if argspec.strip(): + if opname == 'debug_merge_point': + allargs = [argspec] else: - descr = self.consts[poss_descr[len('descr='):]] - allargs = allargs[:-1] - for arg in allargs: - arg = arg.strip() - try: - args.append(self.getvar(arg)) - except KeyError: - raise ParseError("Unknown var: %s" % arg) - if hasattr(descr, '_oparser_uses_descr'): - descr._oparser_uses_descr(self, args) + allargs = argspec.split(",") + + poss_descr = allargs[-1].strip() + if poss_descr.startswith('descr='): + if poss_descr.startswith('descr=<'): + descr = None + else: + descr = self.consts[poss_descr[len('descr='):]] + allargs = allargs[:-1] + for arg in allargs: + arg = arg.strip() + try: + args.append(self.getvar(arg)) + except KeyError: + raise ParseError("Unknown var: %s" % arg) + if hasattr(descr, '_oparser_uses_descr'): + descr._oparser_uses_descr(self, args) + if opnum == rop.FAIL and descr is None and self.invent_fail_descrs: + descr = BasicFailDescr() return opnum, args, descr def parse_result_op(self, line): @@ -221,11 +224,9 @@ raise ParseError("Wrong number of jump targets") if self.jump_targets is None: for jump in self.jumps: - jump.jump_target = loop + jump.jump_target = None else: for jump, jump_target in zip(self.jumps, self.jump_targets): - if jump_target == 'self': - jump_target = loop jump.jump_target = jump_target loop.operations = ops loop.inputargs = inpargs @@ -260,10 +261,14 @@ return base_indent, inpargs def parse(descr, cpu=None, namespace=None, type_system='lltype', - boxkinds=None, jump_targets=None): + boxkinds=None, jump_targets=None, invent_fail_descrs=True): if namespace is None: namespace = {} - return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_targets).parse() + return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_targets, invent_fail_descrs).parse() + +def pure_parse(*args, **kwds): + kwds['invent_fail_descrs'] = False + return parse(*args, **kwds) def _box_counter_more_than(s): if s.isdigit(): From arigo at codespeak.net Fri Sep 25 15:49:54 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 15:49:54 +0200 (CEST) Subject: [pypy-svn] r67887 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090925134954.98E93168030@codespeak.net> Author: arigo Date: Fri Sep 25 15:49:53 2009 New Revision: 67887 Added: pypy/trunk/pypy/jit/metainterp/test/test_tl.py.merge.tmp - copied, changed from r67880, pypy/trunk/pypy/jit/metainterp/test/test_tl.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_tl.py revisions 67829 to 67880: ------------------------------------------------------------------------ r67832 | arigo | 2009-09-21 19:36:14 +0200 (Mon, 21 Sep 2009) | 4 lines (pedronis, arigo) Really kill PrepareLoopFromBridgeIsDisabled, and replace it with a working (if inefficient) solution instead. ------------------------------------------------------------------------ r67830 | arigo | 2009-09-21 18:11:04 +0200 (Mon, 21 Sep 2009) | 2 lines A branch in which we try to remove PrepareLoopFromBridgeIsDisabled. ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/metainterp/test/test_tl.py.merge.tmp (from r67880, pypy/trunk/pypy/jit/metainterp/test/test_tl.py) ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_tl.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_tl.py.merge.tmp Fri Sep 25 15:49:53 2009 @@ -107,7 +107,7 @@ PUSH 1 ADD PICK 0 - PUSH 3 + PUSH 5 LE BR_COND inside PUSH 1 From arigo at codespeak.net Fri Sep 25 15:52:01 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 15:52:01 +0200 (CEST) Subject: [pypy-svn] r67888 - in pypy/trunk/pypy: . jit/backend jit/backend/llgraph jit/backend/llsupport jit/backend/test jit/backend/x86 jit/backend/x86/test jit/metainterp jit/metainterp/test Message-ID: <20090925135201.37F8116801D@codespeak.net> Author: arigo Date: Fri Sep 25 15:52:00 2009 New Revision: 67888 Added: pypy/trunk/pypy/jit/backend/llgraph/ - copied from r67887, pypy/branch/remove-plfbid/pypy/jit/backend/llgraph/ pypy/trunk/pypy/jit/backend/llsupport/ - copied from r67887, pypy/branch/remove-plfbid/pypy/jit/backend/llsupport/ pypy/trunk/pypy/jit/backend/model.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/backend/model.py pypy/trunk/pypy/jit/backend/test/runner_test.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/backend/test/runner_test.py pypy/trunk/pypy/jit/backend/test/test_ll_random.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/backend/test/test_ll_random.py pypy/trunk/pypy/jit/backend/test/test_logger.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/backend/test/test_logger.py pypy/trunk/pypy/jit/backend/test/test_random.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/backend/test/test_random.py pypy/trunk/pypy/jit/backend/x86/assembler.py - copied unchanged from r67887, pypy/trunk/pypy/jit/backend/x86/assembler.py.merge.tmp pypy/trunk/pypy/jit/backend/x86/regalloc.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/backend/x86/regalloc.py pypy/trunk/pypy/jit/backend/x86/runner.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/backend/x86/runner.py pypy/trunk/pypy/jit/backend/x86/test/ - copied from r67887, pypy/branch/remove-plfbid/pypy/jit/backend/x86/test/ pypy/trunk/pypy/jit/metainterp/compile.py - copied unchanged from r67887, pypy/trunk/pypy/jit/metainterp/compile.py.merge.tmp pypy/trunk/pypy/jit/metainterp/dump.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/dump.py pypy/trunk/pypy/jit/metainterp/executor.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/executor.py pypy/trunk/pypy/jit/metainterp/graphpage.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/graphpage.py pypy/trunk/pypy/jit/metainterp/history.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/optimize.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/optimize.py pypy/trunk/pypy/jit/metainterp/optimizeopt.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/optimizeopt.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py - copied unchanged from r67887, pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp pypy/trunk/pypy/jit/metainterp/resoperation.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/resoperation.py pypy/trunk/pypy/jit/metainterp/test/oparser.py - copied unchanged from r67887, pypy/trunk/pypy/jit/metainterp/test/oparser.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_basic.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_basic.py pypy/trunk/pypy/jit/metainterp/test/test_oparser.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_oparser.py pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py - copied unchanged from r67887, pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_send.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/test/test_send.py pypy/trunk/pypy/jit/metainterp/test/test_tl.py - copied unchanged from r67887, pypy/trunk/pypy/jit/metainterp/test/test_tl.py.merge.tmp pypy/trunk/pypy/jit/metainterp/warmspot.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/jit/metainterp/warmspot.py pypy/trunk/pypy/testrunner_cfg.py - copied unchanged from r67887, pypy/branch/remove-plfbid/pypy/testrunner_cfg.py Removed: pypy/trunk/pypy/jit/backend/x86/assembler.py.merge.tmp pypy/trunk/pypy/jit/metainterp/compile.py.merge.tmp pypy/trunk/pypy/jit/metainterp/pyjitpl.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/oparser.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_debug.py pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py.merge.tmp pypy/trunk/pypy/jit/metainterp/test/test_tl.py.merge.tmp Log: (pedronis, arigo) Merge the branch/remove-plfbid. The main change is to not keep any loop around. Changed the interface to the backend. Cleaned up internals of x86 and other things. From arigo at codespeak.net Fri Sep 25 15:52:42 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 15:52:42 +0200 (CEST) Subject: [pypy-svn] r67889 - pypy/branch/remove-plfbid Message-ID: <20090925135242.DA88916801D@codespeak.net> Author: arigo Date: Fri Sep 25 15:52:42 2009 New Revision: 67889 Removed: pypy/branch/remove-plfbid/ Log: Remove merged branch. From arigo at codespeak.net Fri Sep 25 16:01:48 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 16:01:48 +0200 (CEST) Subject: [pypy-svn] r67890 - in pypy/trunk/pypy/jit: backend/test metainterp/test Message-ID: <20090925140148.86B6216801E@codespeak.net> Author: arigo Date: Fri Sep 25 16:01:48 2009 New Revision: 67890 Added: pypy/trunk/pypy/jit/metainterp/test/test_logger.py - copied, changed from r67889, pypy/trunk/pypy/jit/backend/test/test_logger.py Removed: pypy/trunk/pypy/jit/backend/test/test_logger.py Log: Oups, an "error" from the merge. Copied: pypy/trunk/pypy/jit/metainterp/test/test_logger.py (from r67889, pypy/trunk/pypy/jit/backend/test/test_logger.py) ============================================================================== --- pypy/trunk/pypy/jit/backend/test/test_logger.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_logger.py Fri Sep 25 16:01:48 2009 @@ -1,6 +1,6 @@ from pypy.jit.metainterp.test.oparser import pure_parse -from pypy.jit.backend import logger +from pypy.jit.metainterp import logger from pypy.jit.metainterp.typesystem import llhelper from StringIO import StringIO from pypy.jit.metainterp.test.test_optimizeopt import equaloplists @@ -29,6 +29,8 @@ """ parse loop once, then log it and parse again, return both """ + if namespace is None: + namespace = {} loop = pure_parse(inp, namespace=namespace) logger = Logger(self.ts) output = logger.log_loop(loop, namespace) From arigo at codespeak.net Fri Sep 25 16:26:14 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 16:26:14 +0200 (CEST) Subject: [pypy-svn] r67891 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090925142614.51B10168021@codespeak.net> Author: arigo Date: Fri Sep 25 16:26:13 2009 New Revision: 67891 Modified: pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/logger.py pypy/trunk/pypy/jit/metainterp/optimize.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: (pedronis, arigo) Fix the logging of operations. Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Fri Sep 25 16:26:13 2009 @@ -14,7 +14,7 @@ from pypy.jit.metainterp.optimizeutil import InvalidLoop from pypy.rlib.debug import debug_print -def show_loop(metainterp, loop=None, error=None): +def show_loop(metainterp_sd, loop=None, error=None): # debugging if option.view or option.viewloops: if error: @@ -27,7 +27,7 @@ extraloops = [] else: extraloops = [loop] - metainterp.staticdata.stats.view(errmsg=errmsg, extraloops=extraloops) + metainterp_sd.stats.view(errmsg=errmsg, extraloops=extraloops) def create_empty_loop(metainterp): name = metainterp.staticdata.stats.name_for_new_loop() @@ -61,7 +61,7 @@ if DEBUG > 0: debug_print("reusing old loop") return old_loop_token - executable_token = send_loop_to_backend(metainterp, loop, "loop") + executable_token = send_loop_to_backend(metainterp_sd, loop, "loop") loop_token = LoopToken() loop_token.specnodes = loop.specnodes loop_token.executable_token = executable_token @@ -70,18 +70,19 @@ old_loop_tokens.append(loop_token) return loop_token -def send_loop_to_backend(metainterp, loop, type): - metainterp.staticdata.profiler.start_backend() +def send_loop_to_backend(metainterp_sd, loop, type): + metainterp_sd.options.logger_ops.log_loop(loop.inputargs, loop.operations) + metainterp_sd.profiler.start_backend() if not we_are_translated(): - show_loop(metainterp, loop) + show_loop(metainterp_sd, loop) loop.check_consistency() - executable_token = metainterp.cpu.compile_loop(loop.inputargs, - loop.operations) - metainterp.staticdata.profiler.end_backend() - metainterp.staticdata.stats.add_new_loop(loop) + executable_token = metainterp_sd.cpu.compile_loop(loop.inputargs, + loop.operations) + metainterp_sd.profiler.end_backend() + metainterp_sd.stats.add_new_loop(loop) if not we_are_translated(): if type != "entry bridge": - metainterp.staticdata.stats.compiled() + metainterp_sd.stats.compiled() else: loop._ignore_during_counting = True log.info("compiled new " + type) @@ -91,16 +92,17 @@ debug_print("compiled new " + type) return executable_token -def send_bridge_to_backend(metainterp, faildescr, inputargs, operations): - metainterp.staticdata.profiler.start_backend() +def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations): + metainterp_sd.options.logger_ops.log_loop(inputargs, operations) + metainterp_sd.profiler.start_backend() if not we_are_translated(): - show_loop(metainterp) + show_loop(metainterp_sd) TreeLoop.check_consistency_of(inputargs, operations) pass - metainterp.cpu.compile_bridge(faildescr, inputargs, operations) - metainterp.staticdata.profiler.end_backend() + metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations) + metainterp_sd.profiler.end_backend() if not we_are_translated(): - metainterp.staticdata.stats.compiled() + metainterp_sd.stats.compiled() log.info("compiled new bridge") else: from pypy.jit.metainterp.pyjitpl import DEBUG @@ -247,7 +249,8 @@ fail_args = guard_op.suboperations[-1].args if not we_are_translated(): guard_op._debug_suboperations = new_loop.operations - send_bridge_to_backend(metainterp, self, fail_args, new_loop.operations) + send_bridge_to_backend(metainterp.staticdata, self, fail_args, + new_loop.operations) class ResumeFromInterpDescr(ResumeDescr): def __init__(self, original_greenkey, redkey): @@ -263,8 +266,8 @@ metainterp.history.inputargs = self.redkey new_loop.greenkey = self.original_greenkey new_loop.inputargs = self.redkey - executable_token = send_loop_to_backend(metainterp, new_loop, - "entry bridge") + executable_token = send_loop_to_backend(metainterp_sd, new_loop, + "entry bridge") # send the new_loop to warmspot.py, to be called directly the next time metainterp_sd.state.attach_unoptimized_bridge_from_interp( self.original_greenkey, @@ -281,6 +284,7 @@ # Attempt to use optimize_bridge(). This may return None in case # it does not work -- i.e. none of the existing old_loop_tokens match. new_loop = create_empty_loop(metainterp) + new_loop.inputargs = metainterp.history.inputargs new_loop.operations = metainterp.history.operations metainterp_sd = metainterp.staticdata options = metainterp_sd.options Modified: pypy/trunk/pypy/jit/metainterp/logger.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/logger.py (original) +++ pypy/trunk/pypy/jit/metainterp/logger.py Fri Sep 25 16:26:13 2009 @@ -25,8 +25,8 @@ return None return self.log_stream - def log_loop(self, loop): - self.log_operations(loop.inputargs, loop.operations, {}) + def log_loop(self, inputargs, operations): + self.log_operations(inputargs, operations, {}) def repr_of_descr(self, descr): return descr.repr_of_descr() Modified: pypy/trunk/pypy/jit/metainterp/optimize.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimize.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimize.py Fri Sep 25 16:26:13 2009 @@ -10,8 +10,7 @@ return old_loop_tokens[0] else: return None - if options.logger_noopt is not None: - options.logger_noopt.log_loop(loop) + options.logger_noopt.log_loop(loop.inputargs, loop.operations) finder = PerfectSpecializationFinder(cpu) finder.find_nodes_loop(loop) for old_loop_token in old_loop_tokens: @@ -28,8 +27,7 @@ def optimize_bridge(options, old_loop_tokens, bridge, cpu): if not options.specialize: # for tests only return old_loop_tokens[0] - if options.logger_noopt is not None: - options.logger_noopt.log_loop(bridge) + options.logger_noopt.log_loop(bridge.inputargs, bridge.operations) finder = BridgeSpecializationFinder(cpu) finder.find_nodes_bridge(bridge) for old_loop_token in old_loop_tokens: Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Fri Sep 25 16:26:13 2009 @@ -1573,11 +1573,13 @@ suboperations = guard_op.suboperations assert suboperations[-1] is guard_failure self.history = history.History(self.cpu) + self.history.inputargs = guard_failure.args # xxx unhappy self.staticdata.profiler.start_tracing() else: self.staticdata.profiler.start_blackhole() self.history = None # this means that is_blackholing() is true self.rebuild_state_after_failure(resumedescr, guard_failure.args) + # xxx unhappy return resumedescr def initialize_virtualizable(self, original_boxes): From arigo at codespeak.net Fri Sep 25 16:33:38 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 16:33:38 +0200 (CEST) Subject: [pypy-svn] r67892 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090925143338.94683168021@codespeak.net> Author: arigo Date: Fri Sep 25 16:33:37 2009 New Revision: 67892 Modified: pypy/trunk/pypy/jit/backend/x86/viewcode.py Log: A hack to not have arrows after 'ret' instructions. Modified: pypy/trunk/pypy/jit/backend/x86/viewcode.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/viewcode.py (original) +++ pypy/trunk/pypy/jit/backend/x86/viewcode.py Fri Sep 25 16:33:37 2009 @@ -148,6 +148,7 @@ def findjumps(self): text = self.disassemble() lines = text.splitlines() + line = '' for i, line in enumerate(lines): if '\tj' not in line: # poor heuristic to recognize lines that continue # could be jump instructions @@ -157,7 +158,7 @@ addr = addrs[-1] final = '\tjmp' in line yield i, addr, final - if self.fallthrough: + if self.fallthrough and '\tret' not in line: yield len(lines), self.addr + len(self.data), True From fijal at codespeak.net Fri Sep 25 17:32:41 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 25 Sep 2009 17:32:41 +0200 (CEST) Subject: [pypy-svn] r67893 - in pypy/trunk/pypy/jit/backend/x86: . test Message-ID: <20090925153241.E128A168021@codespeak.net> Author: fijal Date: Fri Sep 25 17:32:41 2009 New Revision: 67893 Modified: pypy/trunk/pypy/jit/backend/x86/ri386.py pypy/trunk/pypy/jit/backend/x86/ri386setup.py pypy/trunk/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py Log: (fijal, arigo) Add xmm registers and movsd operations Modified: pypy/trunk/pypy/jit/backend/x86/ri386.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/ri386.py (original) +++ pypy/trunk/pypy/jit/backend/x86/ri386.py Fri Sep 25 17:32:41 2009 @@ -27,6 +27,15 @@ def assembler(self): raise TypeError("Float registers should not appear in assembler") +class XMMREG(OPERAND): + width = 16 + + def __repr__(self): + return '' % self.op + + def assembler(self): + return '%xmm' + str(self.op) + class ST0(FLOATREG): num=0 class ST1(FLOATREG): num=1 class ST2(FLOATREG): num=2 @@ -36,6 +45,15 @@ class ST6(FLOATREG): num=6 class ST7(FLOATREG): num=7 +class XMM0(XMMREG): op=0 +class XMM1(XMMREG): op=1 +class XMM2(XMMREG): op=2 +class XMM3(XMMREG): op=3 +class XMM4(XMMREG): op=4 +class XMM5(XMMREG): op=5 +class XMM6(XMMREG): op=6 +class XMM7(XMMREG): op=7 + class REG8(OPERAND): width = 1 def __repr__(self): @@ -231,8 +249,18 @@ st6 = ST6() st7 = ST7() +xmm0 = XMM0() +xmm1 = XMM1() +xmm2 = XMM2() +xmm3 = XMM3() +xmm4 = XMM4() +xmm5 = XMM5() +xmm6 = XMM6() +xmm7 = XMM7() + registers = [eax, ecx, edx, ebx, esp, ebp, esi, edi] registers8 = [al, cl, dl, bl, ah, ch, dh, bh] +xmm_registers = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] for r in registers + registers8: r.bitmask = 1 << r.op Modified: pypy/trunk/pypy/jit/backend/x86/ri386setup.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/ri386setup.py (original) +++ pypy/trunk/pypy/jit/backend/x86/ri386setup.py Fri Sep 25 17:32:41 2009 @@ -45,6 +45,7 @@ MODRM: [(MODRM, None)], MODRM8: [(MODRM8, None)], MODRM64: [(MODRM64, None)], + XMMREG: [(XMMREG, None)], MISSING: [(MISSING, None)], # missing operands } @@ -499,6 +500,16 @@ # ------------------------- end of floating point ------------------------ +# --------------------------------- SSE2 --------------------------------- + +MOVSD = Instruction() +MOVSD.mode2(XMMREG, XMMREG, ['\xF2\x0F\x10', register(1, 8), + register(2), '\xC0']) +MOVSD.mode2(XMMREG, MODRM64, ['\xF2\x0F\x10', register(1, 8), modrm(2)]) +MOVSD.mode2(MODRM64, XMMREG, ['\xF2\x0F\x11', register(2, 8), modrm(1)]) + +# ------------------------------ end of SSE2 ----------------------------- + UD2 = Instruction() # reserved as an illegal instruction UD2.mode0(['\x0F\x0B']) Modified: pypy/trunk/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py Fri Sep 25 17:32:41 2009 @@ -91,6 +91,9 @@ def modrm64_tests(): return [pick1(i386.memSIB64) for i in range(COUNT2)] +def xmm_tests(): + return i386.xmm_registers + def modrm8_tests(): return i386.registers8 + [pick1(i386.memSIB8) for i in range(COUNT2)] @@ -116,6 +119,7 @@ i386.REG: reg_tests, i386.MODRM: modrm_tests, i386.MODRM64: modrm64_tests, + i386.XMMREG: xmm_tests, i386.IMM32: imm32_tests, i386.REG8: reg8_tests, i386.MODRM8: modrm8_tests, From fijal at codespeak.net Fri Sep 25 17:34:18 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 25 Sep 2009 17:34:18 +0200 (CEST) Subject: [pypy-svn] r67894 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090925153418.9744F168021@codespeak.net> Author: fijal Date: Fri Sep 25 17:34:18 2009 New Revision: 67894 Modified: pypy/trunk/pypy/jit/backend/x86/ri386.py Log: Kill wrong comment Modified: pypy/trunk/pypy/jit/backend/x86/ri386.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/ri386.py (original) +++ pypy/trunk/pypy/jit/backend/x86/ri386.py Fri Sep 25 17:34:18 2009 @@ -198,7 +198,6 @@ class MODRM64(MODRM): width = 8 - # XXX some logic that it cannot be register class MODRM8(MODRM): width = 1 From fijal at codespeak.net Fri Sep 25 17:55:15 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 25 Sep 2009 17:55:15 +0200 (CEST) Subject: [pypy-svn] r67895 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090925155515.5FBAA16801B@codespeak.net> Author: fijal Date: Fri Sep 25 17:55:14 2009 New Revision: 67895 Modified: pypy/trunk/pypy/jit/backend/x86/ri386.py pypy/trunk/pypy/jit/backend/x86/ri386setup.py Log: Add two more operations... Modified: pypy/trunk/pypy/jit/backend/x86/ri386.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/ri386.py (original) +++ pypy/trunk/pypy/jit/backend/x86/ri386.py Fri Sep 25 17:55:14 2009 @@ -28,7 +28,7 @@ raise TypeError("Float registers should not appear in assembler") class XMMREG(OPERAND): - width = 16 + width = 8 def __repr__(self): return '' % self.op Modified: pypy/trunk/pypy/jit/backend/x86/ri386setup.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/ri386setup.py (original) +++ pypy/trunk/pypy/jit/backend/x86/ri386setup.py Fri Sep 25 17:55:14 2009 @@ -508,6 +508,12 @@ MOVSD.mode2(XMMREG, MODRM64, ['\xF2\x0F\x10', register(1, 8), modrm(2)]) MOVSD.mode2(MODRM64, XMMREG, ['\xF2\x0F\x11', register(2, 8), modrm(1)]) +ADDSD = Instruction() +ADDSD.mode2(XMMREG, MODRM64, ['\xF2\x0F\x58', register(1, 8), modrm(2)]) + +SUBSD = Instruction() +SUBSD.mode2(XMMREG, MODRM64, ['\xF2\x0F\x5C', register(1, 8), modrm(2)]) + # ------------------------------ end of SSE2 ----------------------------- UD2 = Instruction() # reserved as an illegal instruction From fijal at codespeak.net Fri Sep 25 18:34:37 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 25 Sep 2009 18:34:37 +0200 (CEST) Subject: [pypy-svn] r67896 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090925163437.AFEAF16801E@codespeak.net> Author: fijal Date: Fri Sep 25 18:34:37 2009 New Revision: 67896 Modified: pypy/trunk/pypy/jit/backend/x86/ri386setup.py Log: Add more operations Modified: pypy/trunk/pypy/jit/backend/x86/ri386setup.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/ri386setup.py (original) +++ pypy/trunk/pypy/jit/backend/x86/ri386setup.py Fri Sep 25 18:34:37 2009 @@ -514,6 +514,12 @@ SUBSD = Instruction() SUBSD.mode2(XMMREG, MODRM64, ['\xF2\x0F\x5C', register(1, 8), modrm(2)]) +MULSD = Instruction() +MULSD.mode2(XMMREG, MODRM64, ['\xF2\x0F\x59', register(1, 8), modrm(2)]) + +DIVSD = Instruction() +DIVSD.mode2(XMMREG, MODRM64, ['\xF2\x0F\x5E', register(1, 8), modrm(2)]) + # ------------------------------ end of SSE2 ----------------------------- UD2 = Instruction() # reserved as an illegal instruction From fijal at codespeak.net Fri Sep 25 18:35:35 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 25 Sep 2009 18:35:35 +0200 (CEST) Subject: [pypy-svn] r67897 - pypy/branch/refactor-x86 Message-ID: <20090925163535.796A416801E@codespeak.net> Author: fijal Date: Fri Sep 25 18:35:35 2009 New Revision: 67897 Added: pypy/branch/refactor-x86/ - copied from r67896, pypy/trunk/ Log: A branch to move register allocation logic to it's own class From arigo at codespeak.net Fri Sep 25 22:00:37 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 22:00:37 +0200 (CEST) Subject: [pypy-svn] r67898 - pypy/branch/execute-star-args-jit Message-ID: <20090925200037.4D71616801E@codespeak.net> Author: arigo Date: Fri Sep 25 22:00:33 2009 New Revision: 67898 Removed: pypy/branch/execute-star-args-jit/ Log: Remove branch merged 4 days ago. From arigo at codespeak.net Fri Sep 25 22:11:36 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 22:11:36 +0200 (CEST) Subject: [pypy-svn] r67899 - pypy/branch/remove-ri386-multimethod Message-ID: <20090925201136.2C80316801E@codespeak.net> Author: arigo Date: Fri Sep 25 22:11:35 2009 New Revision: 67899 Added: pypy/branch/remove-ri386-multimethod/ - copied from r67898, pypy/trunk/ Log: A branch in which to remove ri386's multimethod-based dispatching as used to emit machine code instructions. From pedronis at codespeak.net Fri Sep 25 22:17:46 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 25 Sep 2009 22:17:46 +0200 (CEST) Subject: [pypy-svn] r67900 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090925201746.9FB1D16801E@codespeak.net> Author: pedronis Date: Fri Sep 25 22:17:46 2009 New Revision: 67900 Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py Log: we miss a counter resetting here Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Fri Sep 25 22:17:46 2009 @@ -876,6 +876,7 @@ self.mccounters[argshash] = n return None metainterp = MetaInterp(metainterp_sd) + # XXX ContinueRunningNormally => "reset" counters return metainterp.compile_and_run_once(*args) handle_hash_collision._dont_inline_ = True From arigo at codespeak.net Fri Sep 25 23:59:44 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 25 Sep 2009 23:59:44 +0200 (CEST) Subject: [pypy-svn] r67901 - in pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86: . test Message-ID: <20090925215944.6B3BB168023@codespeak.net> Author: arigo Date: Fri Sep 25 23:59:42 2009 New Revision: 67901 Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py Log: Start from scratch ri386.py. Keep the encoding description but kill the multimethod dispatch. Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py ============================================================================== --- pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py (original) +++ pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py Fri Sep 25 23:59:42 2009 @@ -1,401 +1,133 @@ from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import ComputedIntSymbolic, we_are_translated +from pypy.rlib.objectmodel import specialize +from pypy.rlib.unroll import unrolling_iterable -class OPERAND(object): - _attrs_ = [] - def __repr__(self): - return '<%s %s>' % (self.__class__.__name__, self.assembler()) - -class REG(OPERAND): - width = 4 - def __repr__(self): - return '<%s>' % self.__class__.__name__.lower() - def assembler(self): - return '%' + self.__class__.__name__.lower() - def lowest8bits(self): - if self.op < 4: - return registers8[self.op] - else: - raise ValueError +WORD = 4 -class FLOATREG(OPERAND): - width = 8 +eax = 0 +ecx = 1 +edx = 2 +ebx = 3 +esp = 4 +ebp = 5 +esi = 6 +edi = 7 - def __repr__(self): - return '' % self.num +# ____________________________________________________________ +# Emit a single char - def assembler(self): - raise TypeError("Float registers should not appear in assembler") - -class XMMREG(OPERAND): - width = 8 - - def __repr__(self): - return '' % self.op - - def assembler(self): - return '%xmm' + str(self.op) - -class ST0(FLOATREG): num=0 -class ST1(FLOATREG): num=1 -class ST2(FLOATREG): num=2 -class ST3(FLOATREG): num=3 -class ST4(FLOATREG): num=4 -class ST5(FLOATREG): num=5 -class ST6(FLOATREG): num=6 -class ST7(FLOATREG): num=7 - -class XMM0(XMMREG): op=0 -class XMM1(XMMREG): op=1 -class XMM2(XMMREG): op=2 -class XMM3(XMMREG): op=3 -class XMM4(XMMREG): op=4 -class XMM5(XMMREG): op=5 -class XMM6(XMMREG): op=6 -class XMM7(XMMREG): op=7 - -class REG8(OPERAND): - width = 1 - def __repr__(self): - return '<%s>' % self.__class__.__name__.lower() - def assembler(self): - return '%' + self.__class__.__name__.lower() - -class EAX(REG): op=0 -class ECX(REG): op=1 -class EDX(REG): op=2 -class EBX(REG): op=3 -class ESP(REG): op=4 -class EBP(REG): op=5 -class ESI(REG): op=6 -class EDI(REG): op=7 - -class AL(REG8): op=0 -class CL(REG8): op=1 -class DL(REG8): op=2 -class BL(REG8): op=3 -class AH(REG8): op=4 -class CH(REG8): op=5 -class DH(REG8): op=6 -class BH(REG8): op=7 - -class IMM32(OPERAND): - width = 4 - value = 0 # annotator hack - - def __init__(self, value): - self.value = value - def assembler(self): - return '$%d' % (self.value,) - - def lowest8bits(self): - val = self.value & 0xFF - if val > 0x7F: - val -= 0x100 - return IMM8(val) - -class IMM8(IMM32): - width = 1 - -class IMM16(OPERAND): # only for RET - width = 2 - value = 0 # annotator hack - - def __init__(self, value): - self.value = value - def assembler(self): - return '$%d' % (self.value,) - -class MODRM(OPERAND): - width = 4 - - def __init__(self, byte, extradata): - self.byte = byte - self.extradata = extradata - - def lowest8bits(self): - return MODRM8(self.byte, self.extradata) - - def assembler(self): - mod = self.byte & 0xC0 - rm = self.byte & 0x07 - if mod == 0xC0: - return registers[rm].assembler() - if self.byte == 0x05: - return '%d' % (unpack(self.extradata),) - if mod == 0x00: - offset_bytes = 0 - elif mod == 0x40: - offset_bytes = 1 - else: - offset_bytes = 4 - if rm == 4: - SIB = ord(self.extradata[0]) - scale = (SIB & 0xC0) >> 6 - index = (SIB & 0x38) >> 3 - base = (SIB & 0x07) - if base == 5 and mod == 0x00: - offset_bytes = 4 - basename = '' - else: - basename = registers[base].assembler() - if index == 4: - # no index - s = '(%s)' % (basename,) - else: - indexname = registers[index].assembler() - s = '(%s,%s,%d)' % (basename, indexname, 1 << scale) - offset = self.extradata[1:] - else: - s = '(%s)' % (registers[rm].assembler(),) - offset = self.extradata +def encode_char(mc, char, orbyte, *ignored): + mc.writechar(chr(char | orbyte)) + return 0 - assert len(offset) == offset_bytes - if offset_bytes > 0: - s = '%d%s' % (unpack(offset), s) - return s - - def is_register(self): - mod = self.byte & 0xC0 - return mod == 0xC0 - - def ofs_relative_to_ebp(self): - # very custom: if self is a mem(ebp, ofs) then return ofs - # otherwise raise ValueError - mod = self.byte & 0xC0 - rm = self.byte & 0x07 - if mod == 0xC0: - raise ValueError # self is just a register - if self.byte == 0x05: - raise ValueError # self is just an [immediate] - if rm != 5: - raise ValueError # not a simple [ebp+ofs] - offset = self.extradata - if not offset: - return 0 - else: - return unpack(offset) +# ____________________________________________________________ +# Encode a register number in the orbyte - def is_relative_to_ebp(self): - try: - self.ofs_relative_to_ebp() - except ValueError: - return False - else: - return True + at specialize.arg(1) +def encode_register(mc, (argnum, factor), orbyte, *args): + reg = args[argnum-1] + assert 0 <= reg < 8 + return orbyte | (reg * factor) - def involves_ecx(self): - # very custom: is ecx present in this mod/rm? - mod = self.byte & 0xC0 - rm = self.byte & 0x07 - if mod != 0xC0 and rm == 4: - SIB = ord(self.extradata[0]) - index = (SIB & 0x38) >> 3 - base = (SIB & 0x07) - return base == ECX.op or index == ECX.op - else: - return rm == ECX.op +def register(argnum, factor=1): + return encode_register, (argnum, factor) -class MODRM64(MODRM): - width = 8 +# ____________________________________________________________ +# Encode a constant in the orbyte -class MODRM8(MODRM): - width = 1 +def encode_orbyte(mc, constant, orbyte, *ignored): + return orbyte | constant -class REL32(OPERAND): - width = 4 - def __init__(self, absolute_target): - self.absolute_target = absolute_target - def assembler(self): - return '%d' % (self.absolute_target,) - -class MISSING(OPERAND): - def __repr__(self): - return '' +def orbyte(value): + return encode_orbyte, value # ____________________________________________________________ -# Public interface: the concrete operands to instructions -# -# NB.: UPPERCASE names represent classes of operands (the same -# instruction can have multiple modes, depending on these -# classes), while lowercase names are concrete operands. - - -eax = EAX() -ecx = ECX() -edx = EDX() -ebx = EBX() -esp = ESP() -ebp = EBP() -esi = ESI() -edi = EDI() - -al = AL() -cl = CL() -dl = DL() -bl = BL() -ah = AH() -ch = CH() -dh = DH() -bh = BH() - -st0 = ST0() -st1 = ST1() -st2 = ST2() -st3 = ST3() -st4 = ST4() -st5 = ST5() -st6 = ST6() -st7 = ST7() - -xmm0 = XMM0() -xmm1 = XMM1() -xmm2 = XMM2() -xmm3 = XMM3() -xmm4 = XMM4() -xmm5 = XMM5() -xmm6 = XMM6() -xmm7 = XMM7() - -registers = [eax, ecx, edx, ebx, esp, ebp, esi, edi] -registers8 = [al, cl, dl, bl, ah, ch, dh, bh] -xmm_registers = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] - -for r in registers + registers8: - r.bitmask = 1 << r.op -del r - -imm32 = IMM32 -imm8 = IMM8 -imm16 = IMM16 -rel32 = REL32 - -def imm(value): - if isinstance(value, ComputedIntSymbolic): - value = value.compute_fn() - if not we_are_translated(): - assert type(value) is int - if single_byte(value): - return imm8(value) - else: - return imm32(value) +# Emit an immediate value -def memregister(register): - assert register.width == 4 - return MODRM(0xC0 | register.op, '') - -def mem(basereg, offset=0): - return memSIB(basereg, None, 0, offset) - -def heap(offset): - return memSIB(None, None, 0, offset) - -def heap8(offset): - return memSIB8(None, None, 0, offset) - -def heap64(offset): - return memSIB64(None, None, 0, offset) - -def mem64(basereg, offset=0): - return memSIB64(basereg, None, 0, offset) - -def memSIB(base, index, scaleshift, offset): - return _SIBencode(MODRM, base, index, scaleshift, offset) - -def memSIB64(base, index, scaleshift, offset): - return _SIBencode(MODRM64, base, index, scaleshift, offset) - -def memregister8(register): - assert register.width == 1 - return MODRM8(0xC0 | register.op, '') - -def mem8(basereg, offset=0): - return memSIB8(basereg, None, 0, offset) - -def memSIB8(base, index, scaleshift, offset): - return _SIBencode(MODRM8, base, index, scaleshift, offset) - -def _SIBencode(cls, base, index, scaleshift, offset): - assert base is None or isinstance(base, REG) - assert index is None or (isinstance(index, REG) and index is not esp) - assert 0<=scaleshift<4 - - if base is None: - if index is None: - return cls(0x05, packimm32(offset)) - if scaleshift > 0: - return cls(0x04, chr((scaleshift<<6) | (index.op<<3) | 0x05) + - packimm32(offset)) - base = index - index = None - - if index is not None: - SIB = chr((scaleshift<<6) | (index.op<<3) | base.op) - elif base is esp: - SIB = '\x24' - elif offset == 0 and base is not ebp: - return cls(base.op, '') - elif single_byte(offset): - return cls(0x40 | base.op, packimm8(offset)) - else: - return cls(0x80 | base.op, packimm32(offset)) + at specialize.arg(1) +def encode_immediate(mc, (argnum, width), orbyte, *args): + imm = args[argnum-1] + assert orbyte == 0 + mc.writeimm(imm, width) + return 0 - if offset == 0 and base is not ebp: - return cls(0x04, SIB) - elif single_byte(offset): - return cls(0x44, SIB + packimm8(offset)) - else: - return cls(0x84, SIB + packimm32(offset)) +def immediate(argnum, width='i'): + return encode_immediate, (argnum, width) -def fixedsize_ebp_ofs(offset): - return MODRM(0x80 | EBP.op, packimm32(offset)) +# ____________________________________________________________ +# Emit a mod/rm referencing a stack location +# This depends on the fact that our function prologue contains +# exactly 4 PUSHes. + +def get_ebp_ofs(position): + # Argument is a stack position (0, 1, 2...). + # Returns (ebp-16), (ebp-20), (ebp-24)... + # This depends on the fact that our function prologue contains + # exactly 4 PUSHes. + return -WORD * (4 + position) def single_byte(value): return -128 <= value < 128 -def packimm32(i): - return (chr(i & 0xFF) + - chr((i >> 8) & 0xFF) + - chr((i >> 16) & 0xFF) + - chr((i >> 24) & 0xFF)) - -def packimm8(i): - if i < 0: - i += 256 - return chr(i) - -def packimm16(i): - return (chr(i & 0xFF) + - chr((i >> 8) & 0xFF)) - -def unpack(s): - assert len(s) in (1, 2, 4) - if len(s) == 1: - a = ord(s[0]) - if a > 0x7f: - a -= 0x100 + at specialize.arg(1) +def encode_stack(mc, (argnum, allow_single_byte), orbyte, *args): + offset = get_ebp_ofs(args[argnum-1]) + if allow_single_byte and single_byte(offset): + mc.writechar(chr(0x40 | ebp | orbyte)) + mc.writeimm(offset, 'b') else: - a = ord(s[0]) | (ord(s[1]) << 8) - if len(s) == 2: - if a > 0x7fff: - a -= 0x10000 - else: - a |= (ord(s[2]) << 16) | (ord(s[3]) << 24) - a = intmask(a) - return a + mc.writechar(chr(0x80 | ebp | orbyte)) + mc.writeimm(offset, 'i') + return 0 + +def stack(argnum, allow_single_byte=True): + return encode_stack, (argnum, allow_single_byte) -missing = MISSING() +# ____________________________________________________________ + +def insn(*encoding): + def encode(mc, *args): + orbyte = 0 + for encode_step, encode_static_arg in encoding_steps: + orbyte = encode_step(mc, encode_static_arg, orbyte, *args) + assert orbyte == 0 + # + encoding_steps = [] + for step in encoding: + if isinstance(step, str): + for c in step: + encoding_steps.append((encode_char, ord(c))) + else: + assert type(step) is tuple and len(step) == 2 + encoding_steps.append(step) + encoding_steps = unrolling_iterable(encoding_steps) + return encode + +# ____________________________________________________________ -# __________________________________________________________ -# Abstract base class, with methods like NOP(), ADD(x, y), etc. class I386CodeBuilder(object): + """Abstract base class.""" - def write(self, data): + def writechar(self, char): raise NotImplementedError - def tell(self): - raise NotImplementedError + @specialize.arg(2) + def writeimm(self, imm, width='i'): + self.writechar(chr(imm & 0xFF)) + if width != 'b': # != byte + self.writechar(chr((imm >> 8) & 0xFF)) + if width != 'h': # != 2-bytes word + self.writechar(chr((imm >> 16) & 0xFF)) + self.writechar(chr((imm >> 24) & 0xFF)) + + MOV_ri = insn(register(1), '\xB8', immediate(2)) + MOV_si = insn('\xC7', orbyte(0<<3), stack(1), immediate(2)) + MOV_rr = insn('\x89', register(2,8), register(1), '\xC0') + MOV_sr = insn('\x89', register(2,8), stack(1)) + MOV_rs = insn('\x8B', register(1,8), stack(2)) + NOP = insn('\x90') -import ri386setup # side-effect: add methods to I386CodeBuilder + ADD_rr = insn('\x01', register(2,8), register(1), '\xC0') Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py ============================================================================== --- pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py (original) +++ pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py Fri Sep 25 23:59:42 2009 @@ -5,112 +5,40 @@ def __init__(self): self.buffer = [] - def write(self, data): - for c in data: - self.buffer.append(c) # extend the list of characters - - def tell(self): - return len(self.buffer) + def writechar(self, c): + self.buffer.append(c) # extend the list of characters def getvalue(self): return ''.join(self.buffer) -def test_example(): +def test_mov_ri(): + s = CodeBuilder() + s.MOV_ri(ecx, -2) + assert s.getvalue() == '\xB9\xFE\xFF\xFF\xFF' + +def test_mov_si(): + s = CodeBuilder() + s.MOV_si(5, 1<<24) + assert s.getvalue() == '\xC7\x45\xDC\x00\x00\x00\x01' + +def test_mov_rr(): + s = CodeBuilder() + s.MOV_rr(ebx, ebp) + assert s.getvalue() == '\x89\xEB' + +def test_mov_sr(): + s = CodeBuilder() + s.MOV_sr(5, edx) + assert s.getvalue() == '\x89\x55\xDC' + +def test_mov_rs(): + s = CodeBuilder() + s.MOV_rs(edx, 5) + assert s.getvalue() == '\x8B\x55\xDC' + +def test_nop_add_rr(): s = CodeBuilder() s.NOP() - s.ADD(eax, eax) + s.ADD_rr(eax, eax) assert s.getvalue() == '\x90\x01\xC0' - -def test_modrm(): - assert memregister(ecx).assembler() == '%ecx' - assert memregister(ebp).assembler() == '%ebp' - assert memregister(esp).assembler() == '%esp' - assert memSIB(eax, ebx, 0, 2).assembler() == '2(%eax,%ebx,1)' - assert memSIB(None, ebx, 1, 2).assembler() == '2(,%ebx,2)' - assert memSIB(eax, None, 0, 2).assembler() == '2(%eax)' - assert memSIB(None, None, 0, 2).assembler() == '2' - assert memSIB(ebp, ebx, 0, 2).assembler() == '2(%ebp,%ebx,1)' - assert memSIB(ebp, None, 0, 2).assembler() == '2(%ebp)' - assert memSIB(None, ebp, 1, 2).assembler() == '2(,%ebp,2)' - assert memSIB(ebp, ebp, 0, 2).assembler() == '2(%ebp,%ebp,1)' - assert memSIB(eax, ebx, 0, 0).assembler() == '(%eax,%ebx,1)' - assert memSIB(None, ebx, 1, 0).assembler() == '0(,%ebx,2)' - assert memSIB(eax, None, 0, 0).assembler() == '(%eax)' - assert memSIB(None, None, 0, 0).assembler() == '0' - assert memSIB(ebp, ebx, 0, 0).assembler() == '0(%ebp,%ebx,1)' - assert memSIB(ebp, None, 0, 0).assembler() == '0(%ebp)' - assert memSIB(None, ebp, 1, 0).assembler() == '0(,%ebp,2)' - assert memSIB(ebp, ebp, 0, 0).assembler() == '0(%ebp,%ebp,1)' - - -def test_basic(): - def check(expected, insn, *args): - s = CodeBuilder() - getattr(s, insn)(*args) - assert s.getvalue() == expected - - # nop - yield check, '\x90', 'NOP' - # mov [ebp+19], ecx - yield check, '\x89\x4D\x13', 'MOV', mem(ebp, 19), ecx - # add edx, 0x12345678 - yield check, '\x81\xEA\x78\x56\x34\x12', 'SUB', edx, imm32(0x12345678) - # mov dh, 1 (inefficient encoding) - yield check, '\xC6\xC6\x01', 'MOV', memregister8(dh), imm8(1) - # add esp, 12 - yield check, '\x83\xC4\x0C', 'ADD', esp, imm8(12) - # mov esp, 12 - yield check, '\xBC\x0C\x00\x00\x00', 'MOV', esp, imm8(12) - # sub esi, ecx - yield check, '\x29\xCE', 'SUB', esi, ecx - # ret - yield check, '\xC3', 'RET' - # ret 20 - yield check, '\xC2\x14\x00', 'RET', imm16(20) - # mov eax, [8*ecx] - yield check, '\x89\x04\xcd\x00\x00\x00\x00', \ - 'MOV', memSIB(None,ecx,3,0), eax - # call +17 - yield check, '\xE8\x11\x00\x00\x00', 'CALL', rel32(22) - # fld - #yield check, '\xDD\x44\x24\x04', 'FLD', mem(esp, 4) - # fadd - #yield check, '\xDC\x44\x24\x08', 'FADD', mem(esp, 8) - -##def test_conditional(): -## """Compare the encoding for the instructions JE, JAE, JC etc., -## with the encoding for the 'Jcond' pseudo-instruction. -## """ -## def check(insn, *args): -## from pypy.jit.codegen.i386.ri386setup import Conditions -## for cond, value in Conditions.items(): -## s1 = CodeBuilder() -## getattr(s1, insn+cond)(*args) -## s2 = CodeBuilder() -## getattr(s2, insn+'cond')(imm8(value), *args) - - -def test_translate(): - from pypy.rpython.test.test_llinterp import interpret - - def f(): - s = CodeBuilder() - s.SUB(esi, ecx) - s.MOV(mem(ebp, 19), ecx) - return s.getvalue() - - res = interpret(f, []) - assert ''.join(res.chars) == '\x29\xCE\x89\x4D\x13' - - -def test_unpack_compiled(): - from pypy.translator.c.test.test_genc import compile - - def f(n): - return mem(ebp, n).ofs_relative_to_ebp() - - fn = compile(f, [int]) - for i in [0, 4, 44, 124, 128, 132, 252, 256, 10000000, - -4, -44, -124, -128, -132, -252, -256, -10000000]: - assert fn(i) == i From arigo at codespeak.net Sat Sep 26 10:36:30 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 26 Sep 2009 10:36:30 +0200 (CEST) Subject: [pypy-svn] r67902 - pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86 Message-ID: <20090926083630.BC5B116801E@codespeak.net> Author: arigo Date: Sat Sep 26 10:36:29 2009 New Revision: 67902 Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py Log: Yet another approach, about which I am not too happy so it might get reverted. Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py ============================================================================== --- pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py (original) +++ pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py Sat Sep 26 10:36:29 2009 @@ -14,51 +14,58 @@ esi = 6 edi = 7 -# ____________________________________________________________ -# Emit a single char - -def encode_char(mc, char, orbyte, *ignored): - mc.writechar(chr(char | orbyte)) - return 0 - -# ____________________________________________________________ -# Encode a register number in the orbyte - - at specialize.arg(1) -def encode_register(mc, (argnum, factor), orbyte, *args): - reg = args[argnum-1] - assert 0 <= reg < 8 - return orbyte | (reg * factor) - -def register(argnum, factor=1): - return encode_register, (argnum, factor) - -# ____________________________________________________________ -# Encode a constant in the orbyte - -def encode_orbyte(mc, constant, orbyte, *ignored): - return orbyte | constant -def orbyte(value): - return encode_orbyte, value - -# ____________________________________________________________ -# Emit an immediate value - - at specialize.arg(1) -def encode_immediate(mc, (argnum, width), orbyte, *args): - imm = args[argnum-1] - assert orbyte == 0 - mc.writeimm(imm, width) - return 0 +class CodeStepWriter(object): + def encode(self, mc, args, orbyte): + mc.writechar(chr(self.encode_byte(args) | orbyte)) + def _freeze_(self): + return True + def __or__(self, other): + if isinstance(other, int): + other = Constant(other) + if hasattr(self, 'encode_byte'): + return Compose(self, other) + if hasattr(other, 'encode_byte'): + return Compose(other, self) + return NotImplemented + __ror__ = __or__ + +class Constant(CodeStepWriter): + def __init__(self, charvalue): + self.charvalue = charvalue + def encode_byte(self, args): + return self.charvalue + +class Compose(CodeStepWriter): + def __init__(self, operand1, operand2): + self.operand1 = operand1 + self.operand2 = operand2 + def encode(self, mc, args, orbyte): + orbyte |= self.operand1.encode_byte(args) + self.operand2.encode(mc, args, orbyte) + +class register(CodeStepWriter): + def __init__(self, argnum, shift=0): + self.argnum = argnum + self.shift = shift + def __lshift__(self, num): + return register(self.argnum, self.shift + num) + def encode_byte(self, args): + reg = args[self.argnum-1] + assert 0 <= reg < 8 + return reg << self.shift + +class imm32(CodeStepWriter): + def __init__(self, argnum): + self.argnum = argnum + def encode(self, mc, args, orbyte): + assert orbyte == 0 + imm = args[self.argnum-1] + mc.writechar(chr(imm & 0xFF)) + mc.writechar(chr((imm >> 8) & 0xFF)) + mc.writechar(chr((imm >> 16) & 0xFF)) + mc.writechar(chr((imm >> 24) & 0xFF)) -def immediate(argnum, width='i'): - return encode_immediate, (argnum, width) - -# ____________________________________________________________ -# Emit a mod/rm referencing a stack location -# This depends on the fact that our function prologue contains -# exactly 4 PUSHes. def get_ebp_ofs(position): # Argument is a stack position (0, 1, 2...). @@ -70,36 +77,36 @@ def single_byte(value): return -128 <= value < 128 - at specialize.arg(1) -def encode_stack(mc, (argnum, allow_single_byte), orbyte, *args): - offset = get_ebp_ofs(args[argnum-1]) - if allow_single_byte and single_byte(offset): - mc.writechar(chr(0x40 | ebp | orbyte)) - mc.writeimm(offset, 'b') - else: - mc.writechar(chr(0x80 | ebp | orbyte)) - mc.writeimm(offset, 'i') - return 0 - -def stack(argnum, allow_single_byte=True): - return encode_stack, (argnum, allow_single_byte) +class stack(CodeStepWriter): + def __init__(self, argnum, allow_single_byte=True): + self.argnum = argnum + self.allow_single_byte = allow_single_byte + def encode(self, mc, args, orbyte): + offset = get_ebp_ofs(args[self.argnum-1]) + if self.allow_single_byte and single_byte(offset): + mc.writechar(chr(0x40 | ebp | orbyte)) + mc.writechar(chr(offset & 0xFF)) + else: + mc.writechar(chr(0x80 | ebp | orbyte)) + mc.writechar(chr(offset & 0xFF)) + mc.writechar(chr((offset >> 8) & 0xFF)) + mc.writechar(chr((offset >> 16) & 0xFF)) + mc.writechar(chr((offset >> 24) & 0xFF)) # ____________________________________________________________ def insn(*encoding): def encode(mc, *args): - orbyte = 0 - for encode_step, encode_static_arg in encoding_steps: - orbyte = encode_step(mc, encode_static_arg, orbyte, *args) - assert orbyte == 0 + for step in encoding_steps: + step.encode(mc, args, 0) # encoding_steps = [] for step in encoding: if isinstance(step, str): for c in step: - encoding_steps.append((encode_char, ord(c))) + encoding_steps.append(Constant(ord(c))) else: - assert type(step) is tuple and len(step) == 2 + assert isinstance(step, CodeStepWriter) encoding_steps.append(step) encoding_steps = unrolling_iterable(encoding_steps) return encode @@ -113,21 +120,12 @@ def writechar(self, char): raise NotImplementedError - @specialize.arg(2) - def writeimm(self, imm, width='i'): - self.writechar(chr(imm & 0xFF)) - if width != 'b': # != byte - self.writechar(chr((imm >> 8) & 0xFF)) - if width != 'h': # != 2-bytes word - self.writechar(chr((imm >> 16) & 0xFF)) - self.writechar(chr((imm >> 24) & 0xFF)) - - MOV_ri = insn(register(1), '\xB8', immediate(2)) - MOV_si = insn('\xC7', orbyte(0<<3), stack(1), immediate(2)) - MOV_rr = insn('\x89', register(2,8), register(1), '\xC0') - MOV_sr = insn('\x89', register(2,8), stack(1)) - MOV_rs = insn('\x8B', register(1,8), stack(2)) + MOV_ri = insn(0xB8 | register(1), imm32(2)) + MOV_si = insn('\xC7', 0<<3 | stack(1), imm32(2)) + MOV_rr = insn('\x89', 0xC0 | register(2)<<3 | register(1)) + MOV_sr = insn('\x89', stack(1) | register(2)<<3) + MOV_rs = insn('\x8B', register(1)<<3 | stack(2)) NOP = insn('\x90') - ADD_rr = insn('\x01', register(2,8), register(1), '\xC0') + ADD_rr = insn('\x01', 0xC0 | register(2)<<3 | register(1)) From arigo at codespeak.net Sat Sep 26 10:45:35 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 26 Sep 2009 10:45:35 +0200 (CEST) Subject: [pypy-svn] r67903 - pypy/trunk/pypy/jit/metainterp/test Message-ID: <20090926084535.3A93116801E@codespeak.net> Author: arigo Date: Sat Sep 26 10:45:34 2009 New Revision: 67903 Modified: pypy/trunk/pypy/jit/metainterp/test/test_logger.py Log: Fix the test. Modified: pypy/trunk/pypy/jit/metainterp/test/test_logger.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_logger.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_logger.py Sat Sep 26 10:45:34 2009 @@ -13,7 +13,7 @@ def log_loop(self, loop, namespace={}): self.log_stream = StringIO() self.namespace = namespace - logger.Logger.log_loop(self, loop) + logger.Logger.log_loop(self, loop.inputargs, loop.operations) return self.log_stream.getvalue() def repr_of_descr(self, descr): From arigo at codespeak.net Sat Sep 26 11:10:48 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 26 Sep 2009 11:10:48 +0200 (CEST) Subject: [pypy-svn] r67904 - pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86 Message-ID: <20090926091048.CCCF116801E@codespeak.net> Author: arigo Date: Sat Sep 26 11:10:48 2009 New Revision: 67904 Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py Log: Revert r67902 and simplify stuff a little bit. Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py ============================================================================== --- pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py (original) +++ pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py Sat Sep 26 11:10:48 2009 @@ -14,58 +14,54 @@ esi = 6 edi = 7 +# ____________________________________________________________ +# Emit a single char -class CodeStepWriter(object): - def encode(self, mc, args, orbyte): - mc.writechar(chr(self.encode_byte(args) | orbyte)) - def _freeze_(self): - return True - def __or__(self, other): - if isinstance(other, int): - other = Constant(other) - if hasattr(self, 'encode_byte'): - return Compose(self, other) - if hasattr(other, 'encode_byte'): - return Compose(other, self) - return NotImplemented - __ror__ = __or__ - -class Constant(CodeStepWriter): - def __init__(self, charvalue): - self.charvalue = charvalue - def encode_byte(self, args): - return self.charvalue - -class Compose(CodeStepWriter): - def __init__(self, operand1, operand2): - self.operand1 = operand1 - self.operand2 = operand2 - def encode(self, mc, args, orbyte): - orbyte |= self.operand1.encode_byte(args) - self.operand2.encode(mc, args, orbyte) - -class register(CodeStepWriter): - def __init__(self, argnum, shift=0): - self.argnum = argnum - self.shift = shift - def __lshift__(self, num): - return register(self.argnum, self.shift + num) - def encode_byte(self, args): - reg = args[self.argnum-1] - assert 0 <= reg < 8 - return reg << self.shift - -class imm32(CodeStepWriter): - def __init__(self, argnum): - self.argnum = argnum - def encode(self, mc, args, orbyte): - assert orbyte == 0 - imm = args[self.argnum-1] - mc.writechar(chr(imm & 0xFF)) - mc.writechar(chr((imm >> 8) & 0xFF)) - mc.writechar(chr((imm >> 16) & 0xFF)) - mc.writechar(chr((imm >> 24) & 0xFF)) +def encode_char(mc, _, char, orbyte): + mc.writechar(chr(char | orbyte)) + return 0 + +# ____________________________________________________________ +# Encode a register number in the orbyte + + at specialize.arg(2) +def encode_register(mc, arg, factor, orbyte): + assert 0 <= arg < 8 + return orbyte | (arg * factor) +def register(argnum, factor=1): + return encode_register, argnum, factor + +# ____________________________________________________________ +# Encode a constant in the orbyte + +def encode_orbyte(mc, _, constant, orbyte): + return orbyte | constant + +def orbyte(value): + return encode_orbyte, None, value + +# ____________________________________________________________ +# Emit an immediate value + + at specialize.arg(2) +def encode_immediate(mc, arg, width, orbyte): + assert orbyte == 0 + if width == 'b': + mc.writeimm8(arg) + elif width == 'h': + mc.writeimm16(arg) + else: + mc.writeimm32(arg) + return 0 + +def immediate(argnum, width='i'): + return encode_immediate, argnum, width + +# ____________________________________________________________ +# Emit a mod/rm referencing a stack location +# This depends on the fact that our function prologue contains +# exactly 4 PUSHes. def get_ebp_ofs(position): # Argument is a stack position (0, 1, 2...). @@ -77,36 +73,38 @@ def single_byte(value): return -128 <= value < 128 -class stack(CodeStepWriter): - def __init__(self, argnum, allow_single_byte=True): - self.argnum = argnum - self.allow_single_byte = allow_single_byte - def encode(self, mc, args, orbyte): - offset = get_ebp_ofs(args[self.argnum-1]) - if self.allow_single_byte and single_byte(offset): - mc.writechar(chr(0x40 | ebp | orbyte)) - mc.writechar(chr(offset & 0xFF)) - else: - mc.writechar(chr(0x80 | ebp | orbyte)) - mc.writechar(chr(offset & 0xFF)) - mc.writechar(chr((offset >> 8) & 0xFF)) - mc.writechar(chr((offset >> 16) & 0xFF)) - mc.writechar(chr((offset >> 24) & 0xFF)) + at specialize.arg(2) +def encode_stack(mc, arg, allow_single_byte, orbyte): + offset = get_ebp_ofs(arg) + if allow_single_byte and single_byte(offset): + mc.writechar(chr(0x40 | ebp | orbyte)) + mc.writeimm8(offset) + else: + mc.writechar(chr(0x80 | ebp | orbyte)) + mc.writeimm32(offset) + return 0 + +def stack(argnum, allow_single_byte=True): + return encode_stack, argnum, allow_single_byte # ____________________________________________________________ def insn(*encoding): def encode(mc, *args): - for step in encoding_steps: - step.encode(mc, args, 0) + orbyte = 0 + for encode_step, arg, extra in encoding_steps: + if arg is not None: + arg = args[arg-1] + orbyte = encode_step(mc, arg, extra, orbyte) + assert orbyte == 0 # encoding_steps = [] for step in encoding: if isinstance(step, str): for c in step: - encoding_steps.append(Constant(ord(c))) + encoding_steps.append((encode_char, None, ord(c))) else: - assert isinstance(step, CodeStepWriter) + assert type(step) is tuple and len(step) == 3 encoding_steps.append(step) encoding_steps = unrolling_iterable(encoding_steps) return encode @@ -120,12 +118,25 @@ def writechar(self, char): raise NotImplementedError - MOV_ri = insn(0xB8 | register(1), imm32(2)) - MOV_si = insn('\xC7', 0<<3 | stack(1), imm32(2)) - MOV_rr = insn('\x89', 0xC0 | register(2)<<3 | register(1)) - MOV_sr = insn('\x89', stack(1) | register(2)<<3) - MOV_rs = insn('\x8B', register(1)<<3 | stack(2)) + def writeimm8(self, imm): + self.writechar(chr(imm & 0xFF)) + + def writeimm16(self, imm): + self.writechar(chr(imm & 0xFF)) + self.writechar(chr((imm >> 8) & 0xFF)) + + def writeimm32(self, imm): + self.writechar(chr(imm & 0xFF)) + self.writechar(chr((imm >> 8) & 0xFF)) + self.writechar(chr((imm >> 16) & 0xFF)) + self.writechar(chr((imm >> 24) & 0xFF)) + + MOV_ri = insn(register(1), '\xB8', immediate(2)) + MOV_si = insn('\xC7', orbyte(0<<3), stack(1), immediate(2)) + MOV_rr = insn('\x89', register(2,8), register(1), '\xC0') + MOV_sr = insn('\x89', register(2,8), stack(1)) + MOV_rs = insn('\x8B', register(1,8), stack(2)) NOP = insn('\x90') - ADD_rr = insn('\x01', 0xC0 | register(2)<<3 | register(1)) + ADD_rr = insn('\x01', register(2,8), register(1), '\xC0') From arigo at codespeak.net Sat Sep 26 12:09:30 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 26 Sep 2009 12:09:30 +0200 (CEST) Subject: [pypy-svn] r67905 - in pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86: . test Message-ID: <20090926100930.263FC16801B@codespeak.net> Author: arigo Date: Sat Sep 26 12:09:29 2009 New Revision: 67905 Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py Log: Some more instructions, and start fixing test_ri386_auto_encoding.py. Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py ============================================================================== --- pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py (original) +++ pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/ri386.py Sat Sep 26 12:09:29 2009 @@ -59,29 +59,19 @@ return encode_immediate, argnum, width # ____________________________________________________________ -# Emit a mod/rm referencing a stack location -# This depends on the fact that our function prologue contains -# exactly 4 PUSHes. - -def get_ebp_ofs(position): - # Argument is a stack position (0, 1, 2...). - # Returns (ebp-16), (ebp-20), (ebp-24)... - # This depends on the fact that our function prologue contains - # exactly 4 PUSHes. - return -WORD * (4 + position) +# Emit a mod/rm referencing a stack location (%ebp+arg) def single_byte(value): return -128 <= value < 128 @specialize.arg(2) def encode_stack(mc, arg, allow_single_byte, orbyte): - offset = get_ebp_ofs(arg) - if allow_single_byte and single_byte(offset): + if allow_single_byte and single_byte(arg): mc.writechar(chr(0x40 | ebp | orbyte)) - mc.writeimm8(offset) + mc.writeimm8(arg) else: mc.writechar(chr(0x80 | ebp | orbyte)) - mc.writeimm32(offset) + mc.writeimm32(arg) return 0 def stack(argnum, allow_single_byte=True): @@ -109,6 +99,23 @@ encoding_steps = unrolling_iterable(encoding_steps) return encode +def common_modes(group): + base = group * 8 + INSN_ri8 = insn('\x83', orbyte(group<<3), register(1), '\xC0', + immediate(2,'b')) + INSN_ri32 = insn('\x81', orbyte(group<<3), register(1), '\xC0', + immediate(2)) + INSN_rr = insn(chr(base+1), register(2,8), register(1,1), '\xC0') + INSN_rs = insn(chr(base+3), register(1,8), stack(2)) + + def INSN_ri(mc, reg, immed): + if single_byte(immed): + INSN_ri8(mc, reg, immed) + else: + INSN_ri32(mc, reg, immed) + + return INSN_ri, INSN_rr, INSN_rs + # ____________________________________________________________ @@ -137,6 +144,12 @@ MOV_sr = insn('\x89', register(2,8), stack(1)) MOV_rs = insn('\x8B', register(1,8), stack(2)) - NOP = insn('\x90') + ADD_ri, ADD_rr, ADD_rs = common_modes(0) + OR_ri, OR_rr, OR_rs = common_modes(1) + AND_ri, AND_rr, AND_rs = common_modes(4) + SUB_ri, SUB_rr, SUB_rs = common_modes(5) + XOR_ri, XOR_rr, XOR_rs = common_modes(6) + CMP_ri, CMP_rr, CMP_rs = common_modes(7) - ADD_rr = insn('\x01', register(2,8), register(1), '\xC0') + NOP = insn('\x90') + RET = insn('\xC3') Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py ============================================================================== --- pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py (original) +++ pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386.py Sat Sep 26 12:09:29 2009 @@ -19,7 +19,7 @@ def test_mov_si(): s = CodeBuilder() - s.MOV_si(5, 1<<24) + s.MOV_si(-36, 1<<24) assert s.getvalue() == '\xC7\x45\xDC\x00\x00\x00\x01' def test_mov_rr(): @@ -29,12 +29,12 @@ def test_mov_sr(): s = CodeBuilder() - s.MOV_sr(5, edx) + s.MOV_sr(-36, edx) assert s.getvalue() == '\x89\x55\xDC' def test_mov_rs(): s = CodeBuilder() - s.MOV_rs(edx, 5) + s.MOV_rs(edx, -36) assert s.getvalue() == '\x8B\x55\xDC' def test_nop_add_rr(): Modified: pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py ============================================================================== --- pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py (original) +++ pypy/branch/remove-ri386-multimethod/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py Sat Sep 26 12:09:29 2009 @@ -1,7 +1,6 @@ -import os, random, string, struct +import os, random, struct import py -from pypy.jit.backend.x86 import ri386 as i386 -from pypy.jit.backend.x86.ri386setup import all_instructions +from pypy.jit.backend.x86 import ri386 from pypy.tool.udir import udir INPUTNAME = str(udir.join('checkfile.s')) @@ -12,61 +11,31 @@ COUNT1 = 15 COUNT2 = 25 - -sizes = { - i386.EAX: 4, - i386.ECX: 4, - i386.EDX: 4, - i386.EBX: 4, - i386.ESP: 4, - i386.EBP: 4, - i386.ESI: 4, - i386.EDI: 4, - - i386.AL: 1, - i386.CL: 1, - i386.DL: 1, - i386.BL: 1, - i386.AH: 1, - i386.CH: 1, - i386.DH: 1, - i386.BH: 1, - - i386.REG: 4, - i386.MODRM: 4, - i386.MODRM64: 8, - i386.IMM32: 4, - i386.REG8: 1, - i386.MODRM8: 1, - i386.IMM8: 1, - i386.IMM16: 2, - #i386.REL8: 1, - i386.REL32: 4, -} - suffixes = {0:'', 1:'b', 2:'w', 4:'l'} def reg_tests(): - return i386.registers[:] + return range(8) -def reg8_tests(): - return i386.registers8[:] +def stack_tests(): + return ([0, 4, -4, 124, 128, -128, -132] + + [random.randrange(-0x20000000, 0x20000000) * 4 + for i in range(COUNT1)]) def imm8_tests(): v = [-128,-1,0,1,127] + [random.randrange(-127, 127) for i in range(COUNT1)] - return map(i386.imm8, v) + return v def imm16_tests(): v = [-32768,32767] + [random.randrange(-32767, -128) for i in range(COUNT1)] \ + [random.randrange(128, 32767) for i in range(COUNT1)] - return map(i386.imm16, v) + return v def imm32_tests(): v = ([0x80000000, 0x7FFFFFFF, 128, 256, -129, -255] + [random.randrange(0,65536)<<16 | random.randrange(0,65536) for i in range(COUNT1)] + [random.randrange(128, 256) for i in range(COUNT1)]) - return map(i386.imm32, filter(lambda x: x<-128 or x>=128, v)) + return imm8_tests() + v def pick1(memSIB, cache=[]): base = random.choice([None, None, None] + i386.registers) @@ -98,53 +67,47 @@ return i386.registers8 + [pick1(i386.memSIB8) for i in range(COUNT2)] tests = { - i386.EAX: lambda: [i386.eax], - i386.ECX: lambda: [i386.ecx], - i386.EDX: lambda: [i386.edx], - i386.EBX: lambda: [i386.ebx], - i386.ESP: lambda: [i386.esp], - i386.EBP: lambda: [i386.ebp], - i386.ESI: lambda: [i386.esi], - i386.EDI: lambda: [i386.edi], - - i386.AL: lambda: [i386.al], - i386.CL: lambda: [i386.cl], - i386.DL: lambda: [i386.dl], - i386.BL: lambda: [i386.bl], - i386.AH: lambda: [i386.ah], - i386.CH: lambda: [i386.ch], - i386.DH: lambda: [i386.dh], - i386.BH: lambda: [i386.bh], - - i386.REG: reg_tests, - i386.MODRM: modrm_tests, - i386.MODRM64: modrm64_tests, - i386.XMMREG: xmm_tests, - i386.IMM32: imm32_tests, - i386.REG8: reg8_tests, - i386.MODRM8: modrm8_tests, - i386.IMM8: imm8_tests, - i386.IMM16: imm16_tests, - #i386.REL8: imm8_tests, - i386.REL32: lambda: [], # XXX imm32_tests, + 'r': reg_tests, + 's': stack_tests, + 'i': imm32_tests, + } + +regnames = ['%eax', '%ecx', '%edx', '%ebx', '%esp', '%ebp', '%esi', '%edi'] +def assembler_operand_reg(regnum): + return regnames[regnum] + +def assembler_operand_stack(position): + if position == 0: + return '(%ebp)' + else: + return '%d(%%ebp)' % position + +def assembler_operand_imm(value): + return '$%d' % value + +assembler_operand = { + 'r': assembler_operand_reg, + 's': assembler_operand_stack, + 'i': assembler_operand_imm, } -def run_test(instrname, instr, args_lists): +def run_test(instrname, argmodes, args_lists): global labelcount - instrname = instr.as_alias or instrname labelcount = 0 oplist = [] g = open(INPUTNAME, 'w') g.write('\x09.string "%s"\n' % BEGIN_TAG) for args in args_lists: suffix = "" - all = instr.as_all_suffixes - for m, extra in args: - if m in (i386.MODRM, i386.MODRM8) or all: - if not instrname == 'FNSTCW': - suffix = suffixes[sizes[m]] + suffix +## all = instr.as_all_suffixes +## for m, extra in args: +## if m in (i386.MODRM, i386.MODRM8) or all: +## suffix = suffixes[sizes[m]] + suffix + if argmodes: + suffix = 'l' + following = "" - if instr.indirect: + if False: # instr.indirect: suffix = "" if args[-1][0] == i386.REL32: #in (i386.REL8,i386.REL32): labelcount += 1 @@ -157,15 +120,17 @@ k = -1 else: k = len(args) - for m, extra in args[:k]: - assert m != i386.REL32 #not in (i386.REL8,i386.REL32) - ops = [extra.assembler() for m, extra in args] + #for m, extra in args[:k]: + # assert m != i386.REL32 #not in (i386.REL8,i386.REL32) + ops = [] + for mode, v in zip(argmodes, args): + ops.append(assembler_operand[mode](v)) ops.reverse() - op = '\x09%s%s %s%s' % (instrname, suffix, string.join(ops, ", "), - following) + op = '\t%s%s %s%s' % (instrname.lower(), suffix, + ', '.join(ops), following) g.write('%s\n' % op) oplist.append(op) - g.write('\x09.string "%s"\n' % END_TAG) + g.write('\t.string "%s"\n' % END_TAG) g.close() os.system('as "%s" -o "%s"' % (INPUTNAME, FILENAME)) try: @@ -174,75 +139,66 @@ raise Exception("Assembler error") data = f.read() f.close() -## os.unlink(FILENAME) -## os.unlink(INPUTNAME) - i = string.find(data, BEGIN_TAG) + i = data.find(BEGIN_TAG) assert i>=0 - j = string.find(data, END_TAG, i) + j = data.find(END_TAG, i) assert j>=0 as_code = data[i+len(BEGIN_TAG)+1:j] return oplist, as_code -##def getreg(m, extra): -## if m>=0: -## return m -## if m==i386.REG or m==i386.REG8: -## return extra -## if m==i386.MODRM or m==i386.MODRM8: -## if extra[0]==i386.memRegister: -## return extra[1][0] - -def rec_test_all(instrname, modes, args=[]): +def make_all_tests(methname, modes, args=[]): if modes: m = modes[0] - if instrname.startswith('F') and m is i386.MODRM: - lst = modrm_noreg_tests() - else: - lst = tests[m]() + lst = tests[m]() random.shuffle(lst) result = [] - for extra in lst: - result += rec_test_all(instrname, modes[1:], args+[(m,extra)]) + for v in lst: + result += make_all_tests(methname, modes[1:], args+[v]) return result else: - if instrname == "MOV": -## if args[0] == args[1]: -## return [] # MOV reg, same reg - if ((args[0][1] in (i386.eax, i386.al)) - and args[1][1].assembler().lstrip('-').isdigit()): - return [] # MOV accum, [constant-address] - if ((args[1][1] in (i386.eax, i386.al)) - and args[0][1].assembler().lstrip('-').isdigit()): - return [] # MOV [constant-address], accum - if instrname == "MOV16": - return [] # skipped - if instrname == "LEA": - if (args[1][1].__class__ != i386.MODRM or - args[1][1].is_register()): - return [] - if instrname == "INT": - if args[0][1].value == 3: - return [] - if instrname in ('SHL', 'SHR', 'SAR'): - if args[1][1].assembler() == '$1': - return [] - if instrname in ('MOVZX', 'MOVSX'): - if args[1][1].width == 4: - return [] - if instrname == "TEST": - if (args[0] != args[1] and - isinstance(args[0][1], i386.REG) and - isinstance(args[1][1], i386.REG)): - return [] # TEST reg1, reg2 <=> TEST reg2, reg1 - if instrname.endswith('cond'): - return [] + # special cases + if methname in ('ADD_ri', 'AND_ri', 'CMP_ri', 'OR_ri', + 'SUB_ri', 'XOR_ri'): + if args[0] == ri386.eax: + return [] # ADD EAX, constant: there is a special encoding +## if methname == "MOV_": +#### if args[0] == args[1]: +#### return [] # MOV reg, same reg +## if ((args[0][1] in (i386.eax, i386.al)) +## and args[1][1].assembler().lstrip('-').isdigit()): +## return [] # MOV accum, [constant-address] +## if ((args[1][1] in (i386.eax, i386.al)) +## and args[0][1].assembler().lstrip('-').isdigit()): +## return [] # MOV [constant-address], accum +## if instrname == "MOV16": +## return [] # skipped +## if instrname == "LEA": +## if (args[1][1].__class__ != i386.MODRM or +## args[1][1].is_register()): +## return [] +## if instrname == "INT": +## if args[0][1].value == 3: +## return [] +## if instrname in ('SHL', 'SHR', 'SAR'): +## if args[1][1].assembler() == '$1': +## return [] +## if instrname in ('MOVZX', 'MOVSX'): +## if args[1][1].width == 4: +## return [] +## if instrname == "TEST": +## if (args[0] != args[1] and +## isinstance(args[0][1], i386.REG) and +## isinstance(args[1][1], i386.REG)): +## return [] # TEST reg1, reg2 <=> TEST reg2, reg1 +## if instrname.endswith('cond'): +## return [] return [args] def hexdump(s): - return string.join(["%02X" % ord(c) for c in s], " ") + return ' '.join(["%02X" % ord(c) for c in s]) -class CodeChecker(i386.I386CodeBuilder): +class CodeChecker(ri386.I386CodeBuilder): def __init__(self, expected): self.expected = expected @@ -252,39 +208,32 @@ self.op = op self.instrindex = self.index - def write(self, data): - end = self.index+len(data) - if data != self.expected[self.index:end]: + def writechar(self, char): + if char != self.expected[self.index:self.index+1]: print self.op - print "\x09from ri386.py:", hexdump(self.expected[self.instrindex:self.index] + data)+"..." - print "\x09from 'as': ", hexdump(self.expected[self.instrindex:end])+"..." + print "\x09from ri386.py:", hexdump(self.expected[self.instrindex:self.index] + char)+"..." + print "\x09from 'as': ", hexdump(self.expected[self.instrindex:self.index+1])+"..." raise Exception("Differs") - self.index += len(data) + self.index += 1 + + def done(self): + assert len(self.expected) == self.index -def complete_test(instrname, instr): - print "Testing %s\x09(%d encodings)" % (instrname, len(instr.modes)) - ilist = [] - for modes in instr.modes: - ilist += rec_test_all(instrname, modes) - oplist, as_code = run_test(instrname, instr, ilist) +def complete_test(methname): + if '_' in methname: + instrname, argmodes = methname.split('_') + else: + instrname, argmodes = methname, '' + print "Testing %s with argmodes=%r" % (instrname, argmodes) + ilist = make_all_tests(methname, argmodes) + oplist, as_code = run_test(instrname, argmodes, ilist) cc = CodeChecker(as_code) for op, args in zip(oplist, ilist): if op: cc.begin(op) - getattr(cc, instrname)(*[extra for m, extra in args]) - -def complete_tests(): - FORBIDDEN = ['CMOVPE', 'CMOVPO'] # why doesn't 'as' know about them? - items = i386.__dict__.items() - items.sort() - for key, value in items: - if isinstance(value, i386.Instruction): - if key in FORBIDDEN: - print "Skipped", key - else: - complete_test(key,value) - print "Ok." + getattr(cc, methname)(*args) + cc.done() def test_auto(): import os @@ -294,18 +243,15 @@ if not data.startswith('GNU assembler'): py.test.skip("full tests require the GNU 'as' assembler") - def do_test(name, insn): - #print name + def do_test(name): if name in ('CMOVPE', 'CMOVPO'): py.test.skip("why doesn't 'as' know about CMOVPE/CMOVPO?") - complete_test(name, insn) + complete_test(name) + + for name in all_instructions: + yield do_test, name + - items = all_instructions.items() - items.sort() - for key, value in items: - yield do_test, key, value - del key, value - -if __name__ == "__main__": - #complete_test("TEST", i386.TEST) - complete_tests() +all_instructions = [name for name in ri386.I386CodeBuilder.__dict__ + if name.split('_')[0].isupper()] +all_instructions.sort() From arigo at codespeak.net Sat Sep 26 17:42:40 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 26 Sep 2009 17:42:40 +0200 (CEST) Subject: [pypy-svn] r67906 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090926154240.E85C7168022@codespeak.net> Author: arigo Date: Sat Sep 26 17:42:39 2009 New Revision: 67906 Added: pypy/trunk/pypy/jit/metainterp/test/test_compile.py (contents, props changed) Modified: pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/specnode.py pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/trunk/pypy/jit/metainterp/test/test_send.py pypy/trunk/pypy/jit/metainterp/test/test_specnode.py Log: Restore the insertion of the loop token that is done for entry bridges. The goal is to help with the "aborted tracing" cases by providing a default fall-back loop. Improve the 'old_loop_tokens' list by keeping it sorted, in the sense that a more general entry should not be before a less general one. Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Sat Sep 26 17:42:39 2009 @@ -9,7 +9,7 @@ from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const from pypy.jit.metainterp import history -from pypy.jit.metainterp.specnode import NotSpecNode +from pypy.jit.metainterp.specnode import NotSpecNode, more_general_specnodes from pypy.jit.metainterp.typesystem import llhelper, oohelper from pypy.jit.metainterp.optimizeutil import InvalidLoop from pypy.rlib.debug import debug_print @@ -67,9 +67,22 @@ loop_token.executable_token = executable_token if not we_are_translated(): loop.token = loop_token - old_loop_tokens.append(loop_token) + insert_loop_token(old_loop_tokens, loop_token) return loop_token +def insert_loop_token(old_loop_tokens, loop_token): + # Find where in old_loop_tokens we should insert this new loop_token. + # The following algo means "as late as possible, but before another + # loop token that would be more general and so completely mask off + # the new loop_token". + for i in range(len(old_loop_tokens)): + if more_general_specnodes(old_loop_tokens[i].specnodes, + loop_token.specnodes): + old_loop_tokens.insert(i, loop_token) + break + else: + old_loop_tokens.append(loop_token) + def send_loop_to_backend(metainterp_sd, loop, type): metainterp_sd.options.logger_ops.log_loop(loop.inputargs, loop.operations) metainterp_sd.profiler.start_backend() @@ -272,6 +285,16 @@ metainterp_sd.state.attach_unoptimized_bridge_from_interp( self.original_greenkey, executable_token) + # store the new loop in compiled_merge_points too + glob = metainterp_sd.globaldata + greenargs = glob.unpack_greenkey(self.original_greenkey) + old_loop_tokens = glob.compiled_merge_points.setdefault(greenargs, []) + new_loop_token = LoopToken() + new_loop_token.specnodes = [prebuiltNotSpecNode] * len(self.redkey) + new_loop_token.executable_token = executable_token + # it always goes at the end of the list, as it is the most + # general loop token + old_loop_tokens.append(new_loop_token) def compile_new_bridge(metainterp, old_loop_tokens, resumekey): Modified: pypy/trunk/pypy/jit/metainterp/specnode.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/specnode.py (original) +++ pypy/trunk/pypy/jit/metainterp/specnode.py Sat Sep 26 17:42:39 2009 @@ -6,8 +6,8 @@ __metaclass__ = extendabletype # extended in optimizefindnode.py __slots__ = () - def equals(self, other): - raise NotImplementedError + def equals(self, other, ge): # 'ge' stands for greater-or-equal; + raise NotImplementedError # if false, the default is 'equal'. def extract_runtime_data(self, cpu, valuebox, resultlist): raise NotImplementedError @@ -16,8 +16,8 @@ class NotSpecNode(SpecNode): __slots__ = () - def equals(self, other): - return isinstance(other, NotSpecNode) + def equals(self, other, ge): + return isinstance(other, NotSpecNode) or ge def extract_runtime_data(self, cpu, valuebox, resultlist): resultlist.append(valuebox) @@ -31,7 +31,7 @@ assert isinstance(constbox, Const) self.constbox = constbox - def equals(self, other): + def equals(self, other, ge): return isinstance(other, ConstantSpecNode) and \ self.constbox.same_constant(other.constbox) @@ -43,13 +43,13 @@ def __init__(self, fields): self.fields = fields # list: [(fieldofs, subspecnode)] - def equal_fields(self, other): + def equal_fields(self, other, ge): if len(self.fields) != len(other.fields): return False for i in range(len(self.fields)): o1, s1 = self.fields[i] o2, s2 = other.fields[i] - if not (o1.sort_key() == o2.sort_key() and s1.equals(s2)): + if not (o1.sort_key() == o2.sort_key() and s1.equals(s2, ge)): return False return True @@ -68,11 +68,11 @@ assert isinstance(known_class, Const) self.known_class = known_class - def equals(self, other): + def equals(self, other, ge): if not (isinstance(other, VirtualInstanceSpecNode) and self.known_class.same_constant(other.known_class)): return False - return self.equal_fields(other) + return self.equal_fields(other, ge) class VirtualArraySpecNode(SpecNode): @@ -80,7 +80,7 @@ self.arraydescr = arraydescr self.items = items # list of subspecnodes - def equals(self, other): + def equals(self, other, ge): if not (isinstance(other, VirtualArraySpecNode) and len(self.items) == len(other.items)): return False @@ -88,7 +88,7 @@ for i in range(len(self.items)): s1 = self.items[i] s2 = other.items[i] - if not s1.equals(s2): + if not s1.equals(s2, ge): return False return True @@ -107,16 +107,19 @@ AbstractVirtualStructSpecNode.__init__(self, fields) self.typedescr = typedescr - def equals(self, other): + def equals(self, other, ge): if not isinstance(other, VirtualStructSpecNode): return False assert self.typedescr == other.typedescr - return self.equal_fields(other) + return self.equal_fields(other, ge) -def equals_specnodes(specnodes1, specnodes2): +def equals_specnodes(specnodes1, specnodes2, ge=False): assert len(specnodes1) == len(specnodes2) for i in range(len(specnodes1)): - if not specnodes1[i].equals(specnodes2[i]): + if not specnodes1[i].equals(specnodes2[i], ge): return False return True + +def more_general_specnodes(specnodes1, specnodes2): + return equals_specnodes(specnodes1, specnodes2, ge=True) Added: pypy/trunk/pypy/jit/metainterp/test/test_compile.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/jit/metainterp/test/test_compile.py Sat Sep 26 17:42:39 2009 @@ -0,0 +1,22 @@ +from pypy.jit.metainterp.history import LoopToken, ConstInt +from pypy.jit.metainterp.specnode import NotSpecNode, ConstantSpecNode +from pypy.jit.metainterp.compile import insert_loop_token + + +def test_insert_loop_token(): + lst = [] + # + tok1 = LoopToken() + tok1.specnodes = [NotSpecNode()] + insert_loop_token(lst, tok1) + assert lst == [tok1] + # + tok2 = LoopToken() + tok2.specnodes = [ConstantSpecNode(ConstInt(8))] + insert_loop_token(lst, tok2) + assert lst == [tok2, tok1] + # + tok3 = LoopToken() + tok3.specnodes = [ConstantSpecNode(ConstInt(-13))] + insert_loop_token(lst, tok3) + assert lst == [tok2, tok3, tok1] Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py Sat Sep 26 17:42:39 2009 @@ -210,7 +210,7 @@ lst = self.unpack_specnodes(text) assert len(specnodes) == len(lst) for x, y in zip(specnodes, lst): - assert x.equals(y) + assert x.equals(y, ge=False) return True # ____________________________________________________________ Modified: pypy/trunk/pypy/jit/metainterp/test/test_send.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_send.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_send.py Sat Sep 26 17:42:39 2009 @@ -398,10 +398,11 @@ return x.value res = self.meta_interp(f, [len(cases)]) assert res == 200 - # for now, we really expect only 1 loop. This is known to be kind - # of wrong. XXX later... + # we expect 1 loop, 1 entry bridge, and 1 bridge going from the + # loop back to the start of the entry bridge self.check_loop_count(2) # 1 loop + 1 bridge self.check_tree_loop_count(2) # 1 loop + 1 entry bridge (argh) + self.check_aborted_count(0) def test_three_cases(self): class Node: Modified: pypy/trunk/pypy/jit/metainterp/test/test_specnode.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_specnode.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_specnode.py Sat Sep 26 17:42:39 2009 @@ -6,6 +6,7 @@ from pypy.jit.metainterp.specnode import VirtualStructSpecNode from pypy.jit.metainterp.specnode import ConstantSpecNode from pypy.jit.metainterp.specnode import equals_specnodes +from pypy.jit.metainterp.specnode import more_general_specnodes from pypy.jit.metainterp.test.test_optimizefindnode import LLtypeMixin def _get_vspecnode(classnum=123): @@ -54,6 +55,33 @@ assert not equals_specnodes([foonode], [barnode]) assert not equals_specnodes([foonode], [prebuiltNotSpecNode]) +def test_more_general_specnodes(): + assert more_general_specnodes([prebuiltNotSpecNode, prebuiltNotSpecNode], + [prebuiltNotSpecNode, prebuiltNotSpecNode]) + vspecnode1 = _get_vspecnode(1) + vspecnode2 = _get_vspecnode(2) + assert more_general_specnodes([vspecnode1], [vspecnode1]) + assert not more_general_specnodes([vspecnode1], [vspecnode2]) + assert not more_general_specnodes([vspecnode1], [prebuiltNotSpecNode]) + assert more_general_specnodes([prebuiltNotSpecNode], [vspecnode2]) + aspecnode1 = _get_aspecnode(1) + aspecnode2 = _get_aspecnode(2) + assert more_general_specnodes([aspecnode2], [aspecnode2]) + assert not more_general_specnodes([aspecnode1], [aspecnode2]) + assert not more_general_specnodes([aspecnode1], [prebuiltNotSpecNode]) + assert more_general_specnodes([prebuiltNotSpecNode], [aspecnode2]) + sspecnode1 = _get_sspecnode() + assert more_general_specnodes([sspecnode1], [sspecnode1]) + assert not more_general_specnodes([sspecnode1], [prebuiltNotSpecNode]) + assert more_general_specnodes([prebuiltNotSpecNode], [sspecnode1]) + # + foonode = _get_cspecnode('foo') + barnode = _get_cspecnode('bar') + assert more_general_specnodes([foonode], [foonode]) + assert not more_general_specnodes([foonode], [barnode]) + assert not more_general_specnodes([foonode], [prebuiltNotSpecNode]) + assert more_general_specnodes([prebuiltNotSpecNode], [foonode]) + def test_extract_runtime_data_0(): res = [] node = _get_cspecnode('foo') From arigo at codespeak.net Sat Sep 26 20:18:09 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 26 Sep 2009 20:18:09 +0200 (CEST) Subject: [pypy-svn] r67907 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090926181809.CCB8F168011@codespeak.net> Author: arigo Date: Sat Sep 26 20:18:09 2009 New Revision: 67907 Modified: pypy/trunk/pypy/jit/backend/x86/codebuf.py pypy/trunk/pypy/jit/backend/x86/ri386.py pypy/trunk/pypy/jit/backend/x86/ri386setup.py Log: Avoid calling 'builder.write(chr(n))' from the generated code, because this will make a temporary string out of chr(n). Modified: pypy/trunk/pypy/jit/backend/x86/codebuf.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/codebuf.py (original) +++ pypy/trunk/pypy/jit/backend/x86/codebuf.py Sat Sep 26 20:18:09 2009 @@ -28,6 +28,13 @@ def write(self, data): self._pos = self.overwrite(self._pos, data) + def writechr(self, n): + # purely for performance: don't convert chr(n) to a str + pos = self._pos + assert pos + 1 <= self._size + self._data[pos] = chr(n) + self._pos = pos + 1 + def get_relative_pos(self): return self._pos Modified: pypy/trunk/pypy/jit/backend/x86/ri386.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/ri386.py (original) +++ pypy/trunk/pypy/jit/backend/x86/ri386.py Sat Sep 26 20:18:09 2009 @@ -394,6 +394,9 @@ def write(self, data): raise NotImplementedError + def writechr(self, n): + self.write(chr(n)) + def tell(self): raise NotImplementedError Modified: pypy/trunk/pypy/jit/backend/x86/ri386setup.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/ri386setup.py (original) +++ pypy/trunk/pypy/jit/backend/x86/ri386setup.py Sat Sep 26 20:18:09 2009 @@ -86,7 +86,7 @@ expr = 'arg%d.byte' % self.op if has_orbyte: expr = 'orbyte | %s' % expr - lines.append('builder.write(chr(%s))' % expr) + lines.append('builder.writechr(%s)' % expr) lines.append('builder.write(arg%d.extradata)' % self.op) return False @@ -94,14 +94,13 @@ def eval(self, lines, has_orbyte): assert not has_orbyte, "malformed bytecode" if self.width == 'i': - packer = 'packimm32' + lines.append('builder.write(packimm32(arg%d.value))' % (self.op,)) elif self.width == 'b': - packer = 'packimm8' + lines.append('builder.writechr(arg%d.value & 0xFF)' % (self.op,)) elif self.width == 'h': - packer = 'packimm16' + lines.append('builder.write(packimm16(arg%d.value))' % (self.op,)) else: raise AssertionError, "invalid width %r" % (self.width,) - lines.append('builder.write(%s(arg%d.value))' % (packer, self.op)) return False class relative(operand): @@ -157,11 +156,14 @@ nextbyte = ord(op[0]) if nextbyte: lines.append('orbyte |= %d' % nextbyte) - lines.append('builder.write(chr(orbyte))') + lines.append('builder.writechr(orbyte)') has_orbyte = False op = op[1:] if op: - lines.append('builder.write(%r)' % (op,)) + if len(op) > 1: + lines.append('builder.write(%r)' % (op,)) + else: + lines.append('builder.writechr(%d)' % (ord(op),)) else: has_orbyte = op.eval(lines, has_orbyte) assert not has_orbyte, "malformed bytecode" From fijal at codespeak.net Sat Sep 26 20:39:55 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 26 Sep 2009 20:39:55 +0200 (CEST) Subject: [pypy-svn] r67908 - pypy/branch/refactor-x86/pypy/jit/backend/llsupport Message-ID: <20090926183955.9E2CA168013@codespeak.net> Author: fijal Date: Sat Sep 26 20:39:49 2009 New Revision: 67908 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/llmodel.py Log: Kill _check_addr_range, I don't think it makes any sense any more Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/llmodel.py Sat Sep 26 20:39:49 2009 @@ -13,13 +13,6 @@ from pypy.jit.backend.llsupport.descr import get_array_descr, BaseArrayDescr from pypy.jit.backend.llsupport.descr import get_call_descr, BaseCallDescr -def _check_addr_range(x): - if sys.platform == 'linux2': - # this makes assumption about address ranges that are valid - # only on linux (?) - assert x == 0 or x > (1<<20) or x < (-1<<20) - - class AbstractLLCPU(AbstractCPU): from pypy.jit.metainterp.typesystem import llhelper as ts @@ -187,8 +180,6 @@ def _cast_int_to_gcref(x): # dangerous! only use if you are sure no collection could occur # between reading the integer and casting it to a pointer - if not we_are_translated(): - _check_addr_range(x) return rffi.cast(llmemory.GCREF, x) @staticmethod @@ -197,8 +188,6 @@ @staticmethod def cast_int_to_adr(x): - if not we_are_translated(): - _check_addr_range(x) return rffi.cast(llmemory.Address, x) @staticmethod From pedronis at codespeak.net Sat Sep 26 22:36:50 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 26 Sep 2009 22:36:50 +0200 (CEST) Subject: [pypy-svn] r67909 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090926203650.077E8168011@codespeak.net> Author: pedronis Date: Sat Sep 26 22:36:49 2009 New Revision: 67909 Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py pypy/trunk/pypy/jit/metainterp/warmspot.py Log: - make it a bit easier to add counters in jitprof - test jitprof translation in test_zrp_basic.py Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/jitprof.py (original) +++ pypy/trunk/pypy/jit/metainterp/jitprof.py Sat Sep 26 22:36:49 2009 @@ -5,14 +5,24 @@ import time from pypy.rlib.debug import debug_print -TRACING = 0 -BACKEND = 1 -RUNNING = 2 -BLACKHOLE = 3 -OPS = 4 -RECORDED_OPS = 5 -BLACKHOLED_OPS = 6 -GUARDS = 7 +counters=""" +TRACING +BACKEND +RUNNING +BLACKHOLE +OPS +RECORDED_OPS +BLACKHOLED_OPS +GUARDS +""" + +def _setup(): + names = counters.split() + for i, name in enumerate(names): + globals()[name] = i + global ncounters + ncounters = len(names) +_setup() class EmptyProfiler(object): initialized = True @@ -59,7 +69,7 @@ self.starttime = self.timer() self.t1 = self.starttime self.times = [0, 0, 0, 0] - self.counters = [0, 0, 0, 0, 0, 0, 0, 0] + self.counters = [0] * ncounters self.calls = [[0, 0], [0, 0], [0, 0]] self.current = [] Modified: pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_zrpy_basic.py Sat Sep 26 22:36:49 2009 @@ -4,7 +4,7 @@ from pypy.jit.backend.llgraph import runner from pypy.rlib.jit import JitDriver, OPTIMIZER_FULL from pypy.jit.conftest import option - +from pypy.jit.metainterp.jitprof import Profiler class BasicTest: @@ -49,7 +49,8 @@ from pypy.jit.metainterp import optimize res = rpython_ll_meta_interp(f, [17], loops=2, CPUClass=self.CPUClass, type_system=self.type_system, - optimizer=OPTIMIZER_FULL) + optimizer=OPTIMIZER_FULL, + profile=Profiler) assert res == (17+14+11+8+7+6+5+4) * 10 Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Sat Sep 26 22:36:49 2009 @@ -74,7 +74,8 @@ warmrunnerdesc.state.set_param_hash_bits(hash_bits) warmrunnerdesc.finish() res = interp.eval_graph(graph, args) - warmrunnerdesc.metainterp_sd.profiler.finish() + if not kwds.get('translate_support_code', False): + warmrunnerdesc.metainterp_sd.profiler.finish() print '~~~ return value:', res while repeat > 1: print '~' * 79 From pedronis at codespeak.net Sat Sep 26 22:44:09 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 26 Sep 2009 22:44:09 +0200 (CEST) Subject: [pypy-svn] r67910 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090926204409.163DE168011@codespeak.net> Author: pedronis Date: Sat Sep 26 22:44:09 2009 New Revision: 67910 Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py Log: generic count function Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/jitprof.py (original) +++ pypy/trunk/pypy/jit/metainterp/jitprof.py Sat Sep 26 22:44:09 2009 @@ -57,9 +57,11 @@ def end_blackhole(self): pass - def count_ops(self, opnum, kind=OPS): + def count(self, kind, inc=1): pass + def count_ops(self, opnum, kind=OPS): + pass class Profiler(object): initialized = False @@ -109,6 +111,9 @@ def start_blackhole(self): self._start(BLACKHOLE) def end_blackhole(self): self._end (BLACKHOLE) + def count(self, kind, inc=1): + self.counters[kind] += inc + def count_ops(self, opnum, kind=OPS): from pypy.jit.metainterp.resoperation import rop self.counters[kind] += 1 From fijal at codespeak.net Sun Sep 27 10:10:06 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 27 Sep 2009 10:10:06 +0200 (CEST) Subject: [pypy-svn] r67911 - in pypy/extradoc/talk: pycon2010 rupy2009 Message-ID: <20090927081006.1D59216800D@codespeak.net> Author: fijal Date: Sun Sep 27 10:10:04 2009 New Revision: 67911 Added: pypy/extradoc/talk/pycon2010/ pypy/extradoc/talk/rupy2009/ Log: Directories for upcoming conferences with abstract deadline on 1st October. How time flies... From fijal at codespeak.net Sun Sep 27 10:15:11 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 27 Sep 2009 10:15:11 +0200 (CEST) Subject: [pypy-svn] r67912 - pypy/extradoc/talk/pepm2010 Message-ID: <20090927081511.D3AB8168014@codespeak.net> Author: fijal Date: Sun Sep 27 10:15:11 2009 New Revision: 67912 Added: pypy/extradoc/talk/pepm2010/ Log: This one has deadline for 6th of October From fijal at codespeak.net Sun Sep 27 10:24:52 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 27 Sep 2009 10:24:52 +0200 (CEST) Subject: [pypy-svn] r67913 - in pypy/branch/refactor-x86/pypy/jit/backend/llsupport: . test Message-ID: <20090927082452.AB4DE168014@codespeak.net> Author: fijal Date: Sun Sep 27 10:24:52 2009 New Revision: 67913 Added: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (contents, props changed) pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (contents, props changed) Log: Start moving register allocation in a more abstract manner to llsupport (it's mostly the same interface + tests) Added: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- (empty file) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Sun Sep 27 10:24:52 2009 @@ -0,0 +1,84 @@ + +from pypy.jit.metainterp.history import Const +from pypy.rlib.objectmodel import we_are_translated + +class StackManager(object): + """ Manage stack positions + """ + +class RegisterManager(object): + """ Class that keeps track of register allocations + """ + def __init__(self, register_pool, longevity): + self.free_regs = register_pool[:] + self.all_regs = register_pool + self.longevity = longevity + self.reg_bindings = {} + self.position = 0 + + def next_instruction(self, incr=1): + self.position += incr + + def possibly_free_var(self, v): + if isinstance(v, Const) or v not in self.reg_bindings: + return + if v not in self.longevity or self.longevity[v][1] <= self.position: + self.free_regs.append(self.reg_bindings[v]) + del self.reg_bindings[v] + + def possibly_free_vars(self, vars): + for v in vars: + self.possibly_free_var(v) + + def _check_invariants(self): + if not we_are_translated(): + # make sure no duplicates + assert len(dict.fromkeys(self.reg_bindings.values())) == len(self.reg_bindings) + rev_regs = dict.fromkeys(self.reg_bindings.values()) + for reg in self.free_regs: + assert reg not in rev_regs + assert len(rev_regs) + len(self.free_regs) == len(self.all_regs) + else: + assert len(self.reg_bindings) + len(self.free_regs) == len(self.all_regs) + if self.longevity: + for v in self.reg_bindings: + assert self.longevity[v][1] > self.position + + def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): + assert not isinstance(v, Const) + if selected_reg is not None: + res = self.reg_bindings.get(v, None) + if res: + if res is selected_reg: + return res + else: + del self.reg_bindings[v] + self.free_regs.append(res) + if selected_reg in self.free_regs: + self.free_regs = [reg for reg in self.free_regs + if reg is not selected_reg] + self.reg_bindings[v] = selected_reg + return selected_reg + return None + if need_lower_byte: + loc = self.reg_bindings.get(v, None) + if loc is not None and loc is not edi and loc is not esi: + return loc + for i in range(len(self.free_regs)): + reg = self.free_regs[i] + if reg is not edi and reg is not esi: + if loc is not None: + self.free_regs[i] = loc + else: + del self.free_regs[i] + self.reg_bindings[v] = reg + return reg + return None + try: + return self.reg_bindings[v] + except KeyError: + if self.free_regs: + loc = self.free_regs.pop() + self.reg_bindings[v] = loc + return loc + Added: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- (empty file) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Sun Sep 27 10:24:52 2009 @@ -0,0 +1,40 @@ + +from pypy.jit.metainterp.history import BoxInt, ConstInt +from pypy.jit.backend.llsupport.regalloc import RegisterManager + +def boxes(*values): + return [BoxInt(v) for v in values] + +class FakeReg(object): + pass + +r0, r1, r2, r3 = [FakeReg() for _ in range(4)] +regs = [r0, r1, r2, r3] + +class TestRegalloc(object): + def test_freeing_vars(self): + b0, b1, b2 = boxes(0, 0, 0) + longevity = {b0: (0, 1), b1: (0, 2), b2: (0, 2)} + rm = RegisterManager(regs, longevity) + for b in b0, b1, b2: + rm.try_allocate_reg(b) + rm._check_invariants() + assert len(rm.free_regs) == 1 + assert len(rm.reg_bindings) == 3 + rm.possibly_free_vars([b0, b1, b2]) + assert len(rm.free_regs) == 1 + assert len(rm.reg_bindings) == 3 + rm._check_invariants() + rm.next_instruction() + rm.possibly_free_vars([b0, b1, b2]) + rm._check_invariants() + assert len(rm.free_regs) == 2 + assert len(rm.reg_bindings) == 2 + rm._check_invariants() + rm.next_instruction() + rm.possibly_free_vars([b0, b1, b2]) + rm._check_invariants() + assert len(rm.free_regs) == 4 + assert len(rm.reg_bindings) == 0 + + From pedronis at codespeak.net Sun Sep 27 12:00:02 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 27 Sep 2009 12:00:02 +0200 (CEST) Subject: [pypy-svn] r67914 - pypy/extradoc/planning Message-ID: <20090927100002.8F3EF168013@codespeak.net> Author: pedronis Date: Sun Sep 27 12:00:01 2009 New Revision: 67914 Modified: pypy/extradoc/planning/jit.txt Log: some more todos Modified: pypy/extradoc/planning/jit.txt ============================================================================== --- pypy/extradoc/planning/jit.txt (original) +++ pypy/extradoc/planning/jit.txt Sun Sep 27 12:00:01 2009 @@ -31,6 +31,8 @@ - jit should inline the fast path of mallocs +- improve on predictability: delegate the caching, don't trace into signals ... but produce just a conditional call + - update things in metainterp/doc Python interpreter: From arigo at codespeak.net Sun Sep 27 12:34:03 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 27 Sep 2009 12:34:03 +0200 (CEST) Subject: [pypy-svn] r67915 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090927103403.2F09616800D@codespeak.net> Author: arigo Date: Sun Sep 27 12:34:02 2009 New Revision: 67915 Modified: pypy/trunk/pypy/jit/metainterp/resume.py Log: Kill a copy of a list that was never used. Modified: pypy/trunk/pypy/jit/metainterp/resume.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resume.py (original) +++ pypy/trunk/pypy/jit/metainterp/resume.py Sun Sep 27 12:34:02 2009 @@ -94,7 +94,6 @@ def __init__(self, storage, liveboxes): self.storage = storage - self.nums = storage.rd_nums[:] self.consts = storage.rd_consts[:] assert storage.rd_virtuals is None self.original_liveboxes = liveboxes From fijal at codespeak.net Sun Sep 27 14:28:31 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 27 Sep 2009 14:28:31 +0200 (CEST) Subject: [pypy-svn] r67916 - in pypy/branch/refactor-x86/pypy/jit/backend/llsupport: . test Message-ID: <20090927122831.35AF316800D@codespeak.net> Author: fijal Date: Sun Sep 27 14:28:30 2009 New Revision: 67916 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Log: improve test coverage Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Sun Sep 27 14:28:30 2009 @@ -9,12 +9,13 @@ class RegisterManager(object): """ Class that keeps track of register allocations """ - def __init__(self, register_pool, longevity): + def __init__(self, register_pool, longevity, no_lower_byte_regs=()): self.free_regs = register_pool[:] self.all_regs = register_pool self.longevity = longevity self.reg_bindings = {} self.position = 0 + self.no_lower_byte_regs = no_lower_byte_regs def next_instruction(self, incr=1): self.position += incr @@ -62,11 +63,11 @@ return None if need_lower_byte: loc = self.reg_bindings.get(v, None) - if loc is not None and loc is not edi and loc is not esi: + if loc is not None and loc not in self.no_lower_byte_regs: return loc for i in range(len(self.free_regs)): reg = self.free_regs[i] - if reg is not edi and reg is not esi: + if reg not in self.no_lower_byte_regs: if loc is not None: self.free_regs[i] = loc else: Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Sun Sep 27 14:28:30 2009 @@ -2,9 +2,18 @@ from pypy.jit.metainterp.history import BoxInt, ConstInt from pypy.jit.backend.llsupport.regalloc import RegisterManager -def boxes(*values): +def newboxes(*values): return [BoxInt(v) for v in values] +def boxes_and_longevity(num): + res = [] + longevity = {} + for i in range(num): + box = BoxInt(0) + res.append(box) + longevity[box] = (0, 1) + return res, longevity + class FakeReg(object): pass @@ -13,7 +22,7 @@ class TestRegalloc(object): def test_freeing_vars(self): - b0, b1, b2 = boxes(0, 0, 0) + b0, b1, b2 = newboxes(0, 0, 0) longevity = {b0: (0, 1), b1: (0, 2), b2: (0, 2)} rm = RegisterManager(regs, longevity) for b in b0, b1, b2: @@ -37,4 +46,24 @@ assert len(rm.free_regs) == 4 assert len(rm.reg_bindings) == 0 + def test_register_exhaustion(self): + boxes, longevity = boxes_and_longevity(5) + rm = RegisterManager(regs, longevity) + for b in boxes[:len(regs)]: + assert rm.try_allocate_reg(b) + assert rm.try_allocate_reg(boxes[-1]) is None + rm._check_invariants() + + def test_need_lower_byte(self): + boxes, longevity = boxes_and_longevity(5) + b0, b1, b2, b3, b4 = boxes + no_lower_byte_regs = [r2, r3] + rm = RegisterManager(regs, longevity, no_lower_byte_regs) + loc = rm.try_allocate_reg(b0, need_lower_byte=True) + assert loc not in no_lower_byte_regs + loc = rm.try_allocate_reg(b1, need_lower_byte=True) + assert loc not in no_lower_byte_regs + loc = rm.try_allocate_reg(b2, need_lower_byte=True) + assert loc is None + rm._check_invariants() From fijal at codespeak.net Sun Sep 27 14:48:37 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 27 Sep 2009 14:48:37 +0200 (CEST) Subject: [pypy-svn] r67917 - pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test Message-ID: <20090927124837.8F6D116800D@codespeak.net> Author: fijal Date: Sun Sep 27 14:48:37 2009 New Revision: 67917 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Log: Improve testing coverage, now it's enough to cover all paths in try_allocate_reg Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Sun Sep 27 14:48:37 2009 @@ -59,11 +59,26 @@ b0, b1, b2, b3, b4 = boxes no_lower_byte_regs = [r2, r3] rm = RegisterManager(regs, longevity, no_lower_byte_regs) - loc = rm.try_allocate_reg(b0, need_lower_byte=True) - assert loc not in no_lower_byte_regs + loc0 = rm.try_allocate_reg(b0, need_lower_byte=True) + assert loc0 not in no_lower_byte_regs loc = rm.try_allocate_reg(b1, need_lower_byte=True) assert loc not in no_lower_byte_regs loc = rm.try_allocate_reg(b2, need_lower_byte=True) assert loc is None + loc = rm.try_allocate_reg(b0, need_lower_byte=True) + assert loc is loc0 + rm._check_invariants() + + def test_specific_register(self): + boxes, longevity = boxes_and_longevity(5) + rm = RegisterManager(regs, longevity) + loc = rm.try_allocate_reg(boxes[0], selected_reg=r1) + assert loc is r1 + loc = rm.try_allocate_reg(boxes[1], selected_reg=r1) + assert loc is None + rm._check_invariants() + loc = rm.try_allocate_reg(boxes[0], selected_reg=r1) + assert loc is r1 + loc = rm.try_allocate_reg(boxes[0], selected_reg=r2) + assert loc is r2 rm._check_invariants() - From arigo at codespeak.net Sun Sep 27 15:17:39 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 27 Sep 2009 15:17:39 +0200 (CEST) Subject: [pypy-svn] r67918 - pypy/trunk/pypy/translator/c Message-ID: <20090927131739.A135D16800D@codespeak.net> Author: arigo Date: Sun Sep 27 15:17:39 2009 New Revision: 67918 Modified: pypy/trunk/pypy/translator/c/node.py Log: Kill 'inline_head'. I guess nobody remembers what it is here for, it's not used and not tested anyway. Modified: pypy/trunk/pypy/translator/c/node.py ============================================================================== --- pypy/trunk/pypy/translator/c/node.py (original) +++ pypy/trunk/pypy/translator/c/node.py Sun Sep 27 15:17:39 2009 @@ -114,36 +114,17 @@ return self.prefix + name def verbatim_field_name(self, name): - if name.startswith('c_'): # produced in this way by rffi - return name[2:] - else: - # field names have to start with 'c_' or be meant for names that - # vanish from the C source, like 'head' if 'inline_head' is set - raise ValueError("field %r should not be accessed in this way" % ( - name,)) + assert name.startswith('c_') # produced in this way by rffi + return name[2:] def c_struct_field_type(self, name): return self.STRUCT._flds[name] def access_expr(self, baseexpr, fldname): - if self.STRUCT._hints.get('inline_head'): - first, FIRST = self.STRUCT._first_struct() - if fldname == first: - # "invalid" cast according to C99 but that's what CPython - # requires and does all the time :-/ - return '(*(%s) &(%s))' % (cdecl(self.db.gettype(FIRST), '*'), - baseexpr) fldname = self.c_struct_field_name(fldname) return '%s.%s' % (baseexpr, fldname) def ptr_access_expr(self, baseexpr, fldname): - if self.STRUCT._hints.get('inline_head'): - first, FIRST = self.STRUCT._first_struct() - if fldname == first: - # "invalid" cast according to C99 but that's what CPython - # requires and does all the time :-/ - return '(*(%s) %s)' % (cdecl(self.db.gettype(FIRST), '*'), - baseexpr) fldname = self.c_struct_field_name(fldname) return 'RPyField(%s, %s)' % (baseexpr, fldname) From arigo at codespeak.net Sun Sep 27 17:59:34 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 27 Sep 2009 17:59:34 +0200 (CEST) Subject: [pypy-svn] r67919 - pypy/trunk/pypy/config Message-ID: <20090927155934.C3808168020@codespeak.net> Author: arigo Date: Sun Sep 27 17:59:34 2009 New Revision: 67919 Modified: pypy/trunk/pypy/config/translationoption.py Log: Change the default for the --gc option in the presence of -Ojit. Now we get the hybrid gc with asmgcc by default. Modified: pypy/trunk/pypy/config/translationoption.py ============================================================================== --- pypy/trunk/pypy/config/translationoption.py (original) +++ pypy/trunk/pypy/config/translationoption.py Sun Sep 27 17:59:34 2009 @@ -96,7 +96,8 @@ BoolOption("jit", "generate a JIT", default=False, requires=[("translation.thread", False)], - suggests=[("translation.gc", "boehm"), # for now + suggests=[("translation.gc", "hybrid"), # or "boehm" + ("translation.gcrootfinder", "asmgcc"), ("translation.list_comprehension_operations", True)]), ChoiceOption("jit_backend", "choose the backend for the JIT", ["auto", "x86", "llvm"], @@ -317,7 +318,7 @@ 'mem': 'markcompact lowinline remove_asserts', '2': 'hybrid extraopts', '3': 'hybrid extraopts remove_asserts', - 'jit': 'boehm extraopts jit', # XXX boehm for now, fix me + 'jit': 'hybrid extraopts jit', } def set_opt_level(config, level): From benjamin at codespeak.net Mon Sep 28 01:32:18 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Mon, 28 Sep 2009 01:32:18 +0200 (CEST) Subject: [pypy-svn] r67920 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090927233218.0DED7168013@codespeak.net> Author: benjamin Date: Mon Sep 28 01:32:17 2009 New Revision: 67920 Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py Log: silence some rtyper warnings Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/jitprof.py (original) +++ pypy/trunk/pypy/jit/metainterp/jitprof.py Mon Sep 28 01:32:17 2009 @@ -66,7 +66,13 @@ class Profiler(object): initialized = False timer = time.time - + starttime = 0 + t1 = 0 + times = None + counters = None + calls = None + current = None + def start(self): self.starttime = self.timer() self.t1 = self.starttime From benjamin at codespeak.net Mon Sep 28 01:36:13 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Mon, 28 Sep 2009 01:36:13 +0200 (CEST) Subject: [pypy-svn] r67921 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090927233613.5ACC4168013@codespeak.net> Author: benjamin Date: Mon Sep 28 01:36:12 2009 New Revision: 67921 Modified: pypy/trunk/pypy/jit/backend/x86/jump.py Log: let the annotator not demote _getregkey Modified: pypy/trunk/pypy/jit/backend/x86/jump.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/jump.py (original) +++ pypy/trunk/pypy/jit/backend/x86/jump.py Mon Sep 28 01:36:12 2009 @@ -2,6 +2,12 @@ from pypy.tool.pairtype import extendabletype from pypy.jit.backend.x86.ri386 import * +class __extend__(OPERAND): + __metaclass__ = extendabletype + def _getregkey(self): + raise AssertionError("should only happen to registers and stack " + "positions") + class __extend__(REG): __metaclass__ = extendabletype def _getregkey(self): From fijal at codespeak.net Mon Sep 28 11:18:03 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 11:18:03 +0200 (CEST) Subject: [pypy-svn] r67922 - pypy/extradoc/talk/pepm2010 Message-ID: <20090928091803.BFCBD16801E@codespeak.net> Author: fijal Date: Mon Sep 28 11:18:01 2009 New Revision: 67922 Removed: pypy/extradoc/talk/pepm2010/ Log: it seems this one is dead From pedronis at codespeak.net Mon Sep 28 12:07:50 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 28 Sep 2009 12:07:50 +0200 (CEST) Subject: [pypy-svn] r67923 - pypy/branch/resume-data-chaining Message-ID: <20090928100750.035BC168030@codespeak.net> Author: pedronis Date: Mon Sep 28 12:07:45 2009 New Revision: 67923 Added: pypy/branch/resume-data-chaining/ - copied from r67922, pypy/trunk/ Log: making a branch to work on moving most of the cost of guard construction to optimisation and then go from there From fijal at codespeak.net Mon Sep 28 12:11:35 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 12:11:35 +0200 (CEST) Subject: [pypy-svn] r67924 - in pypy/branch/refactor-x86/pypy/jit/backend/llsupport: . test Message-ID: <20090928101135.72C1B168030@codespeak.net> Author: fijal Date: Mon Sep 28 12:11:35 2009 New Revision: 67924 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Log: Progress (slow, but always) Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 12:11:35 2009 @@ -1,21 +1,53 @@ -from pypy.jit.metainterp.history import Const +from pypy.jit.metainterp.history import Const, Box from pypy.rlib.objectmodel import we_are_translated +class TempBox(Box): + def __init__(self): + pass + + def __repr__(self): + return "" % (id(self),) + +class NoVariableToSpill(Exception): + pass + class StackManager(object): """ Manage stack positions """ + def __init__(self): + self.stack_bindings = {} + self.stack_depth = 0 + + def get(self, box): + return self.stack_bindings.get(box, None) + + def loc(self, box): + res = self.get(box) + if res is not None: + return res + newloc = self.stack_pos(self.stack_depth) + self.stack_bindings[box] = newloc + self.stack_depth += 1 + return newloc + + # abstract methods that need to be overwritten for specific assemblers + def stack_pos(self, loc): + raise NotImplementedError("Purely abstract") class RegisterManager(object): """ Class that keeps track of register allocations """ - def __init__(self, register_pool, longevity, no_lower_byte_regs=()): + def __init__(self, register_pool, longevity, no_lower_byte_regs=(), + stack_manager=None, assembler=None): self.free_regs = register_pool[:] self.all_regs = register_pool self.longevity = longevity self.reg_bindings = {} self.position = 0 self.no_lower_byte_regs = no_lower_byte_regs + self.stack_manager = stack_manager + self.assembler = assembler def next_instruction(self, incr=1): self.position += incr @@ -49,7 +81,7 @@ assert not isinstance(v, Const) if selected_reg is not None: res = self.reg_bindings.get(v, None) - if res: + if res is not None: if res is selected_reg: return res else: @@ -83,3 +115,56 @@ self.reg_bindings[v] = loc return loc + def _spill_var(self, v, forbidden_vars, selected_reg, + need_lower_byte=False): + v_to_spill = self.pick_variable_to_spill(v, forbidden_vars, + selected_reg, need_lower_byte=need_lower_byte) + loc = self.reg_bindings[v_to_spill] + del self.reg_bindings[v_to_spill] + if self.stack_manager.get(v_to_spill) is None: + newloc = self.stack_manager.loc(v_to_spill) + self.assembler.regalloc_store(loc, newloc) + return loc + + def pick_variable_to_spill(self, v, forbidden_vars, selected_reg=None, + need_lower_byte=False): + """ Silly algorithm. + """ + candidates = [] + for next in self.reg_bindings: + reg = self.reg_bindings[next] + if next in forbidden_vars: + continue + if selected_reg is not None: + if reg is selected_reg: + return next + else: + continue + if need_lower_byte and reg in self.no_lower_byte_regs: + continue + return next + raise NoVariableToSpill + + def force_allocate_reg(self, v, forbidden_vars=[], selected_reg=None, + need_lower_byte=False): + if isinstance(v, TempBox): + self.longevity[v] = (self.position, self.position) + loc = self.try_allocate_reg(v, selected_reg, + need_lower_byte=need_lower_byte) + if loc: + return loc + loc = self._spill_var(v, forbidden_vars, selected_reg, + need_lower_byte=need_lower_byte) + prev_loc = self.reg_bindings.get(v, None) + if prev_loc is not None: + self.free_regs.append(prev_loc) + self.reg_bindings[v] = loc + return loc + + def loc(self, box): + # XXX do something + assert not isinstance(box, Const) + try: + return self.reg_bindings[box] + except KeyError: + return self.stack_manager.loc(box) Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Mon Sep 28 12:11:35 2009 @@ -1,6 +1,6 @@ from pypy.jit.metainterp.history import BoxInt, ConstInt -from pypy.jit.backend.llsupport.regalloc import RegisterManager +from pypy.jit.backend.llsupport.regalloc import RegisterManager, StackManager def newboxes(*values): return [BoxInt(v) for v in values] @@ -20,6 +20,14 @@ r0, r1, r2, r3 = [FakeReg() for _ in range(4)] regs = [r0, r1, r2, r3] +class TStackManager(StackManager): + def stack_pos(self, i): + return i + +class MockAsm(object): + def regalloc_store(self, from_loc, to_loc): + pass + class TestRegalloc(object): def test_freeing_vars(self): b0, b1, b2 = newboxes(0, 0, 0) @@ -82,3 +90,31 @@ loc = rm.try_allocate_reg(boxes[0], selected_reg=r2) assert loc is r2 rm._check_invariants() + + def test_force_allocate_reg(self): + boxes, longevity = boxes_and_longevity(5) + b0, b1, b2, b3, b4 = boxes + sm = TStackManager() + rm = RegisterManager(regs, longevity, + no_lower_byte_regs = [r2, r3], + stack_manager=sm, + assembler=MockAsm()) + loc = rm.force_allocate_reg(b0, []) + assert isinstance(loc, FakeReg) + loc = rm.force_allocate_reg(b1, []) + assert isinstance(loc, FakeReg) + loc = rm.force_allocate_reg(b2, []) + assert isinstance(loc, FakeReg) + loc = rm.force_allocate_reg(b3, []) + assert isinstance(loc, FakeReg) + loc = rm.force_allocate_reg(b4, []) + assert isinstance(loc, FakeReg) + # one of those should be now somewhere else + locs = [rm.loc(b) for b in boxes] + used_regs = [loc for loc in locs if isinstance(loc, FakeReg)] + assert len(used_regs) == len(regs) + loc = rm.force_allocate_reg(b0, [], need_lower_byte=True) + assert isinstance(loc, FakeReg) + assert loc not in [r2, r3] + rm._check_invariants() + From fijal at codespeak.net Mon Sep 28 13:31:15 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 13:31:15 +0200 (CEST) Subject: [pypy-svn] r67925 - in pypy/branch/refactor-x86/pypy/jit/backend/llsupport: . test Message-ID: <20090928113115.636F316803B@codespeak.net> Author: fijal Date: Mon Sep 28 13:31:10 2009 New Revision: 67925 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Log: This is more or less it, except that we might not have enough asserts in tests (maybe) Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 13:31:10 2009 @@ -123,7 +123,7 @@ del self.reg_bindings[v_to_spill] if self.stack_manager.get(v_to_spill) is None: newloc = self.stack_manager.loc(v_to_spill) - self.assembler.regalloc_store(loc, newloc) + self.assembler.regalloc_mov(loc, newloc) return loc def pick_variable_to_spill(self, v, forbidden_vars, selected_reg=None, @@ -168,3 +168,82 @@ return self.reg_bindings[box] except KeyError: return self.stack_manager.loc(box) + + def return_constant(self, v, forbidden_vars=[], selected_reg=None, + imm_fine=True): + assert isinstance(v, Const) + if selected_reg or not imm_fine: + # this means we cannot have it in IMM, eh + if selected_reg in self.free_regs: + self.assembler.regalloc_mov(self.convert_to_imm(v), selected_reg) + return selected_reg + if selected_reg is None and self.free_regs: + loc = self.free_regs.pop() + self.assembler.regalloc_mov(self.convert_to_imm(v), loc) + return loc + loc = self._spill_var(v, forbidden_vars, selected_reg) + self.free_regs.append(loc) + self.Load(v, convert_to_imm(v), loc) + return loc + return convert_to_imm(v) + + def make_sure_var_in_reg(self, v, forbidden_vars=[], selected_reg=None, + imm_fine=True, need_lower_byte=False): + if isinstance(v, Const): + return self.return_constant(v, forbidden_vars, selected_reg, + imm_fine) + + prev_loc = self.loc(v) + loc = self.force_allocate_reg(v, forbidden_vars, selected_reg, + need_lower_byte=need_lower_byte) + if prev_loc is not loc: + self.assembler.regalloc_mov(prev_loc, loc) + return loc + + def reallocate_from_to(self, from_v, to_v): + reg = self.reg_bindings[from_v] + del self.reg_bindings[from_v] + self.reg_bindings[to_v] = reg + + def move_variable_away(self, v, prev_loc): + reg = None + if self.free_regs: + loc = self.free_regs.pop() + self.reg_bindings[v] = loc + self.assembler.regalloc_mov(prev_loc, loc) + else: + loc = self.stack_manager.loc(v) + self.assembler.regalloc_mov(prev_loc, loc) + + def force_result_in_reg(self, result_v, v, forbidden_vars=[]): + """ Make sure that result is in the same register as v + and v is copied away if it's further used + """ + if isinstance(v, Const): + loc = self.make_sure_var_in_reg(v, forbidden_vars, + imm_fine=False) + self.reg_bindings[result_v] = loc + self.free_regs = [reg for reg in self.free_regs if reg is not loc] + return loc + if v not in self.reg_bindings: + prev_loc = self.stack_manager.loc(v) + loc = self.force_allocate_reg(v, forbidden_vars) + self.assembler.regalloc_mov(prev_loc, loc) + assert v in self.reg_bindings + if self.longevity[v][1] > self.position: + # we need to find a new place for variable v and + # store result in the same place + loc = self.reg_bindings[v] + del self.reg_bindings[v] + if self.stack_manager.get(v) is None: + self.move_variable_away(v, loc) + self.reg_bindings[result_v] = loc + else: + self.reallocate_from_to(v, result_v) + loc = self.reg_bindings[result_v] + return loc + + # abstract methods, override + + def convert_to_imm(self, c): + raise NotImplementedError("Abstract") Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Mon Sep 28 13:31:10 2009 @@ -1,6 +1,11 @@ from pypy.jit.metainterp.history import BoxInt, ConstInt -from pypy.jit.backend.llsupport.regalloc import RegisterManager, StackManager +from pypy.jit.backend.llsupport.regalloc import StackManager +from pypy.jit.backend.llsupport.regalloc import RegisterManager as BaseRegMan + +class RegisterManager(BaseRegMan): + def convert_to_imm(self, v): + return v def newboxes(*values): return [BoxInt(v) for v in values] @@ -25,8 +30,11 @@ return i class MockAsm(object): - def regalloc_store(self, from_loc, to_loc): - pass + def __init__(self): + self.moves = [] + + def regalloc_mov(self, from_loc, to_loc): + self.moves.append((from_loc, to_loc)) class TestRegalloc(object): def test_freeing_vars(self): @@ -99,22 +107,114 @@ no_lower_byte_regs = [r2, r3], stack_manager=sm, assembler=MockAsm()) - loc = rm.force_allocate_reg(b0, []) + loc = rm.force_allocate_reg(b0) assert isinstance(loc, FakeReg) - loc = rm.force_allocate_reg(b1, []) + loc = rm.force_allocate_reg(b1) assert isinstance(loc, FakeReg) - loc = rm.force_allocate_reg(b2, []) + loc = rm.force_allocate_reg(b2) assert isinstance(loc, FakeReg) - loc = rm.force_allocate_reg(b3, []) + loc = rm.force_allocate_reg(b3) assert isinstance(loc, FakeReg) - loc = rm.force_allocate_reg(b4, []) + loc = rm.force_allocate_reg(b4) assert isinstance(loc, FakeReg) # one of those should be now somewhere else locs = [rm.loc(b) for b in boxes] used_regs = [loc for loc in locs if isinstance(loc, FakeReg)] assert len(used_regs) == len(regs) - loc = rm.force_allocate_reg(b0, [], need_lower_byte=True) + loc = rm.force_allocate_reg(b0, need_lower_byte=True) assert isinstance(loc, FakeReg) assert loc not in [r2, r3] rm._check_invariants() + + def test_make_sure_var_in_reg(self): + boxes, longevity = boxes_and_longevity(5) + sm = TStackManager() + rm = RegisterManager(regs, longevity, stack_manager=sm, + assembler=MockAsm()) + # allocate a stack position + b0, b1, b2, b3, b4 = boxes + sp = sm.loc(b0) + assert sp == 0 + loc = rm.make_sure_var_in_reg(b0) + assert isinstance(loc, FakeReg) + rm._check_invariants() + def test_force_result_in_reg_1(self): + b0, b1 = newboxes(0, 0) + longevity = {b0: (0, 1), b1: (1, 3)} + sm = TStackManager() + asm = MockAsm() + rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + # first path, var is already in reg and dies + loc0 = rm.force_allocate_reg(b0) + rm._check_invariants() + rm.next_instruction() + loc = rm.force_result_in_reg(b1, b0) + assert loc is loc0 + assert len(asm.moves) == 0 + rm._check_invariants() + + def test_force_result_in_reg_2(self): + b0, b1 = newboxes(0, 0) + longevity = {b0: (0, 2), b1: (1, 3)} + sm = TStackManager() + asm = MockAsm() + rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + loc0 = rm.force_allocate_reg(b0) + rm._check_invariants() + rm.next_instruction() + loc = rm.force_result_in_reg(b1, b0) + assert loc is loc0 + assert rm.loc(b0) is not loc0 + assert len(asm.moves) == 1 + rm._check_invariants() + + def test_force_result_in_reg_3(self): + b0, b1, b2, b3, b4 = newboxes(0, 0, 0, 0, 0) + longevity = {b0: (0, 2), b1: (0, 2), b3: (0, 2), b2: (0, 2), b4: (1, 3)} + sm = TStackManager() + asm = MockAsm() + rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + for b in b0, b1, b2, b3: + rm.force_allocate_reg(b) + assert not len(rm.free_regs) + rm._check_invariants() + rm.next_instruction() + rm.force_result_in_reg(b4, b0) + rm._check_invariants() + assert len(asm.moves) == 1 + + def test_force_result_in_reg_4(self): + b0, b1 = newboxes(0, 0) + longevity = {b0: (0, 1), b1: (0, 1)} + sm = TStackManager() + asm = MockAsm() + rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + sm.loc(b0) + rm.force_result_in_reg(b1, b0) + rm._check_invariants() + loc = rm.loc(b1) + assert isinstance(loc, FakeReg) + loc = rm.loc(b0) + assert isinstance(loc, int) + assert len(asm.moves) == 1 + + def test_return_constant(self): + asm = MockAsm() + rm = RegisterManager(regs, {}, assembler=asm) + loc = rm.return_constant(ConstInt(0), imm_fine=False) + assert isinstance(loc, FakeReg) + loc = rm.return_constant(ConstInt(1), selected_reg=r1) + assert loc is r1 + loc = rm.return_constant(ConstInt(1), selected_reg=r1) + assert loc is r1 + + def test_force_result_in_reg_const(self): + boxes, longevity = boxes_and_longevity(2) + sm = TStackManager() + asm = MockAsm() + rm = RegisterManager(regs, longevity, stack_manager=sm, + assembler=asm) + c = ConstInt(0) + rm.force_result_in_reg(boxes[0], c) + rm._check_invariants() From fijal at codespeak.net Mon Sep 28 13:41:46 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 13:41:46 +0200 (CEST) Subject: [pypy-svn] r67926 - in pypy/branch/refactor-x86/pypy/jit/backend/llsupport: . test Message-ID: <20090928114146.3F68916803B@codespeak.net> Author: fijal Date: Mon Sep 28 13:41:45 2009 New Revision: 67926 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Log: missing case Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 13:41:45 2009 @@ -162,8 +162,8 @@ return loc def loc(self, box): - # XXX do something - assert not isinstance(box, Const) + if isinstance(box, Const): + return self.convert_to_imm(box) try: return self.reg_bindings[box] except KeyError: Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Mon Sep 28 13:41:45 2009 @@ -218,3 +218,7 @@ c = ConstInt(0) rm.force_result_in_reg(boxes[0], c) rm._check_invariants() + + def test_loc_of_const(self): + rm = RegisterManager(regs, {}) + assert isinstance(rm.loc(ConstInt(1)), ConstInt) From fijal at codespeak.net Mon Sep 28 13:54:27 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 13:54:27 +0200 (CEST) Subject: [pypy-svn] r67927 - in pypy/branch/refactor-x86/pypy/jit/backend/llsupport: . test Message-ID: <20090928115427.A4C3816803D@codespeak.net> Author: fijal Date: Mon Sep 28 13:54:27 2009 New Revision: 67927 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Log: We start counting from -1 here. I don't feel like changing it... Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 13:54:27 2009 @@ -44,7 +44,7 @@ self.all_regs = register_pool self.longevity = longevity self.reg_bindings = {} - self.position = 0 + self.position = -1 self.no_lower_byte_regs = no_lower_byte_regs self.stack_manager = stack_manager self.assembler = assembler Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Mon Sep 28 13:54:27 2009 @@ -41,6 +41,7 @@ b0, b1, b2 = newboxes(0, 0, 0) longevity = {b0: (0, 1), b1: (0, 2), b2: (0, 2)} rm = RegisterManager(regs, longevity) + rm.next_instruction() for b in b0, b1, b2: rm.try_allocate_reg(b) rm._check_invariants() @@ -65,6 +66,7 @@ def test_register_exhaustion(self): boxes, longevity = boxes_and_longevity(5) rm = RegisterManager(regs, longevity) + rm.next_instruction() for b in boxes[:len(regs)]: assert rm.try_allocate_reg(b) assert rm.try_allocate_reg(boxes[-1]) is None @@ -75,6 +77,7 @@ b0, b1, b2, b3, b4 = boxes no_lower_byte_regs = [r2, r3] rm = RegisterManager(regs, longevity, no_lower_byte_regs) + rm.next_instruction() loc0 = rm.try_allocate_reg(b0, need_lower_byte=True) assert loc0 not in no_lower_byte_regs loc = rm.try_allocate_reg(b1, need_lower_byte=True) @@ -88,6 +91,7 @@ def test_specific_register(self): boxes, longevity = boxes_and_longevity(5) rm = RegisterManager(regs, longevity) + rm.next_instruction() loc = rm.try_allocate_reg(boxes[0], selected_reg=r1) assert loc is r1 loc = rm.try_allocate_reg(boxes[1], selected_reg=r1) @@ -107,6 +111,7 @@ no_lower_byte_regs = [r2, r3], stack_manager=sm, assembler=MockAsm()) + rm.next_instruction() loc = rm.force_allocate_reg(b0) assert isinstance(loc, FakeReg) loc = rm.force_allocate_reg(b1) @@ -131,6 +136,7 @@ sm = TStackManager() rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=MockAsm()) + rm.next_instruction() # allocate a stack position b0, b1, b2, b3, b4 = boxes sp = sm.loc(b0) @@ -145,6 +151,7 @@ sm = TStackManager() asm = MockAsm() rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + rm.next_instruction() # first path, var is already in reg and dies loc0 = rm.force_allocate_reg(b0) rm._check_invariants() @@ -160,6 +167,7 @@ sm = TStackManager() asm = MockAsm() rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + rm.next_instruction() loc0 = rm.force_allocate_reg(b0) rm._check_invariants() rm.next_instruction() @@ -175,6 +183,7 @@ sm = TStackManager() asm = MockAsm() rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + rm.next_instruction() for b in b0, b1, b2, b3: rm.force_allocate_reg(b) assert not len(rm.free_regs) @@ -190,6 +199,7 @@ sm = TStackManager() asm = MockAsm() rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + rm.next_instruction() sm.loc(b0) rm.force_result_in_reg(b1, b0) rm._check_invariants() @@ -202,6 +212,7 @@ def test_return_constant(self): asm = MockAsm() rm = RegisterManager(regs, {}, assembler=asm) + rm.next_instruction() loc = rm.return_constant(ConstInt(0), imm_fine=False) assert isinstance(loc, FakeReg) loc = rm.return_constant(ConstInt(1), selected_reg=r1) @@ -215,10 +226,12 @@ asm = MockAsm() rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + rm.next_instruction() c = ConstInt(0) rm.force_result_in_reg(boxes[0], c) rm._check_invariants() def test_loc_of_const(self): rm = RegisterManager(regs, {}) + rm.next_instruction() assert isinstance(rm.loc(ConstInt(1)), ConstInt) From fijal at codespeak.net Mon Sep 28 13:59:26 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 13:59:26 +0200 (CEST) Subject: [pypy-svn] r67928 - pypy/branch/refactor-x86/pypy/jit/backend/x86 Message-ID: <20090928115926.12DCF168042@codespeak.net> Author: fijal Date: Mon Sep 28 13:59:25 2009 New Revision: 67928 Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Log: Kill a lot of code and start using new interface, only few tests pass so far Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py Mon Sep 28 13:59:25 2009 @@ -8,7 +8,7 @@ from pypy.rpython.lltypesystem.lloperation import llop from pypy.tool.uid import fixid from pypy.jit.backend.x86.regalloc import (RegAlloc, WORD, REGS, TempBox, - lower_byte, stack_pos) + lower_byte) from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.jit.backend.x86 import codebuf from pypy.jit.backend.x86.ri386 import * @@ -168,7 +168,7 @@ self.mc2.done() if we_are_translated() or self.cpu.dont_keepalive_stuff: self._regalloc = None # else keep it around for debugging - stack_depth = regalloc.current_stack_depth + stack_depth = regalloc.sm.stack_depth jump_target = regalloc.jump_target if jump_target is not None: target_stack_depth = jump_target.executable_token._x86_stack_depth @@ -235,11 +235,9 @@ # ------------------------------------------------------------ - def regalloc_load(self, from_loc, to_loc): + def regalloc_mov(self, from_loc, to_loc): self.mc.MOV(to_loc, from_loc) - regalloc_store = regalloc_load - def regalloc_push(self, loc): self.mc.PUSH(loc) Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Mon Sep 28 13:59:25 2009 @@ -14,20 +14,12 @@ from pypy.jit.metainterp.resoperation import rop from pypy.jit.backend.llsupport.descr import BaseFieldDescr, BaseArrayDescr from pypy.jit.backend.llsupport.descr import BaseCallDescr +from pypy.jit.backend.llsupport.regalloc import StackManager, RegisterManager,\ + TempBox REGS = [eax, ecx, edx, ebx, esi, edi] WORD = 4 -class NoVariableToSpill(Exception): - pass - -class TempBox(Box): - def __init__(self): - pass - - def __repr__(self): - return "" % (id(self),) - class checkdict(dict): def __setitem__(self, key, value): assert isinstance(key, Box) @@ -38,19 +30,28 @@ return {} return checkdict() -def convert_to_imm(c): - if isinstance(c, ConstInt): - return imm(c.value) - elif isinstance(c, ConstPtr): - if we_are_translated() and c.value and rgc.can_move(c.value): - print "convert_to_imm: ConstPtr needs special care" +class X86RegisterManager(RegisterManager): + def convert_to_imm(self, c): + if isinstance(c, ConstInt): + return imm(c.value) + elif isinstance(c, ConstPtr): + if we_are_translated() and c.value and rgc.can_move(c.value): + print "convert_to_imm: ConstPtr needs special care" + raise AssertionError + return imm(rffi.cast(lltype.Signed, c.value)) + elif isinstance(c, ConstAddr): + return imm(ll2ctypes.cast_adr_to_int(c.value)) + else: + print "convert_to_imm: got a %s" % c raise AssertionError - return imm(rffi.cast(lltype.Signed, c.value)) - elif isinstance(c, ConstAddr): - return imm(ll2ctypes.cast_adr_to_int(c.value)) - else: - print "convert_to_imm: got a %s" % c - raise AssertionError + +class X86StackManager(StackManager): + + @staticmethod + def stack_pos(i): + res = mem(ebp, get_ebp_ofs(i)) + res.position = i + return res class RegAlloc(object): exc = False @@ -60,28 +61,27 @@ # variables that have place in register self.assembler = assembler self.translate_support_code = translate_support_code - self.reg_bindings = newcheckdict() - self.stack_bindings = newcheckdict() self.position = -1 - self.longevity = None - # to be read/used by the assembler too - self.current_stack_depth = 0 self.jump_target = None def prepare_loop(self, inputargs, operations): cpu = self.assembler.cpu cpu.gc_ll_descr.rewrite_assembler(cpu, operations) # compute longevity of variables - self._compute_vars_longevity(inputargs, operations) + longevity = self._compute_vars_longevity(inputargs, operations) + self.sm = X86StackManager() + self.rm = X86RegisterManager(REGS, longevity, + no_lower_byte_regs = [esi, edi], + stack_manager = self.sm, + assembler = self.assembler) jump = operations[-1] loop_consts = self._compute_loop_consts(inputargs, jump) self.loop_consts = loop_consts - self.current_stack_depth = 0 - self.free_regs = REGS[:] return self._process_inputargs(inputargs) def prepare_bridge(self, prev_stack_depth, inputargs, arglocs, operations): + xxxx cpu = self.assembler.cpu cpu.gc_ll_descr.rewrite_assembler(cpu, operations) # compute longevity of variables @@ -96,23 +96,23 @@ locs = [None] * len(inputargs) # Don't use REGS[0] for passing arguments around a loop. # Must be kept in sync with consider_jump(). - tmpreg = self.free_regs.pop(0) + tmpreg = self.rm.free_regs.pop(0) assert tmpreg == REGS[0] for i in range(len(inputargs)): arg = inputargs[i] assert not isinstance(arg, Const) reg = None - if arg not in self.loop_consts and self.longevity[arg][1] > -1: - reg = self.try_allocate_reg(arg) + if arg not in self.loop_consts and self.rm.longevity[arg][1] > -1: + reg = self.rm.try_allocate_reg(arg) if reg: locs[i] = reg else: - loc = self.stack_loc(arg) + loc = self.sm.loc(arg) locs[i] = loc # otherwise we have it saved on stack, so no worry - self.free_regs.insert(0, tmpreg) + self.rm.free_regs.insert(0, tmpreg) assert tmpreg not in locs - self.eventually_free_vars(inputargs) + self.rm.possibly_free_vars(inputargs) return locs def _compute_loop_consts(self, inputargs, jump): @@ -147,32 +147,6 @@ self.free_regs.append(reg) self._check_invariants() - def _check_invariants(self): - if not we_are_translated(): - # make sure no duplicates - assert len(dict.fromkeys(self.reg_bindings.values())) == len(self.reg_bindings) - assert (len(dict.fromkeys([str(i) for i in self.stack_bindings.values()] - )) == len(self.stack_bindings)) - rev_regs = dict.fromkeys(self.reg_bindings.values()) - for reg in self.free_regs: - assert reg not in rev_regs - assert len(rev_regs) + len(self.free_regs) == len(REGS) - else: - assert len(self.reg_bindings) + len(self.free_regs) == len(REGS) - if self.longevity: - for v in self.reg_bindings: - assert self.longevity[v][1] > self.position - - def Load(self, v, from_loc, to_loc): - if not we_are_translated(): - self.assembler.dump('%s <- %s(%s)' % (to_loc, v, from_loc)) - self.assembler.regalloc_load(from_loc, to_loc) - - def Store(self, v, from_loc, to_loc): - if not we_are_translated(): - self.assembler.dump('%s(%s) -> %s' % (v, from_loc, to_loc)) - self.assembler.regalloc_store(from_loc, to_loc) - def Perform(self, op, arglocs, result_loc): if not we_are_translated(): self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) @@ -187,16 +161,14 @@ def perform_with_guard(self, op, guard_op, arglocs, result_loc): faillocs = self.locs_for_fail(guard_op) self.position += 1 - if not we_are_translated(): - self.assembler.dump('%s <- %s(%s) [GUARDED]' % (result_loc, op, - arglocs)) self.assembler.regalloc_perform_with_guard(op, guard_op, faillocs, arglocs, result_loc, - self.current_stack_depth) - self.eventually_free_var(op.result) - self.eventually_free_vars(guard_op.suboperations[0].args) + self.sm.stack_depth) + self.rm.possibly_free_var(op.result) + self.rm.possibly_free_vars(guard_op.suboperations[0].args) def perform_guard(self, guard_op, arglocs, result_loc): + xxx faillocs = self.locs_for_fail(guard_op) if not we_are_translated(): if result_loc is not None: @@ -223,7 +195,7 @@ return False if operations[i + 1].args[0] is not op.result: return False - if (self.longevity[op.result][1] > i + 1 or + if (self.rm.longevity[op.result][1] > i + 1 or op.result in operations[i + 1].suboperations[0].args): return False return True @@ -233,20 +205,20 @@ #self.operations = operations while i < len(operations): op = operations[i] - self.position = i - if op.has_no_side_effect() and op.result not in self.longevity: + self.rm.position = i + if op.has_no_side_effect() and op.result not in self.rm.longevity: i += 1 - self.eventually_free_vars(op.args) + self.rm.possibly_free_vars(op.args) continue if self.can_optimize_cmp_op(op, i, operations): oplist[op.opnum](self, op, operations[i + 1]) i += 1 else: oplist[op.opnum](self, op, None) - self.eventually_free_var(op.result) - self._check_invariants() + self.rm.possibly_free_var(op.result) + self.rm._check_invariants() i += 1 - assert not self.reg_bindings + assert not self.rm.reg_bindings def _compute_vars_longevity(self, inputargs, operations): # compute a dictionary that maps variables to index in @@ -277,217 +249,10 @@ longevity[arg] = (-1, -1) for arg in longevity: assert isinstance(arg, Box) - self.longevity = longevity - - def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): - assert not isinstance(v, Const) - if selected_reg is not None: - res = self.reg_bindings.get(v, None) - if res: - if res is selected_reg: - return res - else: - del self.reg_bindings[v] - self.free_regs.append(res) - if selected_reg in self.free_regs: - self.free_regs = [reg for reg in self.free_regs - if reg is not selected_reg] - self.reg_bindings[v] = selected_reg - return selected_reg - return None - if need_lower_byte: - loc = self.reg_bindings.get(v, None) - if loc is not None and loc is not edi and loc is not esi: - return loc - for i in range(len(self.free_regs)): - reg = self.free_regs[i] - if reg is not edi and reg is not esi: - if loc is not None: - self.free_regs[i] = loc - else: - del self.free_regs[i] - self.reg_bindings[v] = reg - return reg - return None - try: - return self.reg_bindings[v] - except KeyError: - if self.free_regs: - loc = self.free_regs.pop() - self.reg_bindings[v] = loc - return loc - - def return_constant(self, v, forbidden_vars, selected_reg=None, - imm_fine=True): - assert isinstance(v, Const) - if selected_reg or not imm_fine: - # this means we cannot have it in IMM, eh - if selected_reg in self.free_regs: - self.Load(v, convert_to_imm(v), selected_reg) - return selected_reg - if selected_reg is None and self.free_regs: - loc = self.free_regs.pop() - self.Load(v, convert_to_imm(v), loc) - return loc - loc = self._spill_var(v, forbidden_vars, selected_reg) - self.free_regs.append(loc) - self.Load(v, convert_to_imm(v), loc) - return loc - return convert_to_imm(v) - - def force_allocate_reg(self, v, forbidden_vars, selected_reg=None, - need_lower_byte=False): - if isinstance(v, TempBox): - self.longevity[v] = (self.position, self.position) - loc = self.try_allocate_reg(v, selected_reg, - need_lower_byte=need_lower_byte) - if loc: - return loc - loc = self._spill_var(v, forbidden_vars, selected_reg, - need_lower_byte=need_lower_byte) - prev_loc = self.reg_bindings.get(v, None) - if prev_loc is not None: - self.free_regs.append(prev_loc) - self.reg_bindings[v] = loc - return loc - - def _spill_var(self, v, forbidden_vars, selected_reg, - need_lower_byte=False): - v_to_spill = self.pick_variable_to_spill(v, forbidden_vars, - selected_reg, need_lower_byte=need_lower_byte) - loc = self.reg_bindings[v_to_spill] - del self.reg_bindings[v_to_spill] - if v_to_spill not in self.stack_bindings: - newloc = self.stack_loc(v_to_spill) - self.Store(v_to_spill, loc, newloc) - return loc - - def stack_loc(self, v): - try: - res = self.stack_bindings[v] - except KeyError: - newloc = stack_pos(self.current_stack_depth) - self.stack_bindings[v] = newloc - self.current_stack_depth += 1 - res = newloc - assert isinstance(res, MODRM) - return res - - def make_sure_var_in_reg(self, v, forbidden_vars, selected_reg=None, - imm_fine=True, need_lower_byte=False): - if isinstance(v, Const): - return self.return_constant(v, forbidden_vars, selected_reg, - imm_fine) - - prev_loc = self.loc(v) - loc = self.force_allocate_reg(v, forbidden_vars, selected_reg, - need_lower_byte=need_lower_byte) - if prev_loc is not loc: - self.Load(v, prev_loc, loc) - return loc - - def reallocate_from_to(self, from_v, to_v): - reg = self.reg_bindings[from_v] - del self.reg_bindings[from_v] - self.reg_bindings[to_v] = reg - - def eventually_free_var(self, v): - if isinstance(v, Const) or v not in self.reg_bindings: - return - if v not in self.longevity or self.longevity[v][1] <= self.position: - self.free_regs.append(self.reg_bindings[v]) - del self.reg_bindings[v] - - def eventually_free_vars(self, vlist): - for v in vlist: - self.eventually_free_var(v) + return longevity def loc(self, v): - if isinstance(v, Const): - return convert_to_imm(v) - try: - return self.reg_bindings[v] - except KeyError: - return self.stack_bindings[v] - - def _compute_next_usage(self, v, pos): - for i in range(pos, len(self.operations)): - if v in self.operations[i].args: - return i - if i > self.longevity[v][1]: - return -1 - return -1 - - def pick_variable_to_spill(self, v, forbidden_vars, selected_reg=None, - need_lower_byte=False): - candidates = [] - for next in self.reg_bindings: - reg = self.reg_bindings[next] - if next in forbidden_vars: - continue - if selected_reg is not None: - if reg is selected_reg: - return next - else: - continue - if need_lower_byte and (reg is esi or reg is edi): - continue - return next - raise NoVariableToSpill - # below is the slightly better (even optimal, under certain - # assumptions) algorithm, which is slow. Just go with the - # first hit - #if len(candidates) == 1: - # return candidates[0] - #max = 0 - #chosen = None - #for one in candidates: - # next_usage = self._compute_next_usage(one, self.position) - # if next_usage == -1: - # return one - # elif next_usage > max: - # next_usage = max - # chosen = one - #return chosen - - def move_variable_away(self, v, prev_loc): - reg = None - if self.free_regs: - loc = self.free_regs.pop() - self.reg_bindings[v] = loc - self.Load(v, prev_loc, loc) - else: - loc = self.stack_loc(v) - self.Store(v, prev_loc, loc) - - def force_result_in_reg(self, result_v, v, forbidden_vars): - """ Make sure that result is in the same register as v - and v is copied away if it's further used - """ - if isinstance(v, Const): - loc = self.make_sure_var_in_reg(v, forbidden_vars, - imm_fine=False) - assert not isinstance(loc, IMM8) - self.reg_bindings[result_v] = loc - self.free_regs = [reg for reg in self.free_regs if reg is not loc] - return loc - if v not in self.reg_bindings: - prev_loc = self.stack_bindings[v] - loc = self.force_allocate_reg(v, forbidden_vars) - self.Load(v, prev_loc, loc) - assert v in self.reg_bindings - if self.longevity[v][1] > self.position: - # we need to find a new place for variable v and - # store result in the same place - loc = self.reg_bindings[v] - del self.reg_bindings[v] - if v not in self.stack_bindings: - self.move_variable_away(v, loc) - self.reg_bindings[result_v] = loc - else: - self.reallocate_from_to(v, result_v) - loc = self.reg_bindings[result_v] - return loc + return self.rm.loc(v) def _consider_guard(self, op, ignored): loc = self.make_sure_var_in_reg(op.args[0], []) @@ -501,7 +266,7 @@ locs = [self.loc(arg) for arg in op.args] self.assembler.generate_failure(self.assembler.mc, op.descr, op.args, locs, self.exc) - self.eventually_free_vars(op.args) + self.rm.possibly_free_vars(op.args) consider_finish = consider_fail # for now @@ -540,8 +305,8 @@ def _consider_binop_part(self, op, ignored): x = op.args[0] argloc = self.loc(op.args[1]) - loc = self.force_result_in_reg(op.result, x, op.args) - self.eventually_free_var(op.args[1]) + loc = self.rm.force_result_in_reg(op.result, x, op.args) + self.rm.possibly_free_var(op.args[1]) return loc, argloc def _consider_binop(self, op, ignored): @@ -601,13 +366,12 @@ vx = op.args[0] vy = op.args[1] arglocs = [self.loc(vx), self.loc(vy)] - if (vx in self.reg_bindings or vy in self.reg_bindings or + if (vx in self.rm.reg_bindings or vy in self.rm.reg_bindings or isinstance(vx, Const) or isinstance(vy, Const)): pass else: arglocs[0] = self.make_sure_var_in_reg(vx, []) - self.eventually_free_var(vx) - self.eventually_free_var(vy) + self.rm.possibly_free_vars(op.args) if guard_op is None: loc = self.force_allocate_reg(op.result, op.args, need_lower_byte=True) @@ -885,13 +649,13 @@ arglocs = assembler.target_arglocs(self.jump_target) # compute 'tmploc' to be REGS[0] by spilling what is there box = TempBox() - tmploc = self.force_allocate_reg(box, [], selected_reg=REGS[0]) - src_locations = [self.loc(arg) for arg in op.args] + tmploc = self.rm.force_allocate_reg(box, [], selected_reg=REGS[0]) + src_locations = [self.rm.loc(arg) for arg in op.args] dst_locations = arglocs assert tmploc not in dst_locations remap_stack_layout(assembler, src_locations, dst_locations, tmploc) - self.eventually_free_var(box) - self.eventually_free_vars(op.args) + self.rm.possibly_free_var(box) + self.rm.possibly_free_vars(op.args) assembler.closing_jump(self.jump_target) def consider_debug_merge_point(self, op, ignored): @@ -936,11 +700,6 @@ # exactly 4 PUSHes. return -WORD * (4 + position) -def stack_pos(i): - res = mem(ebp, get_ebp_ofs(i)) - res.position = i - return res - def lower_byte(reg): # argh, kill, use lowest8bits instead if isinstance(reg, MODRM): From fijal at codespeak.net Mon Sep 28 14:23:00 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 14:23:00 +0200 (CEST) Subject: [pypy-svn] r67929 - in pypy/branch/refactor-x86/pypy/jit/backend/llsupport: . test Message-ID: <20090928122300.A4CC3168042@codespeak.net> Author: fijal Date: Mon Sep 28 14:22:59 2009 New Revision: 67929 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Log: Support for calls Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 14:22:59 2009 @@ -38,14 +38,16 @@ class RegisterManager(object): """ Class that keeps track of register allocations """ - def __init__(self, register_pool, longevity, no_lower_byte_regs=(), + no_lower_byte_regs = () + save_around_call_regs = () + + def __init__(self, register_pool, longevity, stack_manager=None, assembler=None): self.free_regs = register_pool[:] self.all_regs = register_pool self.longevity = longevity self.reg_bindings = {} self.position = -1 - self.no_lower_byte_regs = no_lower_byte_regs self.stack_manager = stack_manager self.assembler = assembler @@ -243,7 +245,38 @@ loc = self.reg_bindings[result_v] return loc + def sync_var(self, v): + if not self.stack_manager.get(v): + reg = self.reg_bindings[v] + self.assembler.regalloc_mov(reg, self.stack_manager.loc(v)) + # otherwise it's clean + + def before_call(self, force_store=[]): + for v, reg in self.reg_bindings.items(): + if v not in force_store and self.longevity[v][1] <= self.position: + # variable dies + del self.reg_bindings[v] + self.free_regs.append(reg) + continue + if reg not in self.save_around_call_regs: + # we don't need to + continue + self.sync_var(v) + del self.reg_bindings[v] + self.free_regs.append(reg) + + def after_call(self, v): + if v is not None: + r = self.result_stored_in_reg(v) + self.reg_bindings[v] = r + self.free_regs = [fr for fr in self.free_regs if fr is not r] + # abstract methods, override def convert_to_imm(self, c): raise NotImplementedError("Abstract") + + def result_stored_in_reg(self, v): + # takes a variable and tells where the result will be + # stored + raise NotImplementedError("Abstract") Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Mon Sep 28 14:22:59 2009 @@ -75,13 +75,16 @@ def test_need_lower_byte(self): boxes, longevity = boxes_and_longevity(5) b0, b1, b2, b3, b4 = boxes - no_lower_byte_regs = [r2, r3] - rm = RegisterManager(regs, longevity, no_lower_byte_regs) + + class XRegisterManager(RegisterManager): + no_lower_byte_regs = [r2, r3] + + rm = XRegisterManager(regs, longevity) rm.next_instruction() loc0 = rm.try_allocate_reg(b0, need_lower_byte=True) - assert loc0 not in no_lower_byte_regs + assert loc0 not in XRegisterManager.no_lower_byte_regs loc = rm.try_allocate_reg(b1, need_lower_byte=True) - assert loc not in no_lower_byte_regs + assert loc not in XRegisterManager.no_lower_byte_regs loc = rm.try_allocate_reg(b2, need_lower_byte=True) assert loc is None loc = rm.try_allocate_reg(b0, need_lower_byte=True) @@ -107,10 +110,13 @@ boxes, longevity = boxes_and_longevity(5) b0, b1, b2, b3, b4 = boxes sm = TStackManager() - rm = RegisterManager(regs, longevity, - no_lower_byte_regs = [r2, r3], - stack_manager=sm, - assembler=MockAsm()) + + class XRegisterManager(RegisterManager): + no_lower_byte_regs = [r2, r3] + + rm = XRegisterManager(regs, longevity, + stack_manager=sm, + assembler=MockAsm()) rm.next_instruction() loc = rm.force_allocate_reg(b0) assert isinstance(loc, FakeReg) @@ -235,3 +241,26 @@ rm = RegisterManager(regs, {}) rm.next_instruction() assert isinstance(rm.loc(ConstInt(1)), ConstInt) + + def test_call_support(self): + class XRegisterManager(RegisterManager): + save_around_call_regs = [r1, r2] + + def result_stored_in_reg(self, v): + return r1 + + sm = TStackManager() + asm = MockAsm() + boxes, longevity = boxes_and_longevity(5) + rm = XRegisterManager(regs, longevity, stack_manager=sm, + assembler=asm) + for b in boxes[:-1]: + rm.force_allocate_reg(b) + rm.before_call() + assert len(rm.reg_bindings) == 2 + assert sm.stack_depth == 2 + assert len(asm.moves) == 2 + rm._check_invariants() + rm.after_call(boxes[-1]) + assert len(rm.reg_bindings) == 3 + rm._check_invariants() From fijal at codespeak.net Mon Sep 28 14:51:35 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 14:51:35 +0200 (CEST) Subject: [pypy-svn] r67930 - in pypy/branch/refactor-x86/pypy/jit/backend/llsupport: . test Message-ID: <20090928125135.134FF168042@codespeak.net> Author: fijal Date: Mon Sep 28 14:51:34 2009 New Revision: 67930 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Log: A test and a fix Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 14:51:34 2009 @@ -187,7 +187,7 @@ self.free_regs.append(loc) self.Load(v, convert_to_imm(v), loc) return loc - return convert_to_imm(v) + return self.convert_to_imm(v) def make_sure_var_in_reg(self, v, forbidden_vars=[], selected_reg=None, imm_fine=True, need_lower_byte=False): Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Mon Sep 28 14:51:34 2009 @@ -225,6 +225,8 @@ assert loc is r1 loc = rm.return_constant(ConstInt(1), selected_reg=r1) assert loc is r1 + loc = rm.return_constant(ConstInt(1), imm_fine=True) + assert isinstance(loc, ConstInt) def test_force_result_in_reg_const(self): boxes, longevity = boxes_and_longevity(2) From fijal at codespeak.net Mon Sep 28 15:02:41 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 15:02:41 +0200 (CEST) Subject: [pypy-svn] r67931 - pypy/branch/refactor-x86/pypy/jit/backend/x86 Message-ID: <20090928130241.DC840168008@codespeak.net> Author: fijal Date: Mon Sep 28 15:02:35 2009 New Revision: 67931 Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Log: Progress, now got stopped by cond_gc_call_wb, which directly uses weird hacks Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Mon Sep 28 15:02:35 2009 @@ -31,6 +31,13 @@ return checkdict() class X86RegisterManager(RegisterManager): + + no_lower_byte_regs = [esi, edi] + save_around_call_regs = [eax, edx, ecx] + + def result_stored_in_reg(self, v): + return eax + def convert_to_imm(self, c): if isinstance(c, ConstInt): return imm(c.value) @@ -66,13 +73,12 @@ self.jump_target = None def prepare_loop(self, inputargs, operations): + self.sm = X86StackManager() cpu = self.assembler.cpu cpu.gc_ll_descr.rewrite_assembler(cpu, operations) # compute longevity of variables longevity = self._compute_vars_longevity(inputargs, operations) - self.sm = X86StackManager() self.rm = X86RegisterManager(REGS, longevity, - no_lower_byte_regs = [esi, edi], stack_manager = self.sm, assembler = self.assembler) jump = operations[-1] @@ -81,14 +87,17 @@ return self._process_inputargs(inputargs) def prepare_bridge(self, prev_stack_depth, inputargs, arglocs, operations): - xxxx + self.sm = X86StackManager() cpu = self.assembler.cpu cpu.gc_ll_descr.rewrite_assembler(cpu, operations) # compute longevity of variables - self._compute_vars_longevity(inputargs, operations) + longevity = self._compute_vars_longevity(inputargs, operations) + self.rm = X86RegisterManager(REGS, longevity, + stack_manager = self.sm, + assembler = self.assembler) self.loop_consts = {} self._update_bindings(arglocs, inputargs) - self.current_stack_depth = prev_stack_depth + self.sm.stack_depth = prev_stack_depth def _process_inputargs(self, inputargs): # XXX we can sort out here by longevity if we need something @@ -126,6 +135,7 @@ return loop_consts def _update_bindings(self, locs, args): + # XXX this should probably go to llsupport/regalloc.py newlocs = [] for loc in locs: if not isinstance(loc, IMM8) and not isinstance(loc, IMM32): @@ -136,16 +146,16 @@ for i in range(len(locs)): v = args[i] loc = locs[i] - if isinstance(loc, REG) and self.longevity[v][1] > -1: - self.reg_bindings[v] = loc + if isinstance(loc, REG) and self.rm.longevity[v][1] > -1: + self.rm.reg_bindings[v] = loc used[loc] = None else: self.stack_bindings[v] = loc - self.free_regs = [] + self.rm.free_regs = [] for reg in REGS: if reg not in used: - self.free_regs.append(reg) - self._check_invariants() + self.rm.free_regs.append(reg) + self.rm._check_invariants() def Perform(self, op, arglocs, result_loc): if not we_are_translated(): @@ -168,7 +178,6 @@ self.rm.possibly_free_vars(guard_op.suboperations[0].args) def perform_guard(self, guard_op, arglocs, result_loc): - xxx faillocs = self.locs_for_fail(guard_op) if not we_are_translated(): if result_loc is not None: @@ -178,8 +187,8 @@ self.assembler.dump('%s(%s)' % (guard_op, arglocs)) self.assembler.regalloc_perform_guard(guard_op, faillocs, arglocs, result_loc, - self.current_stack_depth) - self.eventually_free_vars(guard_op.suboperations[0].args) + self.sm.stack_depth) + self.rm.possibly_free_vars(guard_op.suboperations[0].args) def PerformDiscard(self, op, arglocs): if not we_are_translated(): @@ -255,9 +264,9 @@ return self.rm.loc(v) def _consider_guard(self, op, ignored): - loc = self.make_sure_var_in_reg(op.args[0], []) + loc = self.rm.make_sure_var_in_reg(op.args[0]) self.perform_guard(op, [loc], None) - self.eventually_free_var(op.args[0]) + self.rm.possibly_free_var(op.args[0]) consider_guard_true = _consider_guard consider_guard_false = _consider_guard @@ -274,33 +283,33 @@ self.perform_guard(op, [], None) def consider_guard_exception(self, op, ignored): - loc = self.make_sure_var_in_reg(op.args[0], []) + loc = self.rm.make_sure_var_in_reg(op.args[0]) box = TempBox() - loc1 = self.force_allocate_reg(box, op.args) - if op.result in self.longevity: + loc1 = self.rm.force_allocate_reg(box, op.args) + if op.result in self.rm.longevity: # this means, is it ever used - resloc = self.force_allocate_reg(op.result, op.args + [box]) + resloc = self.rm.force_allocate_reg(op.result, op.args + [box]) else: resloc = None self.perform_guard(op, [loc, loc1], resloc) - self.eventually_free_vars(op.args) - self.eventually_free_var(box) + self.rm.possibly_free_vars(op.args) + self.rm.possibly_free_var(box) consider_guard_no_overflow = consider_guard_no_exception consider_guard_overflow = consider_guard_no_exception def consider_guard_value(self, op, ignored): - x = self.make_sure_var_in_reg(op.args[0], []) + x = self.rm.make_sure_var_in_reg(op.args[0]) y = self.loc(op.args[1]) self.perform_guard(op, [x, y], None) - self.eventually_free_vars(op.args) + self.rm.possibly_free_vars(op.args) def consider_guard_class(self, op, ignored): assert isinstance(op.args[0], Box) - x = self.make_sure_var_in_reg(op.args[0], []) + x = self.rm.make_sure_var_in_reg(op.args[0]) y = self.loc(op.args[1]) self.perform_guard(op, [x, y], None) - self.eventually_free_vars(op.args) + self.rm.possibly_free_vars(op.args) def _consider_binop_part(self, op, ignored): x = op.args[0] @@ -325,7 +334,7 @@ consider_int_add_ovf = _consider_binop def consider_int_neg(self, op, ignored): - res = self.force_result_in_reg(op.result, op.args[0], []) + res = self.rm.force_result_in_reg(op.result, op.args[0]) self.Perform(op, [res], res) consider_int_invert = consider_int_neg @@ -335,24 +344,26 @@ if isinstance(op.args[1], Const): loc2 = convert_to_imm(op.args[1]) else: - loc2 = self.make_sure_var_in_reg(op.args[1], [], ecx) - loc1 = self.force_result_in_reg(op.result, op.args[0], op.args) + loc2 = self.rm.make_sure_var_in_reg(op.args[1], selected_reg=ecx) + loc1 = self.rm.force_result_in_reg(op.result, op.args[0], op.args) self.Perform(op, [loc1, loc2], loc1) - self.eventually_free_vars(op.args) + self.rm.possibly_free_vars(op.args) consider_int_rshift = consider_int_lshift consider_uint_rshift = consider_int_lshift def _consider_int_div_or_mod(self, op, resultreg, trashreg): - l0 = self.make_sure_var_in_reg(op.args[0], [], eax) - l1 = self.make_sure_var_in_reg(op.args[1], [], ecx) - l2 = self.force_allocate_reg(op.result, [], resultreg) + l0 = self.rm.make_sure_var_in_reg(op.args[0], selected_reg=eax) + l1 = self.rm.make_sure_var_in_reg(op.args[1], selected_reg=ecx) + l2 = self.rm.force_allocate_reg(op.result, selected_reg=resultreg) # the register (eax or edx) not holding what we are looking for # will be just trash after that operation tmpvar = TempBox() - self.force_allocate_reg(tmpvar, [], trashreg) - assert (l0, l1, l2) == (eax, ecx, resultreg) - self.eventually_free_vars(op.args + [tmpvar]) + self.rm.force_allocate_reg(tmpvar, selected_reg=trashreg) + assert l0 is eax + assert l1 is ecx + assert l2 is resultreg + self.rm.possibly_free_vars(op.args + [tmpvar]) def consider_int_mod(self, op, ignored): self._consider_int_div_or_mod(op, edx, eax) @@ -370,11 +381,11 @@ isinstance(vx, Const) or isinstance(vy, Const)): pass else: - arglocs[0] = self.make_sure_var_in_reg(vx, []) + arglocs[0] = self.rm.make_sure_var_in_reg(vx) self.rm.possibly_free_vars(op.args) if guard_op is None: - loc = self.force_allocate_reg(op.result, op.args, - need_lower_byte=True) + loc = self.rm.force_allocate_reg(op.result, op.args, + need_lower_byte=True) self.Perform(op, arglocs, loc) else: self.perform_with_guard(op, guard_op, arglocs, None) @@ -399,24 +410,9 @@ # otherwise it's clean def _call(self, op, arglocs, force_store=[]): - # we need to store all variables which are now - # in registers eax, ecx and edx - for v, reg in self.reg_bindings.items(): - if v not in force_store and self.longevity[v][1] <= self.position: - # variable dies - del self.reg_bindings[v] - self.free_regs.append(reg) - continue - if reg is ebx or reg is esi or reg is edi: - # we don't need to - continue - self.sync_var(v) - del self.reg_bindings[v] - self.free_regs.append(reg) - if op.result is not None: - self.reg_bindings[op.result] = eax - self.free_regs = [reg for reg in self.free_regs if reg is not eax] + self.rm.before_call(force_store) self.Perform(op, arglocs, eax) + self.rm.after_call(op.result) def consider_call(self, op, ignored): calldescr = op.descr @@ -485,17 +481,17 @@ def _malloc_varsize(self, ofs_items, ofs_length, scale, v, res_v): # XXX kill this function at some point if isinstance(v, Box): - loc = self.make_sure_var_in_reg(v, [v]) - other_loc = self.force_allocate_reg(TempBox(), [v]) + loc = self.rm.make_sure_var_in_reg(v, [v]) + other_loc = self.rm.force_allocate_reg(TempBox(), [v]) self.assembler.load_effective_addr(loc, ofs_items,scale, other_loc) else: other_loc = imm(ofs_items + (v.getint() << scale)) self._call(ResOperation(rop.NEW, [v], res_v), [other_loc], [v]) - loc = self.make_sure_var_in_reg(v, [res_v]) + loc = self.rm.make_sure_var_in_reg(v, [res_v]) assert self.loc(res_v) == eax # now we have to reload length to some reasonable place - self.eventually_free_var(v) + self.rm.possibly_free_var(v) self.PerformDiscard(ResOperation(rop.SETFIELD_GC, [], None), [eax, imm(ofs_length), imm(WORD), loc]) @@ -537,35 +533,35 @@ need_lower_byte = True else: need_lower_byte = False - base_loc = self.make_sure_var_in_reg(op.args[0], op.args) - value_loc = self.make_sure_var_in_reg(op.args[1], op.args, + base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) + value_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args, need_lower_byte=need_lower_byte) - self.eventually_free_vars(op.args) + self.rm.possibly_free_vars(op.args) self.PerformDiscard(op, [base_loc, ofs_loc, size_loc, value_loc]) consider_setfield_raw = consider_setfield_gc def consider_strsetitem(self, op, ignored): - base_loc = self.make_sure_var_in_reg(op.args[0], op.args) - ofs_loc = self.make_sure_var_in_reg(op.args[1], op.args) - value_loc = self.make_sure_var_in_reg(op.args[2], op.args, - need_lower_byte=True) - self.eventually_free_vars([op.args[0], op.args[1], op.args[2]]) + base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) + ofs_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args) + value_loc = self.rm.make_sure_var_in_reg(op.args[2], op.args, + need_lower_byte=True) + self.rm.possibly_free_vars(op.args) self.PerformDiscard(op, [base_loc, ofs_loc, value_loc]) consider_unicodesetitem = consider_strsetitem def consider_setarrayitem_gc(self, op, ignored): scale, ofs, ptr = self._unpack_arraydescr(op.descr) - base_loc = self.make_sure_var_in_reg(op.args[0], op.args) + base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) if scale == 0: need_lower_byte = True else: need_lower_byte = False - value_loc = self.make_sure_var_in_reg(op.args[2], op.args, + value_loc = self.rm.make_sure_var_in_reg(op.args[2], op.args, need_lower_byte=need_lower_byte) - ofs_loc = self.make_sure_var_in_reg(op.args[1], op.args) - self.eventually_free_vars(op.args) + ofs_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args) + self.rm.possibly_free_vars(op.args) self.PerformDiscard(op, [base_loc, ofs_loc, value_loc, imm(scale), imm(ofs)]) @@ -573,19 +569,19 @@ def consider_getfield_gc(self, op, ignored): ofs_loc, size_loc, _ = self._unpack_fielddescr(op.descr) - base_loc = self.make_sure_var_in_reg(op.args[0], op.args) - self.eventually_free_vars(op.args) - result_loc = self.force_allocate_reg(op.result, []) + base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) + self.rm.possibly_free_vars(op.args) + result_loc = self.rm.force_allocate_reg(op.result) self.Perform(op, [base_loc, ofs_loc, size_loc], result_loc) consider_getfield_gc_pure = consider_getfield_gc def consider_getarrayitem_gc(self, op, ignored): scale, ofs, _ = self._unpack_arraydescr(op.descr) - base_loc = self.make_sure_var_in_reg(op.args[0], op.args) - ofs_loc = self.make_sure_var_in_reg(op.args[1], op.args) - self.eventually_free_vars(op.args) - result_loc = self.force_allocate_reg(op.result, []) + base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) + ofs_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args) + self.rm.possibly_free_vars(op.args) + result_loc = self.rm.force_allocate_reg(op.result) self.Perform(op, [base_loc, ofs_loc, imm(scale), imm(ofs)], result_loc) consider_getfield_raw = consider_getfield_gc @@ -595,14 +591,13 @@ def _consider_nullity(self, op, guard_op): # doesn't need a register in arg if guard_op is not None: - argloc = self.make_sure_var_in_reg(op.args[0], []) - self.eventually_free_var(op.args[0]) + argloc = self.rm.make_sure_var_in_reg(op.args[0]) + self.rm.possibly_free_var(op.args[0]) self.perform_with_guard(op, guard_op, [argloc], None) else: argloc = self.loc(op.args[0]) - self.eventually_free_var(op.args[0]) - resloc = self.force_allocate_reg(op.result, [], - need_lower_byte=True) + self.rm.possibly_free_var(op.args[0]) + resloc = self.rm.force_allocate_reg(op.result, need_lower_byte=True) self.Perform(op, [argloc], resloc) consider_int_is_true = _consider_nullity @@ -611,15 +606,15 @@ def consider_same_as(self, op, ignored): argloc = self.loc(op.args[0]) - self.eventually_free_var(op.args[0]) - resloc = self.force_allocate_reg(op.result, []) + self.rm.possibly_free_var(op.args[0]) + resloc = self.rm.force_allocate_reg(op.result) self.Perform(op, [argloc], resloc) consider_cast_ptr_to_int = consider_same_as def consider_strlen(self, op, ignored): - base_loc = self.make_sure_var_in_reg(op.args[0], op.args) - self.eventually_free_vars(op.args) - result_loc = self.force_allocate_reg(op.result, []) + base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) + self.rm.possibly_free_vars(op.args) + result_loc = self.rm.force_allocate_reg(op.result) self.Perform(op, [base_loc], result_loc) consider_unicodelen = consider_strlen @@ -628,16 +623,16 @@ arraydescr = op.descr assert isinstance(arraydescr, BaseArrayDescr) ofs = arraydescr.get_ofs_length(self.translate_support_code) - base_loc = self.make_sure_var_in_reg(op.args[0], op.args) - self.eventually_free_vars(op.args) - result_loc = self.force_allocate_reg(op.result, []) + base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) + self.rm.possibly_free_vars(op.args) + result_loc = self.rm.force_allocate_reg(op.result, []) self.Perform(op, [base_loc, imm(ofs)], result_loc) def consider_strgetitem(self, op, ignored): - base_loc = self.make_sure_var_in_reg(op.args[0], op.args) - ofs_loc = self.make_sure_var_in_reg(op.args[1], op.args) - self.eventually_free_vars([op.args[0], op.args[1]]) - result_loc = self.force_allocate_reg(op.result, []) + base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) + ofs_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args) + self.rm.possibly_free_vars(op.args) + result_loc = self.rm.force_allocate_reg(op.result) self.Perform(op, [base_loc, ofs_loc], result_loc) consider_unicodegetitem = consider_strgetitem From cfbolz at codespeak.net Mon Sep 28 15:10:04 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 28 Sep 2009 15:10:04 +0200 (CEST) Subject: [pypy-svn] r67932 - in pypy/trunk/pypy: module/marshal objspace rlib Message-ID: <20090928131004.7EAF4168009@codespeak.net> Author: cfbolz Date: Mon Sep 28 15:10:03 2009 New Revision: 67932 Added: pypy/trunk/pypy/module/marshal/ - copied from r67931, pypy/branch/bigint-rlonglong/pypy/module/marshal/ pypy/trunk/pypy/objspace/ - copied from r67931, pypy/branch/bigint-rlonglong/pypy/objspace/ pypy/trunk/pypy/rlib/ - copied from r67931, pypy/branch/bigint-rlonglong/pypy/rlib/ Log: merge the bigint-rlonglong branch: a saner implementation of big integers (e.g. longs in the Python interpreter). From cfbolz at codespeak.net Mon Sep 28 15:10:28 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 28 Sep 2009 15:10:28 +0200 (CEST) Subject: [pypy-svn] r67933 - pypy/branch/bigint-rlonglong Message-ID: <20090928131028.7BC3F168007@codespeak.net> Author: cfbolz Date: Mon Sep 28 15:10:27 2009 New Revision: 67933 Removed: pypy/branch/bigint-rlonglong/ Log: kill merged branch From fijal at codespeak.net Mon Sep 28 16:06:23 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 16:06:23 +0200 (CEST) Subject: [pypy-svn] r67934 - pypy/branch/refactor-x86/pypy/jit/backend/x86 Message-ID: <20090928140623.072C0168008@codespeak.net> Author: fijal Date: Mon Sep 28 16:06:21 2009 New Revision: 67934 Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Log: Use register manager here. armin, please write a comment why it's a hack Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Mon Sep 28 16:06:21 2009 @@ -428,9 +428,9 @@ arglocs = [self.loc(arg) for arg in op.args] # add eax, ecx and edx as extra "arguments" to ensure they are # saved and restored. - for v, reg in self.reg_bindings.items(): + for v, reg in self.rm.reg_bindings.items(): if ((reg is eax or reg is ecx or reg is edx) - and self.longevity[v][1] > self.position + and self.rm.longevity[v][1] > self.rm.position and reg not in arglocs[3:]): arglocs.append(reg) self.PerformDiscard(op, arglocs) From fijal at codespeak.net Mon Sep 28 16:07:33 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 16:07:33 +0200 (CEST) Subject: [pypy-svn] r67935 - pypy/branch/refactor-x86/pypy/jit/backend/x86 Message-ID: <20090928140733.D4B4E168008@codespeak.net> Author: fijal Date: Mon Sep 28 16:07:33 2009 New Revision: 67935 Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Log: Enough to pass test_runner Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Mon Sep 28 16:07:33 2009 @@ -342,7 +342,7 @@ def consider_int_lshift(self, op, ignored): if isinstance(op.args[1], Const): - loc2 = convert_to_imm(op.args[1]) + loc2 = self.rm.convert_to_imm(op.args[1]) else: loc2 = self.rm.make_sure_var_in_reg(op.args[1], selected_reg=ecx) loc1 = self.rm.force_result_in_reg(op.result, op.args[0], op.args) @@ -434,7 +434,7 @@ and reg not in arglocs[3:]): arglocs.append(reg) self.PerformDiscard(op, arglocs) - self.eventually_free_vars(op.args) + self.rm.possibly_free_vars(op.args) def consider_new(self, op, ignored): args = self.assembler.cpu.gc_ll_descr.args_for_new(op.descr) From arigo at codespeak.net Mon Sep 28 16:17:49 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 28 Sep 2009 16:17:49 +0200 (CEST) Subject: [pypy-svn] r67936 - in pypy/branch/refactor-x86/pypy: jit/backend/x86 rpython/memory/gc Message-ID: <20090928141749.CB474168008@codespeak.net> Author: arigo Date: Mon Sep 28 16:17:49 2009 New Revision: 67936 Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py pypy/branch/refactor-x86/pypy/rpython/memory/gc/generation.py Log: Add comments about cond_call_gc_wb's particular register usage pattern. Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Mon Sep 28 16:17:49 2009 @@ -403,12 +403,6 @@ consider_oois = _consider_compop consider_ooisnot = _consider_compop - def sync_var(self, v): - if v not in self.stack_bindings: - reg = self.reg_bindings[v] - self.Store(v, reg, self.stack_loc(v)) - # otherwise it's clean - def _call(self, op, arglocs, force_store=[]): self.rm.before_call(force_store) self.Perform(op, arglocs, eax) @@ -427,7 +421,11 @@ assert op.result is None arglocs = [self.loc(arg) for arg in op.args] # add eax, ecx and edx as extra "arguments" to ensure they are - # saved and restored. + # saved and restored. Fish in self.rm to know which of these + # registers really need to be saved (a bit of a hack). Moreover, + # we don't save and restore any SSE register because the called + # function, a GC write barrier, is known not to touch them. + # See remember_young_pointer() in rpython/memory/gc/generation.py. for v, reg in self.rm.reg_bindings.items(): if ((reg is eax or reg is ecx or reg is edx) and self.rm.longevity[v][1] > self.rm.position Modified: pypy/branch/refactor-x86/pypy/rpython/memory/gc/generation.py ============================================================================== --- pypy/branch/refactor-x86/pypy/rpython/memory/gc/generation.py (original) +++ pypy/branch/refactor-x86/pypy/rpython/memory/gc/generation.py Mon Sep 28 16:17:49 2009 @@ -434,6 +434,9 @@ # instead of keeping it as a regular method is to help the JIT call it. # Additionally, it makes the code in write_barrier() marginally smaller # (which is important because it is inlined *everywhere*). + # For x86, there is also an extra requirement: when the JIT calls + # remember_young_pointer(), it assumes that it will not touch the SSE + # registers, so it does not save and restore them (that's a *hack*!). def remember_young_pointer(addr_struct, addr): #llop.debug_print(lltype.Void, "\tremember_young_pointer", # addr_struct, "<-", addr) From fijal at codespeak.net Mon Sep 28 16:32:03 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 16:32:03 +0200 (CEST) Subject: [pypy-svn] r67937 - in pypy/branch/refactor-x86/pypy/jit/backend/llsupport: . test Message-ID: <20090928143203.9EE0A168008@codespeak.net> Author: fijal Date: Mon Sep 28 16:32:03 2009 New Revision: 67937 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Log: A test a fix and add a little helper Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 16:32:03 2009 @@ -51,6 +51,9 @@ self.stack_manager = stack_manager self.assembler = assembler + def stays_alive(self, v): + return self.longevity[v][1] > self.position + def next_instruction(self, incr=1): self.position += incr @@ -185,7 +188,7 @@ return loc loc = self._spill_var(v, forbidden_vars, selected_reg) self.free_regs.append(loc) - self.Load(v, convert_to_imm(v), loc) + self.assembler.regalloc_mov(self.convert_to_imm(v), loc) return loc return self.convert_to_imm(v) Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Mon Sep 28 16:32:03 2009 @@ -217,7 +217,10 @@ def test_return_constant(self): asm = MockAsm() - rm = RegisterManager(regs, {}, assembler=asm) + boxes, longevity = boxes_and_longevity(5) + sm = TStackManager() + rm = RegisterManager(regs, longevity, assembler=asm, + stack_manager=sm) rm.next_instruction() loc = rm.return_constant(ConstInt(0), imm_fine=False) assert isinstance(loc, FakeReg) @@ -227,6 +230,12 @@ assert loc is r1 loc = rm.return_constant(ConstInt(1), imm_fine=True) assert isinstance(loc, ConstInt) + for box in boxes[:-1]: + rm.force_allocate_reg(box) + assert len(asm.moves) == 4 + loc = rm.return_constant(ConstInt(1), imm_fine=False) + assert isinstance(loc, FakeReg) + assert len(asm.moves) == 6 def test_force_result_in_reg_const(self): boxes, longevity = boxes_and_longevity(2) From fijal at codespeak.net Mon Sep 28 16:39:06 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 16:39:06 +0200 (CEST) Subject: [pypy-svn] r67938 - in pypy/branch/refactor-x86/pypy/jit/backend/x86: . test Message-ID: <20090928143906.83528168008@codespeak.net> Author: fijal Date: Mon Sep 28 16:39:05 2009 New Revision: 67938 Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/jump.py pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_gc_integration.py pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py Log: * Skip direct tests, I don't think they're relevant, they need review though * Fix a couple of issues, mostly done Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/jump.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/jump.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/jump.py Mon Sep 28 16:39:05 2009 @@ -76,8 +76,8 @@ def _move(assembler, src, dst, tmpreg): if isinstance(dst, MODRM): if isinstance(src, MODRM): - assembler.regalloc_load(src, tmpreg) + assembler.regalloc_mov(src, tmpreg) src = tmpreg - assembler.regalloc_store(src, dst) + assembler.regalloc_mov(src, dst) else: - assembler.regalloc_load(src, dst) + assembler.regalloc_mov(src, dst) Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Mon Sep 28 16:39:05 2009 @@ -68,7 +68,6 @@ # variables that have place in register self.assembler = assembler self.translate_support_code = translate_support_code - self.position = -1 # to be read/used by the assembler too self.jump_target = None @@ -150,7 +149,7 @@ self.rm.reg_bindings[v] = loc used[loc] = None else: - self.stack_bindings[v] = loc + self.sm.stack_bindings[v] = loc self.rm.free_regs = [] for reg in REGS: if reg not in used: @@ -170,7 +169,7 @@ def perform_with_guard(self, op, guard_op, arglocs, result_loc): faillocs = self.locs_for_fail(guard_op) - self.position += 1 + self.rm.next_instruction() self.assembler.regalloc_perform_with_guard(op, guard_op, faillocs, arglocs, result_loc, self.sm.stack_depth) @@ -656,14 +655,12 @@ def get_mark_gc_roots(self, gcrootmap): shape = gcrootmap.get_basic_shape() - for v, val in self.stack_bindings.items(): - if (isinstance(v, BoxPtr) and - self.longevity[v][1] > self.position): + for v, val in self.sm.stack_bindings.items(): + if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)): assert isinstance(val, MODRM) gcrootmap.add_ebp_offset(shape, get_ebp_ofs(val.position)) - for v, reg in self.reg_bindings.items(): - if (isinstance(v, BoxPtr) and - self.longevity[v][1] > self.position): + for v, reg in self.rm.reg_bindings.items(): + if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)): if reg is ebx: gcrootmap.add_ebx(shape) elif reg is esi: Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_gc_integration.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_gc_integration.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_gc_integration.py Mon Sep 28 16:39:05 2009 @@ -53,6 +53,9 @@ class TestRegallocDirectGcIntegration(object): + def setup_class(cls): + py.test.skip("Rewrite") + def test_mark_gc_roots(self): cpu = CPU(None, None) regalloc = RegAlloc(MockAssembler(cpu, MockGcDescr(False))) Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py Mon Sep 28 16:39:05 2009 @@ -72,6 +72,9 @@ class TestRegallocDirect(object): + def setup_class(cls): + py.test.skip("look and eventually copy, but rather remove") + def test_make_sure_var_in_reg(self): regalloc = RegAlloc(MockAssembler()) boxes = fill_regs(regalloc) From cfbolz at codespeak.net Mon Sep 28 16:45:51 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 28 Sep 2009 16:45:51 +0200 (CEST) Subject: [pypy-svn] r67939 - in pypy/trunk/pypy/translator: backendopt stackless Message-ID: <20090928144551.0C3E6168009@codespeak.net> Author: cfbolz Date: Mon Sep 28 16:45:50 2009 New Revision: 67939 Modified: pypy/trunk/pypy/translator/backendopt/canraise.py pypy/trunk/pypy/translator/backendopt/graphanalyze.py pypy/trunk/pypy/translator/stackless/transform.py Log: Refactor the graph analyzer to be able to use a general lattice instead of just bools. I want to use it to find all the fields of structs that are modified by a graph. Modified: pypy/trunk/pypy/translator/backendopt/canraise.py ============================================================================== --- pypy/trunk/pypy/translator/backendopt/canraise.py (original) +++ pypy/trunk/pypy/translator/backendopt/canraise.py Mon Sep 28 16:45:50 2009 @@ -8,8 +8,8 @@ log = py.log.Producer("canraise") py.log.setconsumer("canraise", ansi_log) -class RaiseAnalyzer(graphanalyze.GraphAnalyzer): - def operation_is_true(self, op): +class RaiseAnalyzer(graphanalyze.BoolGraphAnalyzer): + def analyze_simple_operation(self, op): try: return bool(LL_OPERATIONS[op.opname].canraise) except KeyError: Modified: pypy/trunk/pypy/translator/backendopt/graphanalyze.py ============================================================================== --- pypy/trunk/pypy/translator/backendopt/graphanalyze.py (original) +++ pypy/trunk/pypy/translator/backendopt/graphanalyze.py Mon Sep 28 16:45:50 2009 @@ -3,34 +3,57 @@ from pypy.rpython.lltypesystem import lltype class GraphAnalyzer(object): - """generic way to analyze graphs: recursively follow it until the first - operation is found on which self.operation_is_true returns True""" def __init__(self, translator): self.translator = translator self.analyzed_calls = {} - # methods to be overridden by subclass + # method overridden by subclasses - def operation_is_true(self, op): + @staticmethod + def join_two_results(self, result1, result2): raise NotImplementedError("abstract base class") - def analyze_exceptblock(self, block, seen=None): + @staticmethod + def bottom_result(self): + raise NotImplementedError("abstract base class") + + @staticmethod + def top_result(self): + raise NotImplementedError("abstract base class") + + @staticmethod + def is_top_result(self, result): + # only an optimization, safe to always return False return False + def analyze_simple_operation(self, op): + raise NotImplementedError("abstract base class") + + # some sensible default methods, can also be overridden + + def analyze_exceptblock(self, block, seen=None): + return self.bottom_result() + def analyze_startblock(self, block, seen=None): - return False + return self.bottom_result() def analyze_external_call(self, op): - return True + return self.top_result() def analyze_external_method(self, op, TYPE, meth): - return True + return self.top_result() def analyze_link(self, graph, link): - return False + return self.bottom_result() # general methods + def join_results(self, results): + result = self.bottom_result() + for sub in results: + result = self.join_two_results(result, sub) + return result + def analyze(self, op, seen=None): if op.opname == "direct_call": graph = get_graph(op.args[0], self.translator) @@ -39,7 +62,7 @@ return self.analyze_direct_call(graph, seen) elif op.opname == "indirect_call": if op.args[-1].value is None: - return True + return self.top_result() return self.analyze_indirect_call(op.args[-1].value, seen) elif op.opname == "oosend": name = op.args[0].value @@ -49,8 +72,7 @@ if graph is None: return self.analyze_external_method(op, TYPE, meth) return self.analyze_oosend(TYPE, name, seen) - if self.operation_is_true(op): - return True + return self.analyze_simple_operation(op) def analyze_direct_call(self, graph, seen=None): if graph in self.analyzed_calls: @@ -58,35 +80,34 @@ if seen is None: seen = {} if graph in seen: - self.analyzed_calls[graph] = False - return False + return self.bottom_result() else: seen[graph] = True + result = self.bottom_result() for block in graph.iterblocks(): if block is graph.startblock: - if self.analyze_startblock(block, seen): - self.analyzed_calls[graph] = True - return True - if block is graph.exceptblock: - if self.analyze_exceptblock(block, seen): - self.analyzed_calls[graph] = True - return True + result = self.join_two_results( + result, self.analyze_startblock(block, seen)) + elif block is graph.exceptblock: + result = self.join_two_results( + result, self.analyze_exceptblock(block, seen)) for op in block.operations: - if self.analyze(op, seen): - self.analyzed_calls[graph] = True - return True + result = self.join_two_results( + result, self.analyze(op, seen)) for exit in block.exits: - if self.analyze_link(graph, exit): - self.analyzed_calls[graph] = True - return True - self.analyzed_calls[graph] = False - return False + result = self.join_two_results( + result, self.analyze_link(exit, seen)) + if self.is_top_result(result): + self.analyzed_calls[graph] = result + return result + self.analyzed_calls[graph] = result + return result def analyze_indirect_call(self, graphs, seen=None): + results = [] for graph in graphs: - if self.analyze_direct_call(graph, seen): - return True - return False + results.append(self.analyze_direct_call(graph, seen)) + return self.join_results(results) def analyze_oosend(self, TYPE, name, seen=None): graphs = TYPE._lookup_graphs(name) @@ -98,3 +119,20 @@ for graph in graphs: for block, op in graph.iterblockops(): self.analyze(op) + +class BoolGraphAnalyzer(GraphAnalyzer): + """generic way to analyze graphs: recursively follow it until the first + operation is found on which self.analyze_simple_operation returns True""" + + def join_two_results(self, result1, result2): + return result1 or result2 + + def is_top_result(self, result): + return result + + def bottom_result(self): + return False + + def top_result(self): + return True + Modified: pypy/trunk/pypy/translator/stackless/transform.py ============================================================================== --- pypy/trunk/pypy/translator/stackless/transform.py (original) +++ pypy/trunk/pypy/translator/stackless/transform.py Mon Sep 28 16:45:50 2009 @@ -242,12 +242,12 @@ self.frametypes[key] = (FRAME_TYPE, self.saving_function_for_type(FRAME_TYPE)) -class StacklessAnalyzer(graphanalyze.GraphAnalyzer): +class StacklessAnalyzer(graphanalyze.BoolGraphAnalyzer): def __init__(self, translator, stackless_gc): graphanalyze.GraphAnalyzer.__init__(self, translator) self.stackless_gc = stackless_gc - def operation_is_true(self, op): + def analyze_simple_operation(self, op): if op.opname in ('yield_current_frame_to_caller', 'resume_point', 'resume_state_invoke', 'resume_state_create', 'stack_frames_depth', 'stack_switch', 'stack_unwind', 'stack_capture', From fijal at codespeak.net Mon Sep 28 16:47:53 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 16:47:53 +0200 (CEST) Subject: [pypy-svn] r67940 - pypy/branch/refactor-x86/pypy/jit/backend/x86/test Message-ID: <20090928144753.04AD2168009@codespeak.net> Author: fijal Date: Mon Sep 28 16:47:53 2009 New Revision: 67940 Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_jump.py Log: Fix test Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_jump.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_jump.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_jump.py Mon Sep 28 16:47:53 2009 @@ -1,16 +1,15 @@ from pypy.jit.backend.x86.ri386 import * -from pypy.jit.backend.x86.regalloc import stack_pos +from pypy.jit.backend.x86.regalloc import X86StackManager from pypy.jit.backend.x86.jump import remap_stack_layout +stack_pos = X86StackManager.stack_pos + class MockAssembler: def __init__(self): self.ops = [] - def regalloc_load(self, from_loc, to_loc): - self.ops.append(('load', from_loc, to_loc)) - - def regalloc_store(self, from_loc, to_loc): - self.ops.append(('store', from_loc, to_loc)) + def regalloc_mov(self, from_loc, to_loc): + self.ops.append(('mov', from_loc, to_loc)) def regalloc_push(self, loc): self.ops.append(('push', loc)) @@ -53,9 +52,9 @@ def test_simple_registers(): assembler = MockAssembler() remap_stack_layout(assembler, [eax, ebx, ecx], [edx, esi, edi], '?') - assert assembler.ops == [('load', eax, edx), - ('load', ebx, esi), - ('load', ecx, edi)] + assert assembler.ops == [('mov', eax, edx), + ('mov', ebx, esi), + ('mov', ecx, edi)] def test_simple_stacklocs(): assembler = MockAssembler() @@ -64,10 +63,10 @@ s20 = stack_pos(20) s24 = stack_pos(221) remap_stack_layout(assembler, [s8, eax, s12], [s20, s24, edi], edx) - assert assembler.ops == [('load', s8, edx), - ('store', edx, s20), - ('store', eax, s24), - ('load', s12, edi)] + assert assembler.ops == [('mov', s8, edx), + ('mov', edx, s20), + ('mov', eax, s24), + ('mov', s12, edi)] def test_reordering(): assembler = MockAssembler() @@ -77,10 +76,10 @@ s24 = stack_pos(1) remap_stack_layout(assembler, [eax, s8, s20, ebx], [s8, ebx, eax, edi], '?') - assert assembler.got([('load', ebx, edi), - ('load', s8, ebx), - ('store', eax, s8), - ('load', s20, eax)]) + assert assembler.got([('mov', ebx, edi), + ('mov', s8, ebx), + ('mov', eax, s8), + ('mov', s20, eax)]) def test_cycle(): assembler = MockAssembler() @@ -91,9 +90,9 @@ remap_stack_layout(assembler, [eax, s8, s20, ebx], [s8, ebx, eax, s20], '?') assert assembler.got([('push', s8), - ('store', eax, s8), - ('load', s20, eax), - ('store', ebx, s20), + ('mov', eax, s8), + ('mov', s20, eax), + ('mov', ebx, s20), ('pop', ebx)]) def test_cycle_2(): @@ -108,29 +107,29 @@ [eax, s8, edi, s20, eax, s20, s24, esi, s2, s3], [s8, s20, edi, eax, edx, s24, ebx, s12, s3, s2], ecx) - assert assembler.got([('load', eax, edx), - ('load', s24, ebx), - ('store', esi, s12), - ('load', s20, ecx), - ('store', ecx, s24), + assert assembler.got([('mov', eax, edx), + ('mov', s24, ebx), + ('mov', esi, s12), + ('mov', s20, ecx), + ('mov', ecx, s24), ('push', s8), - ('store', eax, s8), - ('load', s20, eax), + ('mov', eax, s8), + ('mov', s20, eax), ('pop', s20), ('push', s3), - ('load', s2, ecx), - ('store', ecx, s3), + ('mov', s2, ecx), + ('mov', ecx, s3), ('pop', s2)]) def test_constants(): assembler = MockAssembler() c3 = imm(3) remap_stack_layout(assembler, [c3], [eax], '?') - assert assembler.ops == [('load', c3, eax)] + assert assembler.ops == [('mov', c3, eax)] assembler = MockAssembler() s12 = stack_pos(12) remap_stack_layout(assembler, [c3], [s12], '?') - assert assembler.ops == [('store', c3, s12)] + assert assembler.ops == [('mov', c3, s12)] def test_constants_and_cycle(): assembler = MockAssembler() @@ -138,7 +137,7 @@ s12 = stack_pos(13) remap_stack_layout(assembler, [ebx, c3, s12], [s12, eax, ebx], edi) - assert assembler.ops == [('load', c3, eax), + assert assembler.ops == [('mov', c3, eax), ('push', s12), - ('store', ebx, s12), + ('mov', ebx, s12), ('pop', ebx)] From cfbolz at codespeak.net Mon Sep 28 16:50:53 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 28 Sep 2009 16:50:53 +0200 (CEST) Subject: [pypy-svn] r67941 - in pypy/trunk/pypy: rpython/memory/gctransform translator/stackless Message-ID: <20090928145053.0534A168008@codespeak.net> Author: cfbolz Date: Mon Sep 28 16:50:53 2009 New Revision: 67941 Modified: pypy/trunk/pypy/rpython/memory/gctransform/framework.py pypy/trunk/pypy/translator/stackless/transform.py Log: No cookie. Fix two more places. Modified: pypy/trunk/pypy/rpython/memory/gctransform/framework.py ============================================================================== --- pypy/trunk/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/trunk/pypy/rpython/memory/gctransform/framework.py Mon Sep 28 16:50:53 2009 @@ -22,7 +22,7 @@ import sys, types -class CollectAnalyzer(graphanalyze.GraphAnalyzer): +class CollectAnalyzer(graphanalyze.BoolGraphAnalyzer): def analyze_direct_call(self, graph, seen=None): try: @@ -36,7 +36,7 @@ return graphanalyze.GraphAnalyzer.analyze_direct_call(self, graph, seen) - def operation_is_true(self, op): + def analyze_simple_operation(self, op): if op.opname in ('malloc', 'malloc_varsize'): flags = op.args[1].value return flags['flavor'] == 'gc' and not flags.get('nocollect', False) Modified: pypy/trunk/pypy/translator/stackless/transform.py ============================================================================== --- pypy/trunk/pypy/translator/stackless/transform.py (original) +++ pypy/trunk/pypy/translator/stackless/transform.py Mon Sep 28 16:50:53 2009 @@ -826,7 +826,7 @@ continue # go back and look at that malloc if (op.opname in ('direct_call', 'indirect_call') - or self.analyzer.operation_is_true(op)): + or self.analyzer.analyze(op)): if op.opname == 'resume_point': block = self.handle_resume_point(block, i) if block is None: From fijal at codespeak.net Mon Sep 28 17:07:00 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 17:07:00 +0200 (CEST) Subject: [pypy-svn] r67942 - pypy/branch/refactor-x86/pypy/jit/backend/llsupport Message-ID: <20090928150700.00096168008@codespeak.net> Author: fijal Date: Mon Sep 28 17:06:58 2009 New Revision: 67942 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Log: rpython "fixes" Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 17:06:58 2009 @@ -32,14 +32,15 @@ return newloc # abstract methods that need to be overwritten for specific assemblers - def stack_pos(self, loc): + @staticmethod + def stack_pos(loc): raise NotImplementedError("Purely abstract") class RegisterManager(object): """ Class that keeps track of register allocations """ - no_lower_byte_regs = () - save_around_call_regs = () + no_lower_byte_regs = [] + save_around_call_regs = [] def __init__(self, register_pool, longevity, stack_manager=None, assembler=None): From pedronis at codespeak.net Mon Sep 28 17:40:38 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 28 Sep 2009 17:40:38 +0200 (CEST) Subject: [pypy-svn] r67944 - in pypy/branch/resume-data-chaining/pypy/jit/metainterp: . test Message-ID: <20090928154038.22E00168009@codespeak.net> Author: pedronis Date: Mon Sep 28 17:40:37 2009 New Revision: 67944 Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/compile.py pypy/branch/resume-data-chaining/pypy/jit/metainterp/optimizeopt.py pypy/branch/resume-data-chaining/pypy/jit/metainterp/pyjitpl.py pypy/branch/resume-data-chaining/pypy/jit/metainterp/resume.py pypy/branch/resume-data-chaining/pypy/jit/metainterp/simple_optimize.py pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop.py pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop_dummy.py pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop_spec.py pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_optimizeopt.py pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_resume.py Log: (arigo, pedronis) use chaining to capture resume data before optimisation Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/compile.py Mon Sep 28 17:40:37 2009 @@ -197,7 +197,7 @@ def __init__(self, original_greenkey, guard_op): ResumeDescr.__init__(self, original_greenkey) self.guard_op = guard_op - # this class also gets attributes stored by ResumeDataBuilder.finish() + # this class also gets attributes stored by resume.py code def handle_fail(self, metainterp_sd): from pypy.jit.metainterp.pyjitpl import MetaInterp Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/optimizeopt.py Mon Sep 28 17:40:37 2009 @@ -497,26 +497,24 @@ self.exception_might_have_happened = True self.newoperations.append(op) + def _get_faildescr(self, op_fail): + descr = op_fail.descr + assert isinstance(descr, compile.ResumeGuardDescr) + return descr + def clone_guard(self, op2, op1): assert len(op1.suboperations) == 1 op_fail = op1.suboperations[0] assert op_fail.opnum == rop.FAIL - # - if not we_are_translated() and op_fail.descr is None: # for tests - descr = Storage() - builder = resume.ResumeDataBuilder() - builder.generate_boxes(op_fail.args) - builder.finish(descr) - else: - descr = op_fail.descr - assert isinstance(descr, compile.ResumeGuardDescr) + descr = self._get_faildescr(op_fail) oldboxes = [] - for box in op_fail.args: + args = resume.flatten_resumedata(descr) # xxx expensive + for box in args: if box in self.values: box = self.values[box].get_key_box() # may be a Const, too oldboxes.append(box) modifier = resume.ResumeDataVirtualAdder(descr, oldboxes) - for box in op_fail.args: + for box in args: if box in self.values: value = self.values[box] value.get_args_for_fail(modifier) @@ -785,6 +783,3 @@ self.newoperations.append(op) optimize_ops = _findall(Optimizer, 'optimize_') - -class Storage: - "for tests." Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/pyjitpl.py Mon Sep 28 17:40:37 2009 @@ -120,7 +120,9 @@ class MIFrame(object): exception_box = None exc_value_box = None - parent_resumedata = None # for resume.py operation + # for resume.py operation + parent_resumedata_snapshot = None + parent_resumedata_frame_info_list = None def __init__(self, metainterp, jitcode): assert isinstance(jitcode, codewriter.JitCode) @@ -911,9 +913,6 @@ return saved_pc = self.pc self.pc = pc - resumebuilder = resume.ResumeDataBuilder.make(metainterp.framestack) - if metainterp.staticdata.virtualizable_info is not None: - resumebuilder.generate_boxes(metainterp.virtualizable_boxes) if box is not None: moreargs = [box] + extraargs else: @@ -921,9 +920,13 @@ guard_op = metainterp.history.record(opnum, moreargs, None) original_greenkey = metainterp.resumekey.original_greenkey resumedescr = compile.ResumeGuardDescr(original_greenkey, guard_op) - liveboxes = resumebuilder.finish(resumedescr) + virtualizable_boxes = None + if metainterp.staticdata.virtualizable_info is not None: + virtualizable_boxes = metainterp.virtualizable_boxes + resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, + resumedescr) self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count - op = history.ResOperation(rop.FAIL, liveboxes, None, descr=resumedescr) + op = history.ResOperation(rop.FAIL, [], None, descr=resumedescr) guard_op.suboperations = [op] metainterp.attach_debug_info(guard_op) self.pc = saved_pc Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/resume.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/resume.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/resume.py Mon Sep 28 17:40:37 2009 @@ -12,79 +12,177 @@ debug = False -# xxx we would like more "chaining" instead of copying -class ResumeDataBuilder(object): +class Snapshot(object): + __slots__ = ('prev', 'boxes') - def __init__(self, _other=None): - if _other is None: - self.memo = {} - self.liveboxes = [] - self.consts = [] - self.nums = [] - self.frame_infos = [] + def __init__(self, prev, boxes): + self.prev = prev + self.boxes = boxes + +class FrameInfo(object): + __slots__ = ('prev', 'jitcode', 'pc', 'exception_target', 'level') + + def __init__(self, prev, frame): + self.prev = prev + if prev is None: + level = 1 else: - self.memo = _other.memo.copy() - self.liveboxes = _other.liveboxes[:] - self.consts = _other.consts[:] - self.nums = _other.nums[:] - self.frame_infos = _other.frame_infos[:] - - def clone(self): - return ResumeDataBuilder(self) - - def generate_boxes(self, boxes): + level = prev.level + 1 + self.level = level + self.jitcode = frame.jitcode + self.pc = frame.pc + self.exception_target = frame.exception_target + +def _ensure_parent_resumedata(framestack, n): + target = framestack[n] + if n == 0 or target.parent_resumedata_frame_info_list is not None: + return + _ensure_parent_resumedata(framestack, n-1) + back = framestack[n-1] + target.parent_resumedata_frame_info_list = FrameInfo( + back.parent_resumedata_frame_info_list, + back) + target.parent_resumedata_snapshot = Snapshot( + back.parent_resumedata_snapshot, + back.env[:]) + +def capture_resumedata(framestack, virtualizable_boxes, storage): + n = len(framestack)-1 + top = framestack[n] + _ensure_parent_resumedata(framestack, n) + frame_info_list = FrameInfo(top.parent_resumedata_frame_info_list, + top) + storage.rd_frame_info_list = frame_info_list + snapshot = Snapshot(top.parent_resumedata_snapshot, top.env[:]) + if virtualizable_boxes is not None: + snapshot = Snapshot(snapshot, virtualizable_boxes[:]) # xxx for now + storage.rd_snapshot = snapshot + +_placeholder = (None, 0, 0) + +def flatten_resumedata(storage): + frame_info_list = storage.rd_frame_info_list + storage.rd_frame_info_list = None + j = frame_info_list.level + frame_infos = [_placeholder]*j + j -= 1 + while True: # at least one + frame_infos[j] = (frame_info_list.jitcode, frame_info_list.pc, + frame_info_list.exception_target) + frame_info_list = frame_info_list.prev + if frame_info_list is None: + break + j -= 1 + storage.rd_frame_infos = frame_infos + memo = {} + consts = [] + liveboxes = [] + nums = [] + snapshots = [] + snapshot = storage.rd_snapshot + storage.rd_snapshot = None + while True: + snapshots.append(snapshot) + snapshot = snapshot.prev + if snapshot is None: + break + n = len(snapshots)-1 + while n >= 0: + boxes = snapshots[n].boxes + n -= 1 for box in boxes: assert box is not None if isinstance(box, Box): try: - num = self.memo[box] + num = memo[box] except KeyError: - num = len(self.liveboxes) - self.liveboxes.append(box) - self.memo[box] = num + num = len(liveboxes) + liveboxes.append(box) + memo[box] = num else: - num = -2 - len(self.consts) - self.consts.append(box) - self.nums.append(num) - self.nums.append(-1) - - def generate_frame_info(self, *frame_info): - self.frame_infos.append(frame_info) - - def _add_level(self, frame): - self.generate_frame_info(frame.jitcode, frame.pc, - frame.exception_target) - self.generate_boxes(frame.env) - - @staticmethod - def _get_fresh_parent_resumedata(framestack, n): - target = framestack[n] - if target.parent_resumedata is not None: - return target.parent_resumedata.clone() - if n == 0: - parent_resumedata = ResumeDataBuilder() - else: - parent_resumedata = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n-1) - parent_resumedata._add_level(framestack[n-1]) - target.parent_resumedata = parent_resumedata - return parent_resumedata.clone() - - @staticmethod - def make(framestack): - n = len(framestack)-1 - top = framestack[-1] - builder = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n) - builder._add_level(top) - return builder + num = -2 - len(consts) + consts.append(box) + nums.append(num) + nums.append(-1) + nums = nums[:] + storage.rd_nums = nums + storage.rd_consts = consts[:] + storage.rd_virtuals = None + return liveboxes + + +## class ResumeDataBuilder(object): + +## def __init__(self, _other=None): +## if _other is None: +## self.memo = {} +## self.liveboxes = [] +## self.consts = [] +## self.nums = [] +## self.frame_infos = [] +## else: +## self.memo = _other.memo.copy() +## self.liveboxes = _other.liveboxes[:] +## self.consts = _other.consts[:] +## self.nums = _other.nums[:] +## self.frame_infos = _other.frame_infos[:] + +## def clone(self): +## return ResumeDataBuilder(self) + +## def generate_boxes(self, boxes): +## for box in boxes: +## assert box is not None +## if isinstance(box, Box): +## try: +## num = self.memo[box] +## except KeyError: +## num = len(self.liveboxes) +## self.liveboxes.append(box) +## self.memo[box] = num +## else: +## num = -2 - len(self.consts) +## self.consts.append(box) +## self.nums.append(num) +## self.nums.append(-1) + +## def generate_frame_info(self, *frame_info): +## self.frame_infos.append(frame_info) + +## def _add_level(self, frame): +## self.generate_frame_info(frame.jitcode, frame.pc, +## frame.exception_target) +## self.generate_boxes(frame.env) + +## @staticmethod +## def _get_fresh_parent_resumedata(framestack, n): +## target = framestack[n] +## if target.parent_resumedata is not None: +## return target.parent_resumedata.clone() +## if n == 0: +## parent_resumedata = ResumeDataBuilder() +## else: +## parent_resumedata = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n-1) +## parent_resumedata._add_level(framestack[n-1]) +## target.parent_resumedata = parent_resumedata +## return parent_resumedata.clone() + +## @staticmethod +## def make(framestack): +## n = len(framestack)-1 +## top = framestack[-1] +## builder = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n) +## builder._add_level(top) +## return builder - def finish(self, storage): - storage.rd_frame_infos = self.frame_infos[:] - storage.rd_nums = self.nums[:] - storage.rd_consts = self.consts[:] - storage.rd_virtuals = None - if debug: - dump_storage(storage) - return self.liveboxes +## def finish(self, storage): +## storage.rd_frame_infos = self.frame_infos[:] +## storage.rd_nums = self.nums[:] +## storage.rd_consts = self.consts[:] +## storage.rd_virtuals = None +## if debug: +## dump_storage(storage) +## return self.liveboxes VIRTUAL_FLAG = int((sys.maxint+1) // 2) Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/simple_optimize.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/simple_optimize.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/simple_optimize.py Mon Sep 28 17:40:37 2009 @@ -3,6 +3,7 @@ """ from pypy.jit.metainterp.resoperation import rop +from pypy.jit.metainterp import resume def optimize_loop(options, old_loops, loop, cpu=None): if old_loops: @@ -13,7 +14,14 @@ # we need it since the backend can modify those lists, which make # get_guard_op in compile.py invalid # in fact, x86 modifies this list for moving GCs - loop.operations = loop.operations[:] + newoperations = [] + for op in loop.operations: + if op.is_guard(): + op_fail = op.suboperations[-1] + args = resume.flatten_resumedata(op_fail.descr) + op_fail.args = args + newoperations.append(op) + loop.operations = newoperations return None def optimize_bridge(options, old_loops, loop, cpu=None): Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop.py Mon Sep 28 17:40:37 2009 @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE, OPTIMIZER_FULL from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats from pypy.rpython.lltypesystem import lltype from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin @@ -8,10 +8,10 @@ from pypy.jit.metainterp import history class LoopTest: - specialize = False + optimizer = OPTIMIZER_SIMPLE def meta_interp(self, f, args, policy=None): - return ll_meta_interp(f, args, specialize=self.specialize, + return ll_meta_interp(f, args, optimizer=self.optimizer, policy=policy, CPUClass=self.CPUClass, type_system=self.type_system) @@ -54,7 +54,7 @@ res = self.meta_interp(f, [6, 13]) assert res == f(6, 13) self.check_loop_count(1) - if self.specialize: + if self.optimizer == OPTIMIZER_FULL: self.check_loops(getfield_gc = 0, setfield_gc = 1) def test_loop_with_two_paths(self): Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop_dummy.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop_dummy.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop_dummy.py Mon Sep 28 17:40:37 2009 @@ -1,10 +1,11 @@ +# xxx mostly pointless from pypy.jit.metainterp.test import test_loop, test_send from pypy.jit.metainterp.warmspot import ll_meta_interp from pypy.rlib.jit import OPTIMIZER_SIMPLE from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin -class LoopDummyTest(test_loop.LoopTest, test_send.SendTests): +class LoopDummyTest(test_send.SendTests): def meta_interp(self, func, args, **kwds): return ll_meta_interp(func, args, optimizer=OPTIMIZER_SIMPLE, CPUClass=self.CPUClass, Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop_spec.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop_spec.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_loop_spec.py Mon Sep 28 17:40:37 2009 @@ -1,9 +1,10 @@ import py +from pypy.rlib.jit import OPTIMIZER_FULL from pypy.jit.metainterp.test import test_loop from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin class LoopSpecTest(test_loop.LoopTest): - specialize = True + optimizer = OPTIMIZER_FULL # ====> test_loop.py Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_optimizeopt.py Mon Sep 28 17:40:37 2009 @@ -6,14 +6,51 @@ OOtypeMixin, BaseTest) from pypy.jit.metainterp.optimizefindnode import PerfectSpecializationFinder +from pypy.jit.metainterp import optimizeopt from pypy.jit.metainterp.optimizeopt import optimize_loop_1 from pypy.jit.metainterp.optimizeutil import InvalidLoop -from pypy.jit.metainterp.history import AbstractDescr, ConstInt +from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt from pypy.jit.metainterp import resume, executor, compile -from pypy.jit.metainterp.resoperation import rop, opname +from pypy.jit.metainterp.resoperation import rop, opname, ResOperation from pypy.jit.metainterp.test.oparser import pure_parse as parse - +class FakeFrame(object): + parent_resumedata_snapshot = None + parent_resumedata_frame_info_list = None + + def __init__(self, code="", pc=0, exc_target=-1): + self.jitcode = code + self.pc = pc + self.exception_target = exc_target + +def test_clone_guard_simple(): + from pypy.jit.metainterp.compile import ResumeGuardDescr + b0 = BoxInt() + b1 = BoxInt() + opt = optimizeopt.Optimizer(None, None) + op = ResOperation(rop.GUARD_TRUE, [], None) + op.suboperations = [ + ResOperation(rop.FAIL, [], None) + ] + fdescr = ResumeGuardDescr(None, None) + op.suboperations[-1].descr = fdescr + # setup rd data + fi = [("code0", 1, 2), ("code1", 3, -1)] + fdescr.rd_virtuals = None + fi0 = resume.FrameInfo(None, FakeFrame("code0", 1, 2)) + fdescr.rd_frame_info_list = resume.FrameInfo(fi0, + FakeFrame("code1", 3, -1)) + snapshot0 = resume.Snapshot(None, [b0]) + fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1]) + # + op1 = op + opt.clone_guard(op, op1) + assert op1.optimized is op + assert op1.suboperations[-1].args == [b0, b1] + assert fdescr.rd_nums == [0, -1, 1, -1] + assert fdescr.rd_virtuals is None + assert fdescr.rd_consts == [] + assert fdescr.rd_frame_infos == fi # ____________________________________________________________ def equaloplists(oplist1, oplist2, remap={}): @@ -88,6 +125,9 @@ # ____________________________________________________________ +class Storage: + "for tests." + class BaseTestOptimizeOpt(BaseTest): def assert_equal(self, optimized, expected): @@ -118,7 +158,22 @@ assert loop.operations[-1].opnum == rop.JUMP loop.operations[-1].jump_target = loop # - optimize_loop_1(self.cpu, loop) + Optimizer = optimizeopt.Optimizer + old_get_faildescr = Optimizer._get_faildescr + def _get_faildescr(self, op_fail): + if op_fail.descr is None: + descr = Storage() + descr.rd_frame_info_list = resume.FrameInfo(None, + FakeFrame()) + descr.rd_snapshot = resume.Snapshot(None, op_fail.args) + descr.rd_virtuals = None + return descr + return old_get_faildescr(self, op_fail) + Optimizer._get_faildescr = _get_faildescr + try: + optimize_loop_1(self.cpu, loop) + finally: + Optimizer._get_faildescr = old_get_faildescr.im_func # expected = self.parse(optops) self.assert_equal(loop, expected) @@ -1312,11 +1367,12 @@ def _oparser_uses_descr(self, oparse, args): # typically called twice, before and after optimization if len(self.args_seen) == 0: - builder = resume.ResumeDataBuilder() - builder.generate_boxes(args) - liveboxes = builder.finish(fdescr) - assert liveboxes == args + fdescr.rd_frame_info_list = resume.FrameInfo(None, + FakeFrame()) + fdescr.rd_snapshot = resume.Snapshot(None, args) + fdescr.virtuals = None self.args_seen.append((args, oparse)) + # fdescr = instantiate(FailDescr) self.fdescr = fdescr Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_resume.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_resume.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/test/test_resume.py Mon Sep 28 17:40:37 2009 @@ -6,7 +6,6 @@ from pypy.jit.metainterp.test.test_optimizefindnode import LLtypeMixin from pypy.jit.metainterp import executor - class Storage: pass @@ -14,17 +13,15 @@ b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] storage = Storage() - builder = ResumeDataBuilder() - builder.generate_boxes([b1, c1, b1, b2]) - builder.generate_boxes([c2, c3]) - builder.generate_boxes([b1, b2, b3]) - liveboxes = builder.finish(storage) - assert liveboxes == [b1, b2, b3] + storage.rd_frame_infos = [] + storage.rd_virtuals = None + storage.rd_consts = [c1, c2, c3] + storage.rd_nums = [0, -2, 0, 1, -1, + -3, -4, -1, + 0, 1, 2, -1 + ] return storage -# ____________________________________________________________ - - def test_simple(): storage = make_demo_storage() b1s, b2s, b3s = [BoxInt(), BoxPtr(), BoxInt()] @@ -40,14 +37,12 @@ def test_frame_info(): storage = Storage() + storage.rd_frame_infos = [(1, 2, 5), (3, 4, 7)] + storage.rd_consts = [] + storage.rd_nums = [] + storage.rd_virtuals = None # - builder = ResumeDataBuilder() - builder.generate_frame_info(1, 2, 5) - builder.generate_frame_info(3, 4, 7) - liveboxes = builder.finish(storage) - assert liveboxes == [] - # - reader = ResumeDataReader(storage, liveboxes) + reader = ResumeDataReader(storage, []) assert reader.has_more_frame_infos() fi = reader.consume_frame_info() assert fi == (1, 2, 5) @@ -56,9 +51,13 @@ assert fi == (3, 4, 7) assert not reader.has_more_frame_infos() +# ____________________________________________________________ + + class FakeFrame(object): - parent_resumedata = None + parent_resumedata_snapshot = None + parent_resumedata_frame_info_list = None def __init__(self, code, pc, exc_target, *boxes): self.jitcode = code @@ -66,99 +65,136 @@ self.exception_target = exc_target self.env = list(boxes) -def test_ResumeDataBuilder_clone(): +def test_Snapshot_create(): + l = ['b0', 'b1'] + snap = Snapshot(None, l) + assert snap.prev is None + assert snap.boxes is l + + l1 = ['b3'] + snap1 = Snapshot(snap, l1) + assert snap1.prev is snap + assert snap1.boxes is l1 + +def test_FrameInfo_create(): + jitcode = "JITCODE" + frame = FakeFrame(jitcode, 1, 2) + fi = FrameInfo(None, frame) + assert fi.prev is None + assert fi.jitcode is jitcode + assert fi.pc == 1 + assert fi.exception_target == 2 + assert fi.level == 1 + + jitcode1 = "JITCODE1" + frame1 = FakeFrame(jitcode, 3, 4) + fi1 = FrameInfo(fi, frame1) + assert fi1.prev is fi + assert fi1.jitcode is jitcode + assert fi1.pc == 3 + assert fi1.exception_target == 4 + assert fi1.level == 2 + +def test_flatten_resumedata(): + # temporary "expensive" mean to go from the new to the old world b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] - c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] - rd = ResumeDataBuilder() - rd.generate_boxes([b1, c1, b2]) - rd.generate_frame_info(('code1', 2, -1)) - - rd1 = rd.clone() - assert rd1.liveboxes == rd.liveboxes - assert rd1.memo == rd.memo - assert rd1.consts == rd.consts - assert rd1.nums == rd.nums - assert rd1.frame_infos == rd.frame_infos - - assert rd1 is not rd - assert rd1.liveboxes is not rd.liveboxes - assert rd1.memo is not rd.memo - assert rd1.consts is not rd.consts - assert rd1.nums is not rd.nums - assert rd1.frame_infos is not rd.frame_infos + c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] + env = [b1, c1, b2, b1, c2] + snap = Snapshot(None, env) + frame = FakeFrame("JITCODE", 1, 2) + fi = FrameInfo(None, frame) + env1 = [c3, b3, b1, c1] + snap1 = Snapshot(snap, env1) + frame1 = FakeFrame("JITCODE1", 3, 4) + fi1 = FrameInfo(fi, frame1) -def test_ResumeDataBuilder_make(): + storage = Storage() + storage.rd_snapshot = snap1 + storage.rd_frame_info_list = fi1 + + liveboxes = flatten_resumedata(storage) + assert storage.rd_snapshot is None + assert storage.rd_frame_info_list is None + + assert storage.rd_frame_infos == [("JITCODE", 1, 2), + ("JITCODE1", 3, 4)] + assert storage.rd_virtuals is None + assert liveboxes == [b1, b2, b3] + assert storage.rd_consts == [c1, c2, c3, c1] + # check with reading + reader = ResumeDataReader(storage, liveboxes) + l = reader.consume_boxes() + assert l == env + l = reader.consume_boxes() + assert l == env1 + +def test_capture_resumedata(): b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] fs = [FakeFrame("code0", 0, -1, b1, c1, b2)] - rd = ResumeDataBuilder.make(fs) - assert rd.liveboxes == [b1, b2] - assert rd.consts == [c1] - assert rd.nums == [0, -2, 1, -1] - assert rd.frame_infos == [('code0', 0, -1)] - - assert fs[0].parent_resumedata is not None - prd = fs[0].parent_resumedata - assert prd.nums == [] - assert rd is not prd - + storage = Storage() + capture_resumedata(fs, None, storage) + + assert fs[0].parent_resumedata_snapshot is None + assert fs[0].parent_resumedata_frame_info_list is None + + assert storage.rd_frame_info_list.prev is None + assert storage.rd_frame_info_list.jitcode == 'code0' + assert storage.rd_snapshot.prev is None + assert storage.rd_snapshot.boxes == fs[0].env + assert storage.rd_snapshot.boxes is not fs[0].env + + storage = Storage() fs = [FakeFrame("code0", 0, -1, b1, c1, b2), FakeFrame("code1", 3, 7, b3, c2, b1), FakeFrame("code2", 9, -1, c3, b2)] - rd = ResumeDataBuilder.make(fs) - assert rd.liveboxes == [b1, b2, b3] - assert rd.consts == [c1, c2, c3] - assert rd.nums == [0, -2, 1, -1, - 2, -3, 0, -1, - -4, 1, -1] - - assert rd.frame_infos == [('code0', 0, -1), - ('code1', 3, 7), - ('code2', 9, -1)] - - assert fs[0].parent_resumedata is not None - assert fs[1].parent_resumedata is not None - assert fs[2].parent_resumedata is not None - - prd = fs[0].parent_resumedata - assert prd.nums == [] + capture_resumedata(fs, None, storage) - prd = fs[1].parent_resumedata - assert prd.nums == [0, -2, 1, -1] + frame_info_list = storage.rd_frame_info_list + assert frame_info_list.prev is fs[2].parent_resumedata_frame_info_list + assert frame_info_list.jitcode == 'code2' + assert frame_info_list.pc == 9 - prd = fs[2].parent_resumedata - assert prd.nums == [0, -2, 1, -1, - 2, -3, 0, -1] - - rds = (rd, fs[0].parent_resumedata, fs[1].parent_resumedata, - fs[2].parent_resumedata) - for i in range(len(rds)): - for j in range(i+1, len(rds)): - assert rds[i] is not rds[j] + snapshot = storage.rd_snapshot + assert snapshot.prev is fs[2].parent_resumedata_snapshot + assert snapshot.boxes == fs[2].env + assert snapshot.boxes is not fs[2].env + + frame_info_list = frame_info_list.prev + assert frame_info_list.prev is fs[1].parent_resumedata_frame_info_list + assert frame_info_list.jitcode == 'code1' + snapshot = snapshot.prev + assert snapshot.prev is fs[1].parent_resumedata_snapshot + assert snapshot.boxes == fs[1].env + assert snapshot.boxes is not fs[1].env + + frame_info_list = frame_info_list.prev + assert frame_info_list.prev is None + assert frame_info_list.jitcode == 'code0' + snapshot = snapshot.prev + assert snapshot.prev is None + assert snapshot.boxes == fs[0].env + assert snapshot.boxes is not fs[0].env fs[2].env = [b2, b3] fs[2].pc = 15 - rd = ResumeDataBuilder.make(fs) - assert rd.liveboxes == [b1, b2, b3] - assert rd.consts == [c1, c2] - assert rd.nums == [0, -2, 1, -1, - 2, -3, 0, -1, - 1, 2, -1] - - assert rd.frame_infos == [('code0', 0, -1), - ('code1', 3, 7), - ('code2', 15, -1)] - - assert fs[2].parent_resumedata is prd - - rds = (rd, fs[0].parent_resumedata, fs[1].parent_resumedata, - fs[2].parent_resumedata) - for i in range(len(rds)): - for j in range(i+1, len(rds)): - assert rds[i] is not rds[j] - + vbs = [b1, b2] + capture_resumedata(fs, vbs, storage) + + frame_info_list = storage.rd_frame_info_list + assert frame_info_list.prev is fs[2].parent_resumedata_frame_info_list + assert frame_info_list.jitcode == 'code2' + assert frame_info_list.pc == 15 + + snapshot = storage.rd_snapshot + assert snapshot.boxes == vbs + assert snapshot.boxes is not vbs + + snapshot = snapshot.prev + assert snapshot.prev is fs[2].parent_resumedata_snapshot + assert snapshot.boxes == fs[2].env # ____________________________________________________________ From fijal at codespeak.net Mon Sep 28 18:06:47 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 18:06:47 +0200 (CEST) Subject: [pypy-svn] r67945 - pypy/branch/refactor-x86/pypy/jit/backend/x86/test Message-ID: <20090928160647.0F00D168006@codespeak.net> Author: fijal Date: Mon Sep 28 18:06:47 2009 New Revision: 67945 Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_zrpy_gc.py Log: fix imports in test_zrpy_gc Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_zrpy_gc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_zrpy_gc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_zrpy_gc.py Mon Sep 28 18:06:47 2009 @@ -12,8 +12,9 @@ from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE from pypy.jit.backend.x86.runner import CPU386 from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc -from pypy.jit.backend.x86.regalloc import stack_pos +from pypy.jit.backend.x86.regalloc import X86StackManager +stack_pos = X86StackManager.stack_pos class X(object): next = None From fijal at codespeak.net Mon Sep 28 18:14:22 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 18:14:22 +0200 (CEST) Subject: [pypy-svn] r67946 - pypy/branch/refactor-x86/pypy/jit/backend/llsupport Message-ID: <20090928161422.2BB21168006@codespeak.net> Author: fijal Date: Mon Sep 28 18:14:21 2009 New Revision: 67946 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Log: Document public interface. Make non-public method have names starting with _ Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 18:14:21 2009 @@ -59,6 +59,8 @@ self.position += incr def possibly_free_var(self, v): + """ Variable v might not be used any more, if not used any more + """ if isinstance(v, Const) or v not in self.reg_bindings: return if v not in self.longevity or self.longevity[v][1] <= self.position: @@ -66,6 +68,8 @@ del self.reg_bindings[v] def possibly_free_vars(self, vars): + """ Each of v in vars might not be used any more + """ for v in vars: self.possibly_free_var(v) @@ -84,6 +88,13 @@ assert self.longevity[v][1] > self.position def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): + """ Try allocate register, if we have on free + need_lower_byte - if True, allocate one that has a lower byte reg + (ie eax has al) + selected_reg - pick a register which you want + + returns allocated register or None, if not possible + """ assert not isinstance(v, Const) if selected_reg is not None: res = self.reg_bindings.get(v, None) @@ -153,6 +164,12 @@ def force_allocate_reg(self, v, forbidden_vars=[], selected_reg=None, need_lower_byte=False): + """ Force allocate register for variable v (which is not yet used) + If we don't have a free register, spill some other variable, + according to algorithm described in pick_variable_to_spill + + Will not spill a variable from forbidden_vars + """ if isinstance(v, TempBox): self.longevity[v] = (self.position, self.position) loc = self.try_allocate_reg(v, selected_reg, @@ -168,6 +185,8 @@ return loc def loc(self, box): + """ Return a location of box + """ if isinstance(box, Const): return self.convert_to_imm(box) try: @@ -177,6 +196,9 @@ def return_constant(self, v, forbidden_vars=[], selected_reg=None, imm_fine=True): + """ Return a location of constant v, if imm_fine is set to False + will move it's value to register + """ assert isinstance(v, Const) if selected_reg or not imm_fine: # this means we cannot have it in IMM, eh @@ -195,6 +217,9 @@ def make_sure_var_in_reg(self, v, forbidden_vars=[], selected_reg=None, imm_fine=True, need_lower_byte=False): + """ Make sure that a variable v, which is already allocated + is in some register + """ if isinstance(v, Const): return self.return_constant(v, forbidden_vars, selected_reg, imm_fine) @@ -206,12 +231,12 @@ self.assembler.regalloc_mov(prev_loc, loc) return loc - def reallocate_from_to(self, from_v, to_v): + def _reallocate_from_to(self, from_v, to_v): reg = self.reg_bindings[from_v] del self.reg_bindings[from_v] self.reg_bindings[to_v] = reg - def move_variable_away(self, v, prev_loc): + def _move_variable_away(self, v, prev_loc): reg = None if self.free_regs: loc = self.free_regs.pop() @@ -242,20 +267,22 @@ loc = self.reg_bindings[v] del self.reg_bindings[v] if self.stack_manager.get(v) is None: - self.move_variable_away(v, loc) + self._move_variable_away(v, loc) self.reg_bindings[result_v] = loc else: - self.reallocate_from_to(v, result_v) + self._reallocate_from_to(v, result_v) loc = self.reg_bindings[result_v] return loc - def sync_var(self, v): + def _sync_var(self, v): if not self.stack_manager.get(v): reg = self.reg_bindings[v] self.assembler.regalloc_mov(reg, self.stack_manager.loc(v)) # otherwise it's clean def before_call(self, force_store=[]): + """ Sync registers before call, ones that we need + """ for v, reg in self.reg_bindings.items(): if v not in force_store and self.longevity[v][1] <= self.position: # variable dies @@ -265,11 +292,13 @@ if reg not in self.save_around_call_regs: # we don't need to continue - self.sync_var(v) + self._sync_var(v) del self.reg_bindings[v] self.free_regs.append(reg) def after_call(self, v): + """ Adjust registers according to a call result + """ if v is not None: r = self.result_stored_in_reg(v) self.reg_bindings[v] = r @@ -278,9 +307,12 @@ # abstract methods, override def convert_to_imm(self, c): + """ Platform specific - convert a constant to imm + """ raise NotImplementedError("Abstract") def result_stored_in_reg(self, v): - # takes a variable and tells where the result will be - # stored + """ Platform specific - tell where the result of a call will + be stored by a cpu, according to variable type + """ raise NotImplementedError("Abstract") From arigo at codespeak.net Mon Sep 28 18:59:51 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 28 Sep 2009 18:59:51 +0200 (CEST) Subject: [pypy-svn] r67947 - in pypy/branch/refactor-x86/pypy/jit/backend: llsupport llsupport/test x86 x86/test Message-ID: <20090928165951.B667D168007@codespeak.net> Author: arigo Date: Mon Sep 28 18:59:50 2009 New Revision: 67947 Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py Log: Small clean-ups. Improved docstrings for llsupport/regalloc. Various small fixes in tests. Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 18:59:50 2009 @@ -39,13 +39,12 @@ class RegisterManager(object): """ Class that keeps track of register allocations """ + all_regs = [] no_lower_byte_regs = [] save_around_call_regs = [] - def __init__(self, register_pool, longevity, - stack_manager=None, assembler=None): - self.free_regs = register_pool[:] - self.all_regs = register_pool + def __init__(self, longevity, stack_manager=None, assembler=None): + self.free_regs = self.all_regs[:] self.longevity = longevity self.reg_bindings = {} self.position = -1 @@ -59,7 +58,9 @@ self.position += incr def possibly_free_var(self, v): - """ Variable v might not be used any more, if not used any more + """ If v is stored in a register and v is not used beyond the + current position, then free it. Must be called at some + point for all variables that might be in registers. """ if isinstance(v, Const) or v not in self.reg_bindings: return @@ -68,7 +69,7 @@ del self.reg_bindings[v] def possibly_free_vars(self, vars): - """ Each of v in vars might not be used any more + """ Same as 'possibly_free_var', but for all v in vars. """ for v in vars: self.possibly_free_var(v) @@ -88,12 +89,12 @@ assert self.longevity[v][1] > self.position def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): - """ Try allocate register, if we have on free + """ Try to allocate a register, if we have one free. need_lower_byte - if True, allocate one that has a lower byte reg - (ie eax has al) - selected_reg - pick a register which you want + (e.g. eax has al) + selected_reg - if not None, force a specific register - returns allocated register or None, if not possible + returns allocated register or None, if not possible. """ assert not isinstance(v, Const) if selected_reg is not None: @@ -134,7 +135,7 @@ def _spill_var(self, v, forbidden_vars, selected_reg, need_lower_byte=False): - v_to_spill = self.pick_variable_to_spill(v, forbidden_vars, + v_to_spill = self._pick_variable_to_spill(v, forbidden_vars, selected_reg, need_lower_byte=need_lower_byte) loc = self.reg_bindings[v_to_spill] del self.reg_bindings[v_to_spill] @@ -143,8 +144,8 @@ self.assembler.regalloc_mov(loc, newloc) return loc - def pick_variable_to_spill(self, v, forbidden_vars, selected_reg=None, - need_lower_byte=False): + def _pick_variable_to_spill(self, v, forbidden_vars, selected_reg=None, + need_lower_byte=False): """ Silly algorithm. """ candidates = [] @@ -164,11 +165,12 @@ def force_allocate_reg(self, v, forbidden_vars=[], selected_reg=None, need_lower_byte=False): - """ Force allocate register for variable v (which is not yet used) - If we don't have a free register, spill some other variable, - according to algorithm described in pick_variable_to_spill + """ Forcibly allocate a register for the new variable v. + It must not be used so far. If we don't have a free register, + spill some other variable, according to algorithm described in + '_pick_variable_to_spill'. - Will not spill a variable from forbidden_vars + Will not spill a variable from 'forbidden_vars'. """ if isinstance(v, TempBox): self.longevity[v] = (self.position, self.position) @@ -185,7 +187,7 @@ return loc def loc(self, box): - """ Return a location of box + """ Return the location of 'box'. """ if isinstance(box, Const): return self.convert_to_imm(box) @@ -196,8 +198,10 @@ def return_constant(self, v, forbidden_vars=[], selected_reg=None, imm_fine=True): - """ Return a location of constant v, if imm_fine is set to False - will move it's value to register + """ Return the location of the constant v. If 'imm_fine' is False, + or if 'selected_reg' is not None, it will first load its value into + a register. See 'force_allocate_reg' for the meaning of 'selected_reg' + and 'forbidden_vars'. """ assert isinstance(v, Const) if selected_reg or not imm_fine: @@ -217,8 +221,9 @@ def make_sure_var_in_reg(self, v, forbidden_vars=[], selected_reg=None, imm_fine=True, need_lower_byte=False): - """ Make sure that a variable v, which is already allocated - is in some register + """ Make sure that an already-allocated variable v is in some + register. Return the register. See 'return_constant' and + 'force_allocate_reg' for the meaning of the optional arguments. """ if isinstance(v, Const): return self.return_constant(v, forbidden_vars, selected_reg, @@ -247,8 +252,9 @@ self.assembler.regalloc_mov(prev_loc, loc) def force_result_in_reg(self, result_v, v, forbidden_vars=[]): - """ Make sure that result is in the same register as v - and v is copied away if it's further used + """ Make sure that result is in the same register as v. + The variable v is copied away if it's further used. The meaning + of 'forbidden_vars' is the same as in 'force_allocate_reg'. """ if isinstance(v, Const): loc = self.make_sure_var_in_reg(v, forbidden_vars, @@ -281,7 +287,10 @@ # otherwise it's clean def before_call(self, force_store=[]): - """ Sync registers before call, ones that we need + """ Spill registers before a call, as described by + 'self.save_around_call_regs'. Registers are not spilled if + they don't survive past the current operation, unless they + are listed in 'force_store'. """ for v, reg in self.reg_bindings.items(): if v not in force_store and self.longevity[v][1] <= self.position: @@ -297,10 +306,11 @@ self.free_regs.append(reg) def after_call(self, v): - """ Adjust registers according to a call result + """ Adjust registers according to the result of the call, + which is in variable v. """ if v is not None: - r = self.result_stored_in_reg(v) + r = self.call_result_location(v) self.reg_bindings[v] = r self.free_regs = [fr for fr in self.free_regs if fr is not r] @@ -311,8 +321,8 @@ """ raise NotImplementedError("Abstract") - def result_stored_in_reg(self, v): + def call_result_location(self, v): """ Platform specific - tell where the result of a call will - be stored by a cpu, according to variable type + be stored by the cpu, according to the variable type """ raise NotImplementedError("Abstract") Modified: pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/llsupport/test/test_regalloc.py Mon Sep 28 18:59:50 2009 @@ -3,10 +3,6 @@ from pypy.jit.backend.llsupport.regalloc import StackManager from pypy.jit.backend.llsupport.regalloc import RegisterManager as BaseRegMan -class RegisterManager(BaseRegMan): - def convert_to_imm(self, v): - return v - def newboxes(*values): return [BoxInt(v) for v in values] @@ -25,6 +21,11 @@ r0, r1, r2, r3 = [FakeReg() for _ in range(4)] regs = [r0, r1, r2, r3] +class RegisterManager(BaseRegMan): + all_regs = regs + def convert_to_imm(self, v): + return v + class TStackManager(StackManager): def stack_pos(self, i): return i @@ -40,7 +41,7 @@ def test_freeing_vars(self): b0, b1, b2 = newboxes(0, 0, 0) longevity = {b0: (0, 1), b1: (0, 2), b2: (0, 2)} - rm = RegisterManager(regs, longevity) + rm = RegisterManager(longevity) rm.next_instruction() for b in b0, b1, b2: rm.try_allocate_reg(b) @@ -65,7 +66,7 @@ def test_register_exhaustion(self): boxes, longevity = boxes_and_longevity(5) - rm = RegisterManager(regs, longevity) + rm = RegisterManager(longevity) rm.next_instruction() for b in boxes[:len(regs)]: assert rm.try_allocate_reg(b) @@ -79,7 +80,7 @@ class XRegisterManager(RegisterManager): no_lower_byte_regs = [r2, r3] - rm = XRegisterManager(regs, longevity) + rm = XRegisterManager(longevity) rm.next_instruction() loc0 = rm.try_allocate_reg(b0, need_lower_byte=True) assert loc0 not in XRegisterManager.no_lower_byte_regs @@ -93,7 +94,7 @@ def test_specific_register(self): boxes, longevity = boxes_and_longevity(5) - rm = RegisterManager(regs, longevity) + rm = RegisterManager(longevity) rm.next_instruction() loc = rm.try_allocate_reg(boxes[0], selected_reg=r1) assert loc is r1 @@ -114,7 +115,7 @@ class XRegisterManager(RegisterManager): no_lower_byte_regs = [r2, r3] - rm = XRegisterManager(regs, longevity, + rm = XRegisterManager(longevity, stack_manager=sm, assembler=MockAsm()) rm.next_instruction() @@ -140,7 +141,7 @@ def test_make_sure_var_in_reg(self): boxes, longevity = boxes_and_longevity(5) sm = TStackManager() - rm = RegisterManager(regs, longevity, stack_manager=sm, + rm = RegisterManager(longevity, stack_manager=sm, assembler=MockAsm()) rm.next_instruction() # allocate a stack position @@ -156,7 +157,7 @@ longevity = {b0: (0, 1), b1: (1, 3)} sm = TStackManager() asm = MockAsm() - rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + rm = RegisterManager(longevity, stack_manager=sm, assembler=asm) rm.next_instruction() # first path, var is already in reg and dies loc0 = rm.force_allocate_reg(b0) @@ -172,7 +173,7 @@ longevity = {b0: (0, 2), b1: (1, 3)} sm = TStackManager() asm = MockAsm() - rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + rm = RegisterManager(longevity, stack_manager=sm, assembler=asm) rm.next_instruction() loc0 = rm.force_allocate_reg(b0) rm._check_invariants() @@ -188,7 +189,7 @@ longevity = {b0: (0, 2), b1: (0, 2), b3: (0, 2), b2: (0, 2), b4: (1, 3)} sm = TStackManager() asm = MockAsm() - rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + rm = RegisterManager(longevity, stack_manager=sm, assembler=asm) rm.next_instruction() for b in b0, b1, b2, b3: rm.force_allocate_reg(b) @@ -204,7 +205,7 @@ longevity = {b0: (0, 1), b1: (0, 1)} sm = TStackManager() asm = MockAsm() - rm = RegisterManager(regs, longevity, stack_manager=sm, assembler=asm) + rm = RegisterManager(longevity, stack_manager=sm, assembler=asm) rm.next_instruction() sm.loc(b0) rm.force_result_in_reg(b1, b0) @@ -219,7 +220,7 @@ asm = MockAsm() boxes, longevity = boxes_and_longevity(5) sm = TStackManager() - rm = RegisterManager(regs, longevity, assembler=asm, + rm = RegisterManager(longevity, assembler=asm, stack_manager=sm) rm.next_instruction() loc = rm.return_constant(ConstInt(0), imm_fine=False) @@ -241,7 +242,7 @@ boxes, longevity = boxes_and_longevity(2) sm = TStackManager() asm = MockAsm() - rm = RegisterManager(regs, longevity, stack_manager=sm, + rm = RegisterManager(longevity, stack_manager=sm, assembler=asm) rm.next_instruction() c = ConstInt(0) @@ -249,7 +250,7 @@ rm._check_invariants() def test_loc_of_const(self): - rm = RegisterManager(regs, {}) + rm = RegisterManager({}) rm.next_instruction() assert isinstance(rm.loc(ConstInt(1)), ConstInt) @@ -257,13 +258,13 @@ class XRegisterManager(RegisterManager): save_around_call_regs = [r1, r2] - def result_stored_in_reg(self, v): + def call_result_location(self, v): return r1 sm = TStackManager() asm = MockAsm() boxes, longevity = boxes_and_longevity(5) - rm = XRegisterManager(regs, longevity, stack_manager=sm, + rm = XRegisterManager(longevity, stack_manager=sm, assembler=asm) for b in boxes[:-1]: rm.force_allocate_reg(b) Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py Mon Sep 28 18:59:50 2009 @@ -7,8 +7,7 @@ from pypy.rpython.lltypesystem.rclass import OBJECT from pypy.rpython.lltypesystem.lloperation import llop from pypy.tool.uid import fixid -from pypy.jit.backend.x86.regalloc import (RegAlloc, WORD, REGS, TempBox, - lower_byte) +from pypy.jit.backend.x86.regalloc import RegAlloc, WORD, lower_byte from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.jit.backend.x86 import codebuf from pypy.jit.backend.x86.ri386 import * Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py Mon Sep 28 18:59:50 2009 @@ -17,25 +17,15 @@ from pypy.jit.backend.llsupport.regalloc import StackManager, RegisterManager,\ TempBox -REGS = [eax, ecx, edx, ebx, esi, edi] WORD = 4 -class checkdict(dict): - def __setitem__(self, key, value): - assert isinstance(key, Box) - dict.__setitem__(self, key, value) - -def newcheckdict(): - if we_are_translated(): - return {} - return checkdict() - class X86RegisterManager(RegisterManager): + all_regs = [eax, ecx, edx, ebx, esi, edi] no_lower_byte_regs = [esi, edi] save_around_call_regs = [eax, edx, ecx] - def result_stored_in_reg(self, v): + def call_result_location(self, v): return eax def convert_to_imm(self, c): @@ -71,29 +61,25 @@ # to be read/used by the assembler too self.jump_target = None - def prepare_loop(self, inputargs, operations): + def _prepare(self, inputargs, operations): self.sm = X86StackManager() cpu = self.assembler.cpu cpu.gc_ll_descr.rewrite_assembler(cpu, operations) # compute longevity of variables longevity = self._compute_vars_longevity(inputargs, operations) - self.rm = X86RegisterManager(REGS, longevity, + self.rm = X86RegisterManager(longevity, stack_manager = self.sm, assembler = self.assembler) + + def prepare_loop(self, inputargs, operations): + self._prepare(inputargs, operations) jump = operations[-1] loop_consts = self._compute_loop_consts(inputargs, jump) self.loop_consts = loop_consts return self._process_inputargs(inputargs) def prepare_bridge(self, prev_stack_depth, inputargs, arglocs, operations): - self.sm = X86StackManager() - cpu = self.assembler.cpu - cpu.gc_ll_descr.rewrite_assembler(cpu, operations) - # compute longevity of variables - longevity = self._compute_vars_longevity(inputargs, operations) - self.rm = X86RegisterManager(REGS, longevity, - stack_manager = self.sm, - assembler = self.assembler) + self._prepare(inputargs, operations) self.loop_consts = {} self._update_bindings(arglocs, inputargs) self.sm.stack_depth = prev_stack_depth @@ -102,10 +88,11 @@ # XXX we can sort out here by longevity if we need something # more optimal locs = [None] * len(inputargs) - # Don't use REGS[0] for passing arguments around a loop. + # Don't use all_regs[0] for passing arguments around a loop. # Must be kept in sync with consider_jump(). + # XXX this should probably go to llsupport/regalloc.py tmpreg = self.rm.free_regs.pop(0) - assert tmpreg == REGS[0] + assert tmpreg == X86RegisterManager.all_regs[0] for i in range(len(inputargs)): arg = inputargs[i] assert not isinstance(arg, Const) @@ -151,7 +138,7 @@ else: self.sm.stack_bindings[v] = loc self.rm.free_regs = [] - for reg in REGS: + for reg in X86RegisterManager.all_regs: if reg not in used: self.rm.free_regs.append(reg) self.rm._check_invariants() @@ -169,7 +156,7 @@ def perform_with_guard(self, op, guard_op, arglocs, result_loc): faillocs = self.locs_for_fail(guard_op) - self.rm.next_instruction() + self.rm.position += 1 self.assembler.regalloc_perform_with_guard(op, guard_op, faillocs, arglocs, result_loc, self.sm.stack_depth) @@ -427,7 +414,7 @@ # See remember_young_pointer() in rpython/memory/gc/generation.py. for v, reg in self.rm.reg_bindings.items(): if ((reg is eax or reg is ecx or reg is edx) - and self.rm.longevity[v][1] > self.rm.position + and self.rm.stays_alive(v) and reg not in arglocs[3:]): arglocs.append(reg) self.PerformDiscard(op, arglocs) @@ -639,9 +626,10 @@ assert self.jump_target is None self.jump_target = op.jump_target arglocs = assembler.target_arglocs(self.jump_target) - # compute 'tmploc' to be REGS[0] by spilling what is there + # compute 'tmploc' to be all_regs[0] by spilling what is there box = TempBox() - tmploc = self.rm.force_allocate_reg(box, [], selected_reg=REGS[0]) + tmpreg = X86RegisterManager.all_regs[0] + tmploc = self.rm.force_allocate_reg(box, [], selected_reg=tmpreg) src_locations = [self.rm.loc(arg) for arg in op.args] dst_locations = arglocs assert tmploc not in dst_locations Modified: pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/refactor-x86/pypy/jit/backend/x86/test/test_regalloc.py Mon Sep 28 18:59:50 2009 @@ -8,7 +8,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.backend.llsupport.descr import GcCache from pypy.jit.backend.x86.runner import CPU -from pypy.jit.backend.x86.regalloc import RegAlloc, REGS, WORD +from pypy.jit.backend.x86.regalloc import RegAlloc, WORD, X86RegisterManager from pypy.jit.metainterp.test.oparser import parse from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.annlowlevel import llhelper @@ -58,7 +58,7 @@ def fill_regs(regalloc, cls=BoxInt): allboxes = [] - for reg in REGS: + for reg in X86RegisterManager.all_regs: box = cls() allboxes.append(box) regalloc.reg_bindings[box] = reg @@ -70,95 +70,6 @@ def _compute_next_usage(self, v, _): return -1 -class TestRegallocDirect(object): - - def setup_class(cls): - py.test.skip("look and eventually copy, but rather remove") - - def test_make_sure_var_in_reg(self): - regalloc = RegAlloc(MockAssembler()) - boxes = fill_regs(regalloc) - box = boxes[-1] - oldloc = regalloc.loc(box) - newloc = regalloc.make_sure_var_in_reg(box, []) - assert oldloc is newloc - regalloc._check_invariants() - - def test_make_sure_var_in_reg_need_lower_byte(self): - regalloc = RegAlloc(MockAssembler()) - box = BoxInt() - regalloc.reg_bindings[box] = edi - regalloc.free_regs = [eax, ecx, edx, ebx, esi] - loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True) - assert loc is not edi and loc is not esi - assert len(regalloc.assembler.loads) == 1 - regalloc._check_invariants() - - def test_make_sure_var_in_reg_need_lower_byte_no_free_reg(self): - regalloc = RegAllocForTests(MockAssembler()) - box = BoxInt() - regalloc.reg_bindings = {BoxInt(): eax, BoxInt(): ebx, BoxInt(): ecx, - BoxInt(): edx, box:edi} - regalloc.free_regs = [esi] - regalloc._check_invariants() - loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True) - assert loc is not edi and loc is not esi - assert len(regalloc.assembler.loads) == 1 - regalloc._check_invariants() - - def test_make_sure_var_in_reg_mem(self): - regalloc = RegAlloc(MockAssembler()) - regalloc.free_regs = REGS[:] - box = BoxInt() - regalloc.stack_loc(box) - loc = regalloc.make_sure_var_in_reg(box, [], need_lower_byte=True) - assert loc is not edi and loc is not esi - assert len(regalloc.assembler.loads) == 1 - regalloc._check_invariants() - - def test_registers_around_call(self): - cpu = CPU(None, None) - regalloc = RegAlloc(MockAssembler(cpu)) - boxes = fill_regs(regalloc) - TP = lltype.FuncType([], lltype.Void) - calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) - regalloc._check_invariants() - regalloc.longevity = dict.fromkeys(boxes, (0, 1)) - box = boxes[0] - regalloc.position = 0 - regalloc.consider_call(ResOperation(rop.CALL, [box], None, calldescr), - None) - assert len(regalloc.assembler.stores) == 3 - regalloc._check_invariants() - - def test_registers_around_newstr(self): - cpu = CPU(None, None) - regalloc = RegAllocForTests(MockAssembler(cpu)) - boxes = fill_regs(regalloc) - regalloc._check_invariants() - regalloc.longevity = dict.fromkeys(boxes, (0, 1)) - box = boxes[-1] - regalloc.position = 0 - resbox = BoxInt() - regalloc.longevity[resbox] = (1, 1) - regalloc.consider_newstr(ResOperation(rop.NEWSTR, [box], resbox, - None), None) - regalloc._check_invariants() - - def test_move_away_does_not_spill(self): - regalloc = RegAlloc(MockAssembler()) - regalloc.position = 0 - resbox = BoxInt() - box = BoxInt() - regalloc.reg_bindings = {box: eax} - regalloc.free_regs = [ebx, ecx, edx, esi, edi] - regalloc._check_invariants() - regalloc.longevity = {resbox: (0, 1), box: (0, 1)} - regalloc.consider_int_add(ResOperation(rop.INT_ADD, [box, ConstInt(1)], - resbox), None) - regalloc._check_invariants() - assert len(regalloc.assembler.stores) == 0 - class BaseTestRegalloc(object): cpu = CPU(None, None) From arigo at codespeak.net Mon Sep 28 19:05:19 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 28 Sep 2009 19:05:19 +0200 (CEST) Subject: [pypy-svn] r67948 - pypy/trunk/pypy/jit/backend/x86 Message-ID: <20090928170519.B67F6168007@codespeak.net> Author: arigo Date: Mon Sep 28 19:05:17 2009 New Revision: 67948 Added: pypy/trunk/pypy/jit/backend/x86/jump.py.merge.tmp - copied, changed from r67947, pypy/trunk/pypy/jit/backend/x86/jump.py Log: merging of svn+ssh://codespeak.net/svn/pypy/branch/refactor-x86/pypy/jit/backend/x86/jump.py revisions 67896 to 67947: ------------------------------------------------------------------------ r67938 | fijal | 2009-09-28 16:39:05 +0200 (Mon, 28 Sep 2009) | 4 lines * Skip direct tests, I don't think they're relevant, they need review though * Fix a couple of issues, mostly done ------------------------------------------------------------------------ r67897 | fijal | 2009-09-25 18:35:35 +0200 (Fri, 25 Sep 2009) | 2 lines A branch to move register allocation logic to it's own class ------------------------------------------------------------------------ Copied: pypy/trunk/pypy/jit/backend/x86/jump.py.merge.tmp (from r67947, pypy/trunk/pypy/jit/backend/x86/jump.py) ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/jump.py (original) +++ pypy/trunk/pypy/jit/backend/x86/jump.py.merge.tmp Mon Sep 28 19:05:17 2009 @@ -82,8 +82,8 @@ def _move(assembler, src, dst, tmpreg): if isinstance(dst, MODRM): if isinstance(src, MODRM): - assembler.regalloc_load(src, tmpreg) + assembler.regalloc_mov(src, tmpreg) src = tmpreg - assembler.regalloc_store(src, dst) + assembler.regalloc_mov(src, dst) else: - assembler.regalloc_load(src, dst) + assembler.regalloc_mov(src, dst) From arigo at codespeak.net Mon Sep 28 19:09:19 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 28 Sep 2009 19:09:19 +0200 (CEST) Subject: [pypy-svn] r67949 - in pypy/trunk/pypy: jit/backend/llsupport jit/backend/x86 jit/backend/x86/test rpython/memory/gc Message-ID: <20090928170919.B9965168007@codespeak.net> Author: arigo Date: Mon Sep 28 19:09:19 2009 New Revision: 67949 Added: pypy/trunk/pypy/jit/backend/llsupport/ - copied from r67948, pypy/branch/refactor-x86/pypy/jit/backend/llsupport/ pypy/trunk/pypy/jit/backend/x86/assembler.py - copied unchanged from r67948, pypy/branch/refactor-x86/pypy/jit/backend/x86/assembler.py pypy/trunk/pypy/jit/backend/x86/jump.py - copied unchanged from r67948, pypy/trunk/pypy/jit/backend/x86/jump.py.merge.tmp pypy/trunk/pypy/jit/backend/x86/regalloc.py - copied unchanged from r67948, pypy/branch/refactor-x86/pypy/jit/backend/x86/regalloc.py pypy/trunk/pypy/jit/backend/x86/test/ - copied from r67948, pypy/branch/refactor-x86/pypy/jit/backend/x86/test/ pypy/trunk/pypy/rpython/memory/gc/ - copied from r67948, pypy/branch/refactor-x86/pypy/rpython/memory/gc/ Removed: pypy/trunk/pypy/jit/backend/x86/jump.py.merge.tmp Log: (fijal, reviewed by arigo) Merge the 'refactor-x86' branch. Generalize x86 register allocation and move it into llsupport. From arigo at codespeak.net Mon Sep 28 19:09:57 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 28 Sep 2009 19:09:57 +0200 (CEST) Subject: [pypy-svn] r67950 - pypy/branch/refactor-x86 Message-ID: <20090928170957.7674D168005@codespeak.net> Author: arigo Date: Mon Sep 28 19:09:51 2009 New Revision: 67950 Removed: pypy/branch/refactor-x86/ Log: Remove merged branch. From pedronis at codespeak.net Mon Sep 28 19:10:27 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 28 Sep 2009 19:10:27 +0200 (CEST) Subject: [pypy-svn] r67951 - pypy/branch/resume-data-chaining/pypy/jit/metainterp Message-ID: <20090928171027.63C64168007@codespeak.net> Author: pedronis Date: Mon Sep 28 19:10:26 2009 New Revision: 67951 Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/simple_optimize.py Log: translation fix Modified: pypy/branch/resume-data-chaining/pypy/jit/metainterp/simple_optimize.py ============================================================================== --- pypy/branch/resume-data-chaining/pypy/jit/metainterp/simple_optimize.py (original) +++ pypy/branch/resume-data-chaining/pypy/jit/metainterp/simple_optimize.py Mon Sep 28 19:10:26 2009 @@ -3,7 +3,7 @@ """ from pypy.jit.metainterp.resoperation import rop -from pypy.jit.metainterp import resume +from pypy.jit.metainterp import resume, compile def optimize_loop(options, old_loops, loop, cpu=None): if old_loops: @@ -18,7 +18,9 @@ for op in loop.operations: if op.is_guard(): op_fail = op.suboperations[-1] - args = resume.flatten_resumedata(op_fail.descr) + descr = op_fail.descr + assert isinstance(descr, compile.ResumeGuardDescr) + args = resume.flatten_resumedata(descr) op_fail.args = args newoperations.append(op) loop.operations = newoperations From fijal at codespeak.net Mon Sep 28 19:10:53 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 19:10:53 +0200 (CEST) Subject: [pypy-svn] r67952 - pypy/branch/floats-via-sse2 Message-ID: <20090928171053.C49B9168005@codespeak.net> Author: fijal Date: Mon Sep 28 19:10:53 2009 New Revision: 67952 Added: pypy/branch/floats-via-sse2/ - copied from r67951, pypy/trunk/ Log: A branch to implement float support in x86 backend via sse2 From arigo at codespeak.net Mon Sep 28 21:28:19 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 28 Sep 2009 21:28:19 +0200 (CEST) Subject: [pypy-svn] r67953 - pypy/trunk/pypy/translator/c/src Message-ID: <20090928192819.29A31168005@codespeak.net> Author: arigo Date: Mon Sep 28 21:28:15 2009 New Revision: 67953 Modified: pypy/trunk/pypy/translator/c/src/signals.h Log: Kill some warnings from the C compiler. Modified: pypy/trunk/pypy/translator/c/src/signals.h ============================================================================== --- pypy/trunk/pypy/translator/c/src/signals.h (original) +++ pypy/trunk/pypy/translator/c/src/signals.h Mon Sep 28 21:28:15 2009 @@ -76,11 +76,11 @@ use macros when compiling as a stand-alone program, but still export a function with the correct name for testing */ #undef pypysig_getaddr_occurred -char *pypysig_getaddr_occurred(void); +void *pypysig_getaddr_occurred(void); #ifndef PYPY_NOT_MAIN_FILE -char *pypysig_getaddr_occurred(void) { return &pypysig_occurred; } +void *pypysig_getaddr_occurred(void) { return (void *)(&pypysig_occurred); } #endif -#define pypysig_getaddr_occurred() ((char *)(&pypysig_occurred)) +#define pypysig_getaddr_occurred() ((void *)(&pypysig_occurred)) /************************************************************/ /* Implementation */ From fijal at codespeak.net Mon Sep 28 22:41:29 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 28 Sep 2009 22:41:29 +0200 (CEST) Subject: [pypy-svn] r67954 - in pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport: . test Message-ID: <20090928204129.DA30C168006@codespeak.net> Author: fijal Date: Mon Sep 28 22:41:28 2009 New Revision: 67954 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/test/test_regalloc.py Log: Start supporting differing sizes in regalloc Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py Mon Sep 28 22:41:28 2009 @@ -22,26 +22,27 @@ def get(self, box): return self.stack_bindings.get(box, None) - def loc(self, box): + def loc(self, box, size): res = self.get(box) if res is not None: return res - newloc = self.stack_pos(self.stack_depth) + newloc = self.stack_pos(self.stack_depth, size) self.stack_bindings[box] = newloc - self.stack_depth += 1 + self.stack_depth += size return newloc # abstract methods that need to be overwritten for specific assemblers @staticmethod - def stack_pos(loc): + def stack_pos(loc, size): raise NotImplementedError("Purely abstract") class RegisterManager(object): """ Class that keeps track of register allocations """ - all_regs = [] - no_lower_byte_regs = [] + all_regs = [] + no_lower_byte_regs = [] save_around_call_regs = [] + reg_width = 1 # in terms of stack space eaten def __init__(self, longevity, stack_manager=None, assembler=None): self.free_regs = self.all_regs[:] @@ -140,7 +141,7 @@ loc = self.reg_bindings[v_to_spill] del self.reg_bindings[v_to_spill] if self.stack_manager.get(v_to_spill) is None: - newloc = self.stack_manager.loc(v_to_spill) + newloc = self.stack_manager.loc(v_to_spill, self.reg_width) self.assembler.regalloc_mov(loc, newloc) return loc @@ -194,7 +195,7 @@ try: return self.reg_bindings[box] except KeyError: - return self.stack_manager.loc(box) + return self.stack_manager.loc(box, self.reg_width) def return_constant(self, v, forbidden_vars=[], selected_reg=None, imm_fine=True): @@ -248,7 +249,7 @@ self.reg_bindings[v] = loc self.assembler.regalloc_mov(prev_loc, loc) else: - loc = self.stack_manager.loc(v) + loc = self.stack_manager.loc(v, self.reg_width) self.assembler.regalloc_mov(prev_loc, loc) def force_result_in_reg(self, result_v, v, forbidden_vars=[]): @@ -263,7 +264,7 @@ self.free_regs = [reg for reg in self.free_regs if reg is not loc] return loc if v not in self.reg_bindings: - prev_loc = self.stack_manager.loc(v) + prev_loc = self.stack_manager.loc(v, self.reg_width) loc = self.force_allocate_reg(v, forbidden_vars) self.assembler.regalloc_mov(prev_loc, loc) assert v in self.reg_bindings @@ -283,7 +284,8 @@ def _sync_var(self, v): if not self.stack_manager.get(v): reg = self.reg_bindings[v] - self.assembler.regalloc_mov(reg, self.stack_manager.loc(v)) + to = self.stack_manager.loc(v, self.reg_width) + self.assembler.regalloc_mov(reg, to) # otherwise it's clean def before_call(self, force_store=[]): Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/test/test_regalloc.py Mon Sep 28 22:41:28 2009 @@ -1,5 +1,5 @@ -from pypy.jit.metainterp.history import BoxInt, ConstInt +from pypy.jit.metainterp.history import BoxInt, ConstInt, BoxFloat from pypy.jit.backend.llsupport.regalloc import StackManager from pypy.jit.backend.llsupport.regalloc import RegisterManager as BaseRegMan @@ -27,7 +27,7 @@ return v class TStackManager(StackManager): - def stack_pos(self, i): + def stack_pos(self, i, size): return i class MockAsm(object): @@ -146,7 +146,7 @@ rm.next_instruction() # allocate a stack position b0, b1, b2, b3, b4 = boxes - sp = sm.loc(b0) + sp = sm.loc(b0, 1) assert sp == 0 loc = rm.make_sure_var_in_reg(b0) assert isinstance(loc, FakeReg) @@ -207,7 +207,7 @@ asm = MockAsm() rm = RegisterManager(longevity, stack_manager=sm, assembler=asm) rm.next_instruction() - sm.loc(b0) + sm.loc(b0, 1) rm.force_result_in_reg(b1, b0) rm._check_invariants() loc = rm.loc(b1) @@ -276,3 +276,21 @@ rm.after_call(boxes[-1]) assert len(rm.reg_bindings) == 3 rm._check_invariants() + + def test_different_stack_width(self): + class XRegisterManager(RegisterManager): + reg_width = 2 + + sm = TStackManager() + b0 = BoxInt() + longevity = {b0: (0, 1)} + asm = MockAsm() + rm = RegisterManager(longevity, stack_manager=sm, assembler=asm) + f0 = BoxFloat() + longevity = {f0: (0, 1)} + xrm = XRegisterManager(longevity, stack_manager=sm, assembler=asm) + xrm.loc(f0) + rm.loc(b0) + assert sm.stack_depth == 3 + + From pedronis at codespeak.net Mon Sep 28 22:54:17 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 28 Sep 2009 22:54:17 +0200 (CEST) Subject: [pypy-svn] r67955 - in pypy/trunk/pypy: . jit/backend/llvm/test jit/backend/x86/test jit/metainterp jit/metainterp/test Message-ID: <20090928205417.53D7B168007@codespeak.net> Author: pedronis Date: Mon Sep 28 22:54:16 2009 New Revision: 67955 Modified: pypy/trunk/pypy/ (props changed) pypy/trunk/pypy/jit/backend/llvm/test/conftest.py (props changed) pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py (props changed) pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/logger.py (props changed) pypy/trunk/pypy/jit/metainterp/optimizeopt.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/resume.py pypy/trunk/pypy/jit/metainterp/simple_optimize.py pypy/trunk/pypy/jit/metainterp/test/test_loop.py pypy/trunk/pypy/jit/metainterp/test/test_loop_dummy.py pypy/trunk/pypy/jit/metainterp/test/test_loop_spec.py pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py pypy/trunk/pypy/jit/metainterp/test/test_resume.py Log: merge resume-data-chaining use chaining to capture resume data before optimisation, pushes the effort there reducing tracing time because less guards survice to that point Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Mon Sep 28 22:54:16 2009 @@ -197,7 +197,7 @@ def __init__(self, original_greenkey, guard_op): ResumeDescr.__init__(self, original_greenkey) self.guard_op = guard_op - # this class also gets attributes stored by ResumeDataBuilder.finish() + # this class also gets attributes stored by resume.py code def handle_fail(self, metainterp_sd): from pypy.jit.metainterp.pyjitpl import MetaInterp Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimizeopt.py Mon Sep 28 22:54:16 2009 @@ -497,26 +497,24 @@ self.exception_might_have_happened = True self.newoperations.append(op) + def _get_faildescr(self, op_fail): + descr = op_fail.descr + assert isinstance(descr, compile.ResumeGuardDescr) + return descr + def clone_guard(self, op2, op1): assert len(op1.suboperations) == 1 op_fail = op1.suboperations[0] assert op_fail.opnum == rop.FAIL - # - if not we_are_translated() and op_fail.descr is None: # for tests - descr = Storage() - builder = resume.ResumeDataBuilder() - builder.generate_boxes(op_fail.args) - builder.finish(descr) - else: - descr = op_fail.descr - assert isinstance(descr, compile.ResumeGuardDescr) + descr = self._get_faildescr(op_fail) oldboxes = [] - for box in op_fail.args: + args = resume.flatten_resumedata(descr) # xxx expensive + for box in args: if box in self.values: box = self.values[box].get_key_box() # may be a Const, too oldboxes.append(box) modifier = resume.ResumeDataVirtualAdder(descr, oldboxes) - for box in op_fail.args: + for box in args: if box in self.values: value = self.values[box] value.get_args_for_fail(modifier) @@ -785,6 +783,3 @@ self.newoperations.append(op) optimize_ops = _findall(Optimizer, 'optimize_') - -class Storage: - "for tests." Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Mon Sep 28 22:54:16 2009 @@ -120,7 +120,9 @@ class MIFrame(object): exception_box = None exc_value_box = None - parent_resumedata = None # for resume.py operation + # for resume.py operation + parent_resumedata_snapshot = None + parent_resumedata_frame_info_list = None def __init__(self, metainterp, jitcode): assert isinstance(jitcode, codewriter.JitCode) @@ -911,9 +913,6 @@ return saved_pc = self.pc self.pc = pc - resumebuilder = resume.ResumeDataBuilder.make(metainterp.framestack) - if metainterp.staticdata.virtualizable_info is not None: - resumebuilder.generate_boxes(metainterp.virtualizable_boxes) if box is not None: moreargs = [box] + extraargs else: @@ -921,9 +920,13 @@ guard_op = metainterp.history.record(opnum, moreargs, None) original_greenkey = metainterp.resumekey.original_greenkey resumedescr = compile.ResumeGuardDescr(original_greenkey, guard_op) - liveboxes = resumebuilder.finish(resumedescr) + virtualizable_boxes = None + if metainterp.staticdata.virtualizable_info is not None: + virtualizable_boxes = metainterp.virtualizable_boxes + resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, + resumedescr) self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count - op = history.ResOperation(rop.FAIL, liveboxes, None, descr=resumedescr) + op = history.ResOperation(rop.FAIL, [], None, descr=resumedescr) guard_op.suboperations = [op] metainterp.attach_debug_info(guard_op) self.pc = saved_pc Modified: pypy/trunk/pypy/jit/metainterp/resume.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resume.py (original) +++ pypy/trunk/pypy/jit/metainterp/resume.py Mon Sep 28 22:54:16 2009 @@ -12,79 +12,177 @@ debug = False -# xxx we would like more "chaining" instead of copying -class ResumeDataBuilder(object): +class Snapshot(object): + __slots__ = ('prev', 'boxes') - def __init__(self, _other=None): - if _other is None: - self.memo = {} - self.liveboxes = [] - self.consts = [] - self.nums = [] - self.frame_infos = [] + def __init__(self, prev, boxes): + self.prev = prev + self.boxes = boxes + +class FrameInfo(object): + __slots__ = ('prev', 'jitcode', 'pc', 'exception_target', 'level') + + def __init__(self, prev, frame): + self.prev = prev + if prev is None: + level = 1 else: - self.memo = _other.memo.copy() - self.liveboxes = _other.liveboxes[:] - self.consts = _other.consts[:] - self.nums = _other.nums[:] - self.frame_infos = _other.frame_infos[:] - - def clone(self): - return ResumeDataBuilder(self) - - def generate_boxes(self, boxes): + level = prev.level + 1 + self.level = level + self.jitcode = frame.jitcode + self.pc = frame.pc + self.exception_target = frame.exception_target + +def _ensure_parent_resumedata(framestack, n): + target = framestack[n] + if n == 0 or target.parent_resumedata_frame_info_list is not None: + return + _ensure_parent_resumedata(framestack, n-1) + back = framestack[n-1] + target.parent_resumedata_frame_info_list = FrameInfo( + back.parent_resumedata_frame_info_list, + back) + target.parent_resumedata_snapshot = Snapshot( + back.parent_resumedata_snapshot, + back.env[:]) + +def capture_resumedata(framestack, virtualizable_boxes, storage): + n = len(framestack)-1 + top = framestack[n] + _ensure_parent_resumedata(framestack, n) + frame_info_list = FrameInfo(top.parent_resumedata_frame_info_list, + top) + storage.rd_frame_info_list = frame_info_list + snapshot = Snapshot(top.parent_resumedata_snapshot, top.env[:]) + if virtualizable_boxes is not None: + snapshot = Snapshot(snapshot, virtualizable_boxes[:]) # xxx for now + storage.rd_snapshot = snapshot + +_placeholder = (None, 0, 0) + +def flatten_resumedata(storage): + frame_info_list = storage.rd_frame_info_list + storage.rd_frame_info_list = None + j = frame_info_list.level + frame_infos = [_placeholder]*j + j -= 1 + while True: # at least one + frame_infos[j] = (frame_info_list.jitcode, frame_info_list.pc, + frame_info_list.exception_target) + frame_info_list = frame_info_list.prev + if frame_info_list is None: + break + j -= 1 + storage.rd_frame_infos = frame_infos + memo = {} + consts = [] + liveboxes = [] + nums = [] + snapshots = [] + snapshot = storage.rd_snapshot + storage.rd_snapshot = None + while True: + snapshots.append(snapshot) + snapshot = snapshot.prev + if snapshot is None: + break + n = len(snapshots)-1 + while n >= 0: + boxes = snapshots[n].boxes + n -= 1 for box in boxes: assert box is not None if isinstance(box, Box): try: - num = self.memo[box] + num = memo[box] except KeyError: - num = len(self.liveboxes) - self.liveboxes.append(box) - self.memo[box] = num + num = len(liveboxes) + liveboxes.append(box) + memo[box] = num else: - num = -2 - len(self.consts) - self.consts.append(box) - self.nums.append(num) - self.nums.append(-1) - - def generate_frame_info(self, *frame_info): - self.frame_infos.append(frame_info) - - def _add_level(self, frame): - self.generate_frame_info(frame.jitcode, frame.pc, - frame.exception_target) - self.generate_boxes(frame.env) - - @staticmethod - def _get_fresh_parent_resumedata(framestack, n): - target = framestack[n] - if target.parent_resumedata is not None: - return target.parent_resumedata.clone() - if n == 0: - parent_resumedata = ResumeDataBuilder() - else: - parent_resumedata = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n-1) - parent_resumedata._add_level(framestack[n-1]) - target.parent_resumedata = parent_resumedata - return parent_resumedata.clone() - - @staticmethod - def make(framestack): - n = len(framestack)-1 - top = framestack[-1] - builder = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n) - builder._add_level(top) - return builder + num = -2 - len(consts) + consts.append(box) + nums.append(num) + nums.append(-1) + nums = nums[:] + storage.rd_nums = nums + storage.rd_consts = consts[:] + storage.rd_virtuals = None + return liveboxes + + +## class ResumeDataBuilder(object): + +## def __init__(self, _other=None): +## if _other is None: +## self.memo = {} +## self.liveboxes = [] +## self.consts = [] +## self.nums = [] +## self.frame_infos = [] +## else: +## self.memo = _other.memo.copy() +## self.liveboxes = _other.liveboxes[:] +## self.consts = _other.consts[:] +## self.nums = _other.nums[:] +## self.frame_infos = _other.frame_infos[:] + +## def clone(self): +## return ResumeDataBuilder(self) + +## def generate_boxes(self, boxes): +## for box in boxes: +## assert box is not None +## if isinstance(box, Box): +## try: +## num = self.memo[box] +## except KeyError: +## num = len(self.liveboxes) +## self.liveboxes.append(box) +## self.memo[box] = num +## else: +## num = -2 - len(self.consts) +## self.consts.append(box) +## self.nums.append(num) +## self.nums.append(-1) + +## def generate_frame_info(self, *frame_info): +## self.frame_infos.append(frame_info) + +## def _add_level(self, frame): +## self.generate_frame_info(frame.jitcode, frame.pc, +## frame.exception_target) +## self.generate_boxes(frame.env) + +## @staticmethod +## def _get_fresh_parent_resumedata(framestack, n): +## target = framestack[n] +## if target.parent_resumedata is not None: +## return target.parent_resumedata.clone() +## if n == 0: +## parent_resumedata = ResumeDataBuilder() +## else: +## parent_resumedata = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n-1) +## parent_resumedata._add_level(framestack[n-1]) +## target.parent_resumedata = parent_resumedata +## return parent_resumedata.clone() + +## @staticmethod +## def make(framestack): +## n = len(framestack)-1 +## top = framestack[-1] +## builder = ResumeDataBuilder._get_fresh_parent_resumedata(framestack, n) +## builder._add_level(top) +## return builder - def finish(self, storage): - storage.rd_frame_infos = self.frame_infos[:] - storage.rd_nums = self.nums[:] - storage.rd_consts = self.consts[:] - storage.rd_virtuals = None - if debug: - dump_storage(storage) - return self.liveboxes +## def finish(self, storage): +## storage.rd_frame_infos = self.frame_infos[:] +## storage.rd_nums = self.nums[:] +## storage.rd_consts = self.consts[:] +## storage.rd_virtuals = None +## if debug: +## dump_storage(storage) +## return self.liveboxes VIRTUAL_FLAG = int((sys.maxint+1) // 2) Modified: pypy/trunk/pypy/jit/metainterp/simple_optimize.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/simple_optimize.py (original) +++ pypy/trunk/pypy/jit/metainterp/simple_optimize.py Mon Sep 28 22:54:16 2009 @@ -3,6 +3,7 @@ """ from pypy.jit.metainterp.resoperation import rop +from pypy.jit.metainterp import resume, compile def optimize_loop(options, old_loops, loop, cpu=None): if old_loops: @@ -13,7 +14,16 @@ # we need it since the backend can modify those lists, which make # get_guard_op in compile.py invalid # in fact, x86 modifies this list for moving GCs - loop.operations = loop.operations[:] + newoperations = [] + for op in loop.operations: + if op.is_guard(): + op_fail = op.suboperations[-1] + descr = op_fail.descr + assert isinstance(descr, compile.ResumeGuardDescr) + args = resume.flatten_resumedata(descr) + op_fail.args = args + newoperations.append(op) + loop.operations = newoperations return None def optimize_bridge(options, old_loops, loop, cpu=None): Modified: pypy/trunk/pypy/jit/metainterp/test/test_loop.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_loop.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_loop.py Mon Sep 28 22:54:16 2009 @@ -1,5 +1,5 @@ import py -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE, OPTIMIZER_FULL from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats from pypy.rpython.lltypesystem import lltype from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin @@ -8,10 +8,10 @@ from pypy.jit.metainterp import history class LoopTest: - specialize = False + optimizer = OPTIMIZER_SIMPLE def meta_interp(self, f, args, policy=None): - return ll_meta_interp(f, args, specialize=self.specialize, + return ll_meta_interp(f, args, optimizer=self.optimizer, policy=policy, CPUClass=self.CPUClass, type_system=self.type_system) @@ -54,7 +54,7 @@ res = self.meta_interp(f, [6, 13]) assert res == f(6, 13) self.check_loop_count(1) - if self.specialize: + if self.optimizer == OPTIMIZER_FULL: self.check_loops(getfield_gc = 0, setfield_gc = 1) def test_loop_with_two_paths(self): Modified: pypy/trunk/pypy/jit/metainterp/test/test_loop_dummy.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_loop_dummy.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_loop_dummy.py Mon Sep 28 22:54:16 2009 @@ -1,10 +1,11 @@ +# xxx mostly pointless from pypy.jit.metainterp.test import test_loop, test_send from pypy.jit.metainterp.warmspot import ll_meta_interp from pypy.rlib.jit import OPTIMIZER_SIMPLE from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin -class LoopDummyTest(test_loop.LoopTest, test_send.SendTests): +class LoopDummyTest(test_send.SendTests): def meta_interp(self, func, args, **kwds): return ll_meta_interp(func, args, optimizer=OPTIMIZER_SIMPLE, CPUClass=self.CPUClass, Modified: pypy/trunk/pypy/jit/metainterp/test/test_loop_spec.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_loop_spec.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_loop_spec.py Mon Sep 28 22:54:16 2009 @@ -1,9 +1,10 @@ import py +from pypy.rlib.jit import OPTIMIZER_FULL from pypy.jit.metainterp.test import test_loop from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin class LoopSpecTest(test_loop.LoopTest): - specialize = True + optimizer = OPTIMIZER_FULL # ====> test_loop.py Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py Mon Sep 28 22:54:16 2009 @@ -6,14 +6,51 @@ OOtypeMixin, BaseTest) from pypy.jit.metainterp.optimizefindnode import PerfectSpecializationFinder +from pypy.jit.metainterp import optimizeopt from pypy.jit.metainterp.optimizeopt import optimize_loop_1 from pypy.jit.metainterp.optimizeutil import InvalidLoop -from pypy.jit.metainterp.history import AbstractDescr, ConstInt +from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt from pypy.jit.metainterp import resume, executor, compile -from pypy.jit.metainterp.resoperation import rop, opname +from pypy.jit.metainterp.resoperation import rop, opname, ResOperation from pypy.jit.metainterp.test.oparser import pure_parse as parse - +class FakeFrame(object): + parent_resumedata_snapshot = None + parent_resumedata_frame_info_list = None + + def __init__(self, code="", pc=0, exc_target=-1): + self.jitcode = code + self.pc = pc + self.exception_target = exc_target + +def test_clone_guard_simple(): + from pypy.jit.metainterp.compile import ResumeGuardDescr + b0 = BoxInt() + b1 = BoxInt() + opt = optimizeopt.Optimizer(None, None) + op = ResOperation(rop.GUARD_TRUE, [], None) + op.suboperations = [ + ResOperation(rop.FAIL, [], None) + ] + fdescr = ResumeGuardDescr(None, None) + op.suboperations[-1].descr = fdescr + # setup rd data + fi = [("code0", 1, 2), ("code1", 3, -1)] + fdescr.rd_virtuals = None + fi0 = resume.FrameInfo(None, FakeFrame("code0", 1, 2)) + fdescr.rd_frame_info_list = resume.FrameInfo(fi0, + FakeFrame("code1", 3, -1)) + snapshot0 = resume.Snapshot(None, [b0]) + fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1]) + # + op1 = op + opt.clone_guard(op, op1) + assert op1.optimized is op + assert op1.suboperations[-1].args == [b0, b1] + assert fdescr.rd_nums == [0, -1, 1, -1] + assert fdescr.rd_virtuals is None + assert fdescr.rd_consts == [] + assert fdescr.rd_frame_infos == fi # ____________________________________________________________ def equaloplists(oplist1, oplist2, remap={}): @@ -88,6 +125,9 @@ # ____________________________________________________________ +class Storage: + "for tests." + class BaseTestOptimizeOpt(BaseTest): def assert_equal(self, optimized, expected): @@ -118,7 +158,22 @@ assert loop.operations[-1].opnum == rop.JUMP loop.operations[-1].jump_target = loop # - optimize_loop_1(self.cpu, loop) + Optimizer = optimizeopt.Optimizer + old_get_faildescr = Optimizer._get_faildescr + def _get_faildescr(self, op_fail): + if op_fail.descr is None: + descr = Storage() + descr.rd_frame_info_list = resume.FrameInfo(None, + FakeFrame()) + descr.rd_snapshot = resume.Snapshot(None, op_fail.args) + descr.rd_virtuals = None + return descr + return old_get_faildescr(self, op_fail) + Optimizer._get_faildescr = _get_faildescr + try: + optimize_loop_1(self.cpu, loop) + finally: + Optimizer._get_faildescr = old_get_faildescr.im_func # expected = self.parse(optops) self.assert_equal(loop, expected) @@ -1312,11 +1367,12 @@ def _oparser_uses_descr(self, oparse, args): # typically called twice, before and after optimization if len(self.args_seen) == 0: - builder = resume.ResumeDataBuilder() - builder.generate_boxes(args) - liveboxes = builder.finish(fdescr) - assert liveboxes == args + fdescr.rd_frame_info_list = resume.FrameInfo(None, + FakeFrame()) + fdescr.rd_snapshot = resume.Snapshot(None, args) + fdescr.virtuals = None self.args_seen.append((args, oparse)) + # fdescr = instantiate(FailDescr) self.fdescr = fdescr Modified: pypy/trunk/pypy/jit/metainterp/test/test_resume.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_resume.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_resume.py Mon Sep 28 22:54:16 2009 @@ -6,7 +6,6 @@ from pypy.jit.metainterp.test.test_optimizefindnode import LLtypeMixin from pypy.jit.metainterp import executor - class Storage: pass @@ -14,17 +13,15 @@ b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] storage = Storage() - builder = ResumeDataBuilder() - builder.generate_boxes([b1, c1, b1, b2]) - builder.generate_boxes([c2, c3]) - builder.generate_boxes([b1, b2, b3]) - liveboxes = builder.finish(storage) - assert liveboxes == [b1, b2, b3] + storage.rd_frame_infos = [] + storage.rd_virtuals = None + storage.rd_consts = [c1, c2, c3] + storage.rd_nums = [0, -2, 0, 1, -1, + -3, -4, -1, + 0, 1, 2, -1 + ] return storage -# ____________________________________________________________ - - def test_simple(): storage = make_demo_storage() b1s, b2s, b3s = [BoxInt(), BoxPtr(), BoxInt()] @@ -40,14 +37,12 @@ def test_frame_info(): storage = Storage() + storage.rd_frame_infos = [(1, 2, 5), (3, 4, 7)] + storage.rd_consts = [] + storage.rd_nums = [] + storage.rd_virtuals = None # - builder = ResumeDataBuilder() - builder.generate_frame_info(1, 2, 5) - builder.generate_frame_info(3, 4, 7) - liveboxes = builder.finish(storage) - assert liveboxes == [] - # - reader = ResumeDataReader(storage, liveboxes) + reader = ResumeDataReader(storage, []) assert reader.has_more_frame_infos() fi = reader.consume_frame_info() assert fi == (1, 2, 5) @@ -56,9 +51,13 @@ assert fi == (3, 4, 7) assert not reader.has_more_frame_infos() +# ____________________________________________________________ + + class FakeFrame(object): - parent_resumedata = None + parent_resumedata_snapshot = None + parent_resumedata_frame_info_list = None def __init__(self, code, pc, exc_target, *boxes): self.jitcode = code @@ -66,99 +65,136 @@ self.exception_target = exc_target self.env = list(boxes) -def test_ResumeDataBuilder_clone(): +def test_Snapshot_create(): + l = ['b0', 'b1'] + snap = Snapshot(None, l) + assert snap.prev is None + assert snap.boxes is l + + l1 = ['b3'] + snap1 = Snapshot(snap, l1) + assert snap1.prev is snap + assert snap1.boxes is l1 + +def test_FrameInfo_create(): + jitcode = "JITCODE" + frame = FakeFrame(jitcode, 1, 2) + fi = FrameInfo(None, frame) + assert fi.prev is None + assert fi.jitcode is jitcode + assert fi.pc == 1 + assert fi.exception_target == 2 + assert fi.level == 1 + + jitcode1 = "JITCODE1" + frame1 = FakeFrame(jitcode, 3, 4) + fi1 = FrameInfo(fi, frame1) + assert fi1.prev is fi + assert fi1.jitcode is jitcode + assert fi1.pc == 3 + assert fi1.exception_target == 4 + assert fi1.level == 2 + +def test_flatten_resumedata(): + # temporary "expensive" mean to go from the new to the old world b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] - c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] - rd = ResumeDataBuilder() - rd.generate_boxes([b1, c1, b2]) - rd.generate_frame_info(('code1', 2, -1)) - - rd1 = rd.clone() - assert rd1.liveboxes == rd.liveboxes - assert rd1.memo == rd.memo - assert rd1.consts == rd.consts - assert rd1.nums == rd.nums - assert rd1.frame_infos == rd.frame_infos - - assert rd1 is not rd - assert rd1.liveboxes is not rd.liveboxes - assert rd1.memo is not rd.memo - assert rd1.consts is not rd.consts - assert rd1.nums is not rd.nums - assert rd1.frame_infos is not rd.frame_infos + c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] + env = [b1, c1, b2, b1, c2] + snap = Snapshot(None, env) + frame = FakeFrame("JITCODE", 1, 2) + fi = FrameInfo(None, frame) + env1 = [c3, b3, b1, c1] + snap1 = Snapshot(snap, env1) + frame1 = FakeFrame("JITCODE1", 3, 4) + fi1 = FrameInfo(fi, frame1) -def test_ResumeDataBuilder_make(): + storage = Storage() + storage.rd_snapshot = snap1 + storage.rd_frame_info_list = fi1 + + liveboxes = flatten_resumedata(storage) + assert storage.rd_snapshot is None + assert storage.rd_frame_info_list is None + + assert storage.rd_frame_infos == [("JITCODE", 1, 2), + ("JITCODE1", 3, 4)] + assert storage.rd_virtuals is None + assert liveboxes == [b1, b2, b3] + assert storage.rd_consts == [c1, c2, c3, c1] + # check with reading + reader = ResumeDataReader(storage, liveboxes) + l = reader.consume_boxes() + assert l == env + l = reader.consume_boxes() + assert l == env1 + +def test_capture_resumedata(): b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] fs = [FakeFrame("code0", 0, -1, b1, c1, b2)] - rd = ResumeDataBuilder.make(fs) - assert rd.liveboxes == [b1, b2] - assert rd.consts == [c1] - assert rd.nums == [0, -2, 1, -1] - assert rd.frame_infos == [('code0', 0, -1)] - - assert fs[0].parent_resumedata is not None - prd = fs[0].parent_resumedata - assert prd.nums == [] - assert rd is not prd - + storage = Storage() + capture_resumedata(fs, None, storage) + + assert fs[0].parent_resumedata_snapshot is None + assert fs[0].parent_resumedata_frame_info_list is None + + assert storage.rd_frame_info_list.prev is None + assert storage.rd_frame_info_list.jitcode == 'code0' + assert storage.rd_snapshot.prev is None + assert storage.rd_snapshot.boxes == fs[0].env + assert storage.rd_snapshot.boxes is not fs[0].env + + storage = Storage() fs = [FakeFrame("code0", 0, -1, b1, c1, b2), FakeFrame("code1", 3, 7, b3, c2, b1), FakeFrame("code2", 9, -1, c3, b2)] - rd = ResumeDataBuilder.make(fs) - assert rd.liveboxes == [b1, b2, b3] - assert rd.consts == [c1, c2, c3] - assert rd.nums == [0, -2, 1, -1, - 2, -3, 0, -1, - -4, 1, -1] - - assert rd.frame_infos == [('code0', 0, -1), - ('code1', 3, 7), - ('code2', 9, -1)] - - assert fs[0].parent_resumedata is not None - assert fs[1].parent_resumedata is not None - assert fs[2].parent_resumedata is not None - - prd = fs[0].parent_resumedata - assert prd.nums == [] + capture_resumedata(fs, None, storage) - prd = fs[1].parent_resumedata - assert prd.nums == [0, -2, 1, -1] + frame_info_list = storage.rd_frame_info_list + assert frame_info_list.prev is fs[2].parent_resumedata_frame_info_list + assert frame_info_list.jitcode == 'code2' + assert frame_info_list.pc == 9 - prd = fs[2].parent_resumedata - assert prd.nums == [0, -2, 1, -1, - 2, -3, 0, -1] - - rds = (rd, fs[0].parent_resumedata, fs[1].parent_resumedata, - fs[2].parent_resumedata) - for i in range(len(rds)): - for j in range(i+1, len(rds)): - assert rds[i] is not rds[j] + snapshot = storage.rd_snapshot + assert snapshot.prev is fs[2].parent_resumedata_snapshot + assert snapshot.boxes == fs[2].env + assert snapshot.boxes is not fs[2].env + + frame_info_list = frame_info_list.prev + assert frame_info_list.prev is fs[1].parent_resumedata_frame_info_list + assert frame_info_list.jitcode == 'code1' + snapshot = snapshot.prev + assert snapshot.prev is fs[1].parent_resumedata_snapshot + assert snapshot.boxes == fs[1].env + assert snapshot.boxes is not fs[1].env + + frame_info_list = frame_info_list.prev + assert frame_info_list.prev is None + assert frame_info_list.jitcode == 'code0' + snapshot = snapshot.prev + assert snapshot.prev is None + assert snapshot.boxes == fs[0].env + assert snapshot.boxes is not fs[0].env fs[2].env = [b2, b3] fs[2].pc = 15 - rd = ResumeDataBuilder.make(fs) - assert rd.liveboxes == [b1, b2, b3] - assert rd.consts == [c1, c2] - assert rd.nums == [0, -2, 1, -1, - 2, -3, 0, -1, - 1, 2, -1] - - assert rd.frame_infos == [('code0', 0, -1), - ('code1', 3, 7), - ('code2', 15, -1)] - - assert fs[2].parent_resumedata is prd - - rds = (rd, fs[0].parent_resumedata, fs[1].parent_resumedata, - fs[2].parent_resumedata) - for i in range(len(rds)): - for j in range(i+1, len(rds)): - assert rds[i] is not rds[j] - + vbs = [b1, b2] + capture_resumedata(fs, vbs, storage) + + frame_info_list = storage.rd_frame_info_list + assert frame_info_list.prev is fs[2].parent_resumedata_frame_info_list + assert frame_info_list.jitcode == 'code2' + assert frame_info_list.pc == 15 + + snapshot = storage.rd_snapshot + assert snapshot.boxes == vbs + assert snapshot.boxes is not vbs + + snapshot = snapshot.prev + assert snapshot.prev is fs[2].parent_resumedata_snapshot + assert snapshot.boxes == fs[2].env # ____________________________________________________________ From pedronis at codespeak.net Mon Sep 28 22:56:25 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 28 Sep 2009 22:56:25 +0200 (CEST) Subject: [pypy-svn] r67956 - pypy/branch/resume-data-chaining Message-ID: <20090928205625.7E40E168007@codespeak.net> Author: pedronis Date: Mon Sep 28 22:56:25 2009 New Revision: 67956 Removed: pypy/branch/resume-data-chaining/ Log: merged From arigo at codespeak.net Mon Sep 28 23:36:56 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 28 Sep 2009 23:36:56 +0200 (CEST) Subject: [pypy-svn] r67957 - pypy/trunk/pypy/jit/backend/x86/test Message-ID: <20090928213656.B1926168007@codespeak.net> Author: arigo Date: Mon Sep 28 23:36:55 2009 New Revision: 67957 Modified: pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py Log: - Fix import. - Remove a skip that disables a test that is really important; the test fails, but better see it fail than just have it silently skipped. Adding this skip was a bad idea because it's the only test for that feature. No cookie. Modified: pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py Mon Sep 28 23:36:55 2009 @@ -8,7 +8,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.backend.llsupport.descr import GcCache from pypy.jit.backend.x86.runner import CPU -from pypy.jit.backend.x86.regalloc import RegAlloc, REGS, WORD +from pypy.jit.backend.x86.regalloc import RegAlloc, WORD from pypy.jit.metainterp.test.oparser import parse from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.annlowlevel import llhelper @@ -53,9 +53,6 @@ class TestRegallocDirectGcIntegration(object): - def setup_class(cls): - py.test.skip("Rewrite") - def test_mark_gc_roots(self): cpu = CPU(None, None) regalloc = RegAlloc(MockAssembler(cpu, MockGcDescr(False))) From fijal at codespeak.net Tue Sep 29 09:21:06 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 29 Sep 2009 09:21:06 +0200 (CEST) Subject: [pypy-svn] r67958 - pypy/trunk/pypy/jit/backend/x86/test Message-ID: <20090929072106.81BC4168007@codespeak.net> Author: fijal Date: Tue Sep 29 09:21:05 2009 New Revision: 67958 Modified: pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py Log: Refactor test a bit and also underlaying mockery Modified: pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py Tue Sep 29 09:21:05 2009 @@ -17,7 +17,8 @@ from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList, GcPtrFieldDescr from pypy.jit.backend.x86.test.test_regalloc import MockAssembler -from pypy.jit.backend.x86.test.test_regalloc import fill_regs, BaseTestRegalloc +from pypy.jit.backend.x86.test.test_regalloc import BaseTestRegalloc +from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86StackManager class MockGcRootMap(object): def get_basic_shape(self): @@ -56,17 +57,24 @@ def test_mark_gc_roots(self): cpu = CPU(None, None) regalloc = RegAlloc(MockAssembler(cpu, MockGcDescr(False))) + boxes = [BoxPtr() for i in range(len(X86RegisterManager.all_regs))] + longevity = {} + for box in boxes: + longevity[box] = (0, 1) + regalloc.sm = X86StackManager() + regalloc.rm = X86RegisterManager(longevity, regalloc.sm, + assembler=regalloc.assembler) cpu = regalloc.assembler.cpu - boxes = fill_regs(regalloc, cls=BoxPtr) + for box in boxes: + regalloc.rm.try_allocate_reg(box) TP = lltype.FuncType([], lltype.Signed) calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT) - regalloc._check_invariants() - regalloc.longevity = dict.fromkeys(boxes, (0, 1)) + regalloc.rm._check_invariants() box = boxes[0] regalloc.position = 0 regalloc.consider_call(ResOperation(rop.CALL, [box], BoxInt(), calldescr), None) - assert len(regalloc.assembler.stores) == 3 + assert len(regalloc.assembler.movs) == 3 # mark = regalloc.get_mark_gc_roots(cpu.gc_ll_descr.gcrootmap) assert mark[0] == 'compressed' Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py Tue Sep 29 09:21:05 2009 @@ -29,8 +29,7 @@ gcrefs = None def __init__(self, cpu=None, gc_ll_descr=None): - self.loads = [] - self.stores = [] + self.movs = [] self.performs = [] self.lea = [] self.cpu = cpu or CPU(None, None) @@ -41,11 +40,8 @@ def dump(self, *args): pass - def regalloc_load(self, from_loc, to_loc): - self.loads.append((from_loc, to_loc)) - - def regalloc_store(self, from_loc, to_loc): - self.stores.append((from_loc, to_loc)) + def regalloc_mov(self, from_loc, to_loc): + self.movs.append((from_loc, to_loc)) def regalloc_perform(self, op, arglocs, resloc): self.performs.append((op, arglocs, resloc)) @@ -61,8 +57,7 @@ for reg in X86RegisterManager.all_regs: box = cls() allboxes.append(box) - regalloc.reg_bindings[box] = reg - regalloc.free_regs = [] + regalloc.rm.try_allocate_reg() return allboxes class RegAllocForTests(RegAlloc): From arigo at codespeak.net Tue Sep 29 09:22:12 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 09:22:12 +0200 (CEST) Subject: [pypy-svn] r67959 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090929072212.0E9C7168007@codespeak.net> Author: arigo Date: Tue Sep 29 09:22:12 2009 New Revision: 67959 Modified: pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: Remove the sharing of boxes between the loop and its branches. This removes the need for changevalue_xxx(). It was also unsafe in the presence of threads. Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Tue Sep 29 09:22:12 2009 @@ -203,48 +203,7 @@ from pypy.jit.metainterp.pyjitpl import MetaInterp metainterp = MetaInterp(metainterp_sd) fail_op = self.get_guard_op().suboperations[-1] # xxx unhappy - patch = self.patch_boxes_temporarily(metainterp_sd, fail_op) - try: - return metainterp.handle_guard_failure(fail_op, self) - finally: - self.restore_patched_boxes(metainterp_sd, fail_op, patch) - - def patch_boxes_temporarily(self, metainterp_sd, fail_op): - # A bit indirect: when we hit a rop.FAIL, the current values are - # stored somewhere in the CPU backend. Below we fetch them and - # copy them into the real boxes, i.e. the 'fail_op.args'. We - # are in a try:finally path at the end of which, in - # restore_patched_boxes(), we can safely undo exactly the - # changes done here. - cpu = metainterp_sd.cpu - patch = [] - for i in range(len(fail_op.args)): - box = fail_op.args[i] - patch.append(box.clonebox()) - if isinstance(box, BoxInt): - srcvalue = cpu.get_latest_value_int(i) - box.changevalue_int(srcvalue) - elif isinstance(box, cpu.ts.BoxRef): - srcvalue = cpu.get_latest_value_ref(i) - box.changevalue_ref(srcvalue) - elif isinstance(box, Const): - pass # we don't need to do anything - else: - assert False - return patch - - def restore_patched_boxes(self, metainterp_sd, fail_op, patch): - for i in range(len(patch)-1, -1, -1): - srcbox = patch[i] - dstbox = fail_op.args[i] - if isinstance(dstbox, BoxInt): - dstbox.changevalue_int(srcbox.getint()) - elif isinstance(dstbox, metainterp_sd.cpu.ts.BoxRef): - dstbox.changevalue_ref(srcbox.getref_base()) - elif isinstance(dstbox, Const): - pass - else: - assert False + return metainterp.handle_guard_failure(fail_op, self) def get_guard_op(self): guard_op = self.guard_op @@ -257,12 +216,10 @@ def compile_and_attach(self, metainterp, new_loop): # We managed to create a bridge. Attach the new operations # to the corrsponding guard_op and compile from there - # xxx unhappy - guard_op = self.get_guard_op() - fail_args = guard_op.suboperations[-1].args + inputargs = metainterp.history.inputargs if not we_are_translated(): - guard_op._debug_suboperations = new_loop.operations - send_bridge_to_backend(metainterp.staticdata, self, fail_args, + self.get_guard_op()._debug_suboperations = new_loop.operations + send_bridge_to_backend(metainterp.staticdata, self, inputargs, new_loop.operations) class ResumeFromInterpDescr(ResumeDescr): Modified: pypy/trunk/pypy/jit/metainterp/history.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py Tue Sep 29 09:22:12 2009 @@ -452,9 +452,6 @@ def nonconstbox(self): return self - def changevalue_box(self, srcbox): - raise NotImplementedError - def __repr__(self): result = str(self) if self._extended_display: @@ -513,11 +510,6 @@ def repr_rpython(self): return repr_rpython(self, 'bi') - def changevalue_box(self, srcbox): - self.changevalue_int(srcbox.getint()) - - changevalue_int = __init__ - class BoxFloat(Box): type = FLOAT _attrs_ = ('value',) @@ -547,11 +539,6 @@ def repr_rpython(self): return repr_rpython(self, 'bf') - def changevalue_box(self, srcbox): - self.changevalue_float(srcbox.getfloat()) - - changevalue_float = __init__ - class BoxPtr(Box): type = REF _attrs_ = ('value',) @@ -585,11 +572,7 @@ def repr_rpython(self): return repr_rpython(self, 'bp') - def changevalue_box(self, srcbox): - self.changevalue_ref(srcbox.getref_base()) - _getrepr_ = repr_pointer - changevalue_ref = __init__ NULLBOX = BoxPtr() @@ -627,11 +610,7 @@ def repr_rpython(self): return repr_rpython(self, 'bo') - def changevalue_box(self, srcbox): - self.changevalue_ref(srcbox.getref_base()) - _getrepr_ = repr_object - changevalue_ref = __init__ def set_future_values(cpu, boxes): Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Tue Sep 29 09:22:12 2009 @@ -1567,6 +1567,7 @@ def initialize_state_from_guard_failure(self, guard_failure): # guard failure: rebuild a complete MIFrame stack self.in_recursion = -1 # always one portal around + inputargs = self.load_values_from_failure(guard_failure) resumedescr = guard_failure.descr assert isinstance(resumedescr, compile.ResumeGuardDescr) warmrunnerstate = self.staticdata.state @@ -1576,15 +1577,31 @@ suboperations = guard_op.suboperations assert suboperations[-1] is guard_failure self.history = history.History(self.cpu) - self.history.inputargs = guard_failure.args # xxx unhappy + self.history.inputargs = inputargs self.staticdata.profiler.start_tracing() else: self.staticdata.profiler.start_blackhole() self.history = None # this means that is_blackholing() is true - self.rebuild_state_after_failure(resumedescr, guard_failure.args) - # xxx unhappy + self.rebuild_state_after_failure(resumedescr, inputargs) return resumedescr + def load_values_from_failure(self, guard_failure): + cpu = self.cpu + inputargs = [] + for i in range(len(guard_failure.args)): + oldbox = guard_failure.args[i] # xxx unhappy + if isinstance(oldbox, history.BoxInt): + box = history.BoxInt(cpu.get_latest_value_int(i)) + elif isinstance(oldbox, cpu.ts.BoxRef): + box = cpu.ts.BoxRef(cpu.get_latest_value_ref(i)) + elif isinstance(oldbox, history.BoxFloat): + box = history.BoxFloat(cpu.get_latest_value_float(i)) + else: + assert False, "should not see %r in guard_failure.args" % ( + oldbox,) + inputargs.append(box) + return inputargs + def initialize_virtualizable(self, original_boxes): vinfo = self.staticdata.virtualizable_info if vinfo is not None: From arigo at codespeak.net Tue Sep 29 09:44:56 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 09:44:56 +0200 (CEST) Subject: [pypy-svn] r67960 - pypy/trunk/pypy/doc Message-ID: <20090929074456.6DB35168009@codespeak.net> Author: arigo Date: Tue Sep 29 09:44:50 2009 New Revision: 67960 Modified: pypy/trunk/pypy/doc/getting-started-python.txt Log: Add these two dependencies. Modified: pypy/trunk/pypy/doc/getting-started-python.txt ============================================================================== --- pypy/trunk/pypy/doc/getting-started-python.txt (original) +++ pypy/trunk/pypy/doc/getting-started-python.txt Tue Sep 29 09:44:50 2009 @@ -45,6 +45,8 @@ * ``libz-dev`` (for the optional ``zlib`` module) * ``libbz2-dev`` (for the optional ``bz2`` module) * ``libncurses-dev`` (for the optional ``_minimal_curses`` module) + * ``libexpat1-dev`` (for the optional ``pyexpat`` module) + * ``libssl-dev`` (for the optional ``_ssl`` module) * ``libgc-dev`` (only when translating with `--opt=0, 1` or `size`) 2. Translation is somewhat time-consuming (30 min to From cfbolz at codespeak.net Tue Sep 29 09:46:03 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 29 Sep 2009 09:46:03 +0200 (CEST) Subject: [pypy-svn] r67961 - pypy/trunk/pypy/objspace/std/test Message-ID: <20090929074603.89019168009@codespeak.net> Author: cfbolz Date: Tue Sep 29 09:46:02 2009 New Revision: 67961 Modified: pypy/trunk/pypy/objspace/std/test/test_longobject.py Log: Kill the last part of the test, that was just checking the hash of an arbitrary long, which is bound to fail whenever the algorithm changes. Modified: pypy/trunk/pypy/objspace/std/test/test_longobject.py ============================================================================== --- pypy/trunk/pypy/objspace/std/test/test_longobject.py (original) +++ pypy/trunk/pypy/objspace/std/test/test_longobject.py Tue Sep 29 09:46:02 2009 @@ -168,9 +168,6 @@ assert hash(1234567890123456789L) in ( -1895067127, # with 32-bit platforms 1234567890123456789) # with 64-bit platforms - assert hash(-3**333) in ( - -368329968, # with 32-bit platforms - 4437666303107791123) # with 64-bit platforms def math_log(self): import math From arigo at codespeak.net Tue Sep 29 09:59:12 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 09:59:12 +0200 (CEST) Subject: [pypy-svn] r67962 - pypy/branch/remove-fail Message-ID: <20090929075912.68843168009@codespeak.net> Author: arigo Date: Tue Sep 29 09:59:11 2009 New Revision: 67962 Added: pypy/branch/remove-fail/ - copied from r67961, pypy/trunk/ Log: Goal: remove the FAIL operations and the suboperations list. From cfbolz at codespeak.net Tue Sep 29 10:13:59 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 29 Sep 2009 10:13:59 +0200 (CEST) Subject: [pypy-svn] r67963 - in pypy/trunk/pypy/translator/backendopt: . test Message-ID: <20090929081359.BD7D0168009@codespeak.net> Author: cfbolz Date: Tue Sep 29 10:13:59 2009 New Revision: 67963 Modified: pypy/trunk/pypy/translator/backendopt/graphanalyze.py pypy/trunk/pypy/translator/backendopt/test/test_canraise.py Log: Found a bug in the graph analyzer's handling of recursive functions (!). It does not actually matter for the canraise analyzer (because of stackcheck insertion every recursive function can raise) but for more complex ones (e.g. the cancollect analyzer of the framework GCs) it might. Fix it by being a bit inefficient by not caching results too aggressively. In theory it would be necessary to do the full reflowing, abstract-interpretationy thing, but I didn't feel like adding that complexity here, and it should still not be slow in practise. Modified: pypy/trunk/pypy/translator/backendopt/graphanalyze.py ============================================================================== --- pypy/trunk/pypy/translator/backendopt/graphanalyze.py (original) +++ pypy/trunk/pypy/translator/backendopt/graphanalyze.py Tue Sep 29 10:13:59 2009 @@ -6,23 +6,24 @@ def __init__(self, translator): self.translator = translator self.analyzed_calls = {} + self.recursion_hit = False # method overridden by subclasses @staticmethod - def join_two_results(self, result1, result2): + def join_two_results(result1, result2): raise NotImplementedError("abstract base class") @staticmethod - def bottom_result(self): + def bottom_result(): raise NotImplementedError("abstract base class") @staticmethod - def top_result(self): + def top_result(): raise NotImplementedError("abstract base class") @staticmethod - def is_top_result(self, result): + def is_top_result(result): # only an optimization, safe to always return False return False @@ -78,11 +79,15 @@ if graph in self.analyzed_calls: return self.analyzed_calls[graph] if seen is None: - seen = {} - if graph in seen: + seen = set([graph]) + self.recursion_hit = False + started_here = True + elif graph in seen: + self.recursion_hit = True return self.bottom_result() else: - seen[graph] = True + started_here = False + seen.add(graph) result = self.bottom_result() for block in graph.iterblocks(): if block is graph.startblock: @@ -100,7 +105,8 @@ if self.is_top_result(result): self.analyzed_calls[graph] = result return result - self.analyzed_calls[graph] = result + if not self.recursion_hit or started_here: + self.analyzed_calls[graph] = result return result def analyze_indirect_call(self, graphs, seen=None): @@ -124,15 +130,19 @@ """generic way to analyze graphs: recursively follow it until the first operation is found on which self.analyze_simple_operation returns True""" - def join_two_results(self, result1, result2): + @staticmethod + def join_two_results(result1, result2): return result1 or result2 - def is_top_result(self, result): + @staticmethod + def is_top_result(result): return result - def bottom_result(self): + @staticmethod + def bottom_result(): return False - def top_result(self): + @staticmethod + def top_result(): return True Modified: pypy/trunk/pypy/translator/backendopt/test/test_canraise.py ============================================================================== --- pypy/trunk/pypy/translator/backendopt/test/test_canraise.py (original) +++ pypy/trunk/pypy/translator/backendopt/test/test_canraise.py Tue Sep 29 10:13:59 2009 @@ -44,6 +44,27 @@ result = ra.can_raise(ggraph.startblock.operations[-1]) assert result # due to stack check every recursive function can raise + def test_bug_graphanalyze_recursive(self): + # intentionally don't insert stack checks. the test shows a problem + # with using the graph analyzer on recursive functions that is indepent + # of the fact that recursive functions always happen to raise + def g(x): + return f(x) + + def f(x): + if x: + if x % 2: + return x + raise ValueError + return g(x - 1) + t, ra = self.translate(f, [int]) + ggraph = graphof(t, g) + fgraph = graphof(t, f) + result = ra.can_raise(ggraph.startblock.operations[-1]) # the call to f + assert result + result = ra.can_raise(fgraph.startblock.exits[0].target.operations[-1]) # the call to g + assert result + def test_can_raise_exception(self): def g(): raise ValueError From fijal at codespeak.net Tue Sep 29 10:17:44 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 29 Sep 2009 10:17:44 +0200 (CEST) Subject: [pypy-svn] r67964 - pypy/extradoc/talk/pycon2010 Message-ID: <20090929081744.CD171168009@codespeak.net> Author: fijal Date: Tue Sep 29 10:17:44 2009 New Revision: 67964 Added: pypy/extradoc/talk/pycon2010/jit_abstract.txt (contents, props changed) Log: start one abstract Added: pypy/extradoc/talk/pycon2010/jit_abstract.txt ============================================================================== --- (empty file) +++ pypy/extradoc/talk/pycon2010/jit_abstract.txt Tue Sep 29 10:17:44 2009 @@ -0,0 +1,16 @@ +The speed of PyPy +================= + +Summary: + +First part of the talk will cover PyPy's speed achievements, especially +connected to the last year's work on JIT. It'll present benchmarks together +with compatibility comparison. Second part of the talk will cover +basics of how the JIT work and what sort of programs it can greatly +speedup (and which ones it can't). + +Description: + +PyPy's JIT has been in development for quite a while so far and recently +it started showing some real benefits (being faster than psyco on +medium sized benchmarks) (XXX link). XXX finish From cfbolz at codespeak.net Tue Sep 29 10:32:00 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 29 Sep 2009 10:32:00 +0200 (CEST) Subject: [pypy-svn] r67965 - pypy/branch/better-getfield-opts Message-ID: <20090929083200.42DC2168009@codespeak.net> Author: cfbolz Date: Tue Sep 29 10:31:59 2009 New Revision: 67965 Added: pypy/branch/better-getfield-opts/ - copied from r67964, pypy/trunk/ Log: branch to add more optimizations of getfield and getarrayitem From arigo at codespeak.net Tue Sep 29 10:40:32 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 10:40:32 +0200 (CEST) Subject: [pypy-svn] r67966 - pypy/extradoc/talk/pycon2010 Message-ID: <20090929084032.C8CBA168005@codespeak.net> Author: arigo Date: Tue Sep 29 10:40:32 2009 New Revision: 67966 Modified: pypy/extradoc/talk/pycon2010/jit_abstract.txt Log: Add and remove "the" as needed :-) Modified: pypy/extradoc/talk/pycon2010/jit_abstract.txt ============================================================================== --- pypy/extradoc/talk/pycon2010/jit_abstract.txt (original) +++ pypy/extradoc/talk/pycon2010/jit_abstract.txt Tue Sep 29 10:40:32 2009 @@ -3,10 +3,10 @@ Summary: -First part of the talk will cover PyPy's speed achievements, especially -connected to the last year's work on JIT. It'll present benchmarks together -with compatibility comparison. Second part of the talk will cover -basics of how the JIT work and what sort of programs it can greatly +The first part of the talk will cover PyPy's speed achievements, especially +connected to last year's work on the JIT. It will present benchmarks together +with compatibility comparison(?). Second part of the talk will cover the +basics of how the JIT works and what sort of programs it can greatly speedup (and which ones it can't). Description: From cfbolz at codespeak.net Tue Sep 29 10:41:58 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 29 Sep 2009 10:41:58 +0200 (CEST) Subject: [pypy-svn] r67967 - in pypy/branch/better-getfield-opts/pypy/jit/metainterp: . test Message-ID: <20090929084158.1F3ED168005@codespeak.net> Author: cfbolz Date: Tue Sep 29 10:41:57 2009 New Revision: 67967 Modified: pypy/branch/better-getfield-opts/pypy/jit/metainterp/optimizeopt.py pypy/branch/better-getfield-opts/pypy/jit/metainterp/test/test_optimizeopt.py Log: - refactor a bit the way the getfield operations of non-virtuals are optimized. Not completely happy with it, but I didn't like the complete mixup in the old world. - add a optimization for getarrayitem operations similar to that of getfield (this is useful because then e.g. looking up the same global twice gets folded away, or looking up the same attribute of an instance). This is complicated by the fact that setarrayitem(X, (a constant), Y) does not have to invalidate everything. Modified: pypy/branch/better-getfield-opts/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/better-getfield-opts/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/better-getfield-opts/pypy/jit/metainterp/optimizeopt.py Tue Sep 29 10:41:57 2009 @@ -40,9 +40,8 @@ class OptValue(object): - _attrs_ = ('box', 'known_class', 'level', '_fields') + _attrs_ = ('box', 'known_class', 'level') level = LEVEL_UNKNOWN - _fields = None def __init__(self, box): self.box = box @@ -162,6 +161,7 @@ class AbstractVirtualStructValue(AbstractVirtualValue): + _attrs_ = ('_fields', ) def __init__(self, optimizer, keybox, source_op=None): AbstractVirtualValue.__init__(self, optimizer, keybox, source_op) @@ -350,14 +350,8 @@ self.cpu = cpu self.loop = loop self.values = {} - # OptValues to clean when we see an operation with side-effects - # they are ordered by fielddescrs of the affected fields - # note: it is important that this is not a av_newdict2 dict! - # we want more precision to not clear unrelated fields, just because - # they are at the same offset (but in a different struct type) - self.values_to_clean = {} - self.interned_refs = {} + self.heap_op_optimizer = HeapOpOptimizer(self) def getinterned(self, box): constbox = self.get_constant_box(box) @@ -481,6 +475,7 @@ self.loop.operations = self.newoperations def emit_operation(self, op, must_clone=True): + self.heap_op_optimizer.emitting_operation(op) op1 = op for i in range(len(op.args)): arg = op.args[i] @@ -528,21 +523,6 @@ op2.suboperations = op1.suboperations op1.optimized = op2 - def clean_fields_of_values(self, descr=None): - if descr is None: - for descr, values in self.values_to_clean.iteritems(): - for value in values: - value._fields.clear() - self.values_to_clean = {} - else: - for value in self.values_to_clean.get(descr, []): - del value._fields[descr] - self.values_to_clean[descr] = [] - - def register_value_to_clean(self, value, descr): - self.values_to_clean.setdefault(descr, []).append(value) - - def optimize_default(self, op): if op.is_always_pure(): for arg in op.args: @@ -554,8 +534,6 @@ resbox = execute_nonspec(self.cpu, op.opnum, argboxes, op.descr) self.make_constant(op.result, resbox.constbox()) return - elif not op.has_no_side_effect() and not op.is_ovf(): - self.clean_fields_of_values() # otherwise, the operation remains self.emit_operation(op) @@ -677,18 +655,8 @@ assert fieldvalue is not None self.make_equal_to(op.result, fieldvalue) else: - # check if the field was read from another getfield_gc just before - if value._fields is None: - value._fields = av_newdict2() - elif op.descr in value._fields: - self.make_equal_to(op.result, value._fields[op.descr]) - return - # default case: produce the operation value.make_nonnull() - self.optimize_default(op) - # then remember the result of reading the field - value._fields[op.descr] = self.getvalue(op.result) - self.register_value_to_clean(value, op.descr) + self.heap_op_optimizer.optimize_GETFIELD_GC(op, value) # note: the following line does not mean that the two operations are # completely equivalent, because GETFIELD_GC_PURE is_always_pure(). @@ -700,15 +668,8 @@ value.setfield(op.descr, self.getvalue(op.args[1])) else: value.make_nonnull() - self.emit_operation(op) - # kill all fields with the same descr, as those could be affected - # by this setfield (via aliasing) - self.clean_fields_of_values(op.descr) - # remember the result of future reads of the field - if value._fields is None: - value._fields = av_newdict2() - value._fields[op.descr] = self.getvalue(op.args[1]) - self.register_value_to_clean(value, op.descr) + fieldvalue = self.getvalue(op.args[1]) + self.heap_op_optimizer.optimize_SETFIELD_GC(op, value, fieldvalue) def optimize_NEW_WITH_VTABLE(self, op): self.make_virtual(op.args[0], op.result, op) @@ -747,7 +708,7 @@ self.make_equal_to(op.result, itemvalue) return value.make_nonnull() - self.optimize_default(op) + self.heap_op_optimizer.optimize_GETARRAYITEM_GC(op, value) # note: the following line does not mean that the two operations are # completely equivalent, because GETARRAYITEM_GC_PURE is_always_pure(). @@ -761,9 +722,8 @@ value.setitem(indexbox.getint(), self.getvalue(op.args[2])) return value.make_nonnull() - # don't use optimize_default, because otherwise unrelated struct - # fields will be cleared - self.emit_operation(op) + fieldvalue = self.getvalue(op.args[2]) + self.heap_op_optimizer.optimize_SETARRAYITEM_GC(op, value, fieldvalue) def optimize_INSTANCEOF(self, op): value = self.getvalue(op.args[0]) @@ -777,9 +737,143 @@ self.emit_operation(op) def optimize_DEBUG_MERGE_POINT(self, op): - # special-case this operation to prevent e.g. the handling of - # 'values_to_clean' (the op cannot be marked as side-effect-free) - # otherwise it would be removed - self.newoperations.append(op) + self.emit_operation(op) optimize_ops = _findall(Optimizer, 'optimize_') + + +class CachedArrayItems(object): + def __init__(self): + self.fixed_index_items = {} + self.var_index_item = None + self.var_index_indexvalue = None + + +class HeapOpOptimizer(object): + def __init__(self, optimizer): + self.optimizer = optimizer + # cached OptValues for each field descr + # NOTE: it is important that this is not a av_newdict2 dict! + # we want more precision to prevent mixing up of unrelated fields, just + # because they are at the same offset (but in a different struct type) + self.cached_fields = {} + + # cached OptValues for each field descr + self.cached_arrayitems = {} + + def clean_caches(self): + self.cached_fields.clear() + self.cached_arrayitems.clear() + + def cache_field_value(self, descr, value, fieldvalue, write=False): + if write: + d = self.cached_fields[descr] = {} + else: + d = self.cached_fields.setdefault(descr, {}) + d[value] = fieldvalue + + def read_cached_field(self, descr, value): + d = self.cached_fields.get(descr, None) + if d is None: + return None + return d.get(value, None) + + def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False): + d = self.cached_arrayitems.get(descr, None) + if d is None: + d = self.cached_arrayitems[descr] = {} + cache = d.get(value, None) + if cache is None: + cache = d[value] = CachedArrayItems() + indexbox = self.optimizer.get_constant_box(indexvalue.box) + if indexbox is not None: + index = indexbox.getint() + if write: + for value, othercache in d.iteritems(): + # fixed index, clean the variable index cache, in case the + # index is the same + othercache.var_index_indexvalue = None + othercache.var_index_item = None + try: + del othercache.fixed_index_items[index] + except KeyError: + pass + cache.fixed_index_items[index] = fieldvalue + else: + if write: + for value, othercache in d.iteritems(): + # variable index, clear all caches for this descr + othercache.var_index_indexvalue = None + othercache.var_index_item = None + othercache.fixed_index_items.clear() + cache.var_index_indexvalue = indexvalue + cache.var_index_item = fieldvalue + + def read_cached_arrayitem(self, descr, value, indexvalue): + d = self.cached_arrayitems.get(descr, None) + if d is None: + return None + cache = d.get(value, None) + if cache is None: + return None + indexbox = self.optimizer.get_constant_box(indexvalue.box) + if indexbox is not None: + return cache.fixed_index_items.get(indexbox.getint(), None) + elif cache.var_index_indexvalue is indexvalue: + return cache.var_index_item + return None + + def emitting_operation(self, op): + if op.is_always_pure(): + return + if op.has_no_side_effect(): + return + if op.is_ovf(): + return + if op.is_guard(): + return + opnum = op.opnum + if (opnum == rop.GETFIELD_GC or opnum == rop.GETFIELD_GC_PURE or + opnum == rop.SETFIELD_GC or + opnum == rop.GETARRAYITEM_GC or + opnum == rop.SETARRAYITEM_GC or + opnum == rop.DEBUG_MERGE_POINT): + return + self.clean_caches() + + def optimize_GETFIELD_GC(self, op, value): + # check if the field was read from another getfield_gc just before + # or has been written to recently + fieldvalue = self.read_cached_field(op.descr, value) + if fieldvalue is not None: + self.optimizer.make_equal_to(op.result, fieldvalue) + return + # default case: produce the operation + value.make_nonnull() + self.optimizer.optimize_default(op) + # then remember the result of reading the field + fieldvalue = self.optimizer.getvalue(op.result) + self.cache_field_value(op.descr, value, fieldvalue) + + def optimize_SETFIELD_GC(self, op, value, fieldvalue): + self.optimizer.emit_operation(op) + # remember the result of future reads of the field + self.cache_field_value(op.descr, value, fieldvalue, write=True) + + def optimize_GETARRAYITEM_GC(self, op, value): + indexvalue = self.optimizer.getvalue(op.args[1]) + fieldvalue = self.read_cached_arrayitem(op.descr, value, indexvalue) + if fieldvalue is not None: + self.optimizer.make_equal_to(op.result, fieldvalue) + return + self.optimizer.optimize_default(op) + fieldvalue = self.optimizer.getvalue(op.result) + self.cache_arrayitem_value(op.descr, value, indexvalue, fieldvalue) + + def optimize_SETARRAYITEM_GC(self, op, value, fieldvalue): + self.optimizer.emit_operation(op) + indexvalue = self.optimizer.getvalue(op.args[1]) + self.cache_arrayitem_value(op.descr, value, indexvalue, fieldvalue, + write=True) + + Modified: pypy/branch/better-getfield-opts/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/better-getfield-opts/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/better-getfield-opts/pypy/jit/metainterp/test/test_optimizeopt.py Tue Sep 29 10:41:57 2009 @@ -1075,21 +1075,28 @@ def test_duplicate_getfield_1(self): ops = """ - [p1] + [p1, p2] i1 = getfield_gc(p1, descr=valuedescr) - i2 = getfield_gc(p1, descr=valuedescr) + i2 = getfield_gc(p2, descr=valuedescr) + i3 = getfield_gc(p1, descr=valuedescr) + i4 = getfield_gc(p2, descr=valuedescr) escape(i1) escape(i2) - jump(p1) + escape(i3) + escape(i4) + jump(p1, p2) """ expected = """ - [p1] + [p1, p2] i1 = getfield_gc(p1, descr=valuedescr) + i2 = getfield_gc(p2, descr=valuedescr) escape(i1) + escape(i2) escape(i1) - jump(p1) + escape(i2) + jump(p1, p2) """ - self.optimize_loop(ops, 'Not', expected) + self.optimize_loop(ops, 'Not, Not', expected) def test_getfield_after_setfield(self): ops = """ @@ -1261,6 +1268,117 @@ """ self.optimize_loop(ops, 'Not, Not', ops) + def test_duplicate_getarrayitem_1(self): + ops = """ + [p1] + p2 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p1, 1, descr=arraydescr2) + p4 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p5 = getarrayitem_gc(p1, 1, descr=arraydescr2) + escape(p2) + escape(p3) + escape(p4) + escape(p5) + jump(p1) + """ + expected = """ + [p1] + p2 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p3 = getarrayitem_gc(p1, 1, descr=arraydescr2) + escape(p2) + escape(p3) + escape(p2) + escape(p3) + jump(p1) + """ + self.optimize_loop(ops, 'Not', expected) + + def test_duplicate_getarrayitem_after_setarrayitem_1(self): + ops = """ + [p1, p2] + setarrayitem_gc(p1, 0, p2, descr=arraydescr2) + p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + escape(p3) + jump(p1, p3) + """ + expected = """ + [p1, p2] + setarrayitem_gc(p1, 0, p2, descr=arraydescr2) + escape(p2) + jump(p1, p2) + """ + self.optimize_loop(ops, 'Not, Not', expected) + + def test_duplicate_getarrayitem_after_setarrayitem_2(self): + ops = """ + [p1, p2, p3, i1] + setarrayitem_gc(p1, 0, p2, descr=arraydescr2) + setarrayitem_gc(p1, i1, p3, descr=arraydescr2) + p4 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p5 = getarrayitem_gc(p1, i1, descr=arraydescr2) + escape(p4) + escape(p5) + jump(p1, p2, p3, i1) + """ + expected = """ + [p1, p2, p3, i1] + setarrayitem_gc(p1, 0, p2, descr=arraydescr2) + setarrayitem_gc(p1, i1, p3, descr=arraydescr2) + p4 = getarrayitem_gc(p1, 0, descr=arraydescr2) + escape(p4) + escape(p3) + jump(p1, p2, p3, i1) + """ + self.optimize_loop(ops, 'Not, Not, Not, Not', expected) + + def test_duplicate_getarrayitem_after_setarrayitem_3(self): + ops = """ + [p1, p2, p3, p4, i1] + setarrayitem_gc(p1, i1, p2, descr=arraydescr2) + setarrayitem_gc(p1, 0, p3, descr=arraydescr2) + setarrayitem_gc(p1, 1, p4, descr=arraydescr2) + p5 = getarrayitem_gc(p1, i1, descr=arraydescr2) + p6 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p7 = getarrayitem_gc(p1, 1, descr=arraydescr2) + escape(p5) + escape(p6) + escape(p7) + jump(p1, p2, p3, p4, i1) + """ + expected = """ + [p1, p2, p3, p4, i1] + setarrayitem_gc(p1, i1, p2, descr=arraydescr2) + setarrayitem_gc(p1, 0, p3, descr=arraydescr2) + setarrayitem_gc(p1, 1, p4, descr=arraydescr2) + p5 = getarrayitem_gc(p1, i1, descr=arraydescr2) + escape(p5) + escape(p3) + escape(p4) + jump(p1, p2, p3, p4, i1) + """ + self.optimize_loop(ops, 'Not, Not, Not, Not, Not', expected) + + def test_duplicate_getarrayitem_after_setarrayitem_two_arrays(self): + ops = """ + [p1, p2, p3, p4, i1] + setarrayitem_gc(p1, 0, p3, descr=arraydescr2) + setarrayitem_gc(p2, 1, p4, descr=arraydescr2) + p5 = getarrayitem_gc(p1, 0, descr=arraydescr2) + p6 = getarrayitem_gc(p2, 1, descr=arraydescr2) + escape(p5) + escape(p6) + jump(p1, p2, p3, p4, i1) + """ + expected = """ + [p1, p2, p3, p4, i1] + setarrayitem_gc(p1, 0, p3, descr=arraydescr2) + setarrayitem_gc(p2, 1, p4, descr=arraydescr2) + escape(p3) + escape(p4) + jump(p1, p2, p3, p4, i1) + """ + self.optimize_loop(ops, 'Not, Not, Not, Not, Not', expected) + def test_bug_1(self): ops = """ [i0, p1] From cfbolz at codespeak.net Tue Sep 29 10:55:17 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 29 Sep 2009 10:55:17 +0200 (CEST) Subject: [pypy-svn] r67968 - in pypy/branch/better-getfield-opts/pypy/jit/metainterp: . test Message-ID: <20090929085517.AF1A7168005@codespeak.net> Author: cfbolz Date: Tue Sep 29 10:55:12 2009 New Revision: 67968 Modified: pypy/branch/better-getfield-opts/pypy/jit/metainterp/optimizeopt.py pypy/branch/better-getfield-opts/pypy/jit/metainterp/test/test_optimizeopt.py Log: hrmpf. It's obviously fine to not list pure and no-side-effect operations here. Modified: pypy/branch/better-getfield-opts/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/better-getfield-opts/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/better-getfield-opts/pypy/jit/metainterp/optimizeopt.py Tue Sep 29 10:55:12 2009 @@ -833,9 +833,7 @@ if op.is_guard(): return opnum = op.opnum - if (opnum == rop.GETFIELD_GC or opnum == rop.GETFIELD_GC_PURE or - opnum == rop.SETFIELD_GC or - opnum == rop.GETARRAYITEM_GC or + if (opnum == rop.SETFIELD_GC or opnum == rop.SETARRAYITEM_GC or opnum == rop.DEBUG_MERGE_POINT): return Modified: pypy/branch/better-getfield-opts/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/better-getfield-opts/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/better-getfield-opts/pypy/jit/metainterp/test/test_optimizeopt.py Tue Sep 29 10:55:12 2009 @@ -1358,6 +1358,27 @@ """ self.optimize_loop(ops, 'Not, Not, Not, Not, Not', expected) + def test_getarrayitem_pure_does_not_invalidate(self): + ops = """ + [p1, p2] + p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + i4 = getfield_gc_pure(ConstPtr(myptr), descr=valuedescr) + p5 = getarrayitem_gc(p1, 0, descr=arraydescr2) + escape(p3) + escape(i4) + escape(p5) + jump(p1, p2) + """ + expected = """ + [p1, p2] + p3 = getarrayitem_gc(p1, 0, descr=arraydescr2) + escape(p3) + escape(5) + escape(p3) + jump(p1, p2) + """ + self.optimize_loop(ops, 'Not, Not', expected) + def test_duplicate_getarrayitem_after_setarrayitem_two_arrays(self): ops = """ [p1, p2, p3, p4, i1] From arigo at codespeak.net Tue Sep 29 10:58:46 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 10:58:46 +0200 (CEST) Subject: [pypy-svn] r67969 - in pypy/branch/remove-fail/pypy/jit/metainterp: . test Message-ID: <20090929085846.9B1F8168005@codespeak.net> Author: arigo Date: Tue Sep 29 10:58:46 2009 New Revision: 67969 Modified: pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py pypy/branch/remove-fail/pypy/jit/metainterp/test/test_basic.py pypy/branch/remove-fail/pypy/jit/metainterp/typesystem.py Log: Remove clean_up_history. Makes test_basic.test_free_object fail. Removing the FAIL operations and not storing the boxes anywhere (but just the box types) should fix it. Modified: pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py Tue Sep 29 10:58:46 2009 @@ -1430,34 +1430,8 @@ residual_args = self.get_residual_args(loop_token.specnodes, gmp.argboxes[num_green_args:]) history.set_future_values(self.cpu, residual_args) - self.clean_up_history() return loop_token.executable_token - def clean_up_history(self): - # Clear the BoxPtrs used in self.history, at the end. The - # purpose of this is to clear the boxes that are also used in - # the TreeLoop just produced. After this, there should be no - # reference left to temporary values in long-living BoxPtrs. - # A note about recursion: setting to NULL like this should be - # safe, because ResumeGuardDescr.restore_patched_boxes should - # save and restore all the boxes that are also used by callers. - if self.history.inputargs is not None: - for box in self.history.inputargs: - self.cpu.ts.clean_box(box) - lists = [self.history.operations] - while lists: - for op in lists.pop(): - if op is None: - continue - if op.result is not None: - self.cpu.ts.clean_box(op.result) - if op.suboperations is not None: - lists.append(op.suboperations) - if op.optimized is not None: - lists.append(op.optimized.suboperations) - if op.optimized.result is not None: - self.cpu.ts.clean_box(op.optimized.result) - def prepare_resume_from_failure(self, opnum): if opnum == rop.GUARD_TRUE: # a goto_if_not that jumps only now self.framestack[-1].follow_jump() Modified: pypy/branch/remove-fail/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/test/test_basic.py Tue Sep 29 10:58:46 2009 @@ -810,7 +810,7 @@ return r() is None # assert f(30) == 1 - res = self.meta_interp(f, [30]) + res = self.meta_interp(f, [30], no_stats=True) assert res == 1 def test_pass_around(self): Modified: pypy/branch/remove-fail/pypy/jit/metainterp/typesystem.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/typesystem.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/typesystem.py Tue Sep 29 10:58:46 2009 @@ -100,10 +100,6 @@ def cast_to_baseclass(self, value): return lltype.cast_opaque_ptr(lltype.Ptr(rclass.OBJECT), value) - def clean_box(self, box): - if isinstance(box, history.BoxPtr): - box.value = lltype.nullptr(llmemory.GCREF.TO) - def getlength(self, array): return len(array) @@ -201,10 +197,6 @@ def cast_to_baseclass(self, value): return ootype.cast_from_object(ootype.ROOT, value) - def clean_box(self, box): - if isinstance(box, history.BoxObj): - box.value = ootype.NULL - def getlength(self, array): return array.ll_length() From cfbolz at codespeak.net Tue Sep 29 11:01:29 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 29 Sep 2009 11:01:29 +0200 (CEST) Subject: [pypy-svn] r67970 - in pypy/branch/better-getfield-opts/pypy/translator/backendopt: . test Message-ID: <20090929090129.CFE9D168007@codespeak.net> Author: cfbolz Date: Tue Sep 29 11:01:29 2009 New Revision: 67970 Added: pypy/branch/better-getfield-opts/pypy/translator/backendopt/test/test_writeanalyze.py (contents, props changed) pypy/branch/better-getfield-opts/pypy/translator/backendopt/writeanalyze.py (contents, props changed) Log: Add an analysis phase that finds out which structures and arrays an operation can change. Added: pypy/branch/better-getfield-opts/pypy/translator/backendopt/test/test_writeanalyze.py ============================================================================== --- (empty file) +++ pypy/branch/better-getfield-opts/pypy/translator/backendopt/test/test_writeanalyze.py Tue Sep 29 11:01:29 2009 @@ -0,0 +1,154 @@ +import py +from pypy.rpython.lltypesystem import lltype +from pypy.translator.translator import TranslationContext, graphof +from pypy.translator.simplify import get_funcobj +from pypy.translator.backendopt.writeanalyze import WriteAnalyzer, top_set +from pypy.translator.backendopt.all import backend_optimizations +from pypy.conftest import option + + +class TestCanRaise(object): + + def translate(self, func, sig): + t = TranslationContext() + t.buildannotator().build_types(func, sig) + t.buildrtyper().specialize() + if option.view: + t.view() + return t, WriteAnalyzer(t) + + + def test_writes_simple(self): + def g(x): + return True + + def f(x): + return g(x - 1) + t, wa = self.translate(f, [int]) + fgraph = graphof(t, f) + result = wa.analyze(fgraph.startblock.operations[0]) + assert not result + + def test_writes_recursive(self): + from pypy.translator.transform import insert_ll_stackcheck + def g(x): + return f(x) + + def f(x): + if x: + return g(x - 1) + return 1 + t, wa = self.translate(f, [int]) + insert_ll_stackcheck(t) + ggraph = graphof(t, g) + result = wa.analyze(ggraph.startblock.operations[-1]) + assert not result + + def test_method(self): + class A(object): + def f(self): + self.x = 1 + return 1 + def m(self): + raise ValueError + class B(A): + def f(self): + return 2 + def m(self): + return 3 + def f(a): + return a.f() + def m(a): + return a.m() + def h(flag): + if flag: + obj = A() + else: + obj = B() + f(obj) + m(obj) + + t, wa = self.translate(h, [int]) + hgraph = graphof(t, h) + # fiiiish :-( + block = hgraph.startblock.exits[0].target.exits[0].target + op_call_f = block.operations[0] + op_call_m = block.operations[1] + + # check that we fished the expected ops + def check_call(op, fname): + assert op.opname == "direct_call" + assert get_funcobj(op.args[0].value)._name == fname + check_call(op_call_f, "f") + check_call(op_call_m, "m") + + result = wa.analyze(op_call_f) + assert len(result) == 1 + (struct, T, name), = result + assert struct == "struct" + assert name.endswith("x") + assert not wa.analyze(op_call_m) + + def test_instantiate(self): + # instantiate is interesting, because it leads to one of the few cases of + # an indirect call without a list of graphs + from pypy.rlib.objectmodel import instantiate + class A: + pass + class B(A): + pass + def g(x): + if x: + C = A + else: + C = B + a = instantiate(C) + def f(x): + return g(x) + t, wa = self.translate(f, [int]) + fgraph = graphof(t, f) + result = wa.analyze(fgraph.startblock.operations[0]) + assert result is top_set + + def test_llexternal(self): + from pypy.rpython.lltypesystem.rffi import llexternal + from pypy.rpython.lltypesystem import lltype + z = llexternal('z', [lltype.Signed], lltype.Signed) + def f(x): + return z(x) + t, wa = self.translate(f, [int]) + fgraph = graphof(t, f) + backend_optimizations(t) + assert fgraph.startblock.operations[0].opname == 'direct_call' + + result = wa.analyze(fgraph.startblock.operations[0]) + assert not result + + def test_list(self): + def g(x, y, z): + return f(x, y, z) + def f(x, y, z): + l = [0] * x + l.append(y) + return len(l) + z + + + t, wa = self.translate(g, [int, int, int]) + ggraph = graphof(t, g) + assert ggraph.startblock.operations[0].opname == 'direct_call' + + result = sorted(wa.analyze(ggraph.startblock.operations[0])) + array, A = result[0] + assert array == "array" + assert A.TO.OF == lltype.Signed + + struct, S1, name = result[1] + assert struct == "struct" + assert S1.TO.items == A + assert S1.TO.length == lltype.Signed + assert name == "items" + + struct, S2, name = result[2] + assert struct == "struct" + assert name == "length" + assert S1 is S2 Added: pypy/branch/better-getfield-opts/pypy/translator/backendopt/writeanalyze.py ============================================================================== --- (empty file) +++ pypy/branch/better-getfield-opts/pypy/translator/backendopt/writeanalyze.py Tue Sep 29 11:01:29 2009 @@ -0,0 +1,39 @@ +from pypy.translator.backendopt import graphanalyze +reload(graphanalyze) + +top_set = object() +empty_set = frozenset() + +class WriteAnalyzer(graphanalyze.GraphAnalyzer): + + @staticmethod + def join_two_results(result1, result2): + if result1 is top_set: + return top_set + if result2 is top_set: + return top_set + return result1.union(result2) + + @staticmethod + def bottom_result(): + return empty_set + + @staticmethod + def top_result(): + return top_set + + @staticmethod + def is_top_result(result): + return result is top_set + + def analyze_simple_operation(self, op): + if op.opname == "setfield": + return frozenset([ + ("struct", op.args[0].concretetype, op.args[1].value)]) + elif op.opname == "setarrayitem": + return frozenset([("array", op.args[0].concretetype)]) + return empty_set + + def analyze_external_call(self, op): + return self.bottom_result() # an external call cannot change anything + From fijal at codespeak.net Tue Sep 29 12:12:06 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 29 Sep 2009 12:12:06 +0200 (CEST) Subject: [pypy-svn] r67971 - pypy/branch/pyjitpl5-floats Message-ID: <20090929101206.76355168007@codespeak.net> Author: fijal Date: Tue Sep 29 12:12:06 2009 New Revision: 67971 Removed: pypy/branch/pyjitpl5-floats/ Log: I think this branch should be gone by now From fijal at codespeak.net Tue Sep 29 12:21:24 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 29 Sep 2009 12:21:24 +0200 (CEST) Subject: [pypy-svn] r67972 - in pypy/branch/floats-via-sse2/pypy/jit/backend/x86: . test Message-ID: <20090929102124.22023168007@codespeak.net> Author: fijal Date: Tue Sep 29 12:21:23 2009 New Revision: 67972 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_gc_integration.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_jump.py Log: Fix x86 test, always pass size to stack_pos Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Tue Sep 29 12:21:23 2009 @@ -3,7 +3,8 @@ """ from pypy.jit.metainterp.history import (Box, Const, ConstInt, ConstPtr, - ResOperation, ConstAddr, BoxPtr) + ResOperation, ConstAddr, BoxPtr, + INT, REF, FLOAT) from pypy.jit.backend.x86.ri386 import * from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi, rstr from pypy.rlib.objectmodel import we_are_translated @@ -19,6 +20,12 @@ WORD = 4 +width_of_type = { + INT : 1, + REF : 1, + FLOAT : 2, + } + class X86RegisterManager(RegisterManager): all_regs = [eax, ecx, edx, ebx, esi, edi] @@ -45,7 +52,7 @@ class X86StackManager(StackManager): @staticmethod - def stack_pos(i): + def stack_pos(i, size): res = mem(ebp, get_ebp_ofs(i)) res.position = i return res @@ -102,7 +109,7 @@ if reg: locs[i] = reg else: - loc = self.sm.loc(arg) + loc = self.sm.loc(arg, width_of_type[arg.type]) locs[i] = loc # otherwise we have it saved on stack, so no worry self.rm.free_regs.insert(0, tmpreg) Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_gc_integration.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_gc_integration.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_gc_integration.py Tue Sep 29 12:21:23 2009 @@ -8,7 +8,7 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.backend.llsupport.descr import GcCache from pypy.jit.backend.x86.runner import CPU -from pypy.jit.backend.x86.regalloc import RegAlloc, REGS, WORD +from pypy.jit.backend.x86.regalloc import RegAlloc, WORD from pypy.jit.metainterp.test.oparser import parse from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.annlowlevel import llhelper Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_jump.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_jump.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_jump.py Tue Sep 29 12:21:23 2009 @@ -41,9 +41,9 @@ remap_stack_layout(assembler, [eax, ebx, ecx, edx, esi, edi], [eax, ebx, ecx, edx, esi, edi], '?') assert assembler.ops == [] - s8 = stack_pos(1) - s12 = stack_pos(31) - s20 = stack_pos(6) + s8 = stack_pos(1, 1) + s12 = stack_pos(31, 1) + s20 = stack_pos(6, 1) remap_stack_layout(assembler, [eax, ebx, ecx, s20, s8, edx, s12, esi, edi], [eax, ebx, ecx, s20, s8, edx, s12, esi, edi], '?') @@ -58,10 +58,10 @@ def test_simple_stacklocs(): assembler = MockAssembler() - s8 = stack_pos(0) - s12 = stack_pos(13) - s20 = stack_pos(20) - s24 = stack_pos(221) + s8 = stack_pos(0, 1) + s12 = stack_pos(13, 1) + s20 = stack_pos(20, 1) + s24 = stack_pos(221, 1) remap_stack_layout(assembler, [s8, eax, s12], [s20, s24, edi], edx) assert assembler.ops == [('mov', s8, edx), ('mov', edx, s20), @@ -70,10 +70,10 @@ def test_reordering(): assembler = MockAssembler() - s8 = stack_pos(8) - s12 = stack_pos(12) - s20 = stack_pos(19) - s24 = stack_pos(1) + s8 = stack_pos(8, 1) + s12 = stack_pos(12, 1) + s20 = stack_pos(19, 1) + s24 = stack_pos(1, 1) remap_stack_layout(assembler, [eax, s8, s20, ebx], [s8, ebx, eax, edi], '?') assert assembler.got([('mov', ebx, edi), @@ -83,10 +83,10 @@ def test_cycle(): assembler = MockAssembler() - s8 = stack_pos(8) - s12 = stack_pos(12) - s20 = stack_pos(19) - s24 = stack_pos(1) + s8 = stack_pos(8, 1) + s12 = stack_pos(12, 1) + s20 = stack_pos(19, 1) + s24 = stack_pos(1, 1) remap_stack_layout(assembler, [eax, s8, s20, ebx], [s8, ebx, eax, s20], '?') assert assembler.got([('push', s8), @@ -97,12 +97,12 @@ def test_cycle_2(): assembler = MockAssembler() - s8 = stack_pos(8) - s12 = stack_pos(12) - s20 = stack_pos(19) - s24 = stack_pos(1) - s2 = stack_pos(2) - s3 = stack_pos(3) + s8 = stack_pos(8, 1) + s12 = stack_pos(12, 1) + s20 = stack_pos(19, 1) + s24 = stack_pos(1, 1) + s2 = stack_pos(2, 1) + s3 = stack_pos(3, 1) remap_stack_layout(assembler, [eax, s8, edi, s20, eax, s20, s24, esi, s2, s3], [s8, s20, edi, eax, edx, s24, ebx, s12, s3, s2], @@ -127,14 +127,14 @@ remap_stack_layout(assembler, [c3], [eax], '?') assert assembler.ops == [('mov', c3, eax)] assembler = MockAssembler() - s12 = stack_pos(12) + s12 = stack_pos(12, 1) remap_stack_layout(assembler, [c3], [s12], '?') assert assembler.ops == [('mov', c3, s12)] def test_constants_and_cycle(): assembler = MockAssembler() c3 = imm(3) - s12 = stack_pos(13) + s12 = stack_pos(13, 1) remap_stack_layout(assembler, [ebx, c3, s12], [s12, eax, ebx], edi) assert assembler.ops == [('mov', c3, eax), From fijal at codespeak.net Tue Sep 29 13:23:55 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 29 Sep 2009 13:23:55 +0200 (CEST) Subject: [pypy-svn] r67973 - pypy/extradoc/talk/pycon2010 Message-ID: <20090929112355.1B9B4168002@codespeak.net> Author: fijal Date: Tue Sep 29 13:23:54 2009 New Revision: 67973 Added: pypy/extradoc/talk/pycon2010/how_not_to_write_abstract.txt (contents, props changed) Log: start writing another abstract Added: pypy/extradoc/talk/pycon2010/how_not_to_write_abstract.txt ============================================================================== --- (empty file) +++ pypy/extradoc/talk/pycon2010/how_not_to_write_abstract.txt Tue Sep 29 13:23:54 2009 @@ -0,0 +1,15 @@ +How to write cross-interpreter Python programs +============================================== + +Summary: + +This talk will cover basics about writing cross-interpreter +python programs. What to do and most of all what not to do. +This will help you if you want at some point in time to +run program on for example Java platform or faster python +interpreter, but also if you want to keep it running between +CPython releases. + +Description: + +xXX From fijal at codespeak.net Tue Sep 29 13:43:29 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 29 Sep 2009 13:43:29 +0200 (CEST) Subject: [pypy-svn] r67974 - pypy/branch/floats-via-sse2/pypy/jit/metainterp/test Message-ID: <20090929114329.B7575168003@codespeak.net> Author: fijal Date: Tue Sep 29 13:43:29 2009 New Revision: 67974 Modified: pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/oparser.py pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_oparser.py Log: Support for floats in oparser Modified: pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/oparser.py Tue Sep 29 13:43:29 2009 @@ -4,7 +4,7 @@ """ from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ - ConstAddr, ConstObj, ConstPtr, Box, BasicFailDescr + ConstAddr, ConstObj, ConstPtr, Box, BasicFailDescr, BoxFloat, ConstFloat from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.typesystem import llhelper from pypy.rpython.lltypesystem import lltype, llmemory @@ -69,6 +69,9 @@ # integer box = BoxInt() _box_counter_more_than(elem[1:]) + elif elem.startswith('f'): + box = BoxFloat() + _box_counter_more_than(elem[1:]) elif elem.startswith('p'): # pointer ts = getattr(self.cpu, 'ts', llhelper) @@ -95,12 +98,21 @@ self.vars[elem] = box return vars + def is_float(self, arg): + try: + float(arg) + return True + except ValueError: + return False + def getvar(self, arg): if not arg: return ConstInt(0) try: return ConstInt(int(arg)) except ValueError: + if self.is_float(arg): + return ConstFloat(float(arg)) if arg.startswith('"') or arg.startswith("'"): # XXX ootype info = arg.strip("'\"") Modified: pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_oparser.py Tue Sep 29 13:43:29 2009 @@ -3,7 +3,7 @@ from pypy.jit.metainterp.test.oparser import parse from pypy.jit.metainterp.resoperation import rop -from pypy.jit.metainterp.history import AbstractDescr, BoxInt +from pypy.jit.metainterp.history import AbstractDescr, BoxInt, BoxFloat def test_basic_parse(): x = """ @@ -143,6 +143,14 @@ assert loop.operations[-1].jump_target is None assert loop.operations[0].suboperations[0].jump_target is obj +def test_floats(): + x = ''' + [f0] + f1 = float_add(f0, 3.5) + ''' + loop = parse(x) + assert isinstance(loop.operations[0].args[0], BoxFloat) + def test_debug_merge_point(): x = ''' [] From pedronis at codespeak.net Tue Sep 29 13:44:42 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 29 Sep 2009 13:44:42 +0200 (CEST) Subject: [pypy-svn] r67975 - pypy/trunk/pypy/jit/backend/x86/test Message-ID: <20090929114442.95FB7168003@codespeak.net> Author: pedronis Date: Tue Sep 29 13:44:42 2009 New Revision: 67975 Modified: pypy/trunk/pypy/jit/backend/x86/test/test_basic.py Log: fix test, specialize is going away as it is Modified: pypy/trunk/pypy/jit/backend/x86/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_basic.py Tue Sep 29 13:44:42 2009 @@ -3,7 +3,7 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp from pypy.jit.metainterp.test import test_basic from pypy.jit.metainterp.policy import StopAtXPolicy -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE class Jit386Mixin(test_basic.LLJitMixin): type_system = 'lltype' @@ -29,7 +29,7 @@ n -= x.arg x.arg = 6 # prevents 'x.arg' from being annotated as constant return n - res = self.meta_interp(f, [31], specialize=False) + res = self.meta_interp(f, [31], optimizer=OPTIMIZER_SIMPLE) assert res == -4 def test_r_dict(self): From fijal at codespeak.net Tue Sep 29 14:36:49 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 29 Sep 2009 14:36:49 +0200 (CEST) Subject: [pypy-svn] r67976 - in pypy/branch/floats-via-sse2/pypy/jit/backend/x86: . test Message-ID: <20090929123649.30D19168008@codespeak.net> Author: fijal Date: Tue Sep 29 14:36:48 2009 New Revision: 67976 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/runner.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py Log: Yay, pass the first float addition test Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Tue Sep 29 14:36:48 2009 @@ -1,7 +1,7 @@ import sys, os import ctypes from pypy.jit.backend.llsupport import symbolic -from pypy.jit.metainterp.history import Const, Box, BoxPtr, REF +from pypy.jit.metainterp.history import Const, Box, BoxPtr, REF, FLOAT from pypy.jit.metainterp.history import AbstractFailDescr from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory from pypy.rpython.lltypesystem.rclass import OBJECT @@ -85,6 +85,8 @@ MAX_FAIL_BOXES, zero=True) self.fail_boxes_ptr = lltype.malloc(lltype.GcArray(llmemory.GCREF), MAX_FAIL_BOXES, zero=True) + self.fail_boxes_float = lltype.malloc(lltype.GcArray(lltype.Float), + MAX_FAIL_BOXES, zero=True) def leave_jitted_hook(self): fail_boxes_ptr = self.fail_boxes_ptr @@ -95,10 +97,13 @@ if self.mc is None: rffi.cast(lltype.Signed, self.fail_boxes_int) # workaround rffi.cast(lltype.Signed, self.fail_boxes_ptr) # workaround + rffi.cast(lltype.Signed, self.fail_boxes_float) # workaround self.fail_box_int_addr = rffi.cast(lltype.Signed, lltype.direct_arrayitems(self.fail_boxes_int)) self.fail_box_ptr_addr = rffi.cast(lltype.Signed, lltype.direct_arrayitems(self.fail_boxes_ptr)) + self.fail_box_float_addr = rffi.cast(lltype.Signed, + lltype.direct_arrayitems(self.fail_boxes_float)) # the address of the function called by 'new' gc_ll_descr = self.cpu.gc_ll_descr @@ -198,20 +203,30 @@ for i in range(len(arglocs)): loc = arglocs[i] if not isinstance(loc, REG): - if inputargs[i].type == REF: - # This uses XCHG to put zeroes in fail_boxes_ptr after - # reading them - self.mc.XOR(ecx, ecx) - self.mc.XCHG(ecx, addr_add(imm(self.fail_box_ptr_addr), - imm(i*WORD))) + if inputargs[i].type == FLOAT: + self.mc.MOVSD(xmm0, + addr64_add(imm(self.fail_box_float_addr), + imm(i*WORD*2))) + self.mc.MOVSD(loc, xmm0) else: - self.mc.MOV(ecx, addr_add(imm(self.fail_box_int_addr), - imm(i*WORD))) - self.mc.MOV(loc, ecx) + if inputargs[i].type == REF: + # This uses XCHG to put zeroes in fail_boxes_ptr after + # reading them + self.mc.XOR(ecx, ecx) + self.mc.XCHG(ecx, addr_add(imm(self.fail_box_ptr_addr), + imm(i*WORD))) + else: + self.mc.MOV(ecx, addr_add(imm(self.fail_box_int_addr), + imm(i*WORD))) + self.mc.MOV(loc, ecx) for i in range(len(arglocs)): loc = arglocs[i] if isinstance(loc, REG): - if inputargs[i].type == REF: + if inputargs[i].type == FLOAT: + self.mc.MOVSD(loc, + addr64_add(imm(self.fail_box_float_addr), + imm(i*WORD*2))) + elif inputargs[i].type == REF: # This uses XCHG to put zeroes in fail_boxes_ptr after # reading them self.mc.XOR(loc, loc) @@ -235,7 +250,10 @@ # ------------------------------------------------------------ def regalloc_mov(self, from_loc, to_loc): - self.mc.MOV(to_loc, from_loc) + if isinstance(from_loc, XMMREG) or isinstance(to_loc, XMMREG): + self.mc.MOVSD(to_loc, from_loc) + else: + self.mc.MOV(to_loc, from_loc) def regalloc_push(self, loc): self.mc.PUSH(loc) @@ -345,6 +363,7 @@ genop_int_and = _binaryop("AND", True) genop_int_or = _binaryop("OR", True) genop_int_xor = _binaryop("XOR", True) + genop_float_add = _binaryop("ADDSD", True) genop_int_mul_ovf = genop_int_mul genop_int_sub_ovf = genop_int_sub @@ -644,20 +663,29 @@ for i in range(len(locs)): loc = locs[i] if isinstance(loc, REG): - if failargs[i].type == REF: - base = self.fail_box_ptr_addr + if failargs[i].type == FLOAT: + mc.MOVSD(addr64_add(imm(self.fail_box_float_addr), + imm(i*WORD*2)), loc) else: - base = self.fail_box_int_addr - mc.MOV(addr_add(imm(base), imm(i*WORD)), loc) + if failargs[i].type == REF: + base = self.fail_box_ptr_addr + else: + base = self.fail_box_int_addr + mc.MOV(addr_add(imm(base), imm(i*WORD)), loc) for i in range(len(locs)): loc = locs[i] if not isinstance(loc, REG): - if failargs[i].type == REF: - base = self.fail_box_ptr_addr + if failargs[i].type == FLOAT: + mc.MOVSD(xmm0, loc) + mc.MOVSD(addr64_add(imm(self.fail_box_float_addr), + imm(i*WORD*2)), xmm0) else: - base = self.fail_box_int_addr - mc.MOV(eax, loc) - mc.MOV(addr_add(imm(base), imm(i*WORD)), eax) + if failargs[i].type == REF: + base = self.fail_box_ptr_addr + else: + base = self.fail_box_int_addr + mc.MOV(eax, loc) + mc.MOV(addr_add(imm(base), imm(i*WORD)), eax) if self.debug_markers: mc.MOV(eax, imm(pos)) mc.MOV(addr_add(imm(self.fail_box_int_addr), @@ -791,31 +819,24 @@ num = getattr(rop, opname.upper()) genop_list[num] = value -def addr_add(reg_or_imm1, reg_or_imm2, offset=0, scale=0): - if isinstance(reg_or_imm1, IMM32): - if isinstance(reg_or_imm2, IMM32): - return heap(reg_or_imm1.value + offset + - (reg_or_imm2.value << scale)) - else: - return memSIB(None, reg_or_imm2, scale, reg_or_imm1.value + offset) - else: - if isinstance(reg_or_imm2, IMM32): - return mem(reg_or_imm1, offset + (reg_or_imm2.value << scale)) +def new_addr_add(heap, mem, memsib): + def addr_add(reg_or_imm1, reg_or_imm2, offset=0, scale=0): + if isinstance(reg_or_imm1, IMM32): + if isinstance(reg_or_imm2, IMM32): + return heap(reg_or_imm1.value + offset + + (reg_or_imm2.value << scale)) + else: + return memSIB(None, reg_or_imm2, scale, reg_or_imm1.value + offset) else: - return memSIB(reg_or_imm1, reg_or_imm2, scale, offset) + if isinstance(reg_or_imm2, IMM32): + return mem(reg_or_imm1, offset + (reg_or_imm2.value << scale)) + else: + return memSIB(reg_or_imm1, reg_or_imm2, scale, offset) + return addr_add -def addr8_add(reg_or_imm1, reg_or_imm2, offset=0, scale=0): - if isinstance(reg_or_imm1, IMM32): - if isinstance(reg_or_imm2, IMM32): - return heap8(reg_or_imm1.value + (offset << scale) + - reg_or_imm2.value) - else: - return memSIB8(None, reg_or_imm2, scale, reg_or_imm1.value + offset) - else: - if isinstance(reg_or_imm2, IMM32): - return mem8(reg_or_imm1, (offset << scale) + reg_or_imm2.value) - else: - return memSIB8(reg_or_imm1, reg_or_imm2, scale, offset) +addr8_add = new_addr_add(heap8, mem8, memSIB8) +addr_add = new_addr_add(heap, mem, memSIB) +addr64_add = new_addr_add(heap64, mem64, memSIB64) def addr_add_const(reg_or_imm1, offset): if isinstance(reg_or_imm1, IMM32): Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Tue Sep 29 14:36:48 2009 @@ -49,11 +49,35 @@ print "convert_to_imm: got a %s" % c raise AssertionError +class X86XMMRegisterManager(RegisterManager): + + all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] + # we never need lower byte I hope + save_around_call_regs = all_regs + reg_width = 2 + + def convert_to_imm(self, c): + xxx # what to do here... + + def after_call(self, v): + xxx # test + # the result is stored in st0, but we don't have this around, + # so we move it to some stack location + if v is not None: + loc = self.sm.stack_loc(v, 2) + self.assembler.regalloc_mov(st0, loc) + class X86StackManager(StackManager): @staticmethod def stack_pos(i, size): - res = mem(ebp, get_ebp_ofs(i)) + if size == 1: + res = mem(ebp, get_ebp_ofs(i)) + elif size == 2: + res = mem64(ebp, get_ebp_ofs(i)) + else: + print "Unimplemented size %d" % i + raise NotImplementedError("unimplemented size %d" % i) res.position = i return res @@ -77,6 +101,8 @@ self.rm = X86RegisterManager(longevity, stack_manager = self.sm, assembler = self.assembler) + self.xrm = X86XMMRegisterManager(longevity, stack_manager = self.sm, + assembler = self.assembler) def prepare_loop(self, inputargs, operations): self._prepare(inputargs, operations) @@ -105,7 +131,10 @@ assert not isinstance(arg, Const) reg = None if arg not in self.loop_consts and self.rm.longevity[arg][1] > -1: - reg = self.rm.try_allocate_reg(arg) + if arg.type == FLOAT: + reg = self.xrm.try_allocate_reg(arg) + else: + reg = self.rm.try_allocate_reg(arg) if reg: locs[i] = reg else: @@ -254,6 +283,8 @@ return longevity def loc(self, v): + if v.type == FLOAT: + return self.xrm.loc(v) return self.rm.loc(v) def _consider_guard(self, op, ignored): @@ -396,6 +427,11 @@ consider_oois = _consider_compop consider_ooisnot = _consider_compop + def consider_float_add(self, op, ignored): + loc0 = self.xrm.force_result_in_reg(op.result, op.args[0], op.args) + loc1 = self.xrm.loc(op.args[1]) + self.Perform(op, [loc0, loc1], loc0) + def _call(self, op, arglocs, force_store=[]): self.rm.before_call(force_store) self.Perform(op, arglocs, eax) Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386.py Tue Sep 29 14:36:48 2009 @@ -27,7 +27,7 @@ def assembler(self): raise TypeError("Float registers should not appear in assembler") -class XMMREG(OPERAND): +class XMMREG(REG): width = 8 def __repr__(self): @@ -309,6 +309,10 @@ assert register.width == 1 return MODRM8(0xC0 | register.op, '') +def memregister64(register): + assert register.width == 8 + return MODRM64(0xC0 | register.op, '') + def mem8(basereg, offset=0): return memSIB8(basereg, None, 0, offset) Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py Tue Sep 29 14:36:48 2009 @@ -11,6 +11,9 @@ def reg2modrm(builder, reg): return memregister(reg) +def reg2modrm64(builder, reg): + return memregister64(reg) + def reg2modrm8(builder, reg): return memregister8(reg) @@ -45,7 +48,7 @@ MODRM: [(MODRM, None)], MODRM8: [(MODRM8, None)], MODRM64: [(MODRM64, None)], - XMMREG: [(XMMREG, None)], + XMMREG: [(XMMREG, None), (MODRM64, reg2modrm64)], MISSING: [(MISSING, None)], # missing operands } Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/runner.py Tue Sep 29 14:36:48 2009 @@ -11,6 +11,7 @@ class CPU386(AbstractLLCPU): debug = True + supports_floats = True BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) dont_keepalive_stuff = False # for tests @@ -48,6 +49,10 @@ assert index < MAX_FAIL_BOXES, "overflow!" self.assembler.fail_boxes_int[index] = intvalue + def set_future_value_float(self, index, floatvalue): + assert index < MAX_FAIL_BOXES, "overflow!" + self.assembler.fail_boxes_float[index] = floatvalue + def set_future_value_ref(self, index, ptrvalue): assert index < MAX_FAIL_BOXES, "overflow!" self.assembler.fail_boxes_ptr[index] = ptrvalue @@ -55,6 +60,9 @@ def get_latest_value_int(self, index): return self.assembler.fail_boxes_int[index] + def get_latest_value_float(self, index): + return self.assembler.fail_boxes_float[index] + def get_latest_value_ref(self, index): ptrvalue = self.assembler.fail_boxes_ptr[index] # clear after reading Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py Tue Sep 29 14:36:48 2009 @@ -101,6 +101,8 @@ for i, arg in enumerate(args): if isinstance(arg, int): self.cpu.set_future_value_int(i, arg) + elif isinstance(arg, float): + self.cpu.set_future_value_float(i, arg) else: assert isinstance(lltype.typeOf(arg), lltype.Ptr) llgcref = lltype.cast_opaque_ptr(llmemory.GCREF, arg) @@ -115,10 +117,17 @@ def getint(self, index): return self.cpu.get_latest_value_int(index) + def getfloat(self, index): + return self.cpu.get_latest_value_float(index) + def getints(self, end): return [self.cpu.get_latest_value_int(index) for index in range(0, end)] + def getfloats(self, end): + return [self.cpu.get_latest_value_float(index) for + index in range(0, end)] + def getptr(self, index, T): gcref = self.cpu.get_latest_value_ref(index) return lltype.cast_opaque_ptr(T, gcref) @@ -486,3 +495,13 @@ s = lltype.malloc(self.A, 3) self.interpret(ops, [s, ord('a')]) assert s[1] == 'a' + +class TestRegallocFloats(BaseTestRegalloc): + def test_float_adds(self): + ops = ''' + [f0, f1] + f2 = float_add(f0, f1) + fail(f2, f0, f1) + ''' + self.interpret(ops, [3.0, 1.5]) + assert self.getfloats(3) == [4.5, 3.0, 1.5] From arigo at codespeak.net Tue Sep 29 14:37:35 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 14:37:35 +0200 (CEST) Subject: [pypy-svn] r67977 - in pypy/branch/remove-fail/pypy/jit: backend/llgraph backend/test metainterp metainterp/test Message-ID: <20090929123735.9244116800D@codespeak.net> Author: arigo Date: Tue Sep 29 14:37:34 2009 New Revision: 67977 Modified: pypy/branch/remove-fail/pypy/jit/backend/llgraph/llimpl.py pypy/branch/remove-fail/pypy/jit/backend/llgraph/runner.py pypy/branch/remove-fail/pypy/jit/backend/test/runner_test.py pypy/branch/remove-fail/pypy/jit/metainterp/resoperation.py pypy/branch/remove-fail/pypy/jit/metainterp/test/oparser.py Log: Start to remove the FAIL operation. Modified: pypy/branch/remove-fail/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/llgraph/llimpl.py Tue Sep 29 14:37:34 2009 @@ -168,16 +168,16 @@ def as_text(self, lines, indent): for op in self.operations: lines.append('\t'*indent + repr(op)) - if op.is_guard(): - op.subloop.as_text(lines, indent+1) class Operation(object): + result = None + descr = None + jump_target = None + fail_args = None + def __init__(self, opnum): self.opnum = opnum self.args = [] - self.result = None - self.descr = None - self.livevars = [] # for guards only def __repr__(self): if self.result is not None: @@ -352,25 +352,24 @@ def compile_add_fail(loop, fail_index): loop = _from_opaque(loop) - op = loop.operations[-1] + index = len(loop.operations)-1 + op = loop.operations[index] op.fail_index = fail_index + return index -def compile_suboperations(loop): +def compile_add_fail_arg(loop, intvar): loop = _from_opaque(loop) op = loop.operations[-1] - assert op.is_guard() - op.subloop = CompiledLoop() - return _to_opaque(op.subloop) + if op.fail_args is None: + op.fail_args = [] + op.fail_args.append(_variables[intvar]) -def compile_redirect_fail(old_loop, new_loop): +def compile_redirect_fail(old_loop, old_index, new_loop): old_loop = _from_opaque(old_loop) new_loop = _from_opaque(new_loop) - assert len(old_loop.operations) == 1 - assert old_loop.operations[-1].opnum == rop.FAIL - op = Operation(rop.JUMP) - op.args = old_loop.operations[-1].args - op.jump_target = new_loop - old_loop.operations[0] = op + guard_op = old_loop.operations[old_index] + assert guard_op.is_guard() + guard_op.jump_target = new_loop # ------------------------------ @@ -406,9 +405,24 @@ except GuardFailed: assert op.is_guard() _stats.exec_conditional_jumps += 1 - operations = op.subloop.operations - opindex = 0 - continue + if op.fail_args: + args = [self.getenv(v) for v in op.fail_args] + else: + args = [] + if op.jump_target is not None: + # a patched guard, pointing to further code + assert len(op.jump_target.inputargs) == len(args) + self.env = dict(zip(op.jump_target.inputargs, args)) + operations = op.jump_target.operations + opindex = 0 + continue + else: + # a non-patched guard + if self.verbose: + log.trace('failed: %s' % ( + ', '.join(map(str, args)),)) + self.fail_args = args + return op.fail_index #verbose = self.verbose assert (result is None) == (op.result is None) if op.result is not None: @@ -433,12 +447,6 @@ operations = op.jump_target.operations opindex = 0 _stats.exec_jumps += 1 - elif op.opnum == rop.FAIL: - if self.verbose: - log.trace('failed: %s' % ( - ', '.join(map(str, args)),)) - self.fail_args = args - return op.fail_index elif op.opnum == rop.FINISH: if self.verbose: log.trace('finished: %s' % ( @@ -1359,8 +1367,8 @@ setannotation(compile_add_ref_result, annmodel.SomeInteger()) setannotation(compile_add_float_result, annmodel.SomeInteger()) setannotation(compile_add_jump_target, annmodel.s_None) -setannotation(compile_add_fail, annmodel.s_None) -setannotation(compile_suboperations, s_CompiledLoop) +setannotation(compile_add_fail, annmodel.SomeInteger()) +setannotation(compile_add_fail_arg, annmodel.s_None) setannotation(compile_redirect_fail, annmodel.s_None) setannotation(new_frame, s_Frame) Modified: pypy/branch/remove-fail/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/llgraph/runner.py Tue Sep 29 14:37:34 2009 @@ -105,7 +105,8 @@ def compile_bridge(self, faildescr, inputargs, operations): c = self.compile_loop(inputargs, operations) - llimpl.compile_redirect_fail(faildescr._compiled_fail, c) + old, oldindex = faildescr._compiled_fail + llimpl.compile_redirect_fail(old, oldindex, c) def compile_loop(self, inputargs, operations): """In a real assembler backend, this should assemble the given @@ -125,10 +126,10 @@ var2index[box] = llimpl.compile_start_float_var(c) else: raise Exception("box is: %r" % (box,)) - self._compile_branch(c, operations, var2index) + self._compile_operations(c, operations, var2index) return c - def _compile_branch(self, c, operations, var2index): + def _compile_operations(self, c, operations, var2index): for op in operations: llimpl.compile_add(c, op.opnum) descr = op.descr @@ -152,11 +153,14 @@ raise Exception("%s args contain: %r" % (op.getopname(), x)) if op.is_guard(): - c2 = llimpl.compile_suboperations(c) - suboperations = op.suboperations - assert len(suboperations) == 1 - assert suboperations[0].opnum == rop.FAIL - self._compile_branch(c2, op.suboperations, var2index.copy()) + faildescr = op.descr + assert isinstance(faildescr, history.AbstractFailDescr) + index = llimpl.compile_add_fail(c, len(self.fail_descrs)) + faildescr._compiled_fail = c, index + self.fail_descrs.append(faildescr) + if op.fail_args: + for box in op.fail_args: + llimpl.compile_add_fail_arg(c, var2index[box]) x = op.result if x is not None: if isinstance(x, history.BoxInt): @@ -177,12 +181,6 @@ else: target = target.executable_token llimpl.compile_add_jump_target(c, target) - elif op.opnum == rop.FAIL: - faildescr = op.descr - assert isinstance(faildescr, history.AbstractFailDescr) - faildescr._compiled_fail = c - llimpl.compile_add_fail(c, len(self.fail_descrs)) - self.fail_descrs.append(faildescr) elif op.opnum == rop.FINISH: llimpl.compile_add_fail(c, len(self.fail_descrs)) faildescr = op.descr Modified: pypy/branch/remove-fail/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/test/runner_test.py Tue Sep 29 14:37:34 2009 @@ -71,13 +71,11 @@ else: results = [result] operations = [ResOperation(opnum, valueboxes, result), - ResOperation(rop.FAIL, results, None, + ResOperation(rop.FINISH, results, None, descr=BasicFailDescr())] + if operations[0].is_guard() and not descr: + descr = BasicFailDescr() operations[0].descr = descr - if operations[0].is_guard(): - operations[0].suboperations = [ResOperation(rop.FAIL, - [ConstInt(-13)], None, - descr=BasicFailDescr())] inputargs = [] for box in valueboxes: if isinstance(box, Box): @@ -93,7 +91,7 @@ faildescr = BasicFailDescr() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), - ResOperation(rop.FAIL, [i1], None, descr=faildescr) + ResOperation(rop.FINISH, [i1], None, descr=faildescr) ] inputargs = [i0] executable_token = self.cpu.compile_loop(inputargs, operations) @@ -107,17 +105,15 @@ i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() - faildescr = BasicFailDescr() + faildescr = BasicFailDescr() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), - ResOperation(rop.GUARD_TRUE, [i2], None), + ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr), ResOperation(rop.JUMP, [i1], None), ] inputargs = [i0] - operations[2].suboperations = [ - ResOperation(rop.FAIL, [i1], None, descr=faildescr) - ] + operations[2].fail_args = [i1] operations[-1].jump_target = None executable_token = self.cpu.compile_loop(inputargs, operations) @@ -137,23 +133,20 @@ operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), - ResOperation(rop.GUARD_TRUE, [i2], None), + ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr), ResOperation(rop.JUMP, [i1], None), ] inputargs = [i0] - operations[2].suboperations = [ - ResOperation(rop.FAIL, [i1], None, descr=faildescr) - ] + operations[2].fail_args = [i1] operations[-1].jump_target = None wr_i1 = weakref.ref(i1) wr_guard = weakref.ref(operations[2]) - wr_fail = weakref.ref(operations[2].suboperations[0]) executable_token = self.cpu.compile_loop(inputargs, operations) del i0, i1, i2 del inputargs del operations gc.collect() - assert not wr_i1() and not wr_guard() and not wr_fail() + assert not wr_i1() and not wr_guard() def test_compile_bridge(self): i0 = BoxInt() @@ -164,13 +157,11 @@ operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), - ResOperation(rop.GUARD_TRUE, [i2], None), + ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1), ResOperation(rop.JUMP, [i1], None), ] inputargs = [i0] - operations[2].suboperations = [ - ResOperation(rop.FAIL, [i1], None, descr=faildescr1) - ] + operations[2].fail_args = [i1] operations[-1].jump_target = None executable_token = self.cpu.compile_loop(inputargs, operations) loop_token = LoopToken() @@ -180,12 +171,10 @@ i3 = BoxInt() bridge = [ ResOperation(rop.INT_LE, [i1b, ConstInt(19)], i3), - ResOperation(rop.GUARD_TRUE, [i3], None), + ResOperation(rop.GUARD_TRUE, [i3], None, descr=faildescr2), ResOperation(rop.JUMP, [i1b], None), ] - bridge[1].suboperations = [ - ResOperation(rop.FAIL, [i1b], None, descr=faildescr2) - ] + bridge[1].fail_args = [i1b] bridge[-1].jump_target = loop_token self.cpu.compile_bridge(faildescr1, [i1b], bridge) @@ -399,20 +388,20 @@ if not reversed: ops = [ ResOperation(opnum, [v1, v2], v_res), - ResOperation(rop.GUARD_NO_OVERFLOW, [], None), - ResOperation(rop.FAIL, [v_res], None, descr=BasicFailDescr()), + ResOperation(rop.GUARD_NO_OVERFLOW, [], None, + descr=BasicFailDescr()), + ResOperation(rop.FINISH, [v_res], None, + descr=BasicFailDescr()), ] - ops[1].suboperations = [ResOperation(rop.FAIL, [], None, - descr=BasicFailDescr())] else: v_exc = self.cpu.ts.BoxRef() ops = [ ResOperation(opnum, [v1, v2], v_res), - ResOperation(rop.GUARD_OVERFLOW, [], None), - ResOperation(rop.FAIL, [], None, descr=BasicFailDescr()), + ResOperation(rop.GUARD_OVERFLOW, [], None, + descr=BasicFailDescr()), + ResOperation(rop.FINISH, [], None, descr=BasicFailDescr()), ] - ops[1].suboperations = [ResOperation(rop.FAIL, [v_res], None, - descr=BasicFailDescr())] + ops[1].fail_args = [v_res] # executable_token = self.cpu.compile_loop([v1, v2], ops) for x, y, z in testcases: @@ -422,7 +411,7 @@ self.cpu.set_future_value_int(1, y) fail = self.cpu.execute_token(executable_token) if (z == boom) ^ reversed: - assert fail is ops[1].suboperations[0].descr + assert fail is ops[1].descr else: assert fail is ops[-1].descr if z != boom: @@ -491,7 +480,6 @@ for (opname, args) in [(rop.GUARD_TRUE, [BoxInt(1)]), (rop.GUARD_FALSE, [BoxInt(0)]), (rop.GUARD_VALUE, [BoxInt(42), BoxInt(42)]), - #(rop.GUARD_VALUE_INVERSE, [BoxInt(42), BoxInt(41)]), ]: assert self.execute_operation(opname, args, 'void') == None assert not self.guard_failed @@ -1034,10 +1022,10 @@ ops = ''' [i0] + i1 = same_as(1) call(ConstClass(fptr), i0, descr=calldescr) - p0 = guard_exception(ConstClass(xtp)) - fail(1) - fail(0, p0) + p0 = guard_exception(ConstClass(xtp)) [i1] + finish(0, p0) ''' FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) fptr = llhelper(FPTR, func) @@ -1089,10 +1077,10 @@ exc_ptr = xptr ops = ''' [i0] + i1 = same_as(1) call(ConstClass(fptr), i0, descr=calldescr) - guard_no_exception() - fail(1) - fail(0) + guard_no_exception() [i1] + finish(0) ''' loop = parse(ops, self.cpu, namespace=locals()) executable_token = self.cpu.compile_loop(loop.inputargs, Modified: pypy/branch/remove-fail/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/resoperation.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/resoperation.py Tue Sep 29 14:37:34 2009 @@ -8,8 +8,9 @@ jump_target = None # for 'guard_*' - suboperations = None - optimized = None + suboperations = property(lambda x: crash, lambda x, y: crash) # XXX temp + optimized = property(lambda x: crash, lambda x, y: crash) # XXX temp + fail_args = None # for x86 backend and guards inputargs = None @@ -105,7 +106,6 @@ _oplist = [ '_FINAL_FIRST', 'JUMP', - 'FAIL', 'FINISH', '_FINAL_LAST', Modified: pypy/branch/remove-fail/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/test/oparser.py Tue Sep 29 14:37:34 2009 @@ -26,9 +26,6 @@ yield op.result for box in op.args: yield box - if op.suboperations: - for box in opboxes(op.suboperations): - yield box def allboxes(): for box in self.inputargs: yield box @@ -167,25 +164,44 @@ raise ParseError("Unknown var: %s" % arg) if hasattr(descr, '_oparser_uses_descr'): descr._oparser_uses_descr(self, args) - if opnum == rop.FAIL and descr is None and self.invent_fail_descrs: - descr = BasicFailDescr() - return opnum, args, descr + if rop._GUARD_FIRST <= opnum <= rop._GUARD_LAST: + if descr is None and self.invent_fail_descrs: + descr = BasicFailDescr() + i = line.find('[', endnum) + 1 + j = line.find(']', i) + if i <= 0 or j <= 0: + raise ParseError("missing fail_args for guard operation") + fail_args = [] + for arg in line[i:j].split(','): + arg = arg.strip() + try: + fail_args.append(self.vars[arg]) + except KeyError: + raise ParseError("Unknown var in fail_args: %s" % arg) + else: + fail_args = None + if opnum == rop.FINISH: + if descr is None and self.invent_fail_descrs: + descr = BasicFailDescr() + return opnum, args, descr, fail_args def parse_result_op(self, line): res, op = line.split("=", 1) res = res.strip() op = op.strip() - opnum, args, descr = self.parse_op(op) + opnum, args, descr, fail_args = self.parse_op(op) if res in self.vars: raise ParseError("Double assign to var %s in line: %s" % (res, line)) rvar = self.box_for_var(res) self.vars[res] = rvar res = ResOperation(opnum, args, rvar, descr) + res.fail_args = fail_args return res def parse_op_no_result(self, line): - opnum, args, descr = self.parse_op(line) + opnum, args, descr, fail_args = self.parse_op(line) res = ResOperation(opnum, args, None, descr) + res.fail_args = fail_args if opnum == rop.JUMP: self.jumps.append(res) return res @@ -241,10 +257,7 @@ # dedent return num, ops elif line.startswith(" "*(indent + 1)): - # suboperations - new_indent = len(line) - len(line.lstrip()) - num, suboperations = self.parse_ops(new_indent, lines, num) - ops[-1].suboperations = suboperations + raise ParseError("indentation not valid any more") else: ops.append(self.parse_next_op(lines[num].strip())) num += 1 From pedronis at codespeak.net Tue Sep 29 14:58:20 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 29 Sep 2009 14:58:20 +0200 (CEST) Subject: [pypy-svn] r67978 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090929125820.71F34168009@codespeak.net> Author: pedronis Date: Tue Sep 29 14:58:19 2009 New Revision: 67978 Modified: pypy/trunk/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/optimize.py pypy/trunk/pypy/jit/metainterp/test/test_basic.py Log: kill the specialize options, unused, later we really want to unify simple and full optimizing Modified: pypy/trunk/pypy/jit/metainterp/history.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py Tue Sep 29 14:58:19 2009 @@ -895,8 +895,7 @@ class Options: logger_noopt = None - def __init__(self, specialize=True, listops=False): - self.specialize = specialize + def __init__(self, listops=False): self.listops = listops def _freeze_(self): return True Modified: pypy/trunk/pypy/jit/metainterp/optimize.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimize.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimize.py Tue Sep 29 14:58:19 2009 @@ -5,11 +5,6 @@ from pypy.jit.metainterp.specnode import equals_specnodes def optimize_loop(options, old_loop_tokens, loop, cpu): - if not options.specialize: # for tests only - if old_loop_tokens: - return old_loop_tokens[0] - else: - return None options.logger_noopt.log_loop(loop.inputargs, loop.operations) finder = PerfectSpecializationFinder(cpu) finder.find_nodes_loop(loop) @@ -25,8 +20,6 @@ from pypy.jit.metainterp.optimizeopt import optimize_bridge_1 def optimize_bridge(options, old_loop_tokens, bridge, cpu): - if not options.specialize: # for tests only - return old_loop_tokens[0] options.logger_noopt.log_loop(bridge.inputargs, bridge.operations) finder = BridgeSpecializationFinder(cpu) finder.find_nodes_bridge(bridge) Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Tue Sep 29 14:58:19 2009 @@ -23,7 +23,7 @@ stats = history.Stats() cpu = CPUClass(rtyper, stats, False) graph = rtyper.annotator.translator.graphs[0] - opt = history.Options(specialize=False, listops=listops) + opt = history.Options(listops=listops) metainterp_sd = pyjitpl.MetaInterpStaticData(graph, [], cpu, stats, opt) metainterp_sd.finish_setup(optimizer=optimizer) metainterp = pyjitpl.MetaInterp(metainterp_sd) From fijal at codespeak.net Tue Sep 29 15:11:45 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 29 Sep 2009 15:11:45 +0200 (CEST) Subject: [pypy-svn] r67979 - pypy/extradoc/talk/rupy2009 Message-ID: <20090929131145.50E17168007@codespeak.net> Author: fijal Date: Tue Sep 29 15:11:39 2009 New Revision: 67979 Added: pypy/extradoc/talk/rupy2009/abstract.txt (contents, props changed) Log: Quick abstract Added: pypy/extradoc/talk/rupy2009/abstract.txt ============================================================================== --- (empty file) +++ pypy/extradoc/talk/rupy2009/abstract.txt Tue Sep 29 15:11:39 2009 @@ -0,0 +1,9 @@ +PyPy status talk +================ + +In this talk I would like to give update on the status of +the PyPy project. Most of the talk will focus on the PyPy's JIT, +new feature that allows to run (some so far) programs really +fast. I'll also present details how to exploit JIT's possiblities +and future directions. + From fijal at codespeak.net Tue Sep 29 15:13:55 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 29 Sep 2009 15:13:55 +0200 (CEST) Subject: [pypy-svn] r67980 - pypy/extradoc/talk/rupy2009 Message-ID: <20090929131355.2BAA4168007@codespeak.net> Author: fijal Date: Tue Sep 29 15:13:54 2009 New Revision: 67980 Modified: pypy/extradoc/talk/rupy2009/abstract.txt Log: my quick bio Modified: pypy/extradoc/talk/rupy2009/abstract.txt ============================================================================== --- pypy/extradoc/talk/rupy2009/abstract.txt (original) +++ pypy/extradoc/talk/rupy2009/abstract.txt Tue Sep 29 15:13:54 2009 @@ -7,3 +7,9 @@ fast. I'll also present details how to exploit JIT's possiblities and future directions. +Bio: + +I'm a core developer of the PyPy project, involved in it for +last couple years. In recent years I spent lot of time improving +dynamic compilation features of PyPy as well as improving general +PyPy compatibility. From arigo at codespeak.net Tue Sep 29 15:17:46 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 15:17:46 +0200 (CEST) Subject: [pypy-svn] r67981 - pypy/extradoc/talk/rupy2009 Message-ID: <20090929131746.73715168008@codespeak.net> Author: arigo Date: Tue Sep 29 15:17:45 2009 New Revision: 67981 Modified: pypy/extradoc/talk/rupy2009/abstract.txt Log: s//the :-) Modified: pypy/extradoc/talk/rupy2009/abstract.txt ============================================================================== --- pypy/extradoc/talk/rupy2009/abstract.txt (original) +++ pypy/extradoc/talk/rupy2009/abstract.txt Tue Sep 29 15:17:45 2009 @@ -1,15 +1,15 @@ PyPy status talk ================ -In this talk I would like to give update on the status of -the PyPy project. Most of the talk will focus on the PyPy's JIT, -new feature that allows to run (some so far) programs really -fast. I'll also present details how to exploit JIT's possiblities -and future directions. +In this talk I would like to give an update on the status of +the PyPy project. Most of the talk will focus on PyPy's JIT, +a new feature that allows to run (some, so far) programs really +fast. I'll also present in detail how to exploit the JIT's +possiblities and future directions. Bio: -I'm a core developer of the PyPy project, involved in it for -last couple years. In recent years I spent lot of time improving -dynamic compilation features of PyPy as well as improving general -PyPy compatibility. +I'm a core developer of the PyPy project, involved in it for the +last couple of years. In recent years I spent a lot of time improving +the dynamic compilation features of PyPy as well as improving the +general PyPy compatibility. From fijal at codespeak.net Tue Sep 29 16:08:21 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 29 Sep 2009 16:08:21 +0200 (CEST) Subject: [pypy-svn] r67982 - in pypy/branch/floats-via-sse2/pypy/jit/backend/x86: . test Message-ID: <20090929140821.0B553168007@codespeak.net> Author: fijal Date: Tue Sep 29 16:08:19 2009 New Revision: 67982 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py Log: Start supporting float constants. Support MODRM64 etc. Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Tue Sep 29 16:08:19 2009 @@ -49,6 +49,8 @@ print "convert_to_imm: got a %s" % c raise AssertionError +BASE_CONSTANT_SIZE = 1000 + class X86XMMRegisterManager(RegisterManager): all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] @@ -56,9 +58,25 @@ save_around_call_regs = all_regs reg_width = 2 - def convert_to_imm(self, c): - xxx # what to do here... + def new_const_array(self): + return lltype.malloc(rffi.CArray(lltype.Float), BASE_CONSTANT_SIZE, + flavor='raw') + + def __init__(self, *args, **kwds): + RegisterManager.__init__(self, *args, **kwds) + self.constant_arrays = [self.new_const_array()] + self.constant_arrays_counter = 0 + def convert_to_imm(self, c): + if self.constant_arrays_counter >= BASE_CONSTANT_SIZE: + self.constant_arrays.append(self.new_const_array) + self.constant_arrays_counter = 0 + res = self.constant_arrays_counter + self.constant_arrays_counter += 1 + arr = self.constant_arrays[-1] + arr[res] = c.getfloat() + return heap64(rffi.cast(lltype.Signed, arr) + res * WORD * 2) + def after_call(self, v): xxx # test # the result is stored in st0, but we don't have this around, Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py Tue Sep 29 16:08:19 2009 @@ -497,7 +497,7 @@ assert s[1] == 'a' class TestRegallocFloats(BaseTestRegalloc): - def test_float_adds(self): + def test_float_add(self): ops = ''' [f0, f1] f2 = float_add(f0, f1) @@ -505,3 +505,13 @@ ''' self.interpret(ops, [3.0, 1.5]) assert self.getfloats(3) == [4.5, 3.0, 1.5] + + def test_float_adds_stack(self): + ops = ''' + [f0, f1, f2, f3, f4, f5, f6, f7, f8] + f9 = float_add(f0, f1) + f10 = float_add(f8, 3.5) + fail(f9, f10, f2, f3, f4, f5, f6, f7, f8) + ''' + self.interpret(ops, [0.1, .2, .3, .4, .5, .6, .7, .8, .9]) + assert self.getfloats(9) == [.1+.2, .9+3.5, .3, .4, .5, .6, .7, .8, .9] From arigo at codespeak.net Tue Sep 29 16:37:45 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 16:37:45 +0200 (CEST) Subject: [pypy-svn] r67983 - in pypy/branch/remove-fail/pypy/jit/metainterp: . test Message-ID: <20090929143745.C57EE168008@codespeak.net> Author: arigo Date: Tue Sep 29 16:37:44 2009 New Revision: 67983 Modified: pypy/branch/remove-fail/pypy/jit/metainterp/compile.py pypy/branch/remove-fail/pypy/jit/metainterp/graphpage.py pypy/branch/remove-fail/pypy/jit/metainterp/history.py pypy/branch/remove-fail/pypy/jit/metainterp/optimizeopt.py pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py pypy/branch/remove-fail/pypy/jit/metainterp/simple_optimize.py pypy/branch/remove-fail/pypy/jit/metainterp/test/oparser.py pypy/branch/remove-fail/pypy/jit/metainterp/test/test_basic.py pypy/branch/remove-fail/pypy/jit/metainterp/test/test_oparser.py pypy/branch/remove-fail/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/branch/remove-fail/pypy/jit/metainterp/test/test_optimizeopt.py Log: Refactor the world. This is mostly making some of the tests happy again. Modified: pypy/branch/remove-fail/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/compile.py Tue Sep 29 16:37:44 2009 @@ -193,32 +193,24 @@ class ResumeGuardDescr(ResumeDescr): counter = 0 + # this class also gets attributes stored by resume.py code - def __init__(self, original_greenkey, guard_op): - ResumeDescr.__init__(self, original_greenkey) - self.guard_op = guard_op - # this class also gets attributes stored by resume.py code + def store_final_boxes(self, guard_op, boxes): + guard_op.fail_args = boxes + self.guard_opnum = guard_op.opnum + self.fail_arg_types = [box.type for box in boxes] def handle_fail(self, metainterp_sd): from pypy.jit.metainterp.pyjitpl import MetaInterp metainterp = MetaInterp(metainterp_sd) - fail_op = self.get_guard_op().suboperations[-1] # xxx unhappy - return metainterp.handle_guard_failure(fail_op, self) - - def get_guard_op(self): - guard_op = self.guard_op - assert guard_op.is_guard() - if guard_op.optimized is not None: # should always be the case, - return guard_op.optimized # except if not optimizing at all - else: - return guard_op + return metainterp.handle_guard_failure(self) def compile_and_attach(self, metainterp, new_loop): # We managed to create a bridge. Attach the new operations # to the corrsponding guard_op and compile from there inputargs = metainterp.history.inputargs if not we_are_translated(): - self.get_guard_op()._debug_suboperations = new_loop.operations + self._debug_suboperations = new_loop.operations send_bridge_to_backend(metainterp.staticdata, self, inputargs, new_loop.operations) Modified: pypy/branch/remove-fail/pypy/jit/metainterp/graphpage.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/graphpage.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/graphpage.py Tue Sep 29 16:37:44 2009 @@ -17,13 +17,13 @@ for graph, highlight in graphs: for op in graph.get_operations(): if is_interesting_guard(op): - graphs.append((SubGraph(op._debug_suboperations), + graphs.append((SubGraph(op.descr._debug_suboperations), highlight)) graphpage = ResOpGraphPage(graphs, errmsg) graphpage.display() def is_interesting_guard(op): - return hasattr(op, '_debug_suboperations') + return hasattr(op.descr, '_debug_suboperations') class ResOpGraphPage(GraphPage): @@ -155,7 +155,7 @@ op = operations[opindex] lines.append(repr(op)) if is_interesting_guard(op): - tgt = op._debug_suboperations[0] + tgt = op.descr._debug_suboperations[0] tgt_g, tgt_i = self.all_operations[tgt] self.genedge((graphindex, opstartindex), (tgt_g, tgt_i), Modified: pypy/branch/remove-fail/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/history.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/history.py Tue Sep 29 16:37:44 2009 @@ -642,7 +642,7 @@ # The TreeLoop class contains a loop or a generalized loop, i.e. a tree # of operations. Each branch ends in a jump which can go either to -# the top of the same loop, or to another TreeLoop; or it ends in a FAIL. +# the top of the same loop, or to another TreeLoop; or it ends in a FINISH. class Base(object): """Common base class for TreeLoop and History.""" @@ -665,16 +665,16 @@ # ops of the kind 'guard_xxx' contain a further list of operations, # which may itself contain 'guard_xxx' and so on, making a tree. - def _all_operations(self, omit_fails=False): + def _all_operations(self, omit_finish=False): "NOT_RPYTHON" result = [] - _list_all_operations(result, self.operations, omit_fails) + _list_all_operations(result, self.operations, omit_finish) return result def summary(self, adding_insns={}): # for debugging "NOT_RPYTHON" insns = adding_insns.copy() - for op in self._all_operations(omit_fails=True): + for op in self._all_operations(omit_finish=True): opname = op.getopname() insns[opname] = insns.get(opname, 0) + 1 return insns @@ -710,13 +710,16 @@ for box in op.args: if isinstance(box, Box): assert box in seen - assert (op.suboperations is not None) == op.is_guard() if op.is_guard(): - if hasattr(op, '_debug_suboperations'): - ops = op._debug_suboperations - else: - ops = op.suboperations - TreeLoop.check_consistency_of_branch(ops, seen.copy()) + assert op.descr is not None + if hasattr(op.descr, '_debug_suboperations'): + ops = op.descr._debug_suboperations + TreeLoop.check_consistency_of_branch(ops, seen.copy()) + for box in op.fail_args or []: + assert isinstance(box, Box) + assert box in seen + else: + assert op.fail_args is None box = op.result if box is not None: assert isinstance(box, Box) @@ -747,20 +750,16 @@ def __repr__(self): return '<%s>' % (self.name,) -def _list_all_operations(result, operations, omit_fails=True): - if omit_fails and operations[-1].opnum in (rop.FAIL, rop.FINISH): +def _list_all_operations(result, operations, omit_finish=True): + if omit_finish and operations[-1].opnum == rop.FINISH: # xxx obscure return result.extend(operations) for op in operations: - if op.is_guard(): - if hasattr(op, '_debug_suboperations'): - ops = op._debug_suboperations - else: - if omit_fails: - continue - ops = op.suboperations - _list_all_operations(result, ops, omit_fails) + if op.is_guard() and op.descr: + if hasattr(op.descr, '_debug_suboperations'): + ops = op.descr._debug_suboperations + _list_all_operations(result, ops, omit_finish) # ____________________________________________________________ Modified: pypy/branch/remove-fail/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/optimizeopt.py Tue Sep 29 16:37:44 2009 @@ -481,7 +481,6 @@ self.loop.operations = self.newoperations def emit_operation(self, op, must_clone=True): - op1 = op for i in range(len(op.args)): arg = op.args[i] if arg in self.values: @@ -492,21 +491,14 @@ must_clone = False op.args[i] = box if op.is_guard(): - self.clone_guard(op, op1) + self.store_final_boxes_in_guard(op) elif op.can_raise(): self.exception_might_have_happened = True self.newoperations.append(op) - def _get_faildescr(self, op_fail): - descr = op_fail.descr + def store_final_boxes_in_guard(self, op): + descr = op.descr assert isinstance(descr, compile.ResumeGuardDescr) - return descr - - def clone_guard(self, op2, op1): - assert len(op1.suboperations) == 1 - op_fail = op1.suboperations[0] - assert op_fail.opnum == rop.FAIL - descr = self._get_faildescr(op_fail) oldboxes = [] args = resume.flatten_resumedata(descr) # xxx expensive for box in args: @@ -519,14 +511,7 @@ value = self.values[box] value.get_args_for_fail(modifier) newboxes = modifier.finish() - # XXX we mutate op_fail in-place below, as well as op_fail.descr - # via the ResumeDataVirtualAdder. That's bad. Hopefully - # it does not really matter because no-one is going to look again - # at its unoptimized version. We should really clone it (and - # the descr too). - op_fail.args = newboxes - op2.suboperations = op1.suboperations - op1.optimized = op2 + descr.store_final_boxes(op, newboxes) def clean_fields_of_values(self, descr=None): if descr is None: Modified: pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py Tue Sep 29 16:37:44 2009 @@ -917,17 +917,16 @@ moreargs = [box] + extraargs else: moreargs = list(extraargs) - guard_op = metainterp.history.record(opnum, moreargs, None) original_greenkey = metainterp.resumekey.original_greenkey - resumedescr = compile.ResumeGuardDescr(original_greenkey, guard_op) + resumedescr = compile.ResumeGuardDescr(original_greenkey) + guard_op = metainterp.history.record(opnum, moreargs, None, + descr=resumedescr) virtualizable_boxes = None if metainterp.staticdata.virtualizable_info is not None: virtualizable_boxes = metainterp.virtualizable_boxes resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, resumedescr) self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count - op = history.ResOperation(rop.FAIL, [], None, descr=resumedescr) - guard_op.suboperations = [op] metainterp.attach_debug_info(guard_op) self.pc = saved_pc return guard_op @@ -1337,10 +1336,10 @@ except GenerateMergePoint, gmp: return self.designate_target_loop(gmp) - def handle_guard_failure(self, exec_result, key): + def handle_guard_failure(self, key): from pypy.jit.metainterp.warmspot import ContinueRunningNormallyBase - resumedescr = self.initialize_state_from_guard_failure(exec_result) assert isinstance(key, compile.ResumeGuardDescr) + resumedescr = self.initialize_state_from_guard_failure(key) original_greenkey = key.original_greenkey # notice that here we just put the greenkey # use -1 to mark that we will have to give up @@ -1348,10 +1347,9 @@ self.current_merge_points = [(original_greenkey, -1)] self.resumekey = key self.seen_can_enter_jit = False - guard_op = key.get_guard_op() started_as_blackhole = self.is_blackholing() try: - self.prepare_resume_from_failure(guard_op.opnum) + self.prepare_resume_from_failure(key.guard_opnum) self.interpret() assert False, "should always raise" except GenerateMergePoint, gmp: @@ -1538,18 +1536,13 @@ self.initialize_virtualizable(original_boxes) return original_boxes - def initialize_state_from_guard_failure(self, guard_failure): + def initialize_state_from_guard_failure(self, resumedescr): # guard failure: rebuild a complete MIFrame stack self.in_recursion = -1 # always one portal around - inputargs = self.load_values_from_failure(guard_failure) - resumedescr = guard_failure.descr - assert isinstance(resumedescr, compile.ResumeGuardDescr) + inputargs = self.load_values_from_failure(resumedescr) warmrunnerstate = self.staticdata.state must_compile = warmrunnerstate.must_compile_from_failure(resumedescr) if must_compile: - guard_op = resumedescr.get_guard_op() - suboperations = guard_op.suboperations - assert suboperations[-1] is guard_failure self.history = history.History(self.cpu) self.history.inputargs = inputargs self.staticdata.profiler.start_tracing() @@ -1559,16 +1552,17 @@ self.rebuild_state_after_failure(resumedescr, inputargs) return resumedescr - def load_values_from_failure(self, guard_failure): + def load_values_from_failure(self, resumedescr): cpu = self.cpu + fail_arg_types = resumedescr.fail_arg_types inputargs = [] - for i in range(len(guard_failure.args)): - oldbox = guard_failure.args[i] # xxx unhappy - if isinstance(oldbox, history.BoxInt): + for i in range(len(fail_arg_types)): + boxtype = fail_arg_types[i] + if boxtype == history.INT: box = history.BoxInt(cpu.get_latest_value_int(i)) - elif isinstance(oldbox, cpu.ts.BoxRef): + elif boxtype == history.REF: box = cpu.ts.BoxRef(cpu.get_latest_value_ref(i)) - elif isinstance(oldbox, history.BoxFloat): + elif boxtype == history.FLOAT: box = history.BoxFloat(cpu.get_latest_value_float(i)) else: assert False, "should not see %r in guard_failure.args" % ( Modified: pypy/branch/remove-fail/pypy/jit/metainterp/simple_optimize.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/simple_optimize.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/simple_optimize.py Tue Sep 29 16:37:44 2009 @@ -17,11 +17,10 @@ newoperations = [] for op in loop.operations: if op.is_guard(): - op_fail = op.suboperations[-1] - descr = op_fail.descr + descr = op.descr assert isinstance(descr, compile.ResumeGuardDescr) args = resume.flatten_resumedata(descr) - op_fail.args = args + descr.store_final_boxes(op, args) newoperations.append(op) loop.operations = newoperations return None Modified: pypy/branch/remove-fail/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/test/oparser.py Tue Sep 29 16:37:44 2009 @@ -44,8 +44,12 @@ for name, value in kwds.iteritems(): getattr(boxes, name).value = value +def default_fail_descr(fail_args=None): + return BasicFailDescr() + + class OpParser(object): - def __init__(self, descr, cpu, namespace, type_system, boxkinds, jump_targets, invent_fail_descrs=True): + def __init__(self, descr, cpu, namespace, type_system, boxkinds, jump_target, invent_fail_descr=default_fail_descr): self.descr = descr self.vars = {} self.cpu = cpu @@ -53,9 +57,9 @@ self.type_system = type_system self.boxkinds = boxkinds or {} self.jumps = [] - self.jump_targets = jump_targets + self.jump_target = jump_target self._cache = namespace.setdefault('_CACHE_', {}) - self.invent_fail_descrs = invent_fail_descrs + self.invent_fail_descr = invent_fail_descr def box_for_var(self, elem): try: @@ -162,27 +166,28 @@ args.append(self.getvar(arg)) except KeyError: raise ParseError("Unknown var: %s" % arg) - if hasattr(descr, '_oparser_uses_descr'): - descr._oparser_uses_descr(self, args) if rop._GUARD_FIRST <= opnum <= rop._GUARD_LAST: - if descr is None and self.invent_fail_descrs: - descr = BasicFailDescr() i = line.find('[', endnum) + 1 j = line.find(']', i) if i <= 0 or j <= 0: raise ParseError("missing fail_args for guard operation") fail_args = [] - for arg in line[i:j].split(','): - arg = arg.strip() - try: - fail_args.append(self.vars[arg]) - except KeyError: - raise ParseError("Unknown var in fail_args: %s" % arg) + if i < j: + for arg in line[i:j].split(','): + arg = arg.strip() + try: + fail_args.append(self.vars[arg]) + except KeyError: + raise ParseError("Unknown var in fail_args: %s" % arg) + if descr is None and self.invent_fail_descr: + descr = self.invent_fail_descr(fail_args) + if hasattr(descr, '_oparser_uses_descr_of_guard'): + descr._oparser_uses_descr_of_guard(self, fail_args) else: fail_args = None if opnum == rop.FINISH: - if descr is None and self.invent_fail_descrs: - descr = BasicFailDescr() + if descr is None and self.invent_fail_descr: + descr = self.invent_fail_descr() return opnum, args, descr, fail_args def parse_result_op(self, line): @@ -235,15 +240,12 @@ if num < len(newlines): raise ParseError("unexpected dedent at line: %s" % newlines[num]) loop = ExtendedTreeLoop("loop") - if (self.jump_targets is not None and - len(self.jump_targets) != len(self.jumps)): - raise ParseError("Wrong number of jump targets") - if self.jump_targets is None: - for jump in self.jumps: - jump.jump_target = None - else: - for jump, jump_target in zip(self.jumps, self.jump_targets): - jump.jump_target = jump_target + if len(self.jumps) > 1: + raise ParseError("Multiple jumps??") + if self.jump_target is not None and len(self.jumps) != 1: + raise ParseError("A jump is expected if a jump_target is given") + for jump in self.jumps: + jump.jump_target = self.jump_target loop.operations = ops loop.inputargs = inpargs return loop @@ -274,13 +276,15 @@ return base_indent, inpargs def parse(descr, cpu=None, namespace=None, type_system='lltype', - boxkinds=None, jump_targets=None, invent_fail_descrs=True): + boxkinds=None, jump_target=None, + invent_fail_descr=default_fail_descr): if namespace is None: namespace = {} - return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_targets, invent_fail_descrs).parse() + return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_target, + invent_fail_descr).parse() def pure_parse(*args, **kwds): - kwds['invent_fail_descrs'] = False + kwds['invent_fail_descr'] = None return parse(*args, **kwds) def _box_counter_more_than(s): Modified: pypy/branch/remove-fail/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/test/test_basic.py Tue Sep 29 16:37:44 2009 @@ -224,8 +224,8 @@ if self.basic: found = 0 for op in get_stats().loops[0]._all_operations(): - if op.getopname() == 'fail': - liveboxes = op.args + if op.getopname() == 'guard_true': + liveboxes = op.fail_args assert len(liveboxes) == 3 for box in liveboxes: assert isinstance(box, history.BoxInt) Modified: pypy/branch/remove-fail/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/test/test_oparser.py Tue Sep 29 16:37:44 2009 @@ -11,27 +11,26 @@ # a comment i2 = int_add(i0, i1) i3 = int_sub(i2, 3) # another comment - fail() # (tricky) + finish() # (tricky) """ loop = parse(x) assert len(loop.operations) == 3 assert [op.opnum for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, - rop.FAIL] + rop.FINISH] assert len(loop.inputargs) == 2 assert loop.operations[-1].descr def test_const_ptr_subops(): x = """ [p0] - guard_class(p0, ConstClass(vtable)) - fail() + guard_class(p0, ConstClass(vtable)) [] """ S = lltype.Struct('S') vtable = lltype.nullptr(S) loop = parse(x, None, locals()) assert len(loop.operations) == 1 - assert len(loop.operations[0].suboperations) == 1 - assert loop.operations[0].suboperations[-1].descr + assert loop.operations[0].descr + assert loop.operations[0].fail_args == [] def test_descr(): class Xyz(AbstractDescr): @@ -48,8 +47,7 @@ def test_after_fail(): x = """ [i0] - guard_value(i0, 3) - fail() + guard_value(i0, 3) [] i1 = int_add(1, 2) """ loop = parse(x, None, {}) @@ -128,21 +126,9 @@ jump() ''' obj = object() - loop = parse(x, jump_targets=[obj]) + loop = parse(x, jump_target=obj) assert loop.operations[0].jump_target is obj -def test_jump_target_self(): - x = ''' - [i2] - guard_true(i2) - jump() - jump() - ''' - obj = object() - loop = parse(x, jump_targets=[obj, None]) - assert loop.operations[-1].jump_target is None - assert loop.operations[0].suboperations[0].jump_target is obj - def test_debug_merge_point(): x = ''' [] Modified: pypy/branch/remove-fail/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/test/test_optimizefindnode.py Tue Sep 29 16:37:44 2009 @@ -16,7 +16,7 @@ from pypy.jit.metainterp.specnode import VirtualArraySpecNode from pypy.jit.metainterp.specnode import VirtualStructSpecNode from pypy.jit.metainterp.specnode import ConstantSpecNode -from pypy.jit.metainterp.test.oparser import pure_parse as parse +from pypy.jit.metainterp.test.oparser import parse def test_sort_descrs(): class PseudoDescr(AbstractDescr): @@ -159,11 +159,13 @@ namespace = locals() class BaseTest(object): + invent_fail_descr = None def parse(self, s, boxkinds=None): return parse(s, self.cpu, self.namespace, type_system=self.type_system, - boxkinds=boxkinds) + boxkinds=boxkinds, + invent_fail_descr=self.invent_fail_descr) def unpack_specnodes(self, text): # @@ -229,8 +231,7 @@ ops = """ [i] i0 = int_sub(i, 1) - guard_value(i0, 0) - fail(i0) + guard_value(i0, 0) [i0] jump(i0) """ boxes, getnode = self.find_nodes(ops, 'Not') @@ -327,8 +328,7 @@ def test_find_nodes_new_3(self): ops = """ [sum, p1] - guard_class(p1, ConstClass(node_vtable)) - fail() + guard_class(p1, ConstClass(node_vtable)) [] i1 = getfield_gc(p1, descr=valuedescr) i2 = int_sub(i1, 1) sum2 = int_add(sum, i1) @@ -380,11 +380,9 @@ def test_find_nodes_new_aliasing_1(self): ops = """ [sum, p1] - guard_class(p1, ConstClass(node_vtable)) - fail() + guard_class(p1, ConstClass(node_vtable)) [] p3 = getfield_gc(p1, descr=nextdescr) - guard_class(p3, ConstClass(node_vtable)) - fail() + guard_class(p3, ConstClass(node_vtable)) [] i1 = getfield_gc(p1, descr=valuedescr) i2 = int_sub(i1, 1) sum2 = int_add(sum, i1) @@ -412,8 +410,7 @@ def test_find_nodes_new_mismatch(self): ops = """ [p1] - guard_class(p1, ConstClass(node_vtable)) - fail() + guard_class(p1, ConstClass(node_vtable)) [] p2 = new_with_vtable(ConstClass(node_vtable2)) jump(p2) """ @@ -424,10 +421,8 @@ def test_find_nodes_new_aliasing_mismatch(self): ops = """ [p0, p1] - guard_class(p0, ConstClass(node_vtable)) - fail() - guard_class(p1, ConstClass(node_vtable2)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] + guard_class(p1, ConstClass(node_vtable2)) [] p2 = new_with_vtable(ConstClass(node_vtable2)) jump(p2, p2) """ @@ -465,41 +460,29 @@ p0 = new_with_vtable(ConstClass(node_vtable)) p1 = new_with_vtable(ConstClass(node_vtable)) i1 = oononnull(p0) - guard_true(i1) - fail() + guard_true(i1) [] i2 = ooisnull(p0) - guard_false(i2) - fail() + guard_false(i2) [] i3 = ooisnot(p0, NULL) - guard_true(i3) - fail() + guard_true(i3) [] i4 = oois(p0, NULL) - guard_false(i4) - fail() + guard_false(i4) [] i5 = ooisnot(NULL, p0) - guard_true(i5) - fail() + guard_true(i5) [] i6 = oois(NULL, p0) - guard_false(i6) - fail() + guard_false(i6) [] i7 = ooisnot(p0, p1) - guard_true(i7) - fail() + guard_true(i7) [] i8 = oois(p0, p1) - guard_false(i8) - fail() + guard_false(i8) [] i9 = ooisnot(p0, p2) - guard_true(i9) - fail() + guard_true(i9) [] i10 = oois(p0, p2) - guard_false(i10) - fail() + guard_false(i10) [] i11 = ooisnot(p2, p1) - guard_true(i11) - fail() + guard_true(i11) [] i12 = oois(p2, p1) - guard_false(i12) - fail() + guard_false(i12) [] jump(p0, p1, p2) """ self.find_nodes(ops, '''Virtual(node_vtable), @@ -519,8 +502,7 @@ ops = """ [p0] i0 = getfield_gc(p0, descr=valuedescr) - guard_value(i0, 5) - fail() + guard_value(i0, 5) [] p1 = new_with_vtable(ConstClass(node_vtable)) # the field 'value' has its default value of 0 jump(p1) @@ -532,8 +514,7 @@ def test_find_nodes_nonvirtual_guard_class(self): ops = """ [p1] - guard_class(p1, ConstClass(node_vtable)) - fail(p1) + guard_class(p1, ConstClass(node_vtable)) [p1] jump(p1) """ self.find_nodes(ops, 'Not') @@ -574,8 +555,7 @@ def test_find_nodes_p123_guard_class(self): ops = """ [i1, p2, p3] - guard_class(p3, ConstClass(node_vtable)) - fail(i1, p2, p3) + guard_class(p3, ConstClass(node_vtable)) [i1, p2, p3] i3 = getfield_gc(p3, descr=valuedescr) escape(i3) p1 = new_with_vtable(ConstClass(node_vtable)) @@ -717,8 +697,7 @@ def test_find_nodes_guard_value_constant(self): ops = """ [p1] - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] jump(ConstPtr(myptr)) """ self.find_nodes(ops, 'Constant(myptr)') @@ -726,8 +705,7 @@ def test_find_nodes_guard_value_constant_mismatch(self): ops = """ [p1] - guard_value(p1, ConstPtr(myptr2)) - fail() + guard_value(p1, ConstPtr(myptr2)) [] jump(ConstPtr(myptr)) """ py.test.raises(InvalidLoop, self.find_nodes, ops, None) @@ -736,8 +714,7 @@ ops = """ [p1] escape(p1) - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] jump(ConstPtr(myptr)) """ self.find_nodes(ops, 'Constant(myptr)') @@ -745,8 +722,7 @@ def test_find_nodes_guard_value_same_as_constant(self): ops = """ [p1] - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] p2 = same_as(ConstPtr(myptr)) jump(p2) """ @@ -837,25 +813,18 @@ ops = """ [p12] i16 = ooisnull(p12) - guard_false(i16) - fail() - guard_class(p12, ConstClass(node_vtable)) - fail() - guard_class(p12, ConstClass(node_vtable)) - fail() + guard_false(i16) [] + guard_class(p12, ConstClass(node_vtable)) [] + guard_class(p12, ConstClass(node_vtable)) [] i22 = getfield_gc_pure(p12, descr=valuedescr) escape(i22) i25 = ooisnull(p12) - guard_false(i25) - fail() - guard_class(p12, ConstClass(node_vtable)) - fail() - guard_class(p12, ConstClass(node_vtable)) - fail() + guard_false(i25) [] + guard_class(p12, ConstClass(node_vtable)) [] + guard_class(p12, ConstClass(node_vtable)) [] i29 = getfield_gc_pure(p12, descr=valuedescr) i31 = int_add_ovf(i29, 1) - guard_no_overflow() - fail() + guard_no_overflow() [] p33 = new_with_vtable(ConstClass(node_vtable)) # NODE setfield_gc(p33, i31, descr=valuedescr) # @@ -864,13 +833,10 @@ p38 = new_with_vtable(ConstClass(u_vtable)) # U setfield_gc(p38, p35, descr=onedescr) i39 = ooisnull(p38) - guard_false(i39) - fail() + guard_false(i39) [] i40 = oononnull(p38) - guard_true(i40) - fail() - guard_class(p38, ConstClass(u_vtable)) - fail() + guard_true(i40) [] + guard_class(p38, ConstClass(u_vtable)) [] p42 = getfield_gc(p38, descr=onedescr) # Array(NODE) i43 = arraylen_gc(p42, descr=arraydescr3) i45 = int_sub(i43, 0) @@ -879,23 +845,19 @@ p47 = new_array(i45, descr=arraydescr3) # Array(NODE) setfield_gc(p46, p47, descr=ddescr) i48 = int_lt(0, i43) - guard_true(i48) - fail() + guard_true(i48) [] p49 = getarrayitem_gc(p42, 0, descr=arraydescr3) # NODE p50 = getfield_gc(p46, descr=ddescr) # Array(NODE) setarrayitem_gc(p50, 0, p49, descr=arraydescr3) i52 = int_lt(1, i43) - guard_false(i52) - fail() + guard_false(i52) [] i53 = getfield_gc(p46, descr=cdescr) i55 = int_ne(i53, 1) - guard_false(i55) - fail() + guard_false(i55) [] p56 = getfield_gc(p46, descr=ddescr) # Array(NODE) p58 = getarrayitem_gc(p56, 0, descr=arraydescr3) # NODE i59 = ooisnull(p38) - guard_false(i59) - fail() + guard_false(i59) [] jump(p58) """ self.find_nodes(ops, 'Virtual(node_vtable, valuedescr=Not)') @@ -1040,8 +1002,7 @@ ops = """ [p1] p2 = getfield_gc(p1, descr=nextdescr) - guard_class(p2, ConstClass(node_vtable)) - fail() + guard_class(p2, ConstClass(node_vtable)) [] jump(p2) """ self.find_bridge(ops, 'Not', 'Not') @@ -1085,20 +1046,20 @@ nextdescr=Virtual(node_vtable, nextdescr=Not)))''') - def test_bridge_to_fail(self): + def test_bridge_to_finish(self): ops = """ [i1] i2 = int_add(i1, 5) - fail(i2) + finish(i2) """ self.find_bridge(ops, 'Not', 'Not') - def test_bridge_virtual_to_fail(self): + def test_bridge_virtual_to_finish(self): ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i1, descr=valuedescr) - fail(p1) + finish(p1) """ self.find_bridge(ops, 'Not', 'Not') Modified: pypy/branch/remove-fail/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/test/test_optimizeopt.py Tue Sep 29 16:37:44 2009 @@ -12,7 +12,7 @@ from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt from pypy.jit.metainterp import resume, executor, compile from pypy.jit.metainterp.resoperation import rop, opname, ResOperation -from pypy.jit.metainterp.test.oparser import pure_parse as parse +from pypy.jit.metainterp.test.oparser import pure_parse class FakeFrame(object): parent_resumedata_snapshot = None @@ -28,12 +28,8 @@ b0 = BoxInt() b1 = BoxInt() opt = optimizeopt.Optimizer(None, None) - op = ResOperation(rop.GUARD_TRUE, [], None) - op.suboperations = [ - ResOperation(rop.FAIL, [], None) - ] - fdescr = ResumeGuardDescr(None, None) - op.suboperations[-1].descr = fdescr + fdescr = ResumeGuardDescr(None) + op = ResOperation(rop.GUARD_TRUE, [], None, descr=fdescr) # setup rd data fi = [("code0", 1, 2), ("code1", 3, -1)] fdescr.rd_virtuals = None @@ -43,10 +39,8 @@ snapshot0 = resume.Snapshot(None, [b0]) fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1]) # - op1 = op - opt.clone_guard(op, op1) - assert op1.optimized is op - assert op1.suboperations[-1].args == [b0, b1] + opt.store_final_boxes_in_guard(op) + assert op.fail_args == [b0, b1] assert fdescr.rd_nums == [0, -1, 1, -1] assert fdescr.rd_virtuals is None assert fdescr.rd_consts == [] @@ -71,8 +65,10 @@ else: remap[op2.result] = op1.result assert op1.descr == op2.descr - if op1.suboperations: - assert equaloplists(op1.suboperations, op2.suboperations, remap) + if op1.fail_args or op2.fail_args: + assert len(op1.fail_args) == len(op2.fail_args) + for x, y in zip(op1.fail_args, op2.fail_args): + assert x == remap.get(y, y) assert len(oplist1) == len(oplist2) print '-'*57 return True @@ -81,55 +77,56 @@ ops = """ [i0] i1 = int_add(i0, 1) - guard_true(i1) - i2 = int_add(i1, 1) - fail(i2) + i2 = int_add(i1, 1) + guard_true(i1) [i2] jump(i1) """ namespace = {} - loop1 = parse(ops, namespace=namespace) - loop2 = parse(ops, namespace=namespace) - loop3 = parse(ops.replace("i2 = int_add", "i2 = int_sub"), - namespace=namespace) + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops, namespace=namespace) + loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), + namespace=namespace) assert equaloplists(loop1.operations, loop2.operations) py.test.raises(AssertionError, "equaloplists(loop1.operations, loop3.operations)") -def test_equaloplists_remap(): - ops1 = """ +def test_equaloplists_fail_args(): + ops = """ [i0] i1 = int_add(i0, 1) - guard_true(i1) - i2 = int_add(i1, 1) - fail(i2) - jump(i1) - """ - ops2 = """ - [i3] - i1 = int_add(i3, 1) - guard_true(i1) - i5 = int_add(i1, 1) - fail(i5) + i2 = int_add(i1, 1) + guard_true(i1) [i2, i1] jump(i1) """ - loop1 = parse(ops1) - loop2 = parse(ops2) + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), + namespace=namespace) py.test.raises(AssertionError, "equaloplists(loop1.operations, loop2.operations)") - i0 = loop1.inputargs[0] - i3 = loop2.inputargs[0] - i2 = loop1.operations[1].suboperations[0].result - i5 = loop2.operations[1].suboperations[0].result - assert equaloplists(loop1.operations, loop2.operations, - {i3: i0, i5: i2}) # ____________________________________________________________ -class Storage: +class Storage(compile.ResumeGuardDescr): "for tests." + def __init__(self): + pass + def store_final_boxes(self, op, boxes): + op.fail_args = boxes + def __eq__(self, other): + return type(self) is type(other) # xxx obscure class BaseTestOptimizeOpt(BaseTest): + def invent_fail_descr(self, fail_args): + if fail_args is None: + return None + descr = Storage() + descr.rd_frame_info_list = resume.FrameInfo(None, FakeFrame()) + descr.rd_snapshot = resume.Snapshot(None, fail_args) + descr.rd_virtuals = None + return descr + def assert_equal(self, optimized, expected): assert len(optimized.inputargs) == len(expected.inputargs) remap = {} @@ -158,22 +155,7 @@ assert loop.operations[-1].opnum == rop.JUMP loop.operations[-1].jump_target = loop # - Optimizer = optimizeopt.Optimizer - old_get_faildescr = Optimizer._get_faildescr - def _get_faildescr(self, op_fail): - if op_fail.descr is None: - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, - FakeFrame()) - descr.rd_snapshot = resume.Snapshot(None, op_fail.args) - descr.rd_virtuals = None - return descr - return old_get_faildescr(self, op_fail) - Optimizer._get_faildescr = _get_faildescr - try: - optimize_loop_1(self.cpu, loop) - finally: - Optimizer._get_faildescr = old_get_faildescr.im_func + optimize_loop_1(self.cpu, loop) # expected = self.parse(optops) self.assert_equal(loop, expected) @@ -182,8 +164,7 @@ ops = """ [i] i0 = int_sub(i, 1) - guard_value(i0, 0) - fail(i0) + guard_value(i0, 0) [i0] jump(i) """ self.optimize_loop(ops, 'Not', ops) @@ -193,13 +174,10 @@ [] i0 = int_add(2, 3) i1 = int_is_true(i0) - guard_true(i1) - fail() + guard_true(i1) [] i2 = bool_not(i1) - guard_false(i2) - fail() - guard_value(i0, 5) - fail() + guard_false(i2) [] + guard_value(i0, 5) [] jump() """ expected = """ @@ -247,16 +225,13 @@ def test_remove_guard_class_1(self): ops = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] + guard_class(p0, ConstClass(node_vtable)) [] jump(p0) """ expected = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) @@ -266,8 +241,7 @@ [i0] p0 = new_with_vtable(ConstClass(node_vtable)) escape(p0) - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] jump(i0) """ expected = """ @@ -282,8 +256,7 @@ ops = """ [i0] p0 = same_as(ConstPtr(myptr)) - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] jump(i0) """ expected = """ @@ -296,11 +269,9 @@ ops = """ [] i0 = escape() - guard_value(i0, 0) - fail() + guard_value(i0, 0) [] i1 = int_add(i0, 1) - guard_value(i1, 1) - fail() + guard_value(i1, 1) [] i2 = int_add(i1, 2) escape(i2) jump() @@ -308,8 +279,7 @@ expected = """ [] i0 = escape() - guard_value(i0, 0) - fail() + guard_value(i0, 0) [] escape(3) jump() """ @@ -318,8 +288,7 @@ def test_remove_guard_value_if_constant(self): ops = """ [p1] - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] jump(ConstPtr(myptr)) """ expected = """ @@ -331,20 +300,16 @@ def test_ooisnull_oononnull_1(self): ops = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] i0 = oononnull(p0) - guard_true(i0) - fail() + guard_true(i0) [] i1 = ooisnull(p0) - guard_false(i1) - fail() + guard_false(i1) [] jump(p0) """ expected = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) @@ -353,18 +318,15 @@ ops = """ [i0] i1 = int_is_true(i0) - guard_true(i1) - fail() + guard_true(i1) [] i2 = int_is_true(i0) - guard_true(i2) - fail() + guard_true(i2) [] jump(i0) """ expected = """ [i0] i1 = int_is_true(i0) - guard_true(i1) - fail() + guard_true(i1) [] jump(i0) """ self.optimize_loop(ops, 'Not', expected) @@ -373,36 +335,30 @@ ops = """ [p0] i0 = oononnull(p0) # p0 != NULL - guard_true(i0) - fail() + guard_true(i0) [] i1 = ooisnull(p0) - guard_false(i1) - fail() + guard_false(i1) [] jump(p0) """ expected = """ [p0] i0 = oononnull(p0) - guard_true(i0) - fail() + guard_true(i0) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) ops = """ [p0] i1 = ooisnull(p0) - guard_false(i1) - fail() + guard_false(i1) [] i0 = oononnull(p0) # p0 != NULL - guard_true(i0) - fail() + guard_true(i0) [] jump(p0) """ expected = """ [p0] i1 = ooisnull(p0) - guard_false(i1) - fail() + guard_false(i1) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) @@ -412,19 +368,16 @@ [] p0 = escape() i0 = ooisnull(p0) - guard_true(i0) - fail() + guard_true(i0) [] i1 = oononnull(p0) - guard_false(i1) - fail() + guard_false(i1) [] jump() """ expected = """ [] p0 = escape() i0 = ooisnull(p0) - guard_true(i0) - fail() + guard_true(i0) [] jump() """ self.optimize_loop(ops, '', expected) @@ -432,19 +385,16 @@ [] p0 = escape() i0 = oononnull(p0) - guard_false(i0) - fail() + guard_false(i0) [] i1 = ooisnull(p0) - guard_true(i1) - fail() + guard_true(i1) [] jump() """ expected = """ [] p0 = escape() i0 = oononnull(p0) - guard_false(i0) - fail() + guard_false(i0) [] jump() """ self.optimize_loop(ops, '', expected) @@ -455,19 +405,16 @@ pv = new_with_vtable(ConstClass(node_vtable)) setfield_gc(pv, p0, descr=valuedescr) i0 = oononnull(p0) # p0 != NULL - guard_true(i0) - fail() + guard_true(i0) [] p1 = getfield_gc(pv, descr=valuedescr) i1 = ooisnull(p1) - guard_false(i1) - fail() + guard_false(i1) [] jump(p0) """ expected = """ [p0] i0 = oononnull(p0) - guard_true(i0) - fail() + guard_true(i0) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) @@ -475,26 +422,20 @@ def test_oois_1(self): ops = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] i0 = ooisnot(p0, NULL) - guard_true(i0) - fail() + guard_true(i0) [] i1 = oois(p0, NULL) - guard_false(i1) - fail() + guard_false(i1) [] i2 = ooisnot(NULL, p0) - guard_true(i0) - fail() + guard_true(i0) [] i3 = oois(NULL, p0) - guard_false(i1) - fail() + guard_false(i1) [] jump(p0) """ expected = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) @@ -504,23 +445,17 @@ [p0] setfield_gc(p0, 5, descr=valuedescr) # forces p0 != NULL i0 = ooisnot(p0, NULL) - guard_true(i0) - fail() + guard_true(i0) [] i1 = oois(p0, NULL) - guard_false(i1) - fail() + guard_false(i1) [] i2 = ooisnot(NULL, p0) - guard_true(i0) - fail() + guard_true(i0) [] i3 = oois(NULL, p0) - guard_false(i1) - fail() + guard_false(i1) [] i4 = oononnull(p0) - guard_true(i4) - fail() + guard_true(i4) [] i5 = ooisnull(p0) - guard_false(i5) - fail() + guard_false(i5) [] jump(p0) """ expected = """ @@ -534,8 +469,7 @@ ops = """ [] i = int_add(5, 3) - guard_value(i, 8) - fail() + guard_value(i, 8) [] jump() """ expected = """ @@ -548,8 +482,7 @@ ops = """ [] p1 = escape() - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] jump() """ self.optimize_loop(ops, '', ops) @@ -604,16 +537,12 @@ def test_fold_guard_no_exception(self): ops = """ [i] - guard_no_exception() - fail() + guard_no_exception() [] i1 = int_add(i, 3) - guard_no_exception() - fail() + guard_no_exception() [] i2 = call(i1) - guard_no_exception() - fail(i1, i2) - guard_no_exception() - fail() + guard_no_exception() [i1, i2] + guard_no_exception() [] i3 = call(i2) jump(i1) # the exception is considered lost when we loop back """ @@ -621,8 +550,7 @@ [i] i1 = int_add(i, 3) i2 = call(i1) - guard_no_exception() - fail(i1, i2) + guard_no_exception() [i1, i2] i3 = call(i2) jump(i1) """ @@ -667,41 +595,29 @@ ops = """ [p0, p1, p2] i1 = oononnull(p0) - guard_true(i1) - fail() + guard_true(i1) [] i2 = ooisnull(p0) - guard_false(i2) - fail() + guard_false(i2) [] i3 = ooisnot(p0, NULL) - guard_true(i3) - fail() + guard_true(i3) [] i4 = oois(p0, NULL) - guard_false(i4) - fail() + guard_false(i4) [] i5 = ooisnot(NULL, p0) - guard_true(i5) - fail() + guard_true(i5) [] i6 = oois(NULL, p0) - guard_false(i6) - fail() + guard_false(i6) [] i7 = ooisnot(p0, p1) - guard_true(i7) - fail() + guard_true(i7) [] i8 = oois(p0, p1) - guard_false(i8) - fail() + guard_false(i8) [] i9 = ooisnot(p0, p2) - guard_true(i9) - fail() + guard_true(i9) [] i10 = oois(p0, p2) - guard_false(i10) - fail() + guard_false(i10) [] i11 = ooisnot(p2, p1) - guard_true(i11) - fail() + guard_true(i11) [] i12 = oois(p2, p1) - guard_false(i12) - fail() + guard_false(i12) [] jump(p0, p1, p2) """ expected = """ @@ -720,26 +636,19 @@ expected2 = """ [p0, p1, p2] i1 = oononnull(p0) - guard_true(i1) - fail() + guard_true(i1) [] i7 = ooisnot(p0, p1) - guard_true(i7) - fail() + guard_true(i7) [] i8 = oois(p0, p1) - guard_false(i8) - fail() + guard_false(i8) [] i9 = ooisnot(p0, p2) - guard_true(i9) - fail() + guard_true(i9) [] i10 = oois(p0, p2) - guard_false(i10) - fail() + guard_false(i10) [] i11 = ooisnot(p2, p1) - guard_true(i11) - fail() + guard_true(i11) [] i12 = oois(p2, p1) - guard_false(i12) - fail() + guard_false(i12) [] jump(p0, p1, p2) """ self.optimize_loop(ops, 'Not, Not, Not', expected2) @@ -748,16 +657,14 @@ ops = """ [p0] i0 = getfield_gc(p0, descr=valuedescr) - guard_value(i0, 0) - fail() + guard_value(i0, 0) [] p1 = new_with_vtable(ConstClass(node_vtable)) # the field 'value' has its default value of 0 jump(p1) """ expected = """ [i] - guard_value(i, 0) - fail() + guard_value(i, 0) [] jump(0) """ # the 'expected' is sub-optimal, but it should be done by another later @@ -784,8 +691,7 @@ def test_virtual_4(self): ops = """ [i0, p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] i1 = getfield_gc(p0, descr=valuedescr) i2 = int_sub(i1, 1) i3 = int_add(i0, i1) @@ -805,8 +711,7 @@ def test_virtual_5(self): ops = """ [i0, p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] i1 = getfield_gc(p0, descr=valuedescr) i2 = int_sub(i1, 1) i3 = int_add(i0, i1) @@ -959,8 +864,7 @@ [i1] p1 = new_array(3, descr=arraydescr) i3 = arraylen_gc(p1, descr=arraydescr) - guard_value(i3, 3) - fail() + guard_value(i3, 3) [] setarrayitem_gc(p1, 1, i1, descr=arraydescr) setarrayitem_gc(p1, 0, 25, descr=arraydescr) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) @@ -977,7 +881,7 @@ [i1, p0] setarrayitem_gc(p0, 0, i1, descr=arraydescr) i2 = ooisnull(p0) - guard_false(i2) + guard_false(i2) [] p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ @@ -995,8 +899,7 @@ i1 = getarrayitem_gc(p1, 0, descr=arraydescr) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = int_sub(i1, i2) - guard_value(i3, 15) - fail() + guard_value(i3, 15) [] p2 = new_array(2, descr=arraydescr) setarrayitem_gc(p2, 1, i0, descr=arraydescr) setarrayitem_gc(p2, 0, 20, descr=arraydescr) @@ -1005,8 +908,7 @@ expected = """ [i0, i1, i2] i3 = int_sub(i1, i2) - guard_value(i3, 15) - fail() + guard_value(i3, 15) [] jump(i0, 20, i0) """ self.optimize_loop(ops, 'Not, VArray(arraydescr, Not, Not)', expected) @@ -1161,8 +1063,7 @@ [p1] i1 = getfield_gc(p1, descr=valuedescr) i2 = int_add_ovf(i1, 14) - guard_no_overflow() - fail() + guard_no_overflow() [] i3 = getfield_gc(p1, descr=valuedescr) escape(i2) escape(i3) @@ -1172,8 +1073,7 @@ [p1] i1 = getfield_gc(p1, descr=valuedescr) i2 = int_add_ovf(i1, 14) - guard_no_overflow() - fail() + guard_no_overflow() [] escape(i2) escape(i1) jump(p1) @@ -1221,8 +1121,7 @@ def test_duplicate_getfield_guard_value_const(self): ops = """ [p1] - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] i1 = getfield_gc(p1, descr=valuedescr) i2 = getfield_gc(ConstPtr(myptr), descr=valuedescr) escape(i1) @@ -1266,8 +1165,7 @@ [i0, p1] p4 = getfield_gc(p1, descr=nextdescr) i2 = ooisnull(p4) - guard_false(i2) - fail() + guard_false(i2) [] escape(p4) # p2 = new_with_vtable(ConstClass(node_vtable)) @@ -1278,8 +1176,7 @@ expected = """ [i0, p4] i2 = ooisnull(p4) - guard_false(i2) - fail() + guard_false(i2) [] escape(p4) # p3 = escape() @@ -1293,8 +1190,7 @@ [i0, p1] p4 = getarrayitem_gc(p1, 0, descr=arraydescr2) i2 = ooisnull(p4) - guard_false(i2) - fail() + guard_false(i2) [] escape(p4) # p2 = new_array(1, descr=arraydescr2) @@ -1305,8 +1201,7 @@ expected = """ [i0, p4] i2 = ooisnull(p4) - guard_false(i2) - fail() + guard_false(i2) [] escape(p4) # p3 = escape() @@ -1319,8 +1214,7 @@ ops = """ [p1] i1 = ooisnull(p1) - guard_true(i1) - fail() + guard_true(i1) [] # p2 = new_with_vtable(ConstClass(node_vtable)) jump(p2) @@ -1332,8 +1226,7 @@ py.test.skip("this would fail if we had Fixed again in the specnodes") ops = """ [p1] - guard_class(p1, ConstClass(node_vtable2)) - fail() + guard_class(p1, ConstClass(node_vtable2)) [] # p2 = new_with_vtable(ConstClass(node_vtable)) escape(p2) # prevent it from staying Virtual @@ -1347,8 +1240,7 @@ [p1] p2 = getfield_gc(p1, descr=nextdescr) i1 = ooisnull(p2) - guard_true(i1) - fail() + guard_true(i1) [] # p3 = new_with_vtable(ConstClass(node_vtable)) p4 = new_with_vtable(ConstClass(node_vtable)) @@ -1364,15 +1256,14 @@ def make_fail_descr(self): class FailDescr(compile.ResumeGuardDescr): args_seen = [] - def _oparser_uses_descr(self, oparse, args): + def _oparser_uses_descr_of_guard(self, oparse, fail_args): # typically called twice, before and after optimization if len(self.args_seen) == 0: fdescr.rd_frame_info_list = resume.FrameInfo(None, FakeFrame()) - fdescr.rd_snapshot = resume.Snapshot(None, args) + fdescr.rd_snapshot = resume.Snapshot(None, fail_args) fdescr.virtuals = None - self.args_seen.append((args, oparse)) - + self.args_seen.append((fail_args, oparse)) # fdescr = instantiate(FailDescr) self.fdescr = fdescr @@ -1475,14 +1366,12 @@ i4 = getfield_gc(p1, descr=valuedescr) # i2 = int_add(10, 5) - guard_true(i1) - fail(i2, i4, descr=fdescr) + guard_true(i1, descr=fdescr) [i2, i4] jump(i1, i4) """ expected = """ [i1, i3] - guard_true(i1) - fail(i3, descr=fdescr) + guard_true(i1, descr=fdescr) [i3] jump(1, i3) """ self.optimize_loop(ops, 'Not, Not', expected) @@ -1495,14 +1384,12 @@ p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i2, descr=valuedescr) setfield_gc(p1, p1, descr=nextdescr) - guard_true(i1) - fail(p1, descr=fdescr) + guard_true(i1, descr=fdescr) [p1] jump(i1, i2) """ expected = """ [i1, i2] - guard_true(i1) - fail(i2, descr=fdescr) + guard_true(i1, descr=fdescr) [i2] jump(1, i2) """ self.optimize_loop(ops, 'Not, Not', expected) @@ -1520,14 +1407,12 @@ setfield_gc(p1, p2, descr=nextdescr) setfield_gc(p2, i2, descr=valuedescr) setfield_gc(p2, p3, descr=nextdescr) - guard_true(i1) - fail(p1, i3, descr=fdescr) + guard_true(i1, descr=fdescr) [p1, i3] jump(i2, i1, i3, p3) """ expected = """ [i1, i2, i3, p3] - guard_true(i1) - fail(i3, i2, p3, descr=fdescr) + guard_true(i1, descr=fdescr) [i3, i2, p3] jump(i2, 1, i3, p3) """ self.optimize_loop(ops, 'Not, Not, Not, Not', expected) @@ -1550,14 +1435,12 @@ setfield_gc(p1, i2, descr=valuedescr) setfield_gc(p1, p2, descr=nextdescr) setfield_gc(p2, i2, descr=valuedescr) - guard_true(i1) - fail(i4, %s, i3, descr=fdescr) + guard_true(i1, descr=fdescr) [i4, %s, i3] jump(i1, i2, i3) """ expected = """ [i1, i2, i3] - guard_true(i1) - fail(i3, i2, descr=fdescr) + guard_true(i1, descr=fdescr) [i3, i2] jump(1, i2, i3) """ self.optimize_loop(ops % arg, 'Not, Not, Not', expected) @@ -1576,14 +1459,12 @@ setfield_gc(p1, p2, descr=nextdescr) setfield_gc(p2, i2, descr=valuedescr) setfield_gc(p2, p1, descr=nextdescr) # a cycle - guard_true(i1) - fail(p1, i3, p2, i4, descr=fdescr) + guard_true(i1, descr=fdescr) [p1, i3, p2, i4] jump(i2, i1, i3, i4) """ expected = """ [i1, i2, i3, i4] - guard_true(i1) - fail(i3, i4, i2, descr=fdescr) + guard_true(i1, descr=fdescr) [i3, i4, i2] jump(i2, 1, i3, i4) """ self.optimize_loop(ops, 'Not, Not, Not, Not', expected) @@ -1596,16 +1477,14 @@ self.make_fail_descr() ops = """ [p0, i0, i1] - guard_true(i0) - fail(p0, descr=fdescr) + guard_true(i0, descr=fdescr) [p0] p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i1, descr=valuedescr) jump(p1, i1, i1) """ expected = """ [i1b, i0, i1] - guard_true(i0) - fail(i1b, descr=fdescr) + guard_true(i0, descr=fdescr) [i1b] jump(i1, i1, i1) """ self.optimize_loop(ops, '''Virtual(node_vtable, valuedescr=Not), @@ -1621,15 +1500,13 @@ p1 = new_array(3, descr=arraydescr) setarrayitem_gc(p1, 1, i1, descr=arraydescr) setarrayitem_gc(p1, 0, 25, descr=arraydescr) - guard_true(i1) - fail(p1, descr=fdescr) + guard_true(i1, descr=fdescr) [p1] i2 = getarrayitem_gc(p1, 1, descr=arraydescr) jump(i2) """ expected = """ [i1] - guard_true(i1) - fail(i1, descr=fdescr) + guard_true(i1, descr=fdescr) [i1] jump(1) """ self.optimize_loop(ops, 'Not', expected) @@ -1644,16 +1521,14 @@ p2 = new(descr=ssize) setfield_gc(p2, i1, descr=adescr) setfield_gc(p2, p1, descr=bdescr) - guard_true(i1) - fail(p2, descr=fdescr) + guard_true(i1, descr=fdescr) [p2] i3 = getfield_gc(p2, descr=adescr) p3 = getfield_gc(p2, descr=bdescr) jump(i3, p3) """ expected = """ [i1, p1] - guard_true(i1) - fail(i1, p1, descr=fdescr) + guard_true(i1, descr=fdescr) [i1, p1] jump(1, p1) """ self.optimize_loop(ops, 'Not, Not', expected) @@ -1671,8 +1546,7 @@ setfield_gc(p5s, i2, descr=adescr) setfield_gc(p5s, p7v, descr=bdescr) setarrayitem_gc(p1a, 1, p5s, descr=arraydescr2) - guard_true(i1) - fail(p1a, descr=fdescr) + guard_true(i1, descr=fdescr) [p1a] p2s = new(descr=ssize) p3v = new_with_vtable(ConstClass(node_vtable)) p4a = new_array(2, descr=arraydescr2) @@ -1684,8 +1558,7 @@ """ expected = """ [i1, ia, iv, pnull, i2] - guard_true(i1) - fail(ia, iv, i2, descr=fdescr) + guard_true(i1, descr=fdescr) [ia, iv, i2] jump(1, 1, i2, NULL, i2) """ self.optimize_loop(ops, ''' From cfbolz at codespeak.net Tue Sep 29 16:52:47 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 29 Sep 2009 16:52:47 +0200 (CEST) Subject: [pypy-svn] r67984 - in pypy/trunk/pypy: module/marshal/test objspace/std Message-ID: <20090929145247.23287168010@codespeak.net> Author: cfbolz Date: Tue Sep 29 16:52:46 2009 New Revision: 67984 Modified: pypy/trunk/pypy/module/marshal/test/test_marshalimpl.py pypy/trunk/pypy/objspace/std/marshal_impl.py Log: fix bug in marshaler that mutated a prebuilt 0l object Modified: pypy/trunk/pypy/module/marshal/test/test_marshalimpl.py ============================================================================== --- pypy/trunk/pypy/module/marshal/test/test_marshalimpl.py (original) +++ pypy/trunk/pypy/module/marshal/test/test_marshalimpl.py Tue Sep 29 16:52:46 2009 @@ -37,3 +37,11 @@ s = marshal.dumps(array.array('c', 'asd')) t = marshal.loads(s) assert type(t) is str and t == 'asd' + + def test_unmarshal_evil_bool(self): + import marshal + raises(ValueError, marshal.loads, 'l\x02\x00\x00\x00\x00\x00\x00\x00') + z = marshal.loads('I\x00\xe4\x0bT\x02\x00\x00\x00') + assert z == 10000000000 + z = marshal.loads('I\x00\x1c\xf4\xab\xfd\xff\xff\xff') + assert z == -10000000000 Modified: pypy/trunk/pypy/objspace/std/marshal_impl.py ============================================================================== --- pypy/trunk/pypy/objspace/std/marshal_impl.py (original) +++ pypy/trunk/pypy/objspace/std/marshal_impl.py Tue Sep 29 16:52:46 2009 @@ -270,7 +270,10 @@ for i in range(lng): shift = i * SHIFT result = result.add(rbigint.fromint(u.get_short()).lshift(shift)) - result.sign = sign + if lng and not result.tobool(): + raise_exception(space, 'bad marshal data') + if sign == -1: + result = result.neg() else: digits = [0] * lng for i in range(lng): @@ -278,6 +281,8 @@ if digit < 0: raise_exception(space, 'bad marshal data') digits[i] = digit + if digits[-1] == 0: + raise_exception(space, 'bad marshal data') result = rbigint(digits, sign) w_long = W_LongObject(result) return w_long From cfbolz at codespeak.net Tue Sep 29 16:54:59 2009 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 29 Sep 2009 16:54:59 +0200 (CEST) Subject: [pypy-svn] r67985 - pypy/trunk/pypy/module/marshal/test Message-ID: <20090929145459.41F2716801D@codespeak.net> Author: cfbolz Date: Tue Sep 29 16:54:58 2009 New Revision: 67985 Modified: pypy/trunk/pypy/module/marshal/test/test_marshalimpl.py Log: typo Modified: pypy/trunk/pypy/module/marshal/test/test_marshalimpl.py ============================================================================== --- pypy/trunk/pypy/module/marshal/test/test_marshalimpl.py (original) +++ pypy/trunk/pypy/module/marshal/test/test_marshalimpl.py Tue Sep 29 16:54:58 2009 @@ -38,7 +38,7 @@ t = marshal.loads(s) assert type(t) is str and t == 'asd' - def test_unmarshal_evil_bool(self): + def test_unmarshal_evil_long(self): import marshal raises(ValueError, marshal.loads, 'l\x02\x00\x00\x00\x00\x00\x00\x00') z = marshal.loads('I\x00\xe4\x0bT\x02\x00\x00\x00') From arigo at codespeak.net Tue Sep 29 16:59:31 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 16:59:31 +0200 (CEST) Subject: [pypy-svn] r67986 - in pypy/branch/remove-fail/pypy/jit/metainterp: . test Message-ID: <20090929145931.76BE0168010@codespeak.net> Author: arigo Date: Tue Sep 29 16:59:30 2009 New Revision: 67986 Modified: pypy/branch/remove-fail/pypy/jit/metainterp/logger.py pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py pypy/branch/remove-fail/pypy/jit/metainterp/test/test_logger.py pypy/branch/remove-fail/pypy/jit/metainterp/test/test_loop.py pypy/branch/remove-fail/pypy/jit/metainterp/test/test_recursive.py Log: Fixes. Now all tests in metainterp pass. Modified: pypy/branch/remove-fail/pypy/jit/metainterp/logger.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/logger.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/logger.py Tue Sep 29 16:59:30 2009 @@ -70,9 +70,11 @@ res = "" if op.descr is not None: args += ', descr=' + self.repr_of_descr(op.descr) + if op.is_guard() and op.fail_args is not None: + fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg) + for arg in op.fail_args]) + ']' + else: + fail_args = '' self.log_stream.write(pre + res + op.getopname() + - '(' + args + ')\n') - if op.is_guard(): - self.log_operations(None, op.suboperations, memo, - indent=indent+2) + '(' + args + ')' + fail_args + '\n') self.log_stream.flush() Modified: pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/pyjitpl.py Tue Sep 29 16:59:30 2009 @@ -1565,8 +1565,7 @@ elif boxtype == history.FLOAT: box = history.BoxFloat(cpu.get_latest_value_float(i)) else: - assert False, "should not see %r in guard_failure.args" % ( - oldbox,) + assert False, "bad box type: num=%d" % ord(boxtype) inputargs.append(box) return inputargs Modified: pypy/branch/remove-fail/pypy/jit/metainterp/test/test_logger.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/test/test_logger.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/test/test_logger.py Tue Sep 29 16:59:30 2009 @@ -25,9 +25,9 @@ class TestLogger(object): ts = llhelper - def reparse(self, inp, namespace=None): - """ parse loop once, then log it and parse again, - return both + def reparse(self, inp, namespace=None, check_equal=True): + """ parse loop once, then log it and parse again. + Checks that we get the same thing. """ if namespace is None: namespace = {} @@ -35,6 +35,9 @@ logger = Logger(self.ts) output = logger.log_loop(loop, namespace) oloop = pure_parse(output, namespace=namespace) + if check_equal: + equaloplists(loop.operations, oloop.operations) + assert oloop.inputargs == loop.inputargs return loop, oloop def test_simple(self): @@ -44,9 +47,7 @@ i8 = int_add(i6, 3) jump(i0, i8, i6, p3, p4, p5) ''' - loop, oloop = self.reparse(inp) - equaloplists(oloop.operations, loop.operations) - assert oloop.inputargs == loop.inputargs + self.reparse(inp) def test_descr(self): inp = ''' @@ -54,27 +55,22 @@ setfield_gc(p0, 3, descr=somedescr) ''' somedescr = Descr() - loop, oloop = self.reparse(inp, namespace=locals()) - equaloplists(loop.operations, oloop.operations) + self.reparse(inp, namespace=locals()) def test_guard(self): inp = ''' [i0] - guard_true(i0) - i1 = int_add(i0, 1) - guard_true(i1) - fail(i1) - fail(i1) - fail(i0) + i1 = int_add(i0, 1) + guard_true(i0) [i0, i1] + finish(i1) ''' - loop, oloop = self.reparse(inp) - equaloplists(loop.operations, oloop.operations) + self.reparse(inp) def test_debug_merge_point(self): inp = ''' [] debug_merge_point("info") ''' - loop, oloop = self.reparse(inp) + loop, oloop = self.reparse(inp, check_equal=False) + assert loop.operations[0].args[0]._get_str() == 'info' assert oloop.operations[0].args[0]._get_str() == 'info' - Modified: pypy/branch/remove-fail/pypy/jit/metainterp/test/test_loop.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/test/test_loop.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/test/test_loop.py Tue Sep 29 16:59:30 2009 @@ -173,8 +173,8 @@ if self.basic: found = 0 for op in get_stats().loops[0]._all_operations(): - if op.getopname() == 'fail': - liveboxes = op.args + if op.getopname() == 'guard_true': + liveboxes = op.fail_args assert len(liveboxes) == 2 # x, y (in some order) assert isinstance(liveboxes[0], history.BoxInt) assert isinstance(liveboxes[1], history.BoxInt) Modified: pypy/branch/remove-fail/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/branch/remove-fail/pypy/jit/metainterp/test/test_recursive.py Tue Sep 29 16:59:30 2009 @@ -344,8 +344,8 @@ for loop in get_stats().loops: assert len(loop.operations) <= length + 5 # because we only check once per metainterp bytecode for op in loop.operations: - if op.is_guard(): - assert len(op.suboperations) <= length + 5 + if op.is_guard() and hasattr(op.descr, '_debug_suboperations'): + assert len(op.descr._debug_suboperations) <= length + 5 def test_inline_trace_limit(self): myjitdriver = JitDriver(greens=[], reds=['n']) From arigo at codespeak.net Tue Sep 29 17:11:18 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 17:11:18 +0200 (CEST) Subject: [pypy-svn] r67987 - pypy/branch/remove-fail/pypy/jit/backend/test Message-ID: <20090929151118.93DAE168011@codespeak.net> Author: arigo Date: Tue Sep 29 17:11:18 2009 New Revision: 67987 Modified: pypy/branch/remove-fail/pypy/jit/backend/test/test_random.py Log: As usual, fix most of test_random but give up on the most obscure part. Modified: pypy/branch/remove-fail/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/test/test_random.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/test/test_random.py Tue Sep 29 17:11:18 2009 @@ -171,7 +171,7 @@ i, v.value) else: #print >>s, ' assert op is loop.operations[%d].suboperations[0]' % self.should_fail_by_num - for i, v in enumerate(self.should_fail_by.args): + for i, v in enumerate(self.should_fail_by.fail_args): print >>s, ' assert cpu.get_latest_value_int(%d) == %d' % ( i, v.value) self.names = names @@ -246,8 +246,8 @@ builder.intvars[:] = original_intvars else: op = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) - op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, - descr=BasicFailDescr())] + op.descr = BasicFailDescr() + op.fail_args = fail_subset builder.loop.operations.append(op) class BinaryOvfOperation(AbstractOvfOperation, BinaryOperation): @@ -264,11 +264,10 @@ def produce_into(self, builder, r): op, passing = self.gen_guard(builder, r) builder.loop.operations.append(op) - subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=BasicFailDescr())] + op.descr = BasicFailDescr() + op.fail_args = builder.subset_of_intvars(r) if not passing: - builder.should_fail_by = op.suboperations[0] + builder.should_fail_by = op builder.guard_op = op class GuardValueOperation(GuardOperation): @@ -429,7 +428,7 @@ if v not in used_later: endvars.append(v) r.shuffle(endvars) - loop.operations.append(ResOperation(rop.FAIL, endvars, None, + loop.operations.append(ResOperation(rop.FINISH, endvars, None, descr=BasicFailDescr())) if builder.should_fail_by: self.should_fail_by = builder.should_fail_by @@ -438,13 +437,21 @@ self.should_fail_by = loop.operations[-1] self.guard_op = None self.prebuilt_ptr_consts.extend(builder.prebuilt_ptr_consts) - endvars = self.should_fail_by.args + endvars = self.get_fail_args() self.expected = {} for v in endvars: self.expected[v] = v.value if demo_conftest.option.output: builder.print_loop() + def get_fail_args(self): + if self.should_fail_by.is_guard(): + assert self.should_fail_by.fail_args is not None + return self.should_fail_by.fail_args + else: + assert self.should_fail_by.opnum == rop.FINISH + return self.should_fail_by.args + def clear_state(self): for v, S, fields in self.prebuilt_ptr_consts: container = v.value._obj.container @@ -464,7 +471,7 @@ cpu.set_future_value_int(i, v) fail = cpu.execute_token(self.executable_token) assert fail is self.should_fail_by.descr - for i, v in enumerate(self.should_fail_by.args): + for i, v in enumerate(self.get_fail_args()): value = cpu.get_latest_value_int(i) assert value == self.expected[v], ( "Got %d, expected %d for value #%d" % (value, @@ -489,26 +496,25 @@ else: op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box], BoxPtr()) - op.suboperations = [ResOperation(rop.FAIL, [], None, - descr=BasicFailDescr())] + op.descr = BasicFailDescr() + op.fail_args = [] return op if self.dont_generate_more: return False r = self.r guard_op = self.guard_op - fail_args = guard_op.suboperations[-1].args - fail_descr = guard_op.suboperations[-1].descr - guard_op.suboperations = [] + fail_args = guard_op.fail_args + fail_descr = guard_op.descr op = self.should_fail_by - if not op.args: + if not op.fail_args: return False - subloop = DummyLoop(guard_op.suboperations) + subloop = DummyLoop([]) if guard_op.is_guard_exception(): - guard_op.suboperations.append(exc_handling(guard_op)) + subloop.operations.append(exc_handling(guard_op)) bridge_builder = self.builder.fork(self.builder.cpu, subloop, - op.args[:]) - self.generate_ops(bridge_builder, r, subloop, op.args[:]) + op.fail_args[:]) + self.generate_ops(bridge_builder, r, subloop, op.fail_args[:]) dont_compile = False if r.random() < 0.1: subset = bridge_builder.subset_of_intvars(r) @@ -527,8 +533,10 @@ self.expected = rl.expected assert len(rl.loop.inputargs) == len(args) if self.guard_op is None: - guard_op.suboperations[-1] = jump_op + subloop.operations[-1] = jump_op else: + print "fix me again" + return False args = self.guard_op.suboperations[-1].args + fail_args self.guard_op.suboperations[-1].args = args self.builder.cpu.compile_bridge(fail_descr, fail_args, @@ -548,7 +556,7 @@ return False if not dont_compile: self.builder.cpu.compile_bridge(fail_descr, fail_args, - guard_op.suboperations) # xxx insane + subloop.operations) return True def check_random_function(cpu, BuilderClass, r, num=None, max=None): From arigo at codespeak.net Tue Sep 29 17:16:28 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 17:16:28 +0200 (CEST) Subject: [pypy-svn] r67988 - pypy/branch/remove-fail/pypy/jit/backend/test Message-ID: <20090929151628.9E12F16800D@codespeak.net> Author: arigo Date: Tue Sep 29 17:16:27 2009 New Revision: 67988 Modified: pypy/branch/remove-fail/pypy/jit/backend/test/test_ll_random.py Log: Fix this too. Modified: pypy/branch/remove-fail/pypy/jit/backend/test/test_ll_random.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/test/test_ll_random.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/test/test_ll_random.py Tue Sep 29 17:16:27 2009 @@ -449,9 +449,9 @@ args = [c_addr] + subset descr = builder.cpu.calldescrof(TP, TP.ARGS, TP.RESULT) self.put(builder, args, descr) - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None) - op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, - descr=BasicFailDescr())] + op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None, + descr=BasicFailDescr()) + op.fail_args = fail_subset builder.loop.operations.append(op) # 5. Non raising-call and GUARD_EXCEPTION @@ -471,12 +471,11 @@ self.put(builder, args, descr) _, vtableptr = builder.get_random_structure_type_and_vtable(r) exc_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) - op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr()) - subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=BasicFailDescr())] + op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), + descr=BasicFailDescr()) + op.fail_args = builder.subset_of_intvars(r) op._exc_box = None - builder.should_fail_by = op.suboperations[0] + builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op) @@ -495,9 +494,9 @@ exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) assert builder.cpu.get_exception() builder.cpu.clear_exception() - op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr()) - op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, - descr=BasicFailDescr())] + op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), + descr=BasicFailDescr()) + op.fail_args = fail_subset builder.loop.operations.append(op) # 4. raising call and guard_no_exception @@ -513,12 +512,11 @@ self.put(builder, args, descr) assert builder.cpu.get_exception() builder.cpu.clear_exception() - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], BoxPtr()) + op = ResOperation(rop.GUARD_NO_EXCEPTION, [], BoxPtr(), + descr=BasicFailDescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) - subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=BasicFailDescr())] - builder.should_fail_by = op.suboperations[0] + op.fail_args = builder.subset_of_intvars(r) + builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op) @@ -540,12 +538,11 @@ if vtableptr != exc: break other_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) - op = ResOperation(rop.GUARD_EXCEPTION, [other_box], BoxPtr()) + op = ResOperation(rop.GUARD_EXCEPTION, [other_box], BoxPtr(), + descr=BasicFailDescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) - subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=BasicFailDescr())] - builder.should_fail_by = op.suboperations[0] + op.fail_args = builder.subset_of_intvars(r) + builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op) From arigo at codespeak.net Tue Sep 29 17:18:41 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 17:18:41 +0200 (CEST) Subject: [pypy-svn] r67989 - pypy/branch/remove-fail/pypy/jit/backend/llsupport Message-ID: <20090929151841.0D1FA168007@codespeak.net> Author: arigo Date: Tue Sep 29 17:18:40 2009 New Revision: 67989 Modified: pypy/branch/remove-fail/pypy/jit/backend/llsupport/descr.py Log: Fix. Modified: pypy/branch/remove-fail/pypy/jit/backend/llsupport/descr.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/llsupport/descr.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/llsupport/descr.py Tue Sep 29 17:18:40 2009 @@ -200,11 +200,11 @@ result_list = [result] operations = [ ResOperation(rop.CALL, args, result, self), - ResOperation(rop.GUARD_NO_EXCEPTION, [], None), - ResOperation(rop.FAIL, result_list, None, + ResOperation(rop.GUARD_NO_EXCEPTION, [], None, + descr=BasicFailDescr()), + ResOperation(rop.FINISH, result_list, None, descr=BasicFailDescr())] - operations[1].suboperations = [ResOperation(rop.FAIL, [], None, - descr=BasicFailDescr())] + operations[1].fail_args = [] executable_token = cpu.compile_loop(args, operations) self.executable_token = executable_token return executable_token From arigo at codespeak.net Tue Sep 29 18:01:11 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 18:01:11 +0200 (CEST) Subject: [pypy-svn] r67990 - in pypy/branch/remove-fail/pypy/jit/backend: llgraph llsupport test x86 x86/test Message-ID: <20090929160111.53534168014@codespeak.net> Author: arigo Date: Tue Sep 29 18:01:10 2009 New Revision: 67990 Modified: pypy/branch/remove-fail/pypy/jit/backend/llgraph/runner.py pypy/branch/remove-fail/pypy/jit/backend/llsupport/gc.py pypy/branch/remove-fail/pypy/jit/backend/test/runner_test.py pypy/branch/remove-fail/pypy/jit/backend/x86/assembler.py pypy/branch/remove-fail/pypy/jit/backend/x86/regalloc.py pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_basic.py pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_gc_integration.py pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_recompilation.py pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_regalloc.py pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_regalloc2.py pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_runner.py Log: Fix the tests in the x86 backend. Modified: pypy/branch/remove-fail/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/llgraph/runner.py Tue Sep 29 18:01:10 2009 @@ -158,9 +158,8 @@ index = llimpl.compile_add_fail(c, len(self.fail_descrs)) faildescr._compiled_fail = c, index self.fail_descrs.append(faildescr) - if op.fail_args: - for box in op.fail_args: - llimpl.compile_add_fail_arg(c, var2index[box]) + for box in op.fail_args: + llimpl.compile_add_fail_arg(c, var2index[box]) x = op.result if x is not None: if isinstance(x, history.BoxInt): Modified: pypy/branch/remove-fail/pypy/jit/backend/llsupport/gc.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/llsupport/gc.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/llsupport/gc.py Tue Sep 29 18:01:10 2009 @@ -492,8 +492,6 @@ op = ResOperation(rop.SETARRAYITEM_RAW, op.args, None, descr=op.descr) # ---------- - if op.is_guard(): - self.rewrite_assembler(cpu, op.suboperations) newops.append(op) del operations[:] operations.extend(newops) Modified: pypy/branch/remove-fail/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/test/runner_test.py Tue Sep 29 18:01:10 2009 @@ -73,8 +73,10 @@ operations = [ResOperation(opnum, valueboxes, result), ResOperation(rop.FINISH, results, None, descr=BasicFailDescr())] - if operations[0].is_guard() and not descr: - descr = BasicFailDescr() + if operations[0].is_guard(): + operations[0].fail_args = [] + if not descr: + descr = BasicFailDescr() operations[0].descr = descr inputargs = [] for box in valueboxes: @@ -393,6 +395,7 @@ ResOperation(rop.FINISH, [v_res], None, descr=BasicFailDescr()), ] + ops[1].fail_args = [] else: v_exc = self.cpu.ts.BoxRef() ops = [ Modified: pypy/branch/remove-fail/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/x86/assembler.py Tue Sep 29 18:01:10 2009 @@ -251,11 +251,10 @@ def regalloc_perform_with_guard(self, op, guard_op, faillocs, arglocs, resloc, current_stack_depth): - fail_op = guard_op.suboperations[0] - faildescr = fail_op.descr + faildescr = guard_op.descr assert isinstance(faildescr, AbstractFailDescr) faildescr._x86_current_stack_depth = current_stack_depth - failargs = fail_op.args + failargs = guard_op.fail_args guard_opnum = guard_op.opnum failaddr = self.implement_guard_recovery(guard_opnum, faildescr, failargs, Modified: pypy/branch/remove-fail/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/x86/regalloc.py Tue Sep 29 18:01:10 2009 @@ -149,10 +149,7 @@ self.assembler.regalloc_perform(op, arglocs, result_loc) def locs_for_fail(self, guard_op): - assert len(guard_op.suboperations) == 1 - fail_op = guard_op.suboperations[0] - assert fail_op.opnum == rop.FAIL - return [self.loc(v) for v in fail_op.args] + return [self.loc(v) for v in guard_op.fail_args] def perform_with_guard(self, op, guard_op, arglocs, result_loc): faillocs = self.locs_for_fail(guard_op) @@ -161,7 +158,7 @@ arglocs, result_loc, self.sm.stack_depth) self.rm.possibly_free_var(op.result) - self.rm.possibly_free_vars(guard_op.suboperations[0].args) + self.rm.possibly_free_vars(guard_op.fail_args) def perform_guard(self, guard_op, arglocs, result_loc): faillocs = self.locs_for_fail(guard_op) @@ -174,7 +171,7 @@ self.assembler.regalloc_perform_guard(guard_op, faillocs, arglocs, result_loc, self.sm.stack_depth) - self.rm.possibly_free_vars(guard_op.suboperations[0].args) + self.rm.possibly_free_vars(guard_op.fail_args) def PerformDiscard(self, op, arglocs): if not we_are_translated(): @@ -191,7 +188,7 @@ if operations[i + 1].args[0] is not op.result: return False if (self.rm.longevity[op.result][1] > i + 1 or - op.result in operations[i + 1].suboperations[0].args): + op.result in operations[i + 1].fail_args): return False return True @@ -233,12 +230,12 @@ raise AssertionError longevity[arg] = (start_live[arg], i) if op.is_guard(): - for arg in op.suboperations[0].args: - if isinstance(arg, Box): - if arg not in start_live: - print "Bogus arg in guard %d at %d" % (op.opnum, i) - raise AssertionError - longevity[arg] = (start_live[arg], i) + for arg in op.fail_args: + assert isinstance(arg, Box) + if arg not in start_live: + print "Bogus arg in guard %d at %d" % (op.opnum, i) + raise AssertionError + longevity[arg] = (start_live[arg], i) for arg in inputargs: if arg not in longevity: longevity[arg] = (-1, -1) @@ -257,14 +254,12 @@ consider_guard_true = _consider_guard consider_guard_false = _consider_guard - def consider_fail(self, op, ignored): + def consider_finish(self, op, ignored): locs = [self.loc(arg) for arg in op.args] self.assembler.generate_failure(self.assembler.mc, op.descr, op.args, locs, self.exc) self.rm.possibly_free_vars(op.args) - consider_finish = consider_fail # for now - def consider_guard_no_exception(self, op, ignored): self.perform_guard(op, [], None) Modified: pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_basic.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_basic.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_basic.py Tue Sep 29 18:01:10 2009 @@ -3,7 +3,7 @@ from pypy.jit.metainterp.warmspot import ll_meta_interp from pypy.jit.metainterp.test import test_basic from pypy.jit.metainterp.policy import StopAtXPolicy -from pypy.rlib.jit import JitDriver +from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE class Jit386Mixin(test_basic.LLJitMixin): type_system = 'lltype' @@ -29,7 +29,7 @@ n -= x.arg x.arg = 6 # prevents 'x.arg' from being annotated as constant return n - res = self.meta_interp(f, [31], specialize=False) + res = self.meta_interp(f, [31], optimizer=OPTIMIZER_SIMPLE) assert res == -4 def test_r_dict(self): Modified: pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_gc_integration.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_gc_integration.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_gc_integration.py Tue Sep 29 18:01:10 2009 @@ -107,7 +107,7 @@ ops = ''' [p0] p1 = getfield_gc(p0, descr=fielddescr) - fail(p1) + finish(p1) ''' self.interpret(ops, [self.struct_ptr]) assert not self.getptr(0, lltype.Ptr(self.S)) @@ -116,7 +116,7 @@ ops = ''' [] p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) - fail(p1) + finish(p1) ''' self.interpret(ops, []) assert not self.getptr(0, lltype.Ptr(self.S)) @@ -124,29 +124,22 @@ def test_bug_0(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] - guard_value(i2, 1) - fail(i2, i3, i4, i5, i6, i7, i0, i1, i8) - guard_class(i4, 138998336) - fail(i4, i5, i6, i7, i0, i1, i8) + guard_value(i2, 1) [i2, i3, i4, i5, i6, i7, i0, i1, i8] + guard_class(i4, 138998336) [i4, i5, i6, i7, i0, i1, i8] i11 = getfield_gc(i4, descr=descr0) i12 = ooisnull(i11) - guard_false(i12) - fail(i4, i5, i6, i7, i0, i1, i11, i8) + guard_false(i12) [i4, i5, i6, i7, i0, i1, i11, i8] i13 = getfield_gc(i11, descr=descr0) i14 = ooisnull(i13) - guard_true(i14) - fail(i4, i5, i6, i7, i0, i1, i11, i8) + guard_true(i14) [i4, i5, i6, i7, i0, i1, i11, i8] i15 = getfield_gc(i4, descr=descr0) i17 = int_lt(i15, 0) - guard_false(i17) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) + guard_false(i17) [i4, i5, i6, i7, i0, i1, i11, i15, i8] i18 = getfield_gc(i11, descr=descr0) i19 = int_ge(i15, i18) - guard_false(i19) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) + guard_false(i19) [i4, i5, i6, i7, i0, i1, i11, i15, i8] i20 = int_lt(i15, 0) - guard_false(i20) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) + guard_false(i20) [i4, i5, i6, i7, i0, i1, i11, i15, i8] i21 = getfield_gc(i11, descr=descr0) i22 = getfield_gc(i11, descr=descr0) i23 = int_mul(i15, i22) @@ -157,11 +150,9 @@ i29 = getfield_raw(144839744, descr=descr0) i31 = int_and(i29, -2141192192) i32 = int_is_true(i31) - guard_false(i32) - fail(i4, i6, i7, i0, i1, i24) + guard_false(i32) [i4, i6, i7, i0, i1, i24] i33 = getfield_gc(i0, descr=descr0) - guard_value(i33, ConstPtr(ptr0)) - fail(i4, i6, i7, i0, i1, i33, i24) + guard_value(i33, ConstPtr(ptr0)) [i4, i6, i7, i0, i1, i33, i24] jump(i0, i1, 1, 17, i4, ConstPtr(ptr0), i6, i7, i24) ''' self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0, 0], run=False) Modified: pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_recompilation.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_recompilation.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_recompilation.py Tue Sep 29 18:01:10 2009 @@ -8,8 +8,7 @@ [i0] i1 = int_add(i0, 1) i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) + guard_true(i2) [i1] jump(i1) ''' loop = self.interpret(ops, [0]) @@ -17,7 +16,7 @@ ops = ''' [i1] i3 = int_add(i1, 1) - fail(i3) + finish(i3) ''' bridge = self.attach_bridge(ops, loop, -2) self.cpu.set_future_value_int(0, 0) @@ -30,8 +29,7 @@ [i0] i1 = int_add(i0, 1) i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) + guard_true(i2) [i1] jump(i1) ''' loop = self.interpret(ops, [0]) @@ -46,11 +44,11 @@ i7 = int_add(i5, i4) i8 = int_add(i7, 1) i9 = int_add(i8, 1) - fail(i3, i4, i5, i6, i7, i8, i9) + finish(i3, i4, i5, i6, i7, i8, i9) ''' bridge = self.attach_bridge(ops, loop, -2) - fail_op = loop._loop.operations[2].suboperations[0] - new = fail_op.descr._x86_bridge_stack_depth + descr = loop._loop.operations[2].descr + new = descr._x86_bridge_stack_depth assert new > previous self.cpu.set_future_value_int(0, 0) fail = self.run(loop) @@ -65,42 +63,40 @@ [i0, i10, i11, i12, i13, i14, i15, i16] i1 = int_add(i0, 1) i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) + guard_true(i2) [i1] jump(i1, i10, i11, i12, i13, i14, i15, i16) ''', [0]) other_loop = self.interpret(''' [i3] - guard_false(i3) - fail(i3) + guard_false(i3) [i3] jump(i3) ''', [1]) ops = ''' [i3] jump(i3, 1, 2, 3, 4, 5, 6, 7) ''' - bridge = self.attach_bridge(ops, other_loop, 0, jump_targets=[loop]) + bridge = self.attach_bridge(ops, other_loop, 0, jump_target=loop) self.cpu.set_future_value_int(0, 1) fail = self.run(other_loop) - assert fail is loop._loop.operations[2].suboperations[0].descr + assert fail is loop._loop.operations[2].descr def test_bridge_jumps_to_self_deeper(self): loop = self.interpret(''' [i0, i1, i2, i31, i32, i33] + i98 = same_as(0) + i99 = same_as(1) i30 = int_add(i1, i2) i3 = int_add(i0, 1) i4 = int_and(i3, 1) - guard_false(i4) - fail(0, i3) + guard_false(i4) [i98, i3] i5 = int_lt(i3, 20) - guard_true(i5) - fail(1, i3) + guard_true(i5) [i99, i3] jump(i3, i30, 1, i30, i30, i30) ''', [0]) assert self.getint(0) == 0 assert self.getint(1) == 1 ops = ''' - [i3] + [i97, i3] i10 = int_mul(i3, 2) i8 = int_add(i3, 1) i6 = int_add(i8, i10) @@ -109,10 +105,10 @@ i11 = int_add(i12, i6) jump(i3, i12, i11, i10, i6, i7) ''' - bridge = self.attach_bridge(ops, loop, 3, jump_targets=[loop]) - fail_op = loop._loop.operations[3].suboperations[0] + bridge = self.attach_bridge(ops, loop, 5, jump_target=loop) + guard_op = loop._loop.operations[5] loop_stack_depth = loop.executable_token._x86_stack_depth - assert fail_op.descr._x86_bridge_stack_depth > loop_stack_depth + assert guard_op.descr._x86_bridge_stack_depth > loop_stack_depth self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) self.cpu.set_future_value_int(2, 0) @@ -123,22 +119,22 @@ def test_bridge_jumps_to_self_shallower(self): loop = self.interpret(''' [i0, i1, i2] + i98 = same_as(0) + i99 = same_as(1) i3 = int_add(i0, 1) i4 = int_and(i3, 1) - guard_false(i4) - fail(0, i3) + guard_false(i4) [i98, i3] i5 = int_lt(i3, 20) - guard_true(i5) - fail(1, i3) + guard_true(i5) [i99, i3] jump(i3, i1, i2) ''', [0]) assert self.getint(0) == 0 assert self.getint(1) == 1 ops = ''' - [i3] + [i97, i3] jump(i3, 0, 1) ''' - bridge = self.attach_bridge(ops, loop, 2, jump_targets=[loop]) + bridge = self.attach_bridge(ops, loop, 4, jump_target=loop) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) self.cpu.set_future_value_int(2, 0) Modified: pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_regalloc.py Tue Sep 29 18:01:10 2009 @@ -83,14 +83,14 @@ namespace = locals().copy() type_system = 'lltype' - def parse(self, s, boxkinds=None, jump_targets=None): + def parse(self, s, boxkinds=None, jump_target=None): return parse(s, self.cpu, self.namespace, type_system=self.type_system, - jump_targets=jump_targets, + jump_target=jump_target, boxkinds=boxkinds) - def interpret(self, ops, args, jump_targets=None, run=True): - loop = self.parse(ops, jump_targets=jump_targets) + def interpret(self, ops, args, jump_target=None, run=True): + loop = self.parse(ops, jump_target=jump_target) executable_token = self.cpu.compile_loop(loop.inputargs, loop.operations) for i, arg in enumerate(args): @@ -122,7 +122,7 @@ guard_op = loop_token._loop.operations[guard_op_index] assert guard_op.is_guard() bridge = self.parse(ops, **kwds) - faildescr = guard_op.suboperations[0].descr + faildescr = guard_op.descr self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations) return bridge @@ -135,8 +135,7 @@ [i0] i1 = int_add(i0, 1) i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) + guard_true(i2) [i1] jump(i1) ''' self.interpret(ops, [0]) @@ -147,8 +146,7 @@ [i0, i1, i2, i3] i4 = int_add(i0, 1) i5 = int_lt(i4, 20) - guard_true(i5) - fail(i4, i1, i2, i3) + guard_true(i5) [i4, i1, i2, i3] jump(i4, i1, i2, i3) ''' loop = self.interpret(ops, [0, 0, 0, 0]) @@ -158,8 +156,7 @@ i3 = int_add(i1, 1) i4 = int_add(i3, 1) i2 = int_lt(i4, 30) - guard_true(i2) - fail(i4) + guard_true(i2) [i4] jump(i4) ''' loop2 = self.interpret(ops2, [0]) @@ -167,7 +164,7 @@ [i4] jump(i4, i4, i4, i4) ''' - bridge = self.attach_bridge(bridge_ops, loop2, 4, jump_targets=[loop]) + bridge = self.attach_bridge(bridge_ops, loop2, 4, jump_target=loop) self.cpu.set_future_value_int(0, 0) self.run(loop2) assert self.getint(0) == 31 @@ -180,8 +177,7 @@ [i0, p0] i1 = int_add(i0, 1) i2 = int_lt(i1, 10) - guard_true(i2) - fail(p0) + guard_true(i2) [p0] jump(i1, p0) ''' S = lltype.GcStruct('S') @@ -194,20 +190,20 @@ def test_exception_bridge_no_exception(self): ops = ''' [i0] + i1 = same_as(1) call(ConstClass(raising_fptr), i0, descr=raising_calldescr) - guard_exception(ConstClass(zero_division_error)) - fail(1) - fail(0) + guard_exception(ConstClass(zero_division_error)) [i1] + finish(0) ''' bridge_ops = ''' - [] - guard_no_exception() - fail(2) - fail(1) + [i3] + i2 = same_as(2) + guard_no_exception() [i2] + finish(1) ''' loop = self.interpret(ops, [0]) assert self.getint(0) == 1 - bridge = self.attach_bridge(bridge_ops, loop, 1) + bridge = self.attach_bridge(bridge_ops, loop, 2) self.cpu.set_future_value_int(0, 0) self.run(loop) assert self.getint(0) == 1 @@ -215,7 +211,7 @@ def test_inputarg_unused(self): ops = ''' [i0] - fail(1) + finish(1) ''' self.interpret(ops, [0]) # assert did not explode @@ -223,15 +219,13 @@ def test_nested_guards(self): ops = ''' [i0, i1] - guard_true(i0) - fail(i0, i1) - fail(4) + guard_true(i0) [i0, i1] + finish(4) ''' bridge_ops = ''' [i0, i1] - guard_true(i0) - fail(i0, i1) - fail(3) + guard_true(i0) [i0, i1] + finish(3) ''' loop = self.interpret(ops, [0, 10]) assert self.getint(0) == 0 @@ -246,15 +240,14 @@ def test_nested_unused_arg(self): ops = ''' [i0, i1] - guard_true(i0) - fail(i0, i1) - fail(1) + guard_true(i0) [i0, i1] + finish(1) ''' loop = self.interpret(ops, [0, 1]) assert self.getint(0) == 0 bridge_ops = ''' [i0, i1] - fail(1, 2) + finish(1, 2) ''' self.attach_bridge(bridge_ops, loop, 0) self.cpu.set_future_value_int(0, 0) @@ -266,8 +259,7 @@ [i0, i1, i2, i3] i4 = int_add(3, i1) i5 = int_lt(i4, 30) - guard_true(i5) - fail(i0, i4, i2, i3) + guard_true(i5) [i0, i4, i2, i3] jump(1, i4, 3, 4) ''' self.interpret(ops, [0, 0, 0, 0]) @@ -279,8 +271,7 @@ i4 = int_lshift(1, i1) i5 = int_add(1, i1) i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4, i5, i2, i3) + guard_true(i6) [i4, i5, i2, i3] jump(i4, 3, i5, 4) ''' self.interpret(ops, [0, 0, 0, 0]) @@ -290,8 +281,7 @@ i4 = int_lshift(1, i1) i5 = int_add(1, i1) i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4, i5, i2, i3) + guard_true(i6) [i4, i5, i2, i3] jump(i4, i5, 3, 4) ''' self.interpret(ops, [0, 0, 0, 0]) @@ -301,8 +291,7 @@ i4 = int_lshift(1, i1) i5 = int_add(1, i1) i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4, i5, i2, i3) + guard_true(i6) [i4, i5, i2, i3] jump(i4, 4, i5, 3) ''' self.interpret(ops, [0, 0, 0, 0]) @@ -314,8 +303,7 @@ i6 = int_neg(i2) i7 = int_add(1, i1) i4 = int_lt(i7, 10) - guard_true(i4) - fail(i0, i6, i7) + guard_true(i4) [i0, i6, i7] jump(1, i7, i2, i6) ''' self.interpret(ops, [0, 0, 3, 0]) @@ -327,8 +315,7 @@ i4 = int_lt(i0, i1) i5 = int_add(i3, 1) i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4) + guard_true(i6) [i4] jump(i0, i1, i4, i5) ''' self.interpret(ops, [0, 10, 0, 0]) @@ -339,8 +326,7 @@ [i0, i15, i16, i18, i1, i2, i3] i4 = int_add(i3, 1) i5 = int_lt(i4, 20) - guard_true(i5) - fail(i2, i1) + guard_true(i5) [i2, i1] jump(i0, i18, i15, i16, i2, i1, i4) ''' self.interpret(ops, [0, 1, 2, 3]) @@ -349,16 +335,15 @@ ops = ''' [i0, i1] i2 = int_add(i0, i1) - fail(0) + finish(0) ''' self.interpret(ops, [0, 0]) def test_guard_value_two_boxes(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7] - guard_value(i6, i1) - fail(i0, i2, i3, i4, i5, i6) - fail(i0, i2, i3, i4, i5, i6) + guard_value(i6, i1) [i0, i2, i3, i4, i5, i6] + finish(i0, i2, i3, i4, i5, i6) ''' self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0]) assert self.getint(0) == 0 @@ -366,18 +351,18 @@ def test_bug_wrong_stack_adj(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] - guard_true(i0) - fail(0, i0, i1, i2, i3, i4, i5, i6, i7, i8) - fail(1, i0, i1, i2, i3, i4, i5, i6, i7, i8) + i9 = same_as(0) + guard_true(i0) [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8] + finish(1, i0, i1, i2, i3, i4, i5, i6, i7, i8) ''' loop = self.interpret(ops, [0, 1, 2, 3, 4, 5, 6, 7, 8]) assert self.getint(0) == 0 bridge_ops = ''' - [i0, i1, i2, i3, i4, i5, i6, i7, i8] + [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8] call(ConstClass(raising_fptr), 0, descr=raising_calldescr) - fail(i0, i1, i2, i3, i4, i5, i6, i7, i8) + finish(i0, i1, i2, i3, i4, i5, i6, i7, i8) ''' - self.attach_bridge(bridge_ops, loop, 0) + self.attach_bridge(bridge_ops, loop, 1) for i in range(9): self.cpu.set_future_value_int(i, i) self.run(loop) @@ -388,10 +373,10 @@ def test_cmp_op_0(self): ops = ''' [i0, i3] + i1 = same_as(1) i2 = int_lt(i0, 100) - guard_true(i3) - fail(1, i2) - fail(0, i2) + guard_true(i3) [i1, i2] + finish(0, i2) ''' self.interpret(ops, [0, 1]) assert self.getint(0) == 0 @@ -419,7 +404,7 @@ i15 = int_is_true(i5) i16 = int_is_true(i6) i17 = int_is_true(i7) - fail(i10, i11, i12, i13, i14, i15, i16, i17) + finish(i10, i11, i12, i13, i14, i15, i16, i17) ''' self.interpret(ops, [0, 42, 12, 0, 13, 0, 0, 3333]) assert self.getints(8) == [0, 1, 1, 0, 1, 0, 0, 1] @@ -433,7 +418,7 @@ i13 = int_eq(i5, i6) i14 = int_gt(i6, i2) i15 = int_ne(i2, i6) - fail(i10, i11, i12, i13, i14, i15) + finish(i10, i11, i12, i13, i14, i15) ''' self.interpret(ops, [0, 1, 2, 3, 4, 5, 6]) assert self.getints(6) == [1, 1, 0, 0, 1, 1] @@ -447,7 +432,7 @@ i13 = oononnull(i3) i14 = ooisnull(i6) i15 = ooisnull(i5) - fail(i10, i11, i12, i13, i14, i15) + finish(i10, i11, i12, i13, i14, i15) ''' self.interpret(ops, [0, 1, 2, 3, 4, 5, 6]) assert self.getints(6) == [0, 0, 1, 1, 0, 0] @@ -456,7 +441,7 @@ ops = ''' [p0, i] strsetitem(p0, 1, i) - fail() + finish() ''' llstr = rstr.mallocstr(10) self.interpret(ops, [llstr, ord('a')]) @@ -466,7 +451,7 @@ ops = ''' [p0, i] setfield_gc(p0, i, descr=fielddescr) - fail() + finish() ''' s = lltype.malloc(self.S) self.interpret(ops, [s, ord('a')]) @@ -476,7 +461,7 @@ ops = ''' [p0, i] setarrayitem_gc(p0, 1, i, descr=arraydescr) - fail() + finish() ''' s = lltype.malloc(self.A, 3) self.interpret(ops, [s, ord('a')]) Modified: pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_regalloc2.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_regalloc2.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_regalloc2.py Tue Sep 29 18:01:10 2009 @@ -14,7 +14,7 @@ ResOperation(rop.INT_ADD, [v1, v1], v2), ResOperation(rop.INT_INVERT, [v2], v3), ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4), - ResOperation(rop.FAIL, [v4, v3], None, descr=BasicFailDescr()), + ResOperation(rop.FINISH, [v4, v3], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) @@ -35,7 +35,7 @@ ResOperation(rop.INT_MUL, [v2, v1], v3), ResOperation(rop.INT_IS_TRUE, [v2], tmp5), ResOperation(rop.BOOL_NOT, [tmp5], v4), - ResOperation(rop.FAIL, [v4, v3, tmp5], None, descr=BasicFailDescr()), + ResOperation(rop.FINISH, [v4, v3, tmp5], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) @@ -130,7 +130,7 @@ ResOperation(rop.UINT_GT, [v33, ConstInt(-11)], v38), ResOperation(rop.INT_NEG, [v7], v39), ResOperation(rop.INT_GT, [v24, v32], v40), - ResOperation(rop.FAIL, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None, descr=BasicFailDescr()), + ResOperation(rop.FINISH, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) @@ -243,7 +243,7 @@ ResOperation(rop.INT_GT, [v4, v11], v38), ResOperation(rop.INT_LT, [v27, v22], v39), ResOperation(rop.INT_NEG, [v27], v40), - ResOperation(rop.FAIL, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None, descr=BasicFailDescr()), + ResOperation(rop.FINISH, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) Modified: pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_runner.py ============================================================================== --- pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_runner.py (original) +++ pypy/branch/remove-fail/pypy/jit/backend/x86/test/test_runner.py Tue Sep 29 18:01:10 2009 @@ -77,12 +77,12 @@ ResOperation(rop.INT_ADD, [x, y], z), ResOperation(rop.INT_SUB, [y, ConstInt(1)], t), ResOperation(rop.INT_EQ, [t, ConstInt(0)], u), - ResOperation(rop.GUARD_FALSE, [u], None), + ResOperation(rop.GUARD_FALSE, [u], None, + descr=BasicFailDescr()), ResOperation(rop.JUMP, [z, t], None), ] operations[-1].jump_target = None - operations[-2].suboperations = [ResOperation(rop.FAIL, [t, z], None, - descr=BasicFailDescr())] + operations[-2].fail_args = [t, z] executable_token = cpu.compile_loop([x, y], operations) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 10) @@ -317,15 +317,16 @@ bp = BoxPtr(p) n = BoxPtr(nullptr) for b in (bp, n): + i1 = BoxInt(1) ops = [ + ResOperation(rop.SAME_AS, [ConstInt(1)], i1), ResOperation(op, [b], f), - ResOperation(guard, [f], None), - ResOperation(rop.FAIL, [ConstInt(0)], None, + ResOperation(guard, [f], None, + descr=BasicFailDescr()), + ResOperation(rop.FINISH, [ConstInt(0)], None, descr=BasicFailDescr()), ] - ops[1].suboperations = [ResOperation(rop.FAIL, - [ConstInt(1)], None, - descr=BasicFailDescr())] + ops[-2].fail_args = [i1] executable_token = self.cpu.compile_loop([b], ops) if op == rop.INT_IS_TRUE: self.cpu.set_future_value_int(0, b.value) @@ -362,15 +363,16 @@ for guard in guards: for op in all: res = BoxInt() + i1 = BoxInt(1) ops = [ + ResOperation(rop.SAME_AS, [ConstInt(1)], i1), ResOperation(op, [a, b], res), - ResOperation(guard, [res], None), - ResOperation(rop.FAIL, [ConstInt(0)], None, + ResOperation(guard, [res], None, + descr=BasicFailDescr()), + ResOperation(rop.FINISH, [ConstInt(0)], None, descr=BasicFailDescr()), ] - ops[1].suboperations = [ResOperation(rop.FAIL, - [ConstInt(1)], None, - descr=BasicFailDescr())] + ops[-2].fail_args = [i1] inputargs = [i for i in (a, b) if isinstance(i, Box)] executable_token = self.cpu.compile_loop(inputargs, ops) for i, box in enumerate(inputargs): @@ -399,7 +401,7 @@ next_v = BoxInt() ops.append(ResOperation(rop.INT_ADD, [v, ConstInt(1)], next_v)) v = next_v - ops.append(ResOperation(rop.FAIL, [v], None, + ops.append(ResOperation(rop.FINISH, [v], None, descr=BasicFailDescr())) executable_token = self.cpu.compile_loop([base_v], ops) assert self.cpu.assembler.mc != old_mc # overflowed From hpk at codespeak.net Tue Sep 29 18:18:24 2009 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 29 Sep 2009 18:18:24 +0200 (CEST) Subject: [pypy-svn] r67991 - pypy/extradoc/talk/pycon2010 Message-ID: <20090929161824.B2B09168015@codespeak.net> Author: hpk Date: Tue Sep 29 18:18:24 2009 New Revision: 67991 Modified: pypy/extradoc/talk/pycon2010/jit_abstract.txt Log: review Modified: pypy/extradoc/talk/pycon2010/jit_abstract.txt ============================================================================== --- pypy/extradoc/talk/pycon2010/jit_abstract.txt (original) +++ pypy/extradoc/talk/pycon2010/jit_abstract.txt Tue Sep 29 18:18:24 2009 @@ -1,16 +1,21 @@ -The speed of PyPy -================= +The speed of PyPy's Python +============================== Summary: -The first part of the talk will cover PyPy's speed achievements, especially -connected to last year's work on the JIT. It will present benchmarks together -with compatibility comparison(?). Second part of the talk will cover the -basics of how the JIT works and what sort of programs it can greatly -speedup (and which ones it can't). +The first part of the talk will cover PyPy's speed achievements resulting +from the last year's work on the Just-In-Time Compiler. I'll present +and discuss a number of benchmarks and compare against other Python-speed +projects. And I'll cover the basics of how the JIT works and what +sort of programs it can greatly speedup (and which ones it can't). Description: -PyPy's JIT has been in development for quite a while so far and recently -it started showing some real benefits (being faster than psyco on -medium sized benchmarks) (XXX link). XXX finish +PyPy's JIT has been in development for some years now. More recently +it became more practical and begins to be faster than Psyco on some +examples. This is the status in September 2009 and currently it's fast-paced +development so we expect to have very interesting results for February 2010, +worth discussing and comparing. If possible a 45 minute talk would be cool +due to the "explaining the JIT" bit of the talk. + +XXX link, review From arigo at codespeak.net Tue Sep 29 18:18:41 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 18:18:41 +0200 (CEST) Subject: [pypy-svn] r67992 - in pypy/trunk/pypy/jit: backend/llgraph backend/llsupport backend/test backend/x86 backend/x86/test metainterp metainterp/test Message-ID: <20090929161841.A4B23168015@codespeak.net> Author: arigo Date: Tue Sep 29 18:18:40 2009 New Revision: 67992 Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py pypy/trunk/pypy/jit/backend/llgraph/runner.py pypy/trunk/pypy/jit/backend/llsupport/descr.py pypy/trunk/pypy/jit/backend/llsupport/gc.py pypy/trunk/pypy/jit/backend/test/runner_test.py pypy/trunk/pypy/jit/backend/test/test_ll_random.py pypy/trunk/pypy/jit/backend/test/test_random.py pypy/trunk/pypy/jit/backend/x86/assembler.py pypy/trunk/pypy/jit/backend/x86/regalloc.py pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py pypy/trunk/pypy/jit/backend/x86/test/test_regalloc2.py pypy/trunk/pypy/jit/backend/x86/test/test_runner.py pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/graphpage.py pypy/trunk/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/logger.py pypy/trunk/pypy/jit/metainterp/optimizeopt.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/resoperation.py pypy/trunk/pypy/jit/metainterp/simple_optimize.py pypy/trunk/pypy/jit/metainterp/test/oparser.py pypy/trunk/pypy/jit/metainterp/test/test_basic.py pypy/trunk/pypy/jit/metainterp/test/test_logger.py pypy/trunk/pypy/jit/metainterp/test/test_loop.py pypy/trunk/pypy/jit/metainterp/test/test_oparser.py pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py pypy/trunk/pypy/jit/metainterp/test/test_recursive.py pypy/trunk/pypy/jit/metainterp/typesystem.py Log: Merge the branch 'remove-fail'. Kills 'suboperations' from guards and the FAIL operation. For now, move the arguments of the FAIL to the guard op, as 'fail_args'. Remove the last few "xxx unhappy" and the last few places that change the .value stored in a Box. Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py Tue Sep 29 18:18:40 2009 @@ -168,16 +168,16 @@ def as_text(self, lines, indent): for op in self.operations: lines.append('\t'*indent + repr(op)) - if op.is_guard(): - op.subloop.as_text(lines, indent+1) class Operation(object): + result = None + descr = None + jump_target = None + fail_args = None + def __init__(self, opnum): self.opnum = opnum self.args = [] - self.result = None - self.descr = None - self.livevars = [] # for guards only def __repr__(self): if self.result is not None: @@ -352,25 +352,24 @@ def compile_add_fail(loop, fail_index): loop = _from_opaque(loop) - op = loop.operations[-1] + index = len(loop.operations)-1 + op = loop.operations[index] op.fail_index = fail_index + return index -def compile_suboperations(loop): +def compile_add_fail_arg(loop, intvar): loop = _from_opaque(loop) op = loop.operations[-1] - assert op.is_guard() - op.subloop = CompiledLoop() - return _to_opaque(op.subloop) + if op.fail_args is None: + op.fail_args = [] + op.fail_args.append(_variables[intvar]) -def compile_redirect_fail(old_loop, new_loop): +def compile_redirect_fail(old_loop, old_index, new_loop): old_loop = _from_opaque(old_loop) new_loop = _from_opaque(new_loop) - assert len(old_loop.operations) == 1 - assert old_loop.operations[-1].opnum == rop.FAIL - op = Operation(rop.JUMP) - op.args = old_loop.operations[-1].args - op.jump_target = new_loop - old_loop.operations[0] = op + guard_op = old_loop.operations[old_index] + assert guard_op.is_guard() + guard_op.jump_target = new_loop # ------------------------------ @@ -406,9 +405,24 @@ except GuardFailed: assert op.is_guard() _stats.exec_conditional_jumps += 1 - operations = op.subloop.operations - opindex = 0 - continue + if op.fail_args: + args = [self.getenv(v) for v in op.fail_args] + else: + args = [] + if op.jump_target is not None: + # a patched guard, pointing to further code + assert len(op.jump_target.inputargs) == len(args) + self.env = dict(zip(op.jump_target.inputargs, args)) + operations = op.jump_target.operations + opindex = 0 + continue + else: + # a non-patched guard + if self.verbose: + log.trace('failed: %s' % ( + ', '.join(map(str, args)),)) + self.fail_args = args + return op.fail_index #verbose = self.verbose assert (result is None) == (op.result is None) if op.result is not None: @@ -433,12 +447,6 @@ operations = op.jump_target.operations opindex = 0 _stats.exec_jumps += 1 - elif op.opnum == rop.FAIL: - if self.verbose: - log.trace('failed: %s' % ( - ', '.join(map(str, args)),)) - self.fail_args = args - return op.fail_index elif op.opnum == rop.FINISH: if self.verbose: log.trace('finished: %s' % ( @@ -1359,8 +1367,8 @@ setannotation(compile_add_ref_result, annmodel.SomeInteger()) setannotation(compile_add_float_result, annmodel.SomeInteger()) setannotation(compile_add_jump_target, annmodel.s_None) -setannotation(compile_add_fail, annmodel.s_None) -setannotation(compile_suboperations, s_CompiledLoop) +setannotation(compile_add_fail, annmodel.SomeInteger()) +setannotation(compile_add_fail_arg, annmodel.s_None) setannotation(compile_redirect_fail, annmodel.s_None) setannotation(new_frame, s_Frame) Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/runner.py Tue Sep 29 18:18:40 2009 @@ -105,7 +105,8 @@ def compile_bridge(self, faildescr, inputargs, operations): c = self.compile_loop(inputargs, operations) - llimpl.compile_redirect_fail(faildescr._compiled_fail, c) + old, oldindex = faildescr._compiled_fail + llimpl.compile_redirect_fail(old, oldindex, c) def compile_loop(self, inputargs, operations): """In a real assembler backend, this should assemble the given @@ -125,10 +126,10 @@ var2index[box] = llimpl.compile_start_float_var(c) else: raise Exception("box is: %r" % (box,)) - self._compile_branch(c, operations, var2index) + self._compile_operations(c, operations, var2index) return c - def _compile_branch(self, c, operations, var2index): + def _compile_operations(self, c, operations, var2index): for op in operations: llimpl.compile_add(c, op.opnum) descr = op.descr @@ -152,11 +153,13 @@ raise Exception("%s args contain: %r" % (op.getopname(), x)) if op.is_guard(): - c2 = llimpl.compile_suboperations(c) - suboperations = op.suboperations - assert len(suboperations) == 1 - assert suboperations[0].opnum == rop.FAIL - self._compile_branch(c2, op.suboperations, var2index.copy()) + faildescr = op.descr + assert isinstance(faildescr, history.AbstractFailDescr) + index = llimpl.compile_add_fail(c, len(self.fail_descrs)) + faildescr._compiled_fail = c, index + self.fail_descrs.append(faildescr) + for box in op.fail_args: + llimpl.compile_add_fail_arg(c, var2index[box]) x = op.result if x is not None: if isinstance(x, history.BoxInt): @@ -177,12 +180,6 @@ else: target = target.executable_token llimpl.compile_add_jump_target(c, target) - elif op.opnum == rop.FAIL: - faildescr = op.descr - assert isinstance(faildescr, history.AbstractFailDescr) - faildescr._compiled_fail = c - llimpl.compile_add_fail(c, len(self.fail_descrs)) - self.fail_descrs.append(faildescr) elif op.opnum == rop.FINISH: llimpl.compile_add_fail(c, len(self.fail_descrs)) faildescr = op.descr Modified: pypy/trunk/pypy/jit/backend/llsupport/descr.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llsupport/descr.py (original) +++ pypy/trunk/pypy/jit/backend/llsupport/descr.py Tue Sep 29 18:18:40 2009 @@ -200,11 +200,11 @@ result_list = [result] operations = [ ResOperation(rop.CALL, args, result, self), - ResOperation(rop.GUARD_NO_EXCEPTION, [], None), - ResOperation(rop.FAIL, result_list, None, + ResOperation(rop.GUARD_NO_EXCEPTION, [], None, + descr=BasicFailDescr()), + ResOperation(rop.FINISH, result_list, None, descr=BasicFailDescr())] - operations[1].suboperations = [ResOperation(rop.FAIL, [], None, - descr=BasicFailDescr())] + operations[1].fail_args = [] executable_token = cpu.compile_loop(args, operations) self.executable_token = executable_token return executable_token Modified: pypy/trunk/pypy/jit/backend/llsupport/gc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llsupport/gc.py (original) +++ pypy/trunk/pypy/jit/backend/llsupport/gc.py Tue Sep 29 18:18:40 2009 @@ -492,8 +492,6 @@ op = ResOperation(rop.SETARRAYITEM_RAW, op.args, None, descr=op.descr) # ---------- - if op.is_guard(): - self.rewrite_assembler(cpu, op.suboperations) newops.append(op) del operations[:] operations.extend(newops) Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/runner_test.py (original) +++ pypy/trunk/pypy/jit/backend/test/runner_test.py Tue Sep 29 18:18:40 2009 @@ -71,13 +71,13 @@ else: results = [result] operations = [ResOperation(opnum, valueboxes, result), - ResOperation(rop.FAIL, results, None, + ResOperation(rop.FINISH, results, None, descr=BasicFailDescr())] - operations[0].descr = descr if operations[0].is_guard(): - operations[0].suboperations = [ResOperation(rop.FAIL, - [ConstInt(-13)], None, - descr=BasicFailDescr())] + operations[0].fail_args = [] + if not descr: + descr = BasicFailDescr() + operations[0].descr = descr inputargs = [] for box in valueboxes: if isinstance(box, Box): @@ -93,7 +93,7 @@ faildescr = BasicFailDescr() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), - ResOperation(rop.FAIL, [i1], None, descr=faildescr) + ResOperation(rop.FINISH, [i1], None, descr=faildescr) ] inputargs = [i0] executable_token = self.cpu.compile_loop(inputargs, operations) @@ -107,17 +107,15 @@ i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() - faildescr = BasicFailDescr() + faildescr = BasicFailDescr() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), - ResOperation(rop.GUARD_TRUE, [i2], None), + ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr), ResOperation(rop.JUMP, [i1], None), ] inputargs = [i0] - operations[2].suboperations = [ - ResOperation(rop.FAIL, [i1], None, descr=faildescr) - ] + operations[2].fail_args = [i1] operations[-1].jump_target = None executable_token = self.cpu.compile_loop(inputargs, operations) @@ -137,23 +135,20 @@ operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), - ResOperation(rop.GUARD_TRUE, [i2], None), + ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr), ResOperation(rop.JUMP, [i1], None), ] inputargs = [i0] - operations[2].suboperations = [ - ResOperation(rop.FAIL, [i1], None, descr=faildescr) - ] + operations[2].fail_args = [i1] operations[-1].jump_target = None wr_i1 = weakref.ref(i1) wr_guard = weakref.ref(operations[2]) - wr_fail = weakref.ref(operations[2].suboperations[0]) executable_token = self.cpu.compile_loop(inputargs, operations) del i0, i1, i2 del inputargs del operations gc.collect() - assert not wr_i1() and not wr_guard() and not wr_fail() + assert not wr_i1() and not wr_guard() def test_compile_bridge(self): i0 = BoxInt() @@ -164,13 +159,11 @@ operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), - ResOperation(rop.GUARD_TRUE, [i2], None), + ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1), ResOperation(rop.JUMP, [i1], None), ] inputargs = [i0] - operations[2].suboperations = [ - ResOperation(rop.FAIL, [i1], None, descr=faildescr1) - ] + operations[2].fail_args = [i1] operations[-1].jump_target = None executable_token = self.cpu.compile_loop(inputargs, operations) loop_token = LoopToken() @@ -180,12 +173,10 @@ i3 = BoxInt() bridge = [ ResOperation(rop.INT_LE, [i1b, ConstInt(19)], i3), - ResOperation(rop.GUARD_TRUE, [i3], None), + ResOperation(rop.GUARD_TRUE, [i3], None, descr=faildescr2), ResOperation(rop.JUMP, [i1b], None), ] - bridge[1].suboperations = [ - ResOperation(rop.FAIL, [i1b], None, descr=faildescr2) - ] + bridge[1].fail_args = [i1b] bridge[-1].jump_target = loop_token self.cpu.compile_bridge(faildescr1, [i1b], bridge) @@ -399,20 +390,21 @@ if not reversed: ops = [ ResOperation(opnum, [v1, v2], v_res), - ResOperation(rop.GUARD_NO_OVERFLOW, [], None), - ResOperation(rop.FAIL, [v_res], None, descr=BasicFailDescr()), + ResOperation(rop.GUARD_NO_OVERFLOW, [], None, + descr=BasicFailDescr()), + ResOperation(rop.FINISH, [v_res], None, + descr=BasicFailDescr()), ] - ops[1].suboperations = [ResOperation(rop.FAIL, [], None, - descr=BasicFailDescr())] + ops[1].fail_args = [] else: v_exc = self.cpu.ts.BoxRef() ops = [ ResOperation(opnum, [v1, v2], v_res), - ResOperation(rop.GUARD_OVERFLOW, [], None), - ResOperation(rop.FAIL, [], None, descr=BasicFailDescr()), + ResOperation(rop.GUARD_OVERFLOW, [], None, + descr=BasicFailDescr()), + ResOperation(rop.FINISH, [], None, descr=BasicFailDescr()), ] - ops[1].suboperations = [ResOperation(rop.FAIL, [v_res], None, - descr=BasicFailDescr())] + ops[1].fail_args = [v_res] # executable_token = self.cpu.compile_loop([v1, v2], ops) for x, y, z in testcases: @@ -422,7 +414,7 @@ self.cpu.set_future_value_int(1, y) fail = self.cpu.execute_token(executable_token) if (z == boom) ^ reversed: - assert fail is ops[1].suboperations[0].descr + assert fail is ops[1].descr else: assert fail is ops[-1].descr if z != boom: @@ -491,7 +483,6 @@ for (opname, args) in [(rop.GUARD_TRUE, [BoxInt(1)]), (rop.GUARD_FALSE, [BoxInt(0)]), (rop.GUARD_VALUE, [BoxInt(42), BoxInt(42)]), - #(rop.GUARD_VALUE_INVERSE, [BoxInt(42), BoxInt(41)]), ]: assert self.execute_operation(opname, args, 'void') == None assert not self.guard_failed @@ -1034,10 +1025,10 @@ ops = ''' [i0] + i1 = same_as(1) call(ConstClass(fptr), i0, descr=calldescr) - p0 = guard_exception(ConstClass(xtp)) - fail(1) - fail(0, p0) + p0 = guard_exception(ConstClass(xtp)) [i1] + finish(0, p0) ''' FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) fptr = llhelper(FPTR, func) @@ -1089,10 +1080,10 @@ exc_ptr = xptr ops = ''' [i0] + i1 = same_as(1) call(ConstClass(fptr), i0, descr=calldescr) - guard_no_exception() - fail(1) - fail(0) + guard_no_exception() [i1] + finish(0) ''' loop = parse(ops, self.cpu, namespace=locals()) executable_token = self.cpu.compile_loop(loop.inputargs, Modified: pypy/trunk/pypy/jit/backend/test/test_ll_random.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/test_ll_random.py (original) +++ pypy/trunk/pypy/jit/backend/test/test_ll_random.py Tue Sep 29 18:18:40 2009 @@ -449,9 +449,9 @@ args = [c_addr] + subset descr = builder.cpu.calldescrof(TP, TP.ARGS, TP.RESULT) self.put(builder, args, descr) - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None) - op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, - descr=BasicFailDescr())] + op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None, + descr=BasicFailDescr()) + op.fail_args = fail_subset builder.loop.operations.append(op) # 5. Non raising-call and GUARD_EXCEPTION @@ -471,12 +471,11 @@ self.put(builder, args, descr) _, vtableptr = builder.get_random_structure_type_and_vtable(r) exc_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) - op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr()) - subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=BasicFailDescr())] + op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), + descr=BasicFailDescr()) + op.fail_args = builder.subset_of_intvars(r) op._exc_box = None - builder.should_fail_by = op.suboperations[0] + builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op) @@ -495,9 +494,9 @@ exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) assert builder.cpu.get_exception() builder.cpu.clear_exception() - op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr()) - op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, - descr=BasicFailDescr())] + op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), + descr=BasicFailDescr()) + op.fail_args = fail_subset builder.loop.operations.append(op) # 4. raising call and guard_no_exception @@ -513,12 +512,11 @@ self.put(builder, args, descr) assert builder.cpu.get_exception() builder.cpu.clear_exception() - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], BoxPtr()) + op = ResOperation(rop.GUARD_NO_EXCEPTION, [], BoxPtr(), + descr=BasicFailDescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) - subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=BasicFailDescr())] - builder.should_fail_by = op.suboperations[0] + op.fail_args = builder.subset_of_intvars(r) + builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op) @@ -540,12 +538,11 @@ if vtableptr != exc: break other_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) - op = ResOperation(rop.GUARD_EXCEPTION, [other_box], BoxPtr()) + op = ResOperation(rop.GUARD_EXCEPTION, [other_box], BoxPtr(), + descr=BasicFailDescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) - subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=BasicFailDescr())] - builder.should_fail_by = op.suboperations[0] + op.fail_args = builder.subset_of_intvars(r) + builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op) Modified: pypy/trunk/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/test_random.py (original) +++ pypy/trunk/pypy/jit/backend/test/test_random.py Tue Sep 29 18:18:40 2009 @@ -171,7 +171,7 @@ i, v.value) else: #print >>s, ' assert op is loop.operations[%d].suboperations[0]' % self.should_fail_by_num - for i, v in enumerate(self.should_fail_by.args): + for i, v in enumerate(self.should_fail_by.fail_args): print >>s, ' assert cpu.get_latest_value_int(%d) == %d' % ( i, v.value) self.names = names @@ -246,8 +246,8 @@ builder.intvars[:] = original_intvars else: op = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) - op.suboperations = [ResOperation(rop.FAIL, fail_subset, None, - descr=BasicFailDescr())] + op.descr = BasicFailDescr() + op.fail_args = fail_subset builder.loop.operations.append(op) class BinaryOvfOperation(AbstractOvfOperation, BinaryOperation): @@ -264,11 +264,10 @@ def produce_into(self, builder, r): op, passing = self.gen_guard(builder, r) builder.loop.operations.append(op) - subset = builder.subset_of_intvars(r) - op.suboperations = [ResOperation(rop.FAIL, subset, None, - descr=BasicFailDescr())] + op.descr = BasicFailDescr() + op.fail_args = builder.subset_of_intvars(r) if not passing: - builder.should_fail_by = op.suboperations[0] + builder.should_fail_by = op builder.guard_op = op class GuardValueOperation(GuardOperation): @@ -429,7 +428,7 @@ if v not in used_later: endvars.append(v) r.shuffle(endvars) - loop.operations.append(ResOperation(rop.FAIL, endvars, None, + loop.operations.append(ResOperation(rop.FINISH, endvars, None, descr=BasicFailDescr())) if builder.should_fail_by: self.should_fail_by = builder.should_fail_by @@ -438,13 +437,21 @@ self.should_fail_by = loop.operations[-1] self.guard_op = None self.prebuilt_ptr_consts.extend(builder.prebuilt_ptr_consts) - endvars = self.should_fail_by.args + endvars = self.get_fail_args() self.expected = {} for v in endvars: self.expected[v] = v.value if demo_conftest.option.output: builder.print_loop() + def get_fail_args(self): + if self.should_fail_by.is_guard(): + assert self.should_fail_by.fail_args is not None + return self.should_fail_by.fail_args + else: + assert self.should_fail_by.opnum == rop.FINISH + return self.should_fail_by.args + def clear_state(self): for v, S, fields in self.prebuilt_ptr_consts: container = v.value._obj.container @@ -464,7 +471,7 @@ cpu.set_future_value_int(i, v) fail = cpu.execute_token(self.executable_token) assert fail is self.should_fail_by.descr - for i, v in enumerate(self.should_fail_by.args): + for i, v in enumerate(self.get_fail_args()): value = cpu.get_latest_value_int(i) assert value == self.expected[v], ( "Got %d, expected %d for value #%d" % (value, @@ -489,26 +496,25 @@ else: op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box], BoxPtr()) - op.suboperations = [ResOperation(rop.FAIL, [], None, - descr=BasicFailDescr())] + op.descr = BasicFailDescr() + op.fail_args = [] return op if self.dont_generate_more: return False r = self.r guard_op = self.guard_op - fail_args = guard_op.suboperations[-1].args - fail_descr = guard_op.suboperations[-1].descr - guard_op.suboperations = [] + fail_args = guard_op.fail_args + fail_descr = guard_op.descr op = self.should_fail_by - if not op.args: + if not op.fail_args: return False - subloop = DummyLoop(guard_op.suboperations) + subloop = DummyLoop([]) if guard_op.is_guard_exception(): - guard_op.suboperations.append(exc_handling(guard_op)) + subloop.operations.append(exc_handling(guard_op)) bridge_builder = self.builder.fork(self.builder.cpu, subloop, - op.args[:]) - self.generate_ops(bridge_builder, r, subloop, op.args[:]) + op.fail_args[:]) + self.generate_ops(bridge_builder, r, subloop, op.fail_args[:]) dont_compile = False if r.random() < 0.1: subset = bridge_builder.subset_of_intvars(r) @@ -527,8 +533,10 @@ self.expected = rl.expected assert len(rl.loop.inputargs) == len(args) if self.guard_op is None: - guard_op.suboperations[-1] = jump_op + subloop.operations[-1] = jump_op else: + print "fix me again" + return False args = self.guard_op.suboperations[-1].args + fail_args self.guard_op.suboperations[-1].args = args self.builder.cpu.compile_bridge(fail_descr, fail_args, @@ -548,7 +556,7 @@ return False if not dont_compile: self.builder.cpu.compile_bridge(fail_descr, fail_args, - guard_op.suboperations) # xxx insane + subloop.operations) return True def check_random_function(cpu, BuilderClass, r, num=None, max=None): Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py Tue Sep 29 18:18:40 2009 @@ -251,11 +251,10 @@ def regalloc_perform_with_guard(self, op, guard_op, faillocs, arglocs, resloc, current_stack_depth): - fail_op = guard_op.suboperations[0] - faildescr = fail_op.descr + faildescr = guard_op.descr assert isinstance(faildescr, AbstractFailDescr) faildescr._x86_current_stack_depth = current_stack_depth - failargs = fail_op.args + failargs = guard_op.fail_args guard_opnum = guard_op.opnum failaddr = self.implement_guard_recovery(guard_opnum, faildescr, failargs, Modified: pypy/trunk/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/regalloc.py Tue Sep 29 18:18:40 2009 @@ -149,10 +149,7 @@ self.assembler.regalloc_perform(op, arglocs, result_loc) def locs_for_fail(self, guard_op): - assert len(guard_op.suboperations) == 1 - fail_op = guard_op.suboperations[0] - assert fail_op.opnum == rop.FAIL - return [self.loc(v) for v in fail_op.args] + return [self.loc(v) for v in guard_op.fail_args] def perform_with_guard(self, op, guard_op, arglocs, result_loc): faillocs = self.locs_for_fail(guard_op) @@ -161,7 +158,7 @@ arglocs, result_loc, self.sm.stack_depth) self.rm.possibly_free_var(op.result) - self.rm.possibly_free_vars(guard_op.suboperations[0].args) + self.rm.possibly_free_vars(guard_op.fail_args) def perform_guard(self, guard_op, arglocs, result_loc): faillocs = self.locs_for_fail(guard_op) @@ -174,7 +171,7 @@ self.assembler.regalloc_perform_guard(guard_op, faillocs, arglocs, result_loc, self.sm.stack_depth) - self.rm.possibly_free_vars(guard_op.suboperations[0].args) + self.rm.possibly_free_vars(guard_op.fail_args) def PerformDiscard(self, op, arglocs): if not we_are_translated(): @@ -191,7 +188,7 @@ if operations[i + 1].args[0] is not op.result: return False if (self.rm.longevity[op.result][1] > i + 1 or - op.result in operations[i + 1].suboperations[0].args): + op.result in operations[i + 1].fail_args): return False return True @@ -233,12 +230,12 @@ raise AssertionError longevity[arg] = (start_live[arg], i) if op.is_guard(): - for arg in op.suboperations[0].args: - if isinstance(arg, Box): - if arg not in start_live: - print "Bogus arg in guard %d at %d" % (op.opnum, i) - raise AssertionError - longevity[arg] = (start_live[arg], i) + for arg in op.fail_args: + assert isinstance(arg, Box) + if arg not in start_live: + print "Bogus arg in guard %d at %d" % (op.opnum, i) + raise AssertionError + longevity[arg] = (start_live[arg], i) for arg in inputargs: if arg not in longevity: longevity[arg] = (-1, -1) @@ -257,14 +254,12 @@ consider_guard_true = _consider_guard consider_guard_false = _consider_guard - def consider_fail(self, op, ignored): + def consider_finish(self, op, ignored): locs = [self.loc(arg) for arg in op.args] self.assembler.generate_failure(self.assembler.mc, op.descr, op.args, locs, self.exc) self.rm.possibly_free_vars(op.args) - consider_finish = consider_fail # for now - def consider_guard_no_exception(self, op, ignored): self.perform_guard(op, [], None) Modified: pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py Tue Sep 29 18:18:40 2009 @@ -107,7 +107,7 @@ ops = ''' [p0] p1 = getfield_gc(p0, descr=fielddescr) - fail(p1) + finish(p1) ''' self.interpret(ops, [self.struct_ptr]) assert not self.getptr(0, lltype.Ptr(self.S)) @@ -116,7 +116,7 @@ ops = ''' [] p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) - fail(p1) + finish(p1) ''' self.interpret(ops, []) assert not self.getptr(0, lltype.Ptr(self.S)) @@ -124,29 +124,22 @@ def test_bug_0(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] - guard_value(i2, 1) - fail(i2, i3, i4, i5, i6, i7, i0, i1, i8) - guard_class(i4, 138998336) - fail(i4, i5, i6, i7, i0, i1, i8) + guard_value(i2, 1) [i2, i3, i4, i5, i6, i7, i0, i1, i8] + guard_class(i4, 138998336) [i4, i5, i6, i7, i0, i1, i8] i11 = getfield_gc(i4, descr=descr0) i12 = ooisnull(i11) - guard_false(i12) - fail(i4, i5, i6, i7, i0, i1, i11, i8) + guard_false(i12) [i4, i5, i6, i7, i0, i1, i11, i8] i13 = getfield_gc(i11, descr=descr0) i14 = ooisnull(i13) - guard_true(i14) - fail(i4, i5, i6, i7, i0, i1, i11, i8) + guard_true(i14) [i4, i5, i6, i7, i0, i1, i11, i8] i15 = getfield_gc(i4, descr=descr0) i17 = int_lt(i15, 0) - guard_false(i17) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) + guard_false(i17) [i4, i5, i6, i7, i0, i1, i11, i15, i8] i18 = getfield_gc(i11, descr=descr0) i19 = int_ge(i15, i18) - guard_false(i19) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) + guard_false(i19) [i4, i5, i6, i7, i0, i1, i11, i15, i8] i20 = int_lt(i15, 0) - guard_false(i20) - fail(i4, i5, i6, i7, i0, i1, i11, i15, i8) + guard_false(i20) [i4, i5, i6, i7, i0, i1, i11, i15, i8] i21 = getfield_gc(i11, descr=descr0) i22 = getfield_gc(i11, descr=descr0) i23 = int_mul(i15, i22) @@ -157,11 +150,9 @@ i29 = getfield_raw(144839744, descr=descr0) i31 = int_and(i29, -2141192192) i32 = int_is_true(i31) - guard_false(i32) - fail(i4, i6, i7, i0, i1, i24) + guard_false(i32) [i4, i6, i7, i0, i1, i24] i33 = getfield_gc(i0, descr=descr0) - guard_value(i33, ConstPtr(ptr0)) - fail(i4, i6, i7, i0, i1, i33, i24) + guard_value(i33, ConstPtr(ptr0)) [i4, i6, i7, i0, i1, i33, i24] jump(i0, i1, 1, 17, i4, ConstPtr(ptr0), i6, i7, i24) ''' self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0, 0], run=False) Modified: pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py Tue Sep 29 18:18:40 2009 @@ -8,8 +8,7 @@ [i0] i1 = int_add(i0, 1) i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) + guard_true(i2) [i1] jump(i1) ''' loop = self.interpret(ops, [0]) @@ -17,7 +16,7 @@ ops = ''' [i1] i3 = int_add(i1, 1) - fail(i3) + finish(i3) ''' bridge = self.attach_bridge(ops, loop, -2) self.cpu.set_future_value_int(0, 0) @@ -30,8 +29,7 @@ [i0] i1 = int_add(i0, 1) i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) + guard_true(i2) [i1] jump(i1) ''' loop = self.interpret(ops, [0]) @@ -46,11 +44,11 @@ i7 = int_add(i5, i4) i8 = int_add(i7, 1) i9 = int_add(i8, 1) - fail(i3, i4, i5, i6, i7, i8, i9) + finish(i3, i4, i5, i6, i7, i8, i9) ''' bridge = self.attach_bridge(ops, loop, -2) - fail_op = loop._loop.operations[2].suboperations[0] - new = fail_op.descr._x86_bridge_stack_depth + descr = loop._loop.operations[2].descr + new = descr._x86_bridge_stack_depth assert new > previous self.cpu.set_future_value_int(0, 0) fail = self.run(loop) @@ -65,42 +63,40 @@ [i0, i10, i11, i12, i13, i14, i15, i16] i1 = int_add(i0, 1) i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) + guard_true(i2) [i1] jump(i1, i10, i11, i12, i13, i14, i15, i16) ''', [0]) other_loop = self.interpret(''' [i3] - guard_false(i3) - fail(i3) + guard_false(i3) [i3] jump(i3) ''', [1]) ops = ''' [i3] jump(i3, 1, 2, 3, 4, 5, 6, 7) ''' - bridge = self.attach_bridge(ops, other_loop, 0, jump_targets=[loop]) + bridge = self.attach_bridge(ops, other_loop, 0, jump_target=loop) self.cpu.set_future_value_int(0, 1) fail = self.run(other_loop) - assert fail is loop._loop.operations[2].suboperations[0].descr + assert fail is loop._loop.operations[2].descr def test_bridge_jumps_to_self_deeper(self): loop = self.interpret(''' [i0, i1, i2, i31, i32, i33] + i98 = same_as(0) + i99 = same_as(1) i30 = int_add(i1, i2) i3 = int_add(i0, 1) i4 = int_and(i3, 1) - guard_false(i4) - fail(0, i3) + guard_false(i4) [i98, i3] i5 = int_lt(i3, 20) - guard_true(i5) - fail(1, i3) + guard_true(i5) [i99, i3] jump(i3, i30, 1, i30, i30, i30) ''', [0]) assert self.getint(0) == 0 assert self.getint(1) == 1 ops = ''' - [i3] + [i97, i3] i10 = int_mul(i3, 2) i8 = int_add(i3, 1) i6 = int_add(i8, i10) @@ -109,10 +105,10 @@ i11 = int_add(i12, i6) jump(i3, i12, i11, i10, i6, i7) ''' - bridge = self.attach_bridge(ops, loop, 3, jump_targets=[loop]) - fail_op = loop._loop.operations[3].suboperations[0] + bridge = self.attach_bridge(ops, loop, 5, jump_target=loop) + guard_op = loop._loop.operations[5] loop_stack_depth = loop.executable_token._x86_stack_depth - assert fail_op.descr._x86_bridge_stack_depth > loop_stack_depth + assert guard_op.descr._x86_bridge_stack_depth > loop_stack_depth self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) self.cpu.set_future_value_int(2, 0) @@ -123,22 +119,22 @@ def test_bridge_jumps_to_self_shallower(self): loop = self.interpret(''' [i0, i1, i2] + i98 = same_as(0) + i99 = same_as(1) i3 = int_add(i0, 1) i4 = int_and(i3, 1) - guard_false(i4) - fail(0, i3) + guard_false(i4) [i98, i3] i5 = int_lt(i3, 20) - guard_true(i5) - fail(1, i3) + guard_true(i5) [i99, i3] jump(i3, i1, i2) ''', [0]) assert self.getint(0) == 0 assert self.getint(1) == 1 ops = ''' - [i3] + [i97, i3] jump(i3, 0, 1) ''' - bridge = self.attach_bridge(ops, loop, 2, jump_targets=[loop]) + bridge = self.attach_bridge(ops, loop, 4, jump_target=loop) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) self.cpu.set_future_value_int(2, 0) Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py Tue Sep 29 18:18:40 2009 @@ -83,14 +83,14 @@ namespace = locals().copy() type_system = 'lltype' - def parse(self, s, boxkinds=None, jump_targets=None): + def parse(self, s, boxkinds=None, jump_target=None): return parse(s, self.cpu, self.namespace, type_system=self.type_system, - jump_targets=jump_targets, + jump_target=jump_target, boxkinds=boxkinds) - def interpret(self, ops, args, jump_targets=None, run=True): - loop = self.parse(ops, jump_targets=jump_targets) + def interpret(self, ops, args, jump_target=None, run=True): + loop = self.parse(ops, jump_target=jump_target) executable_token = self.cpu.compile_loop(loop.inputargs, loop.operations) for i, arg in enumerate(args): @@ -122,7 +122,7 @@ guard_op = loop_token._loop.operations[guard_op_index] assert guard_op.is_guard() bridge = self.parse(ops, **kwds) - faildescr = guard_op.suboperations[0].descr + faildescr = guard_op.descr self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations) return bridge @@ -135,8 +135,7 @@ [i0] i1 = int_add(i0, 1) i2 = int_lt(i1, 20) - guard_true(i2) - fail(i1) + guard_true(i2) [i1] jump(i1) ''' self.interpret(ops, [0]) @@ -147,8 +146,7 @@ [i0, i1, i2, i3] i4 = int_add(i0, 1) i5 = int_lt(i4, 20) - guard_true(i5) - fail(i4, i1, i2, i3) + guard_true(i5) [i4, i1, i2, i3] jump(i4, i1, i2, i3) ''' loop = self.interpret(ops, [0, 0, 0, 0]) @@ -158,8 +156,7 @@ i3 = int_add(i1, 1) i4 = int_add(i3, 1) i2 = int_lt(i4, 30) - guard_true(i2) - fail(i4) + guard_true(i2) [i4] jump(i4) ''' loop2 = self.interpret(ops2, [0]) @@ -167,7 +164,7 @@ [i4] jump(i4, i4, i4, i4) ''' - bridge = self.attach_bridge(bridge_ops, loop2, 4, jump_targets=[loop]) + bridge = self.attach_bridge(bridge_ops, loop2, 4, jump_target=loop) self.cpu.set_future_value_int(0, 0) self.run(loop2) assert self.getint(0) == 31 @@ -180,8 +177,7 @@ [i0, p0] i1 = int_add(i0, 1) i2 = int_lt(i1, 10) - guard_true(i2) - fail(p0) + guard_true(i2) [p0] jump(i1, p0) ''' S = lltype.GcStruct('S') @@ -194,20 +190,20 @@ def test_exception_bridge_no_exception(self): ops = ''' [i0] + i1 = same_as(1) call(ConstClass(raising_fptr), i0, descr=raising_calldescr) - guard_exception(ConstClass(zero_division_error)) - fail(1) - fail(0) + guard_exception(ConstClass(zero_division_error)) [i1] + finish(0) ''' bridge_ops = ''' - [] - guard_no_exception() - fail(2) - fail(1) + [i3] + i2 = same_as(2) + guard_no_exception() [i2] + finish(1) ''' loop = self.interpret(ops, [0]) assert self.getint(0) == 1 - bridge = self.attach_bridge(bridge_ops, loop, 1) + bridge = self.attach_bridge(bridge_ops, loop, 2) self.cpu.set_future_value_int(0, 0) self.run(loop) assert self.getint(0) == 1 @@ -215,7 +211,7 @@ def test_inputarg_unused(self): ops = ''' [i0] - fail(1) + finish(1) ''' self.interpret(ops, [0]) # assert did not explode @@ -223,15 +219,13 @@ def test_nested_guards(self): ops = ''' [i0, i1] - guard_true(i0) - fail(i0, i1) - fail(4) + guard_true(i0) [i0, i1] + finish(4) ''' bridge_ops = ''' [i0, i1] - guard_true(i0) - fail(i0, i1) - fail(3) + guard_true(i0) [i0, i1] + finish(3) ''' loop = self.interpret(ops, [0, 10]) assert self.getint(0) == 0 @@ -246,15 +240,14 @@ def test_nested_unused_arg(self): ops = ''' [i0, i1] - guard_true(i0) - fail(i0, i1) - fail(1) + guard_true(i0) [i0, i1] + finish(1) ''' loop = self.interpret(ops, [0, 1]) assert self.getint(0) == 0 bridge_ops = ''' [i0, i1] - fail(1, 2) + finish(1, 2) ''' self.attach_bridge(bridge_ops, loop, 0) self.cpu.set_future_value_int(0, 0) @@ -266,8 +259,7 @@ [i0, i1, i2, i3] i4 = int_add(3, i1) i5 = int_lt(i4, 30) - guard_true(i5) - fail(i0, i4, i2, i3) + guard_true(i5) [i0, i4, i2, i3] jump(1, i4, 3, 4) ''' self.interpret(ops, [0, 0, 0, 0]) @@ -279,8 +271,7 @@ i4 = int_lshift(1, i1) i5 = int_add(1, i1) i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4, i5, i2, i3) + guard_true(i6) [i4, i5, i2, i3] jump(i4, 3, i5, 4) ''' self.interpret(ops, [0, 0, 0, 0]) @@ -290,8 +281,7 @@ i4 = int_lshift(1, i1) i5 = int_add(1, i1) i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4, i5, i2, i3) + guard_true(i6) [i4, i5, i2, i3] jump(i4, i5, 3, 4) ''' self.interpret(ops, [0, 0, 0, 0]) @@ -301,8 +291,7 @@ i4 = int_lshift(1, i1) i5 = int_add(1, i1) i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4, i5, i2, i3) + guard_true(i6) [i4, i5, i2, i3] jump(i4, 4, i5, 3) ''' self.interpret(ops, [0, 0, 0, 0]) @@ -314,8 +303,7 @@ i6 = int_neg(i2) i7 = int_add(1, i1) i4 = int_lt(i7, 10) - guard_true(i4) - fail(i0, i6, i7) + guard_true(i4) [i0, i6, i7] jump(1, i7, i2, i6) ''' self.interpret(ops, [0, 0, 3, 0]) @@ -327,8 +315,7 @@ i4 = int_lt(i0, i1) i5 = int_add(i3, 1) i6 = int_lt(i5, 30) - guard_true(i6) - fail(i4) + guard_true(i6) [i4] jump(i0, i1, i4, i5) ''' self.interpret(ops, [0, 10, 0, 0]) @@ -339,8 +326,7 @@ [i0, i15, i16, i18, i1, i2, i3] i4 = int_add(i3, 1) i5 = int_lt(i4, 20) - guard_true(i5) - fail(i2, i1) + guard_true(i5) [i2, i1] jump(i0, i18, i15, i16, i2, i1, i4) ''' self.interpret(ops, [0, 1, 2, 3]) @@ -349,16 +335,15 @@ ops = ''' [i0, i1] i2 = int_add(i0, i1) - fail(0) + finish(0) ''' self.interpret(ops, [0, 0]) def test_guard_value_two_boxes(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7] - guard_value(i6, i1) - fail(i0, i2, i3, i4, i5, i6) - fail(i0, i2, i3, i4, i5, i6) + guard_value(i6, i1) [i0, i2, i3, i4, i5, i6] + finish(i0, i2, i3, i4, i5, i6) ''' self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0]) assert self.getint(0) == 0 @@ -366,18 +351,18 @@ def test_bug_wrong_stack_adj(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] - guard_true(i0) - fail(0, i0, i1, i2, i3, i4, i5, i6, i7, i8) - fail(1, i0, i1, i2, i3, i4, i5, i6, i7, i8) + i9 = same_as(0) + guard_true(i0) [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8] + finish(1, i0, i1, i2, i3, i4, i5, i6, i7, i8) ''' loop = self.interpret(ops, [0, 1, 2, 3, 4, 5, 6, 7, 8]) assert self.getint(0) == 0 bridge_ops = ''' - [i0, i1, i2, i3, i4, i5, i6, i7, i8] + [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8] call(ConstClass(raising_fptr), 0, descr=raising_calldescr) - fail(i0, i1, i2, i3, i4, i5, i6, i7, i8) + finish(i0, i1, i2, i3, i4, i5, i6, i7, i8) ''' - self.attach_bridge(bridge_ops, loop, 0) + self.attach_bridge(bridge_ops, loop, 1) for i in range(9): self.cpu.set_future_value_int(i, i) self.run(loop) @@ -388,10 +373,10 @@ def test_cmp_op_0(self): ops = ''' [i0, i3] + i1 = same_as(1) i2 = int_lt(i0, 100) - guard_true(i3) - fail(1, i2) - fail(0, i2) + guard_true(i3) [i1, i2] + finish(0, i2) ''' self.interpret(ops, [0, 1]) assert self.getint(0) == 0 @@ -419,7 +404,7 @@ i15 = int_is_true(i5) i16 = int_is_true(i6) i17 = int_is_true(i7) - fail(i10, i11, i12, i13, i14, i15, i16, i17) + finish(i10, i11, i12, i13, i14, i15, i16, i17) ''' self.interpret(ops, [0, 42, 12, 0, 13, 0, 0, 3333]) assert self.getints(8) == [0, 1, 1, 0, 1, 0, 0, 1] @@ -433,7 +418,7 @@ i13 = int_eq(i5, i6) i14 = int_gt(i6, i2) i15 = int_ne(i2, i6) - fail(i10, i11, i12, i13, i14, i15) + finish(i10, i11, i12, i13, i14, i15) ''' self.interpret(ops, [0, 1, 2, 3, 4, 5, 6]) assert self.getints(6) == [1, 1, 0, 0, 1, 1] @@ -447,7 +432,7 @@ i13 = oononnull(i3) i14 = ooisnull(i6) i15 = ooisnull(i5) - fail(i10, i11, i12, i13, i14, i15) + finish(i10, i11, i12, i13, i14, i15) ''' self.interpret(ops, [0, 1, 2, 3, 4, 5, 6]) assert self.getints(6) == [0, 0, 1, 1, 0, 0] @@ -456,7 +441,7 @@ ops = ''' [p0, i] strsetitem(p0, 1, i) - fail() + finish() ''' llstr = rstr.mallocstr(10) self.interpret(ops, [llstr, ord('a')]) @@ -466,7 +451,7 @@ ops = ''' [p0, i] setfield_gc(p0, i, descr=fielddescr) - fail() + finish() ''' s = lltype.malloc(self.S) self.interpret(ops, [s, ord('a')]) @@ -476,7 +461,7 @@ ops = ''' [p0, i] setarrayitem_gc(p0, 1, i, descr=arraydescr) - fail() + finish() ''' s = lltype.malloc(self.A, 3) self.interpret(ops, [s, ord('a')]) Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc2.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_regalloc2.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_regalloc2.py Tue Sep 29 18:18:40 2009 @@ -14,7 +14,7 @@ ResOperation(rop.INT_ADD, [v1, v1], v2), ResOperation(rop.INT_INVERT, [v2], v3), ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4), - ResOperation(rop.FAIL, [v4, v3], None, descr=BasicFailDescr()), + ResOperation(rop.FINISH, [v4, v3], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) @@ -35,7 +35,7 @@ ResOperation(rop.INT_MUL, [v2, v1], v3), ResOperation(rop.INT_IS_TRUE, [v2], tmp5), ResOperation(rop.BOOL_NOT, [tmp5], v4), - ResOperation(rop.FAIL, [v4, v3, tmp5], None, descr=BasicFailDescr()), + ResOperation(rop.FINISH, [v4, v3, tmp5], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) @@ -130,7 +130,7 @@ ResOperation(rop.UINT_GT, [v33, ConstInt(-11)], v38), ResOperation(rop.INT_NEG, [v7], v39), ResOperation(rop.INT_GT, [v24, v32], v40), - ResOperation(rop.FAIL, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None, descr=BasicFailDescr()), + ResOperation(rop.FINISH, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) @@ -243,7 +243,7 @@ ResOperation(rop.INT_GT, [v4, v11], v38), ResOperation(rop.INT_LT, [v27, v22], v39), ResOperation(rop.INT_NEG, [v27], v40), - ResOperation(rop.FAIL, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None, descr=BasicFailDescr()), + ResOperation(rop.FINISH, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) executable_token = cpu.compile_loop(inputargs, operations) Modified: pypy/trunk/pypy/jit/backend/x86/test/test_runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_runner.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_runner.py Tue Sep 29 18:18:40 2009 @@ -77,12 +77,12 @@ ResOperation(rop.INT_ADD, [x, y], z), ResOperation(rop.INT_SUB, [y, ConstInt(1)], t), ResOperation(rop.INT_EQ, [t, ConstInt(0)], u), - ResOperation(rop.GUARD_FALSE, [u], None), + ResOperation(rop.GUARD_FALSE, [u], None, + descr=BasicFailDescr()), ResOperation(rop.JUMP, [z, t], None), ] operations[-1].jump_target = None - operations[-2].suboperations = [ResOperation(rop.FAIL, [t, z], None, - descr=BasicFailDescr())] + operations[-2].fail_args = [t, z] executable_token = cpu.compile_loop([x, y], operations) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 10) @@ -317,15 +317,16 @@ bp = BoxPtr(p) n = BoxPtr(nullptr) for b in (bp, n): + i1 = BoxInt(1) ops = [ + ResOperation(rop.SAME_AS, [ConstInt(1)], i1), ResOperation(op, [b], f), - ResOperation(guard, [f], None), - ResOperation(rop.FAIL, [ConstInt(0)], None, + ResOperation(guard, [f], None, + descr=BasicFailDescr()), + ResOperation(rop.FINISH, [ConstInt(0)], None, descr=BasicFailDescr()), ] - ops[1].suboperations = [ResOperation(rop.FAIL, - [ConstInt(1)], None, - descr=BasicFailDescr())] + ops[-2].fail_args = [i1] executable_token = self.cpu.compile_loop([b], ops) if op == rop.INT_IS_TRUE: self.cpu.set_future_value_int(0, b.value) @@ -362,15 +363,16 @@ for guard in guards: for op in all: res = BoxInt() + i1 = BoxInt(1) ops = [ + ResOperation(rop.SAME_AS, [ConstInt(1)], i1), ResOperation(op, [a, b], res), - ResOperation(guard, [res], None), - ResOperation(rop.FAIL, [ConstInt(0)], None, + ResOperation(guard, [res], None, + descr=BasicFailDescr()), + ResOperation(rop.FINISH, [ConstInt(0)], None, descr=BasicFailDescr()), ] - ops[1].suboperations = [ResOperation(rop.FAIL, - [ConstInt(1)], None, - descr=BasicFailDescr())] + ops[-2].fail_args = [i1] inputargs = [i for i in (a, b) if isinstance(i, Box)] executable_token = self.cpu.compile_loop(inputargs, ops) for i, box in enumerate(inputargs): @@ -399,7 +401,7 @@ next_v = BoxInt() ops.append(ResOperation(rop.INT_ADD, [v, ConstInt(1)], next_v)) v = next_v - ops.append(ResOperation(rop.FAIL, [v], None, + ops.append(ResOperation(rop.FINISH, [v], None, descr=BasicFailDescr())) executable_token = self.cpu.compile_loop([base_v], ops) assert self.cpu.assembler.mc != old_mc # overflowed Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Tue Sep 29 18:18:40 2009 @@ -193,32 +193,24 @@ class ResumeGuardDescr(ResumeDescr): counter = 0 + # this class also gets attributes stored by resume.py code - def __init__(self, original_greenkey, guard_op): - ResumeDescr.__init__(self, original_greenkey) - self.guard_op = guard_op - # this class also gets attributes stored by resume.py code + def store_final_boxes(self, guard_op, boxes): + guard_op.fail_args = boxes + self.guard_opnum = guard_op.opnum + self.fail_arg_types = [box.type for box in boxes] def handle_fail(self, metainterp_sd): from pypy.jit.metainterp.pyjitpl import MetaInterp metainterp = MetaInterp(metainterp_sd) - fail_op = self.get_guard_op().suboperations[-1] # xxx unhappy - return metainterp.handle_guard_failure(fail_op, self) - - def get_guard_op(self): - guard_op = self.guard_op - assert guard_op.is_guard() - if guard_op.optimized is not None: # should always be the case, - return guard_op.optimized # except if not optimizing at all - else: - return guard_op + return metainterp.handle_guard_failure(self) def compile_and_attach(self, metainterp, new_loop): # We managed to create a bridge. Attach the new operations # to the corrsponding guard_op and compile from there inputargs = metainterp.history.inputargs if not we_are_translated(): - self.get_guard_op()._debug_suboperations = new_loop.operations + self._debug_suboperations = new_loop.operations send_bridge_to_backend(metainterp.staticdata, self, inputargs, new_loop.operations) Modified: pypy/trunk/pypy/jit/metainterp/graphpage.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/graphpage.py (original) +++ pypy/trunk/pypy/jit/metainterp/graphpage.py Tue Sep 29 18:18:40 2009 @@ -17,13 +17,13 @@ for graph, highlight in graphs: for op in graph.get_operations(): if is_interesting_guard(op): - graphs.append((SubGraph(op._debug_suboperations), + graphs.append((SubGraph(op.descr._debug_suboperations), highlight)) graphpage = ResOpGraphPage(graphs, errmsg) graphpage.display() def is_interesting_guard(op): - return hasattr(op, '_debug_suboperations') + return hasattr(op.descr, '_debug_suboperations') class ResOpGraphPage(GraphPage): @@ -155,7 +155,7 @@ op = operations[opindex] lines.append(repr(op)) if is_interesting_guard(op): - tgt = op._debug_suboperations[0] + tgt = op.descr._debug_suboperations[0] tgt_g, tgt_i = self.all_operations[tgt] self.genedge((graphindex, opstartindex), (tgt_g, tgt_i), Modified: pypy/trunk/pypy/jit/metainterp/history.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py Tue Sep 29 18:18:40 2009 @@ -642,7 +642,7 @@ # The TreeLoop class contains a loop or a generalized loop, i.e. a tree # of operations. Each branch ends in a jump which can go either to -# the top of the same loop, or to another TreeLoop; or it ends in a FAIL. +# the top of the same loop, or to another TreeLoop; or it ends in a FINISH. class Base(object): """Common base class for TreeLoop and History.""" @@ -665,16 +665,16 @@ # ops of the kind 'guard_xxx' contain a further list of operations, # which may itself contain 'guard_xxx' and so on, making a tree. - def _all_operations(self, omit_fails=False): + def _all_operations(self, omit_finish=False): "NOT_RPYTHON" result = [] - _list_all_operations(result, self.operations, omit_fails) + _list_all_operations(result, self.operations, omit_finish) return result def summary(self, adding_insns={}): # for debugging "NOT_RPYTHON" insns = adding_insns.copy() - for op in self._all_operations(omit_fails=True): + for op in self._all_operations(omit_finish=True): opname = op.getopname() insns[opname] = insns.get(opname, 0) + 1 return insns @@ -710,13 +710,16 @@ for box in op.args: if isinstance(box, Box): assert box in seen - assert (op.suboperations is not None) == op.is_guard() if op.is_guard(): - if hasattr(op, '_debug_suboperations'): - ops = op._debug_suboperations - else: - ops = op.suboperations - TreeLoop.check_consistency_of_branch(ops, seen.copy()) + assert op.descr is not None + if hasattr(op.descr, '_debug_suboperations'): + ops = op.descr._debug_suboperations + TreeLoop.check_consistency_of_branch(ops, seen.copy()) + for box in op.fail_args or []: + assert isinstance(box, Box) + assert box in seen + else: + assert op.fail_args is None box = op.result if box is not None: assert isinstance(box, Box) @@ -747,20 +750,16 @@ def __repr__(self): return '<%s>' % (self.name,) -def _list_all_operations(result, operations, omit_fails=True): - if omit_fails and operations[-1].opnum in (rop.FAIL, rop.FINISH): +def _list_all_operations(result, operations, omit_finish=True): + if omit_finish and operations[-1].opnum == rop.FINISH: # xxx obscure return result.extend(operations) for op in operations: - if op.is_guard(): - if hasattr(op, '_debug_suboperations'): - ops = op._debug_suboperations - else: - if omit_fails: - continue - ops = op.suboperations - _list_all_operations(result, ops, omit_fails) + if op.is_guard() and op.descr: + if hasattr(op.descr, '_debug_suboperations'): + ops = op.descr._debug_suboperations + _list_all_operations(result, ops, omit_finish) # ____________________________________________________________ Modified: pypy/trunk/pypy/jit/metainterp/logger.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/logger.py (original) +++ pypy/trunk/pypy/jit/metainterp/logger.py Tue Sep 29 18:18:40 2009 @@ -70,9 +70,11 @@ res = "" if op.descr is not None: args += ', descr=' + self.repr_of_descr(op.descr) + if op.is_guard() and op.fail_args is not None: + fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg) + for arg in op.fail_args]) + ']' + else: + fail_args = '' self.log_stream.write(pre + res + op.getopname() + - '(' + args + ')\n') - if op.is_guard(): - self.log_operations(None, op.suboperations, memo, - indent=indent+2) + '(' + args + ')' + fail_args + '\n') self.log_stream.flush() Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimizeopt.py Tue Sep 29 18:18:40 2009 @@ -481,7 +481,6 @@ self.loop.operations = self.newoperations def emit_operation(self, op, must_clone=True): - op1 = op for i in range(len(op.args)): arg = op.args[i] if arg in self.values: @@ -492,21 +491,14 @@ must_clone = False op.args[i] = box if op.is_guard(): - self.clone_guard(op, op1) + self.store_final_boxes_in_guard(op) elif op.can_raise(): self.exception_might_have_happened = True self.newoperations.append(op) - def _get_faildescr(self, op_fail): - descr = op_fail.descr + def store_final_boxes_in_guard(self, op): + descr = op.descr assert isinstance(descr, compile.ResumeGuardDescr) - return descr - - def clone_guard(self, op2, op1): - assert len(op1.suboperations) == 1 - op_fail = op1.suboperations[0] - assert op_fail.opnum == rop.FAIL - descr = self._get_faildescr(op_fail) oldboxes = [] args = resume.flatten_resumedata(descr) # xxx expensive for box in args: @@ -519,14 +511,7 @@ value = self.values[box] value.get_args_for_fail(modifier) newboxes = modifier.finish() - # XXX we mutate op_fail in-place below, as well as op_fail.descr - # via the ResumeDataVirtualAdder. That's bad. Hopefully - # it does not really matter because no-one is going to look again - # at its unoptimized version. We should really clone it (and - # the descr too). - op_fail.args = newboxes - op2.suboperations = op1.suboperations - op1.optimized = op2 + descr.store_final_boxes(op, newboxes) def clean_fields_of_values(self, descr=None): if descr is None: Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Tue Sep 29 18:18:40 2009 @@ -917,17 +917,16 @@ moreargs = [box] + extraargs else: moreargs = list(extraargs) - guard_op = metainterp.history.record(opnum, moreargs, None) original_greenkey = metainterp.resumekey.original_greenkey - resumedescr = compile.ResumeGuardDescr(original_greenkey, guard_op) + resumedescr = compile.ResumeGuardDescr(original_greenkey) + guard_op = metainterp.history.record(opnum, moreargs, None, + descr=resumedescr) virtualizable_boxes = None if metainterp.staticdata.virtualizable_info is not None: virtualizable_boxes = metainterp.virtualizable_boxes resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, resumedescr) self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count - op = history.ResOperation(rop.FAIL, [], None, descr=resumedescr) - guard_op.suboperations = [op] metainterp.attach_debug_info(guard_op) self.pc = saved_pc return guard_op @@ -1337,10 +1336,10 @@ except GenerateMergePoint, gmp: return self.designate_target_loop(gmp) - def handle_guard_failure(self, exec_result, key): + def handle_guard_failure(self, key): from pypy.jit.metainterp.warmspot import ContinueRunningNormallyBase - resumedescr = self.initialize_state_from_guard_failure(exec_result) assert isinstance(key, compile.ResumeGuardDescr) + resumedescr = self.initialize_state_from_guard_failure(key) original_greenkey = key.original_greenkey # notice that here we just put the greenkey # use -1 to mark that we will have to give up @@ -1348,10 +1347,9 @@ self.current_merge_points = [(original_greenkey, -1)] self.resumekey = key self.seen_can_enter_jit = False - guard_op = key.get_guard_op() started_as_blackhole = self.is_blackholing() try: - self.prepare_resume_from_failure(guard_op.opnum) + self.prepare_resume_from_failure(key.guard_opnum) self.interpret() assert False, "should always raise" except GenerateMergePoint, gmp: @@ -1430,34 +1428,8 @@ residual_args = self.get_residual_args(loop_token.specnodes, gmp.argboxes[num_green_args:]) history.set_future_values(self.cpu, residual_args) - self.clean_up_history() return loop_token.executable_token - def clean_up_history(self): - # Clear the BoxPtrs used in self.history, at the end. The - # purpose of this is to clear the boxes that are also used in - # the TreeLoop just produced. After this, there should be no - # reference left to temporary values in long-living BoxPtrs. - # A note about recursion: setting to NULL like this should be - # safe, because ResumeGuardDescr.restore_patched_boxes should - # save and restore all the boxes that are also used by callers. - if self.history.inputargs is not None: - for box in self.history.inputargs: - self.cpu.ts.clean_box(box) - lists = [self.history.operations] - while lists: - for op in lists.pop(): - if op is None: - continue - if op.result is not None: - self.cpu.ts.clean_box(op.result) - if op.suboperations is not None: - lists.append(op.suboperations) - if op.optimized is not None: - lists.append(op.optimized.suboperations) - if op.optimized.result is not None: - self.cpu.ts.clean_box(op.optimized.result) - def prepare_resume_from_failure(self, opnum): if opnum == rop.GUARD_TRUE: # a goto_if_not that jumps only now self.framestack[-1].follow_jump() @@ -1564,18 +1536,13 @@ self.initialize_virtualizable(original_boxes) return original_boxes - def initialize_state_from_guard_failure(self, guard_failure): + def initialize_state_from_guard_failure(self, resumedescr): # guard failure: rebuild a complete MIFrame stack self.in_recursion = -1 # always one portal around - inputargs = self.load_values_from_failure(guard_failure) - resumedescr = guard_failure.descr - assert isinstance(resumedescr, compile.ResumeGuardDescr) + inputargs = self.load_values_from_failure(resumedescr) warmrunnerstate = self.staticdata.state must_compile = warmrunnerstate.must_compile_from_failure(resumedescr) if must_compile: - guard_op = resumedescr.get_guard_op() - suboperations = guard_op.suboperations - assert suboperations[-1] is guard_failure self.history = history.History(self.cpu) self.history.inputargs = inputargs self.staticdata.profiler.start_tracing() @@ -1585,20 +1552,20 @@ self.rebuild_state_after_failure(resumedescr, inputargs) return resumedescr - def load_values_from_failure(self, guard_failure): + def load_values_from_failure(self, resumedescr): cpu = self.cpu + fail_arg_types = resumedescr.fail_arg_types inputargs = [] - for i in range(len(guard_failure.args)): - oldbox = guard_failure.args[i] # xxx unhappy - if isinstance(oldbox, history.BoxInt): + for i in range(len(fail_arg_types)): + boxtype = fail_arg_types[i] + if boxtype == history.INT: box = history.BoxInt(cpu.get_latest_value_int(i)) - elif isinstance(oldbox, cpu.ts.BoxRef): + elif boxtype == history.REF: box = cpu.ts.BoxRef(cpu.get_latest_value_ref(i)) - elif isinstance(oldbox, history.BoxFloat): + elif boxtype == history.FLOAT: box = history.BoxFloat(cpu.get_latest_value_float(i)) else: - assert False, "should not see %r in guard_failure.args" % ( - oldbox,) + assert False, "bad box type: num=%d" % ord(boxtype) inputargs.append(box) return inputargs Modified: pypy/trunk/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resoperation.py (original) +++ pypy/trunk/pypy/jit/metainterp/resoperation.py Tue Sep 29 18:18:40 2009 @@ -8,8 +8,9 @@ jump_target = None # for 'guard_*' - suboperations = None - optimized = None + suboperations = property(lambda x: crash, lambda x, y: crash) # XXX temp + optimized = property(lambda x: crash, lambda x, y: crash) # XXX temp + fail_args = None # for x86 backend and guards inputargs = None @@ -105,7 +106,6 @@ _oplist = [ '_FINAL_FIRST', 'JUMP', - 'FAIL', 'FINISH', '_FINAL_LAST', Modified: pypy/trunk/pypy/jit/metainterp/simple_optimize.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/simple_optimize.py (original) +++ pypy/trunk/pypy/jit/metainterp/simple_optimize.py Tue Sep 29 18:18:40 2009 @@ -17,11 +17,10 @@ newoperations = [] for op in loop.operations: if op.is_guard(): - op_fail = op.suboperations[-1] - descr = op_fail.descr + descr = op.descr assert isinstance(descr, compile.ResumeGuardDescr) args = resume.flatten_resumedata(descr) - op_fail.args = args + descr.store_final_boxes(op, args) newoperations.append(op) loop.operations = newoperations return None Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/oparser.py Tue Sep 29 18:18:40 2009 @@ -26,9 +26,6 @@ yield op.result for box in op.args: yield box - if op.suboperations: - for box in opboxes(op.suboperations): - yield box def allboxes(): for box in self.inputargs: yield box @@ -47,8 +44,12 @@ for name, value in kwds.iteritems(): getattr(boxes, name).value = value +def default_fail_descr(fail_args=None): + return BasicFailDescr() + + class OpParser(object): - def __init__(self, descr, cpu, namespace, type_system, boxkinds, jump_targets, invent_fail_descrs=True): + def __init__(self, descr, cpu, namespace, type_system, boxkinds, jump_target, invent_fail_descr=default_fail_descr): self.descr = descr self.vars = {} self.cpu = cpu @@ -56,9 +57,9 @@ self.type_system = type_system self.boxkinds = boxkinds or {} self.jumps = [] - self.jump_targets = jump_targets + self.jump_target = jump_target self._cache = namespace.setdefault('_CACHE_', {}) - self.invent_fail_descrs = invent_fail_descrs + self.invent_fail_descr = invent_fail_descr def box_for_var(self, elem): try: @@ -165,27 +166,47 @@ args.append(self.getvar(arg)) except KeyError: raise ParseError("Unknown var: %s" % arg) - if hasattr(descr, '_oparser_uses_descr'): - descr._oparser_uses_descr(self, args) - if opnum == rop.FAIL and descr is None and self.invent_fail_descrs: - descr = BasicFailDescr() - return opnum, args, descr + if rop._GUARD_FIRST <= opnum <= rop._GUARD_LAST: + i = line.find('[', endnum) + 1 + j = line.find(']', i) + if i <= 0 or j <= 0: + raise ParseError("missing fail_args for guard operation") + fail_args = [] + if i < j: + for arg in line[i:j].split(','): + arg = arg.strip() + try: + fail_args.append(self.vars[arg]) + except KeyError: + raise ParseError("Unknown var in fail_args: %s" % arg) + if descr is None and self.invent_fail_descr: + descr = self.invent_fail_descr(fail_args) + if hasattr(descr, '_oparser_uses_descr_of_guard'): + descr._oparser_uses_descr_of_guard(self, fail_args) + else: + fail_args = None + if opnum == rop.FINISH: + if descr is None and self.invent_fail_descr: + descr = self.invent_fail_descr() + return opnum, args, descr, fail_args def parse_result_op(self, line): res, op = line.split("=", 1) res = res.strip() op = op.strip() - opnum, args, descr = self.parse_op(op) + opnum, args, descr, fail_args = self.parse_op(op) if res in self.vars: raise ParseError("Double assign to var %s in line: %s" % (res, line)) rvar = self.box_for_var(res) self.vars[res] = rvar res = ResOperation(opnum, args, rvar, descr) + res.fail_args = fail_args return res def parse_op_no_result(self, line): - opnum, args, descr = self.parse_op(line) + opnum, args, descr, fail_args = self.parse_op(line) res = ResOperation(opnum, args, None, descr) + res.fail_args = fail_args if opnum == rop.JUMP: self.jumps.append(res) return res @@ -219,15 +240,12 @@ if num < len(newlines): raise ParseError("unexpected dedent at line: %s" % newlines[num]) loop = ExtendedTreeLoop("loop") - if (self.jump_targets is not None and - len(self.jump_targets) != len(self.jumps)): - raise ParseError("Wrong number of jump targets") - if self.jump_targets is None: - for jump in self.jumps: - jump.jump_target = None - else: - for jump, jump_target in zip(self.jumps, self.jump_targets): - jump.jump_target = jump_target + if len(self.jumps) > 1: + raise ParseError("Multiple jumps??") + if self.jump_target is not None and len(self.jumps) != 1: + raise ParseError("A jump is expected if a jump_target is given") + for jump in self.jumps: + jump.jump_target = self.jump_target loop.operations = ops loop.inputargs = inpargs return loop @@ -241,10 +259,7 @@ # dedent return num, ops elif line.startswith(" "*(indent + 1)): - # suboperations - new_indent = len(line) - len(line.lstrip()) - num, suboperations = self.parse_ops(new_indent, lines, num) - ops[-1].suboperations = suboperations + raise ParseError("indentation not valid any more") else: ops.append(self.parse_next_op(lines[num].strip())) num += 1 @@ -261,13 +276,15 @@ return base_indent, inpargs def parse(descr, cpu=None, namespace=None, type_system='lltype', - boxkinds=None, jump_targets=None, invent_fail_descrs=True): + boxkinds=None, jump_target=None, + invent_fail_descr=default_fail_descr): if namespace is None: namespace = {} - return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_targets, invent_fail_descrs).parse() + return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_target, + invent_fail_descr).parse() def pure_parse(*args, **kwds): - kwds['invent_fail_descrs'] = False + kwds['invent_fail_descr'] = None return parse(*args, **kwds) def _box_counter_more_than(s): Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Tue Sep 29 18:18:40 2009 @@ -224,8 +224,8 @@ if self.basic: found = 0 for op in get_stats().loops[0]._all_operations(): - if op.getopname() == 'fail': - liveboxes = op.args + if op.getopname() == 'guard_true': + liveboxes = op.fail_args assert len(liveboxes) == 3 for box in liveboxes: assert isinstance(box, history.BoxInt) @@ -810,7 +810,7 @@ return r() is None # assert f(30) == 1 - res = self.meta_interp(f, [30]) + res = self.meta_interp(f, [30], no_stats=True) assert res == 1 def test_pass_around(self): Modified: pypy/trunk/pypy/jit/metainterp/test/test_logger.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_logger.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_logger.py Tue Sep 29 18:18:40 2009 @@ -25,9 +25,9 @@ class TestLogger(object): ts = llhelper - def reparse(self, inp, namespace=None): - """ parse loop once, then log it and parse again, - return both + def reparse(self, inp, namespace=None, check_equal=True): + """ parse loop once, then log it and parse again. + Checks that we get the same thing. """ if namespace is None: namespace = {} @@ -35,6 +35,9 @@ logger = Logger(self.ts) output = logger.log_loop(loop, namespace) oloop = pure_parse(output, namespace=namespace) + if check_equal: + equaloplists(loop.operations, oloop.operations) + assert oloop.inputargs == loop.inputargs return loop, oloop def test_simple(self): @@ -44,9 +47,7 @@ i8 = int_add(i6, 3) jump(i0, i8, i6, p3, p4, p5) ''' - loop, oloop = self.reparse(inp) - equaloplists(oloop.operations, loop.operations) - assert oloop.inputargs == loop.inputargs + self.reparse(inp) def test_descr(self): inp = ''' @@ -54,27 +55,22 @@ setfield_gc(p0, 3, descr=somedescr) ''' somedescr = Descr() - loop, oloop = self.reparse(inp, namespace=locals()) - equaloplists(loop.operations, oloop.operations) + self.reparse(inp, namespace=locals()) def test_guard(self): inp = ''' [i0] - guard_true(i0) - i1 = int_add(i0, 1) - guard_true(i1) - fail(i1) - fail(i1) - fail(i0) + i1 = int_add(i0, 1) + guard_true(i0) [i0, i1] + finish(i1) ''' - loop, oloop = self.reparse(inp) - equaloplists(loop.operations, oloop.operations) + self.reparse(inp) def test_debug_merge_point(self): inp = ''' [] debug_merge_point("info") ''' - loop, oloop = self.reparse(inp) + loop, oloop = self.reparse(inp, check_equal=False) + assert loop.operations[0].args[0]._get_str() == 'info' assert oloop.operations[0].args[0]._get_str() == 'info' - Modified: pypy/trunk/pypy/jit/metainterp/test/test_loop.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_loop.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_loop.py Tue Sep 29 18:18:40 2009 @@ -173,8 +173,8 @@ if self.basic: found = 0 for op in get_stats().loops[0]._all_operations(): - if op.getopname() == 'fail': - liveboxes = op.args + if op.getopname() == 'guard_true': + liveboxes = op.fail_args assert len(liveboxes) == 2 # x, y (in some order) assert isinstance(liveboxes[0], history.BoxInt) assert isinstance(liveboxes[1], history.BoxInt) Modified: pypy/trunk/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_oparser.py Tue Sep 29 18:18:40 2009 @@ -11,27 +11,26 @@ # a comment i2 = int_add(i0, i1) i3 = int_sub(i2, 3) # another comment - fail() # (tricky) + finish() # (tricky) """ loop = parse(x) assert len(loop.operations) == 3 assert [op.opnum for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, - rop.FAIL] + rop.FINISH] assert len(loop.inputargs) == 2 assert loop.operations[-1].descr def test_const_ptr_subops(): x = """ [p0] - guard_class(p0, ConstClass(vtable)) - fail() + guard_class(p0, ConstClass(vtable)) [] """ S = lltype.Struct('S') vtable = lltype.nullptr(S) loop = parse(x, None, locals()) assert len(loop.operations) == 1 - assert len(loop.operations[0].suboperations) == 1 - assert loop.operations[0].suboperations[-1].descr + assert loop.operations[0].descr + assert loop.operations[0].fail_args == [] def test_descr(): class Xyz(AbstractDescr): @@ -48,8 +47,7 @@ def test_after_fail(): x = """ [i0] - guard_value(i0, 3) - fail() + guard_value(i0, 3) [] i1 = int_add(1, 2) """ loop = parse(x, None, {}) @@ -128,21 +126,9 @@ jump() ''' obj = object() - loop = parse(x, jump_targets=[obj]) + loop = parse(x, jump_target=obj) assert loop.operations[0].jump_target is obj -def test_jump_target_self(): - x = ''' - [i2] - guard_true(i2) - jump() - jump() - ''' - obj = object() - loop = parse(x, jump_targets=[obj, None]) - assert loop.operations[-1].jump_target is None - assert loop.operations[0].suboperations[0].jump_target is obj - def test_debug_merge_point(): x = ''' [] Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py Tue Sep 29 18:18:40 2009 @@ -16,7 +16,7 @@ from pypy.jit.metainterp.specnode import VirtualArraySpecNode from pypy.jit.metainterp.specnode import VirtualStructSpecNode from pypy.jit.metainterp.specnode import ConstantSpecNode -from pypy.jit.metainterp.test.oparser import pure_parse as parse +from pypy.jit.metainterp.test.oparser import parse def test_sort_descrs(): class PseudoDescr(AbstractDescr): @@ -159,11 +159,13 @@ namespace = locals() class BaseTest(object): + invent_fail_descr = None def parse(self, s, boxkinds=None): return parse(s, self.cpu, self.namespace, type_system=self.type_system, - boxkinds=boxkinds) + boxkinds=boxkinds, + invent_fail_descr=self.invent_fail_descr) def unpack_specnodes(self, text): # @@ -229,8 +231,7 @@ ops = """ [i] i0 = int_sub(i, 1) - guard_value(i0, 0) - fail(i0) + guard_value(i0, 0) [i0] jump(i0) """ boxes, getnode = self.find_nodes(ops, 'Not') @@ -327,8 +328,7 @@ def test_find_nodes_new_3(self): ops = """ [sum, p1] - guard_class(p1, ConstClass(node_vtable)) - fail() + guard_class(p1, ConstClass(node_vtable)) [] i1 = getfield_gc(p1, descr=valuedescr) i2 = int_sub(i1, 1) sum2 = int_add(sum, i1) @@ -380,11 +380,9 @@ def test_find_nodes_new_aliasing_1(self): ops = """ [sum, p1] - guard_class(p1, ConstClass(node_vtable)) - fail() + guard_class(p1, ConstClass(node_vtable)) [] p3 = getfield_gc(p1, descr=nextdescr) - guard_class(p3, ConstClass(node_vtable)) - fail() + guard_class(p3, ConstClass(node_vtable)) [] i1 = getfield_gc(p1, descr=valuedescr) i2 = int_sub(i1, 1) sum2 = int_add(sum, i1) @@ -412,8 +410,7 @@ def test_find_nodes_new_mismatch(self): ops = """ [p1] - guard_class(p1, ConstClass(node_vtable)) - fail() + guard_class(p1, ConstClass(node_vtable)) [] p2 = new_with_vtable(ConstClass(node_vtable2)) jump(p2) """ @@ -424,10 +421,8 @@ def test_find_nodes_new_aliasing_mismatch(self): ops = """ [p0, p1] - guard_class(p0, ConstClass(node_vtable)) - fail() - guard_class(p1, ConstClass(node_vtable2)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] + guard_class(p1, ConstClass(node_vtable2)) [] p2 = new_with_vtable(ConstClass(node_vtable2)) jump(p2, p2) """ @@ -465,41 +460,29 @@ p0 = new_with_vtable(ConstClass(node_vtable)) p1 = new_with_vtable(ConstClass(node_vtable)) i1 = oononnull(p0) - guard_true(i1) - fail() + guard_true(i1) [] i2 = ooisnull(p0) - guard_false(i2) - fail() + guard_false(i2) [] i3 = ooisnot(p0, NULL) - guard_true(i3) - fail() + guard_true(i3) [] i4 = oois(p0, NULL) - guard_false(i4) - fail() + guard_false(i4) [] i5 = ooisnot(NULL, p0) - guard_true(i5) - fail() + guard_true(i5) [] i6 = oois(NULL, p0) - guard_false(i6) - fail() + guard_false(i6) [] i7 = ooisnot(p0, p1) - guard_true(i7) - fail() + guard_true(i7) [] i8 = oois(p0, p1) - guard_false(i8) - fail() + guard_false(i8) [] i9 = ooisnot(p0, p2) - guard_true(i9) - fail() + guard_true(i9) [] i10 = oois(p0, p2) - guard_false(i10) - fail() + guard_false(i10) [] i11 = ooisnot(p2, p1) - guard_true(i11) - fail() + guard_true(i11) [] i12 = oois(p2, p1) - guard_false(i12) - fail() + guard_false(i12) [] jump(p0, p1, p2) """ self.find_nodes(ops, '''Virtual(node_vtable), @@ -519,8 +502,7 @@ ops = """ [p0] i0 = getfield_gc(p0, descr=valuedescr) - guard_value(i0, 5) - fail() + guard_value(i0, 5) [] p1 = new_with_vtable(ConstClass(node_vtable)) # the field 'value' has its default value of 0 jump(p1) @@ -532,8 +514,7 @@ def test_find_nodes_nonvirtual_guard_class(self): ops = """ [p1] - guard_class(p1, ConstClass(node_vtable)) - fail(p1) + guard_class(p1, ConstClass(node_vtable)) [p1] jump(p1) """ self.find_nodes(ops, 'Not') @@ -574,8 +555,7 @@ def test_find_nodes_p123_guard_class(self): ops = """ [i1, p2, p3] - guard_class(p3, ConstClass(node_vtable)) - fail(i1, p2, p3) + guard_class(p3, ConstClass(node_vtable)) [i1, p2, p3] i3 = getfield_gc(p3, descr=valuedescr) escape(i3) p1 = new_with_vtable(ConstClass(node_vtable)) @@ -717,8 +697,7 @@ def test_find_nodes_guard_value_constant(self): ops = """ [p1] - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] jump(ConstPtr(myptr)) """ self.find_nodes(ops, 'Constant(myptr)') @@ -726,8 +705,7 @@ def test_find_nodes_guard_value_constant_mismatch(self): ops = """ [p1] - guard_value(p1, ConstPtr(myptr2)) - fail() + guard_value(p1, ConstPtr(myptr2)) [] jump(ConstPtr(myptr)) """ py.test.raises(InvalidLoop, self.find_nodes, ops, None) @@ -736,8 +714,7 @@ ops = """ [p1] escape(p1) - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] jump(ConstPtr(myptr)) """ self.find_nodes(ops, 'Constant(myptr)') @@ -745,8 +722,7 @@ def test_find_nodes_guard_value_same_as_constant(self): ops = """ [p1] - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] p2 = same_as(ConstPtr(myptr)) jump(p2) """ @@ -837,25 +813,18 @@ ops = """ [p12] i16 = ooisnull(p12) - guard_false(i16) - fail() - guard_class(p12, ConstClass(node_vtable)) - fail() - guard_class(p12, ConstClass(node_vtable)) - fail() + guard_false(i16) [] + guard_class(p12, ConstClass(node_vtable)) [] + guard_class(p12, ConstClass(node_vtable)) [] i22 = getfield_gc_pure(p12, descr=valuedescr) escape(i22) i25 = ooisnull(p12) - guard_false(i25) - fail() - guard_class(p12, ConstClass(node_vtable)) - fail() - guard_class(p12, ConstClass(node_vtable)) - fail() + guard_false(i25) [] + guard_class(p12, ConstClass(node_vtable)) [] + guard_class(p12, ConstClass(node_vtable)) [] i29 = getfield_gc_pure(p12, descr=valuedescr) i31 = int_add_ovf(i29, 1) - guard_no_overflow() - fail() + guard_no_overflow() [] p33 = new_with_vtable(ConstClass(node_vtable)) # NODE setfield_gc(p33, i31, descr=valuedescr) # @@ -864,13 +833,10 @@ p38 = new_with_vtable(ConstClass(u_vtable)) # U setfield_gc(p38, p35, descr=onedescr) i39 = ooisnull(p38) - guard_false(i39) - fail() + guard_false(i39) [] i40 = oononnull(p38) - guard_true(i40) - fail() - guard_class(p38, ConstClass(u_vtable)) - fail() + guard_true(i40) [] + guard_class(p38, ConstClass(u_vtable)) [] p42 = getfield_gc(p38, descr=onedescr) # Array(NODE) i43 = arraylen_gc(p42, descr=arraydescr3) i45 = int_sub(i43, 0) @@ -879,23 +845,19 @@ p47 = new_array(i45, descr=arraydescr3) # Array(NODE) setfield_gc(p46, p47, descr=ddescr) i48 = int_lt(0, i43) - guard_true(i48) - fail() + guard_true(i48) [] p49 = getarrayitem_gc(p42, 0, descr=arraydescr3) # NODE p50 = getfield_gc(p46, descr=ddescr) # Array(NODE) setarrayitem_gc(p50, 0, p49, descr=arraydescr3) i52 = int_lt(1, i43) - guard_false(i52) - fail() + guard_false(i52) [] i53 = getfield_gc(p46, descr=cdescr) i55 = int_ne(i53, 1) - guard_false(i55) - fail() + guard_false(i55) [] p56 = getfield_gc(p46, descr=ddescr) # Array(NODE) p58 = getarrayitem_gc(p56, 0, descr=arraydescr3) # NODE i59 = ooisnull(p38) - guard_false(i59) - fail() + guard_false(i59) [] jump(p58) """ self.find_nodes(ops, 'Virtual(node_vtable, valuedescr=Not)') @@ -1040,8 +1002,7 @@ ops = """ [p1] p2 = getfield_gc(p1, descr=nextdescr) - guard_class(p2, ConstClass(node_vtable)) - fail() + guard_class(p2, ConstClass(node_vtable)) [] jump(p2) """ self.find_bridge(ops, 'Not', 'Not') @@ -1085,20 +1046,20 @@ nextdescr=Virtual(node_vtable, nextdescr=Not)))''') - def test_bridge_to_fail(self): + def test_bridge_to_finish(self): ops = """ [i1] i2 = int_add(i1, 5) - fail(i2) + finish(i2) """ self.find_bridge(ops, 'Not', 'Not') - def test_bridge_virtual_to_fail(self): + def test_bridge_virtual_to_finish(self): ops = """ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i1, descr=valuedescr) - fail(p1) + finish(p1) """ self.find_bridge(ops, 'Not', 'Not') Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py Tue Sep 29 18:18:40 2009 @@ -12,7 +12,7 @@ from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt from pypy.jit.metainterp import resume, executor, compile from pypy.jit.metainterp.resoperation import rop, opname, ResOperation -from pypy.jit.metainterp.test.oparser import pure_parse as parse +from pypy.jit.metainterp.test.oparser import pure_parse class FakeFrame(object): parent_resumedata_snapshot = None @@ -28,12 +28,8 @@ b0 = BoxInt() b1 = BoxInt() opt = optimizeopt.Optimizer(None, None) - op = ResOperation(rop.GUARD_TRUE, [], None) - op.suboperations = [ - ResOperation(rop.FAIL, [], None) - ] - fdescr = ResumeGuardDescr(None, None) - op.suboperations[-1].descr = fdescr + fdescr = ResumeGuardDescr(None) + op = ResOperation(rop.GUARD_TRUE, [], None, descr=fdescr) # setup rd data fi = [("code0", 1, 2), ("code1", 3, -1)] fdescr.rd_virtuals = None @@ -43,10 +39,8 @@ snapshot0 = resume.Snapshot(None, [b0]) fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1]) # - op1 = op - opt.clone_guard(op, op1) - assert op1.optimized is op - assert op1.suboperations[-1].args == [b0, b1] + opt.store_final_boxes_in_guard(op) + assert op.fail_args == [b0, b1] assert fdescr.rd_nums == [0, -1, 1, -1] assert fdescr.rd_virtuals is None assert fdescr.rd_consts == [] @@ -71,8 +65,10 @@ else: remap[op2.result] = op1.result assert op1.descr == op2.descr - if op1.suboperations: - assert equaloplists(op1.suboperations, op2.suboperations, remap) + if op1.fail_args or op2.fail_args: + assert len(op1.fail_args) == len(op2.fail_args) + for x, y in zip(op1.fail_args, op2.fail_args): + assert x == remap.get(y, y) assert len(oplist1) == len(oplist2) print '-'*57 return True @@ -81,55 +77,56 @@ ops = """ [i0] i1 = int_add(i0, 1) - guard_true(i1) - i2 = int_add(i1, 1) - fail(i2) + i2 = int_add(i1, 1) + guard_true(i1) [i2] jump(i1) """ namespace = {} - loop1 = parse(ops, namespace=namespace) - loop2 = parse(ops, namespace=namespace) - loop3 = parse(ops.replace("i2 = int_add", "i2 = int_sub"), - namespace=namespace) + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops, namespace=namespace) + loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), + namespace=namespace) assert equaloplists(loop1.operations, loop2.operations) py.test.raises(AssertionError, "equaloplists(loop1.operations, loop3.operations)") -def test_equaloplists_remap(): - ops1 = """ +def test_equaloplists_fail_args(): + ops = """ [i0] i1 = int_add(i0, 1) - guard_true(i1) - i2 = int_add(i1, 1) - fail(i2) - jump(i1) - """ - ops2 = """ - [i3] - i1 = int_add(i3, 1) - guard_true(i1) - i5 = int_add(i1, 1) - fail(i5) + i2 = int_add(i1, 1) + guard_true(i1) [i2, i1] jump(i1) """ - loop1 = parse(ops1) - loop2 = parse(ops2) + namespace = {} + loop1 = pure_parse(ops, namespace=namespace) + loop2 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), + namespace=namespace) py.test.raises(AssertionError, "equaloplists(loop1.operations, loop2.operations)") - i0 = loop1.inputargs[0] - i3 = loop2.inputargs[0] - i2 = loop1.operations[1].suboperations[0].result - i5 = loop2.operations[1].suboperations[0].result - assert equaloplists(loop1.operations, loop2.operations, - {i3: i0, i5: i2}) # ____________________________________________________________ -class Storage: +class Storage(compile.ResumeGuardDescr): "for tests." + def __init__(self): + pass + def store_final_boxes(self, op, boxes): + op.fail_args = boxes + def __eq__(self, other): + return type(self) is type(other) # xxx obscure class BaseTestOptimizeOpt(BaseTest): + def invent_fail_descr(self, fail_args): + if fail_args is None: + return None + descr = Storage() + descr.rd_frame_info_list = resume.FrameInfo(None, FakeFrame()) + descr.rd_snapshot = resume.Snapshot(None, fail_args) + descr.rd_virtuals = None + return descr + def assert_equal(self, optimized, expected): assert len(optimized.inputargs) == len(expected.inputargs) remap = {} @@ -158,22 +155,7 @@ assert loop.operations[-1].opnum == rop.JUMP loop.operations[-1].jump_target = loop # - Optimizer = optimizeopt.Optimizer - old_get_faildescr = Optimizer._get_faildescr - def _get_faildescr(self, op_fail): - if op_fail.descr is None: - descr = Storage() - descr.rd_frame_info_list = resume.FrameInfo(None, - FakeFrame()) - descr.rd_snapshot = resume.Snapshot(None, op_fail.args) - descr.rd_virtuals = None - return descr - return old_get_faildescr(self, op_fail) - Optimizer._get_faildescr = _get_faildescr - try: - optimize_loop_1(self.cpu, loop) - finally: - Optimizer._get_faildescr = old_get_faildescr.im_func + optimize_loop_1(self.cpu, loop) # expected = self.parse(optops) self.assert_equal(loop, expected) @@ -182,8 +164,7 @@ ops = """ [i] i0 = int_sub(i, 1) - guard_value(i0, 0) - fail(i0) + guard_value(i0, 0) [i0] jump(i) """ self.optimize_loop(ops, 'Not', ops) @@ -193,13 +174,10 @@ [] i0 = int_add(2, 3) i1 = int_is_true(i0) - guard_true(i1) - fail() + guard_true(i1) [] i2 = bool_not(i1) - guard_false(i2) - fail() - guard_value(i0, 5) - fail() + guard_false(i2) [] + guard_value(i0, 5) [] jump() """ expected = """ @@ -247,16 +225,13 @@ def test_remove_guard_class_1(self): ops = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] + guard_class(p0, ConstClass(node_vtable)) [] jump(p0) """ expected = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) @@ -266,8 +241,7 @@ [i0] p0 = new_with_vtable(ConstClass(node_vtable)) escape(p0) - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] jump(i0) """ expected = """ @@ -282,8 +256,7 @@ ops = """ [i0] p0 = same_as(ConstPtr(myptr)) - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] jump(i0) """ expected = """ @@ -296,11 +269,9 @@ ops = """ [] i0 = escape() - guard_value(i0, 0) - fail() + guard_value(i0, 0) [] i1 = int_add(i0, 1) - guard_value(i1, 1) - fail() + guard_value(i1, 1) [] i2 = int_add(i1, 2) escape(i2) jump() @@ -308,8 +279,7 @@ expected = """ [] i0 = escape() - guard_value(i0, 0) - fail() + guard_value(i0, 0) [] escape(3) jump() """ @@ -318,8 +288,7 @@ def test_remove_guard_value_if_constant(self): ops = """ [p1] - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] jump(ConstPtr(myptr)) """ expected = """ @@ -331,20 +300,16 @@ def test_ooisnull_oononnull_1(self): ops = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] i0 = oononnull(p0) - guard_true(i0) - fail() + guard_true(i0) [] i1 = ooisnull(p0) - guard_false(i1) - fail() + guard_false(i1) [] jump(p0) """ expected = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) @@ -353,18 +318,15 @@ ops = """ [i0] i1 = int_is_true(i0) - guard_true(i1) - fail() + guard_true(i1) [] i2 = int_is_true(i0) - guard_true(i2) - fail() + guard_true(i2) [] jump(i0) """ expected = """ [i0] i1 = int_is_true(i0) - guard_true(i1) - fail() + guard_true(i1) [] jump(i0) """ self.optimize_loop(ops, 'Not', expected) @@ -373,36 +335,30 @@ ops = """ [p0] i0 = oononnull(p0) # p0 != NULL - guard_true(i0) - fail() + guard_true(i0) [] i1 = ooisnull(p0) - guard_false(i1) - fail() + guard_false(i1) [] jump(p0) """ expected = """ [p0] i0 = oononnull(p0) - guard_true(i0) - fail() + guard_true(i0) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) ops = """ [p0] i1 = ooisnull(p0) - guard_false(i1) - fail() + guard_false(i1) [] i0 = oononnull(p0) # p0 != NULL - guard_true(i0) - fail() + guard_true(i0) [] jump(p0) """ expected = """ [p0] i1 = ooisnull(p0) - guard_false(i1) - fail() + guard_false(i1) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) @@ -412,19 +368,16 @@ [] p0 = escape() i0 = ooisnull(p0) - guard_true(i0) - fail() + guard_true(i0) [] i1 = oononnull(p0) - guard_false(i1) - fail() + guard_false(i1) [] jump() """ expected = """ [] p0 = escape() i0 = ooisnull(p0) - guard_true(i0) - fail() + guard_true(i0) [] jump() """ self.optimize_loop(ops, '', expected) @@ -432,19 +385,16 @@ [] p0 = escape() i0 = oononnull(p0) - guard_false(i0) - fail() + guard_false(i0) [] i1 = ooisnull(p0) - guard_true(i1) - fail() + guard_true(i1) [] jump() """ expected = """ [] p0 = escape() i0 = oononnull(p0) - guard_false(i0) - fail() + guard_false(i0) [] jump() """ self.optimize_loop(ops, '', expected) @@ -455,19 +405,16 @@ pv = new_with_vtable(ConstClass(node_vtable)) setfield_gc(pv, p0, descr=valuedescr) i0 = oononnull(p0) # p0 != NULL - guard_true(i0) - fail() + guard_true(i0) [] p1 = getfield_gc(pv, descr=valuedescr) i1 = ooisnull(p1) - guard_false(i1) - fail() + guard_false(i1) [] jump(p0) """ expected = """ [p0] i0 = oononnull(p0) - guard_true(i0) - fail() + guard_true(i0) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) @@ -475,26 +422,20 @@ def test_oois_1(self): ops = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] i0 = ooisnot(p0, NULL) - guard_true(i0) - fail() + guard_true(i0) [] i1 = oois(p0, NULL) - guard_false(i1) - fail() + guard_false(i1) [] i2 = ooisnot(NULL, p0) - guard_true(i0) - fail() + guard_true(i0) [] i3 = oois(NULL, p0) - guard_false(i1) - fail() + guard_false(i1) [] jump(p0) """ expected = """ [p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] jump(p0) """ self.optimize_loop(ops, 'Not', expected) @@ -504,23 +445,17 @@ [p0] setfield_gc(p0, 5, descr=valuedescr) # forces p0 != NULL i0 = ooisnot(p0, NULL) - guard_true(i0) - fail() + guard_true(i0) [] i1 = oois(p0, NULL) - guard_false(i1) - fail() + guard_false(i1) [] i2 = ooisnot(NULL, p0) - guard_true(i0) - fail() + guard_true(i0) [] i3 = oois(NULL, p0) - guard_false(i1) - fail() + guard_false(i1) [] i4 = oononnull(p0) - guard_true(i4) - fail() + guard_true(i4) [] i5 = ooisnull(p0) - guard_false(i5) - fail() + guard_false(i5) [] jump(p0) """ expected = """ @@ -534,8 +469,7 @@ ops = """ [] i = int_add(5, 3) - guard_value(i, 8) - fail() + guard_value(i, 8) [] jump() """ expected = """ @@ -548,8 +482,7 @@ ops = """ [] p1 = escape() - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] jump() """ self.optimize_loop(ops, '', ops) @@ -604,16 +537,12 @@ def test_fold_guard_no_exception(self): ops = """ [i] - guard_no_exception() - fail() + guard_no_exception() [] i1 = int_add(i, 3) - guard_no_exception() - fail() + guard_no_exception() [] i2 = call(i1) - guard_no_exception() - fail(i1, i2) - guard_no_exception() - fail() + guard_no_exception() [i1, i2] + guard_no_exception() [] i3 = call(i2) jump(i1) # the exception is considered lost when we loop back """ @@ -621,8 +550,7 @@ [i] i1 = int_add(i, 3) i2 = call(i1) - guard_no_exception() - fail(i1, i2) + guard_no_exception() [i1, i2] i3 = call(i2) jump(i1) """ @@ -667,41 +595,29 @@ ops = """ [p0, p1, p2] i1 = oononnull(p0) - guard_true(i1) - fail() + guard_true(i1) [] i2 = ooisnull(p0) - guard_false(i2) - fail() + guard_false(i2) [] i3 = ooisnot(p0, NULL) - guard_true(i3) - fail() + guard_true(i3) [] i4 = oois(p0, NULL) - guard_false(i4) - fail() + guard_false(i4) [] i5 = ooisnot(NULL, p0) - guard_true(i5) - fail() + guard_true(i5) [] i6 = oois(NULL, p0) - guard_false(i6) - fail() + guard_false(i6) [] i7 = ooisnot(p0, p1) - guard_true(i7) - fail() + guard_true(i7) [] i8 = oois(p0, p1) - guard_false(i8) - fail() + guard_false(i8) [] i9 = ooisnot(p0, p2) - guard_true(i9) - fail() + guard_true(i9) [] i10 = oois(p0, p2) - guard_false(i10) - fail() + guard_false(i10) [] i11 = ooisnot(p2, p1) - guard_true(i11) - fail() + guard_true(i11) [] i12 = oois(p2, p1) - guard_false(i12) - fail() + guard_false(i12) [] jump(p0, p1, p2) """ expected = """ @@ -720,26 +636,19 @@ expected2 = """ [p0, p1, p2] i1 = oononnull(p0) - guard_true(i1) - fail() + guard_true(i1) [] i7 = ooisnot(p0, p1) - guard_true(i7) - fail() + guard_true(i7) [] i8 = oois(p0, p1) - guard_false(i8) - fail() + guard_false(i8) [] i9 = ooisnot(p0, p2) - guard_true(i9) - fail() + guard_true(i9) [] i10 = oois(p0, p2) - guard_false(i10) - fail() + guard_false(i10) [] i11 = ooisnot(p2, p1) - guard_true(i11) - fail() + guard_true(i11) [] i12 = oois(p2, p1) - guard_false(i12) - fail() + guard_false(i12) [] jump(p0, p1, p2) """ self.optimize_loop(ops, 'Not, Not, Not', expected2) @@ -748,16 +657,14 @@ ops = """ [p0] i0 = getfield_gc(p0, descr=valuedescr) - guard_value(i0, 0) - fail() + guard_value(i0, 0) [] p1 = new_with_vtable(ConstClass(node_vtable)) # the field 'value' has its default value of 0 jump(p1) """ expected = """ [i] - guard_value(i, 0) - fail() + guard_value(i, 0) [] jump(0) """ # the 'expected' is sub-optimal, but it should be done by another later @@ -784,8 +691,7 @@ def test_virtual_4(self): ops = """ [i0, p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] i1 = getfield_gc(p0, descr=valuedescr) i2 = int_sub(i1, 1) i3 = int_add(i0, i1) @@ -805,8 +711,7 @@ def test_virtual_5(self): ops = """ [i0, p0] - guard_class(p0, ConstClass(node_vtable)) - fail() + guard_class(p0, ConstClass(node_vtable)) [] i1 = getfield_gc(p0, descr=valuedescr) i2 = int_sub(i1, 1) i3 = int_add(i0, i1) @@ -959,8 +864,7 @@ [i1] p1 = new_array(3, descr=arraydescr) i3 = arraylen_gc(p1, descr=arraydescr) - guard_value(i3, 3) - fail() + guard_value(i3, 3) [] setarrayitem_gc(p1, 1, i1, descr=arraydescr) setarrayitem_gc(p1, 0, 25, descr=arraydescr) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) @@ -977,7 +881,7 @@ [i1, p0] setarrayitem_gc(p0, 0, i1, descr=arraydescr) i2 = ooisnull(p0) - guard_false(i2) + guard_false(i2) [] p1 = new_array(i1, descr=arraydescr) jump(i1, p1) """ @@ -995,8 +899,7 @@ i1 = getarrayitem_gc(p1, 0, descr=arraydescr) i2 = getarrayitem_gc(p1, 1, descr=arraydescr) i3 = int_sub(i1, i2) - guard_value(i3, 15) - fail() + guard_value(i3, 15) [] p2 = new_array(2, descr=arraydescr) setarrayitem_gc(p2, 1, i0, descr=arraydescr) setarrayitem_gc(p2, 0, 20, descr=arraydescr) @@ -1005,8 +908,7 @@ expected = """ [i0, i1, i2] i3 = int_sub(i1, i2) - guard_value(i3, 15) - fail() + guard_value(i3, 15) [] jump(i0, 20, i0) """ self.optimize_loop(ops, 'Not, VArray(arraydescr, Not, Not)', expected) @@ -1161,8 +1063,7 @@ [p1] i1 = getfield_gc(p1, descr=valuedescr) i2 = int_add_ovf(i1, 14) - guard_no_overflow() - fail() + guard_no_overflow() [] i3 = getfield_gc(p1, descr=valuedescr) escape(i2) escape(i3) @@ -1172,8 +1073,7 @@ [p1] i1 = getfield_gc(p1, descr=valuedescr) i2 = int_add_ovf(i1, 14) - guard_no_overflow() - fail() + guard_no_overflow() [] escape(i2) escape(i1) jump(p1) @@ -1221,8 +1121,7 @@ def test_duplicate_getfield_guard_value_const(self): ops = """ [p1] - guard_value(p1, ConstPtr(myptr)) - fail() + guard_value(p1, ConstPtr(myptr)) [] i1 = getfield_gc(p1, descr=valuedescr) i2 = getfield_gc(ConstPtr(myptr), descr=valuedescr) escape(i1) @@ -1266,8 +1165,7 @@ [i0, p1] p4 = getfield_gc(p1, descr=nextdescr) i2 = ooisnull(p4) - guard_false(i2) - fail() + guard_false(i2) [] escape(p4) # p2 = new_with_vtable(ConstClass(node_vtable)) @@ -1278,8 +1176,7 @@ expected = """ [i0, p4] i2 = ooisnull(p4) - guard_false(i2) - fail() + guard_false(i2) [] escape(p4) # p3 = escape() @@ -1293,8 +1190,7 @@ [i0, p1] p4 = getarrayitem_gc(p1, 0, descr=arraydescr2) i2 = ooisnull(p4) - guard_false(i2) - fail() + guard_false(i2) [] escape(p4) # p2 = new_array(1, descr=arraydescr2) @@ -1305,8 +1201,7 @@ expected = """ [i0, p4] i2 = ooisnull(p4) - guard_false(i2) - fail() + guard_false(i2) [] escape(p4) # p3 = escape() @@ -1319,8 +1214,7 @@ ops = """ [p1] i1 = ooisnull(p1) - guard_true(i1) - fail() + guard_true(i1) [] # p2 = new_with_vtable(ConstClass(node_vtable)) jump(p2) @@ -1332,8 +1226,7 @@ py.test.skip("this would fail if we had Fixed again in the specnodes") ops = """ [p1] - guard_class(p1, ConstClass(node_vtable2)) - fail() + guard_class(p1, ConstClass(node_vtable2)) [] # p2 = new_with_vtable(ConstClass(node_vtable)) escape(p2) # prevent it from staying Virtual @@ -1347,8 +1240,7 @@ [p1] p2 = getfield_gc(p1, descr=nextdescr) i1 = ooisnull(p2) - guard_true(i1) - fail() + guard_true(i1) [] # p3 = new_with_vtable(ConstClass(node_vtable)) p4 = new_with_vtable(ConstClass(node_vtable)) @@ -1364,15 +1256,14 @@ def make_fail_descr(self): class FailDescr(compile.ResumeGuardDescr): args_seen = [] - def _oparser_uses_descr(self, oparse, args): + def _oparser_uses_descr_of_guard(self, oparse, fail_args): # typically called twice, before and after optimization if len(self.args_seen) == 0: fdescr.rd_frame_info_list = resume.FrameInfo(None, FakeFrame()) - fdescr.rd_snapshot = resume.Snapshot(None, args) + fdescr.rd_snapshot = resume.Snapshot(None, fail_args) fdescr.virtuals = None - self.args_seen.append((args, oparse)) - + self.args_seen.append((fail_args, oparse)) # fdescr = instantiate(FailDescr) self.fdescr = fdescr @@ -1475,14 +1366,12 @@ i4 = getfield_gc(p1, descr=valuedescr) # i2 = int_add(10, 5) - guard_true(i1) - fail(i2, i4, descr=fdescr) + guard_true(i1, descr=fdescr) [i2, i4] jump(i1, i4) """ expected = """ [i1, i3] - guard_true(i1) - fail(i3, descr=fdescr) + guard_true(i1, descr=fdescr) [i3] jump(1, i3) """ self.optimize_loop(ops, 'Not, Not', expected) @@ -1495,14 +1384,12 @@ p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i2, descr=valuedescr) setfield_gc(p1, p1, descr=nextdescr) - guard_true(i1) - fail(p1, descr=fdescr) + guard_true(i1, descr=fdescr) [p1] jump(i1, i2) """ expected = """ [i1, i2] - guard_true(i1) - fail(i2, descr=fdescr) + guard_true(i1, descr=fdescr) [i2] jump(1, i2) """ self.optimize_loop(ops, 'Not, Not', expected) @@ -1520,14 +1407,12 @@ setfield_gc(p1, p2, descr=nextdescr) setfield_gc(p2, i2, descr=valuedescr) setfield_gc(p2, p3, descr=nextdescr) - guard_true(i1) - fail(p1, i3, descr=fdescr) + guard_true(i1, descr=fdescr) [p1, i3] jump(i2, i1, i3, p3) """ expected = """ [i1, i2, i3, p3] - guard_true(i1) - fail(i3, i2, p3, descr=fdescr) + guard_true(i1, descr=fdescr) [i3, i2, p3] jump(i2, 1, i3, p3) """ self.optimize_loop(ops, 'Not, Not, Not, Not', expected) @@ -1550,14 +1435,12 @@ setfield_gc(p1, i2, descr=valuedescr) setfield_gc(p1, p2, descr=nextdescr) setfield_gc(p2, i2, descr=valuedescr) - guard_true(i1) - fail(i4, %s, i3, descr=fdescr) + guard_true(i1, descr=fdescr) [i4, %s, i3] jump(i1, i2, i3) """ expected = """ [i1, i2, i3] - guard_true(i1) - fail(i3, i2, descr=fdescr) + guard_true(i1, descr=fdescr) [i3, i2] jump(1, i2, i3) """ self.optimize_loop(ops % arg, 'Not, Not, Not', expected) @@ -1576,14 +1459,12 @@ setfield_gc(p1, p2, descr=nextdescr) setfield_gc(p2, i2, descr=valuedescr) setfield_gc(p2, p1, descr=nextdescr) # a cycle - guard_true(i1) - fail(p1, i3, p2, i4, descr=fdescr) + guard_true(i1, descr=fdescr) [p1, i3, p2, i4] jump(i2, i1, i3, i4) """ expected = """ [i1, i2, i3, i4] - guard_true(i1) - fail(i3, i4, i2, descr=fdescr) + guard_true(i1, descr=fdescr) [i3, i4, i2] jump(i2, 1, i3, i4) """ self.optimize_loop(ops, 'Not, Not, Not, Not', expected) @@ -1596,16 +1477,14 @@ self.make_fail_descr() ops = """ [p0, i0, i1] - guard_true(i0) - fail(p0, descr=fdescr) + guard_true(i0, descr=fdescr) [p0] p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i1, descr=valuedescr) jump(p1, i1, i1) """ expected = """ [i1b, i0, i1] - guard_true(i0) - fail(i1b, descr=fdescr) + guard_true(i0, descr=fdescr) [i1b] jump(i1, i1, i1) """ self.optimize_loop(ops, '''Virtual(node_vtable, valuedescr=Not), @@ -1621,15 +1500,13 @@ p1 = new_array(3, descr=arraydescr) setarrayitem_gc(p1, 1, i1, descr=arraydescr) setarrayitem_gc(p1, 0, 25, descr=arraydescr) - guard_true(i1) - fail(p1, descr=fdescr) + guard_true(i1, descr=fdescr) [p1] i2 = getarrayitem_gc(p1, 1, descr=arraydescr) jump(i2) """ expected = """ [i1] - guard_true(i1) - fail(i1, descr=fdescr) + guard_true(i1, descr=fdescr) [i1] jump(1) """ self.optimize_loop(ops, 'Not', expected) @@ -1644,16 +1521,14 @@ p2 = new(descr=ssize) setfield_gc(p2, i1, descr=adescr) setfield_gc(p2, p1, descr=bdescr) - guard_true(i1) - fail(p2, descr=fdescr) + guard_true(i1, descr=fdescr) [p2] i3 = getfield_gc(p2, descr=adescr) p3 = getfield_gc(p2, descr=bdescr) jump(i3, p3) """ expected = """ [i1, p1] - guard_true(i1) - fail(i1, p1, descr=fdescr) + guard_true(i1, descr=fdescr) [i1, p1] jump(1, p1) """ self.optimize_loop(ops, 'Not, Not', expected) @@ -1671,8 +1546,7 @@ setfield_gc(p5s, i2, descr=adescr) setfield_gc(p5s, p7v, descr=bdescr) setarrayitem_gc(p1a, 1, p5s, descr=arraydescr2) - guard_true(i1) - fail(p1a, descr=fdescr) + guard_true(i1, descr=fdescr) [p1a] p2s = new(descr=ssize) p3v = new_with_vtable(ConstClass(node_vtable)) p4a = new_array(2, descr=arraydescr2) @@ -1684,8 +1558,7 @@ """ expected = """ [i1, ia, iv, pnull, i2] - guard_true(i1) - fail(ia, iv, i2, descr=fdescr) + guard_true(i1, descr=fdescr) [ia, iv, i2] jump(1, 1, i2, NULL, i2) """ self.optimize_loop(ops, ''' Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Tue Sep 29 18:18:40 2009 @@ -344,8 +344,8 @@ for loop in get_stats().loops: assert len(loop.operations) <= length + 5 # because we only check once per metainterp bytecode for op in loop.operations: - if op.is_guard(): - assert len(op.suboperations) <= length + 5 + if op.is_guard() and hasattr(op.descr, '_debug_suboperations'): + assert len(op.descr._debug_suboperations) <= length + 5 def test_inline_trace_limit(self): myjitdriver = JitDriver(greens=[], reds=['n']) Modified: pypy/trunk/pypy/jit/metainterp/typesystem.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/typesystem.py (original) +++ pypy/trunk/pypy/jit/metainterp/typesystem.py Tue Sep 29 18:18:40 2009 @@ -100,10 +100,6 @@ def cast_to_baseclass(self, value): return lltype.cast_opaque_ptr(lltype.Ptr(rclass.OBJECT), value) - def clean_box(self, box): - if isinstance(box, history.BoxPtr): - box.value = lltype.nullptr(llmemory.GCREF.TO) - def getlength(self, array): return len(array) @@ -201,10 +197,6 @@ def cast_to_baseclass(self, value): return ootype.cast_from_object(ootype.ROOT, value) - def clean_box(self, box): - if isinstance(box, history.BoxObj): - box.value = ootype.NULL - def getlength(self, array): return array.ll_length() From arigo at codespeak.net Tue Sep 29 18:19:02 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 18:19:02 +0200 (CEST) Subject: [pypy-svn] r67993 - pypy/branch/remove-fail Message-ID: <20090929161902.B482316801E@codespeak.net> Author: arigo Date: Tue Sep 29 18:19:02 2009 New Revision: 67993 Removed: pypy/branch/remove-fail/ Log: Remove merged branch. From arigo at codespeak.net Tue Sep 29 18:48:20 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 18:48:20 +0200 (CEST) Subject: [pypy-svn] r67994 - pypy/trunk/pypy/jit/backend/test Message-ID: <20090929164820.DFDB816800D@codespeak.net> Author: arigo Date: Tue Sep 29 18:48:20 2009 New Revision: 67994 Modified: pypy/trunk/pypy/jit/backend/test/test_random.py Log: Remove the "fix me" code section completely, with a comment for why I think that it is actually useless complexity. Modified: pypy/trunk/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/test_random.py (original) +++ pypy/trunk/pypy/jit/backend/test/test_random.py Tue Sep 29 18:48:20 2009 @@ -509,14 +509,26 @@ op = self.should_fail_by if not op.fail_args: return False + # generate the branch: a sequence of operations that ends in a FINISH subloop = DummyLoop([]) if guard_op.is_guard_exception(): subloop.operations.append(exc_handling(guard_op)) bridge_builder = self.builder.fork(self.builder.cpu, subloop, op.fail_args[:]) self.generate_ops(bridge_builder, r, subloop, op.fail_args[:]) - dont_compile = False - if r.random() < 0.1: + # note that 'self.guard_op' now points to the guard that will fail in + # this new bridge, while 'guard_op' still points to the guard that + # has just failed. + + if r.random() < 0.1 and self.guard_op is None: + # Occasionally, instead of ending in a FINISH, we end in a jump + # to another loop. We don't do it, however, if the new bridge's + # execution will hit 'self.guard_op', but only if it executes + # to the FINISH normally. (There is no point to the extra + # complexity, as we might get the same effect by two calls + # to build_bridge().) + + # First make up the other loop... subset = bridge_builder.subset_of_intvars(r) subset = [i for i in subset if i in fail_args] if len(subset) == 0: @@ -526,37 +538,23 @@ r, args) executable_token = self.cpu.compile_loop(rl.loop.inputargs, rl.loop.operations) + # done jump_op = ResOperation(rop.JUMP, subset, None) jump_op.jump_target = LoopToken() jump_op.jump_target.executable_token = executable_token self.should_fail_by = rl.should_fail_by self.expected = rl.expected assert len(rl.loop.inputargs) == len(args) - if self.guard_op is None: - subloop.operations[-1] = jump_op - else: - print "fix me again" - return False - args = self.guard_op.suboperations[-1].args + fail_args - self.guard_op.suboperations[-1].args = args - self.builder.cpu.compile_bridge(fail_descr, fail_args, - guard_op.suboperations) - fail_descr_2 = self.guard_op.suboperations[0].descr - ops = [] - if self.guard_op.is_guard_exception(): - # exception clearing - ops = [exc_handling(self.guard_op)] - ops.append(jump_op) - self.builder.cpu.compile_bridge(fail_descr_2, args, ops) - dont_compile = True + # The new bridge's execution will end normally at its FINISH. + # Just replace the FINISH with the JUMP to the new loop. + subloop.operations[-1] = jump_op self.guard_op = rl.guard_op self.prebuilt_ptr_consts += rl.prebuilt_ptr_consts self.dont_generate_more = True if r.random() < .05: return False - if not dont_compile: - self.builder.cpu.compile_bridge(fail_descr, fail_args, - subloop.operations) + self.builder.cpu.compile_bridge(fail_descr, fail_args, + subloop.operations) return True def check_random_function(cpu, BuilderClass, r, num=None, max=None): From arigo at codespeak.net Tue Sep 29 19:06:01 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 19:06:01 +0200 (CEST) Subject: [pypy-svn] r67995 - pypy/branch/floats-via-sse2/pypy/jit/backend/x86 Message-ID: <20090929170601.F1D47168014@codespeak.net> Author: arigo Date: Tue Sep 29 19:06:01 2009 New Revision: 67995 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Log: Just a few fixes and comments. Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Tue Sep 29 19:06:01 2009 @@ -65,14 +65,15 @@ def __init__(self, *args, **kwds): RegisterManager.__init__(self, *args, **kwds) self.constant_arrays = [self.new_const_array()] - self.constant_arrays_counter = 0 + self.constant_array_counter = 0 def convert_to_imm(self, c): - if self.constant_arrays_counter >= BASE_CONSTANT_SIZE: - self.constant_arrays.append(self.new_const_array) - self.constant_arrays_counter = 0 - res = self.constant_arrays_counter - self.constant_arrays_counter += 1 + if self.constant_array_counter >= BASE_CONSTANT_SIZE: + xxx # test me + self.constant_arrays.append(self.new_const_array()) + self.constant_array_counter = 0 + res = self.constant_array_counter + self.constant_array_counter += 1 arr = self.constant_arrays[-1] arr[res] = c.getfloat() return heap64(rffi.cast(lltype.Signed, arr) + res * WORD * 2) @@ -116,6 +117,7 @@ cpu.gc_ll_descr.rewrite_assembler(cpu, operations) # compute longevity of variables longevity = self._compute_vars_longevity(inputargs, operations) + self.longevity = longevity self.rm = X86RegisterManager(longevity, stack_manager = self.sm, assembler = self.assembler) @@ -148,8 +150,10 @@ arg = inputargs[i] assert not isinstance(arg, Const) reg = None - if arg not in self.loop_consts and self.rm.longevity[arg][1] > -1: + if arg not in self.loop_consts and self.longevity[arg][1] > -1: if arg.type == FLOAT: + # xxx is it really a good idea? at the first CALL they + # will all be flushed anyway reg = self.xrm.try_allocate_reg(arg) else: reg = self.rm.try_allocate_reg(arg) @@ -186,7 +190,8 @@ for i in range(len(locs)): v = args[i] loc = locs[i] - if isinstance(loc, REG) and self.rm.longevity[v][1] > -1: + if isinstance(loc, REG) and self.longevity[v][1] > -1: + # XXX xmm regs self.rm.reg_bindings[v] = loc used[loc] = None else: @@ -244,7 +249,7 @@ return False if operations[i + 1].args[0] is not op.result: return False - if (self.rm.longevity[op.result][1] > i + 1 or + if (self.longevity[op.result][1] > i + 1 or op.result in operations[i + 1].suboperations[0].args): return False return True @@ -255,7 +260,7 @@ while i < len(operations): op = operations[i] self.rm.position = i - if op.has_no_side_effect() and op.result not in self.rm.longevity: + if op.has_no_side_effect() and op.result not in self.longevity: i += 1 self.rm.possibly_free_vars(op.args) continue @@ -328,7 +333,7 @@ loc = self.rm.make_sure_var_in_reg(op.args[0]) box = TempBox() loc1 = self.rm.force_allocate_reg(box, op.args) - if op.result in self.rm.longevity: + if op.result in self.longevity: # this means, is it ever used resloc = self.rm.force_allocate_reg(op.result, op.args + [box]) else: From arigo at codespeak.net Tue Sep 29 19:23:12 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 19:23:12 +0200 (CEST) Subject: [pypy-svn] r67996 - in pypy/branch/floats-via-sse2/pypy/jit/backend: llsupport x86 Message-ID: <20090929172312.B550B168007@codespeak.net> Author: arigo Date: Tue Sep 29 19:23:11 2009 New Revision: 67996 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Log: More fixes and comments and bugs showing up because of extra asserts. I suppose I will stop there :-) Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py Tue Sep 29 19:23:11 2009 @@ -39,6 +39,7 @@ class RegisterManager(object): """ Class that keeps track of register allocations """ + box_types = None # or a list of acceptable types all_regs = [] no_lower_byte_regs = [] save_around_call_regs = [] @@ -58,11 +59,16 @@ def next_instruction(self, incr=1): self.position += incr + def _check_type(self, v): + if not we_are_translated() and self.box_types is not None: + assert isinstance(v, TempBox) or v.type in self.box_types + def possibly_free_var(self, v): """ If v is stored in a register and v is not used beyond the current position, then free it. Must be called at some point for all variables that might be in registers. """ + self._check_type(v) if isinstance(v, Const) or v not in self.reg_bindings: return if v not in self.longevity or self.longevity[v][1] <= self.position: @@ -97,6 +103,7 @@ returns allocated register or None, if not possible. """ + self._check_type(v) assert not isinstance(v, Const) if selected_reg is not None: res = self.reg_bindings.get(v, None) @@ -173,6 +180,7 @@ Will not spill a variable from 'forbidden_vars'. """ + self._check_type(v) if isinstance(v, TempBox): self.longevity[v] = (self.position, self.position) loc = self.try_allocate_reg(v, selected_reg, @@ -190,6 +198,7 @@ def loc(self, box): """ Return the location of 'box'. """ + self._check_type(box) if isinstance(box, Const): return self.convert_to_imm(box) try: @@ -204,6 +213,7 @@ a register. See 'force_allocate_reg' for the meaning of 'selected_reg' and 'forbidden_vars'. """ + self._check_type(v) assert isinstance(v, Const) if selected_reg or not imm_fine: # this means we cannot have it in IMM, eh @@ -226,6 +236,7 @@ register. Return the register. See 'return_constant' and 'force_allocate_reg' for the meaning of the optional arguments. """ + self._check_type(v) if isinstance(v, Const): return self.return_constant(v, forbidden_vars, selected_reg, imm_fine) @@ -257,6 +268,8 @@ The variable v is copied away if it's further used. The meaning of 'forbidden_vars' is the same as in 'force_allocate_reg'. """ + self._check_type(result_v) + self._check_type(v) if isinstance(v, Const): loc = self.make_sure_var_in_reg(v, forbidden_vars, imm_fine=False) @@ -312,6 +325,7 @@ which is in variable v. """ if v is not None: + self._check_type(v) r = self.call_result_location(v) self.reg_bindings[v] = r self.free_regs = [fr for fr in self.free_regs if fr is not r] Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Tue Sep 29 19:23:11 2009 @@ -28,6 +28,7 @@ class X86RegisterManager(RegisterManager): + box_types = [INT, REF] all_regs = [eax, ecx, edx, ebx, esi, edi] no_lower_byte_regs = [esi, edi] save_around_call_regs = [eax, edx, ecx] @@ -53,6 +54,7 @@ class X86XMMRegisterManager(RegisterManager): + box_types = [FLOAT] all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] # we never need lower byte I hope save_around_call_regs = all_regs @@ -201,6 +203,7 @@ if reg not in used: self.rm.free_regs.append(reg) self.rm._check_invariants() + self.xrm._check_invariants() def Perform(self, op, arglocs, result_loc): if not we_are_translated(): @@ -260,6 +263,7 @@ while i < len(operations): op = operations[i] self.rm.position = i + # XXX ^^^ and also self.xrm.position = i.... :-( if op.has_no_side_effect() and op.result not in self.longevity: i += 1 self.rm.possibly_free_vars(op.args) @@ -269,10 +273,13 @@ i += 1 else: oplist[op.opnum](self, op, None) - self.rm.possibly_free_var(op.result) + if op.result is not None: + self.rm.possibly_free_var(op.result) self.rm._check_invariants() + self.xrm._check_invariants() i += 1 assert not self.rm.reg_bindings + assert not self.xrm.reg_bindings def _compute_vars_longevity(self, inputargs, operations): # compute a dictionary that maps variables to index in From arigo at codespeak.net Tue Sep 29 21:06:02 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 21:06:02 +0200 (CEST) Subject: [pypy-svn] r67997 - in pypy/trunk/pypy/jit/backend: . x86/test Message-ID: <20090929190602.97B8A168007@codespeak.net> Author: arigo Date: Tue Sep 29 21:05:58 2009 New Revision: 67997 Added: pypy/trunk/pypy/jit/backend/x86/test/conftest.py (contents, props changed) Modified: pypy/trunk/pypy/jit/backend/detect_cpu.py Log: - skip x86 tests on non-x86 platforms. - print the cpu name found by detect_cpu when running it. Modified: pypy/trunk/pypy/jit/backend/detect_cpu.py ============================================================================== --- pypy/trunk/pypy/jit/backend/detect_cpu.py (original) +++ pypy/trunk/pypy/jit/backend/detect_cpu.py Tue Sep 29 21:05:58 2009 @@ -52,3 +52,6 @@ else: raise ProcessorAutodetectError, "unsupported cpu '%s'" % backend_name return CPU + +if __name__ == '__main__': + print autodetect() Added: pypy/trunk/pypy/jit/backend/x86/test/conftest.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/jit/backend/x86/test/conftest.py Tue Sep 29 21:05:58 2009 @@ -0,0 +1,9 @@ +import py +from pypy.jit.backend import detect_cpu + +class Directory(py.test.collect.Directory): + def collect(self): + cpu = detect_cpu.autodetect() + if cpu != 'i386': + py.test.skip("x86 directory skipped: cpu is %r" % (cpu,)) + return super(Directory, self).collect() From arigo at codespeak.net Tue Sep 29 21:09:03 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 21:09:03 +0200 (CEST) Subject: [pypy-svn] r67998 - in pypy/trunk/pypy/jit/backend: llsupport/test x86/test Message-ID: <20090929190903.ADA87168007@codespeak.net> Author: arigo Date: Tue Sep 29 21:08:58 2009 New Revision: 67998 Added: pypy/trunk/pypy/jit/backend/llsupport/test/test_symbolic.py - copied unchanged from r67990, pypy/trunk/pypy/jit/backend/x86/test/test_symbolic.py Removed: pypy/trunk/pypy/jit/backend/x86/test/test_symbolic.py Log: Move this test file together with the file it tests. From arigo at codespeak.net Tue Sep 29 21:32:53 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 21:32:53 +0200 (CEST) Subject: [pypy-svn] r67999 - pypy/trunk/pypy/rpython/lltypesystem/test Message-ID: <20090929193253.B5962168007@codespeak.net> Author: arigo Date: Tue Sep 29 21:32:51 2009 New Revision: 67999 Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Log: Fixes for 64 bit. Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Tue Sep 29 21:32:51 2009 @@ -751,7 +751,7 @@ #include - static int x = 3; + static long x = 3; char **z = NULL; #endif /* _SOME_H */ @@ -808,21 +808,21 @@ def test_qsort_callback(self): TP = rffi.CArrayPtr(rffi.INT) a = lltype.malloc(TP.TO, 5, flavor='raw') - a[0] = 5 - a[1] = 3 - a[2] = 2 - a[3] = 1 - a[4] = 4 + a[0] = rffi.r_int(5) + a[1] = rffi.r_int(3) + a[2] = rffi.r_int(2) + a[3] = rffi.r_int(1) + a[4] = rffi.r_int(4) def compare(a, b): if a[0] > b[0]: - return 1 + return rffi.r_int(1) else: - return -1 + return rffi.r_int(-1) CALLBACK = rffi.CCallback([rffi.VOIDP, rffi.VOIDP], rffi.INT) - qsort = rffi.llexternal('qsort', [rffi.VOIDP, rffi.INT, - rffi.INT, CALLBACK], lltype.Void) + qsort = rffi.llexternal('qsort', [rffi.VOIDP, rffi.SIZE_T, + rffi.SIZE_T, CALLBACK], lltype.Void) qsort(rffi.cast(rffi.VOIDP, a), 5, rffi.sizeof(rffi.INT), compare) for i in range(5): @@ -929,7 +929,7 @@ return x.x c_source = py.code.Source(""" - int eating_callback(void *arg, int(*call)(int)) + long eating_callback(void *arg, long(*call)(void*)) { return call(arg); } @@ -938,8 +938,8 @@ eci = ExternalCompilationInfo(separate_module_sources=[c_source], export_symbols=['eating_callback']) - args = [T, rffi.CCallback([T], rffi.INT)] - eating_callback = rffi.llexternal('eating_callback', args, rffi.INT, + args = [T, rffi.CCallback([T], rffi.LONG)] + eating_callback = rffi.llexternal('eating_callback', args, rffi.LONG, compilation_info=eci) res = eating_callback(X(), callback) From arigo at codespeak.net Tue Sep 29 21:35:21 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 21:35:21 +0200 (CEST) Subject: [pypy-svn] r68000 - in pypy/trunk/pypy/rpython/lltypesystem: . test Message-ID: <20090929193521.E509A168007@codespeak.net> Author: arigo Date: Tue Sep 29 21:35:21 2009 New Revision: 68000 Modified: pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Log: Fix the length field of C arrays. Modified: pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/ll2ctypes.py Tue Sep 29 21:35:21 2009 @@ -115,7 +115,7 @@ class CArray(ctypes.Structure): if not A._hints.get('nolength'): - _fields_ = [('length', ctypes.c_int), + _fields_ = [('length', ctypes.c_long), ('items', max_n * ctypes_item)] else: _fields_ = [('items', max_n * ctypes_item)] Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Tue Sep 29 21:35:21 2009 @@ -108,6 +108,7 @@ ac = lltype2ctypes(a, normalize=False) assert isinstance(ac.contents, ctypes.Structure) assert ac.contents.length == 10 + assert ac.contents._fields_[0] == ('length', ctypes.c_long) assert ac.contents.items[1] == 101 ac.contents.items[2] = 456 assert a[2] == 456 From arigo at codespeak.net Tue Sep 29 21:39:36 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 21:39:36 +0200 (CEST) Subject: [pypy-svn] r68001 - pypy/trunk/pypy/rpython/lltypesystem/test Message-ID: <20090929193936.34AAD168008@codespeak.net> Author: arigo Date: Tue Sep 29 21:39:35 2009 New Revision: 68001 Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_rffi.py Log: Fix the test for 64 bits. Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_rffi.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/test/test_rffi.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/test/test_rffi.py Tue Sep 29 21:39:35 2009 @@ -349,7 +349,7 @@ h_source = py.code.Source(""" #ifndef _CALLBACK_H #define _CALLBACK_H - extern int eating_callback(int arg, int(*call)(int)); + extern long eating_callback(long arg, long(*call)(long)); #endif /* _CALLBACK_H */ """) @@ -357,9 +357,9 @@ h_include.write(h_source) c_source = py.code.Source(""" - int eating_callback(int arg, int(*call)(int)) + long eating_callback(long arg, long(*call)(long)) { - int res = call(arg); + long res = call(arg); if (res == -1) return -1; return res; @@ -371,8 +371,8 @@ separate_module_sources=[c_source], export_symbols=['eating_callback']) - args = [INT, CCallback([INT], INT)] - eating_callback = llexternal('eating_callback', args, INT, + args = [LONG, CCallback([LONG], LONG)] + eating_callback = llexternal('eating_callback', args, LONG, compilation_info=eci) return eating_callback From arigo at codespeak.net Tue Sep 29 21:54:29 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 21:54:29 +0200 (CEST) Subject: [pypy-svn] r68002 - pypy/trunk/pypy/rpython/test Message-ID: <20090929195429.2F3A1168007@codespeak.net> Author: arigo Date: Tue Sep 29 21:54:28 2009 New Revision: 68002 Modified: pypy/trunk/pypy/rpython/test/test_rint.py Log: Tentatively whack for 64 bit machines. Modified: pypy/trunk/pypy/rpython/test/test_rint.py ============================================================================== --- pypy/trunk/pypy/rpython/test/test_rint.py (original) +++ pypy/trunk/pypy/rpython/test/test_rint.py Tue Sep 29 21:54:28 2009 @@ -6,6 +6,12 @@ from pypy.rlib.rarithmetic import ovfcheck from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin +if r_longlong is not r_int: + int64 = r_longlong +else: + int64 = int + + class TestSnippet(object): def _test(self, func, types): @@ -140,7 +146,7 @@ return [None] if isinstance(x, str): return x - if isinstance(x, r_longlong): + if isinstance(x, int64): return int(x) return "XXX" wrap._annspecialcase_ = 'specialize:argtype(0)' @@ -148,7 +154,7 @@ space = FakeSpace() def wrap(x): return space.wrap(x) - res = self.interpret(wrap, [r_longlong(0)]) + res = self.interpret(wrap, [int64(0)]) assert res == 0 def test_truediv(self): @@ -162,25 +168,25 @@ def test_float_conversion(self): def f(ii): return float(ii) - res = self.interpret(f, [r_longlong(100000000)]) + res = self.interpret(f, [int64(100000000)]) assert type(res) is float assert res == 100000000. - res = self.interpret(f, [r_longlong(1234567890123456789)]) + res = self.interpret(f, [int64(1234567890123456789)]) assert type(res) is float assert self.float_eq(res, 1.2345678901234568e+18) def test_float_conversion_implicit(self): def f(ii): return 1.0 + ii - res = self.interpret(f, [r_longlong(100000000)]) + res = self.interpret(f, [int64(100000000)]) assert type(res) is float assert res == 100000001. - res = self.interpret(f, [r_longlong(1234567890123456789)]) + res = self.interpret(f, [int64(1234567890123456789)]) assert type(res) is float assert self.float_eq(res, 1.2345678901234568e+18) def test_rarithmetic(self): - inttypes = [int, r_uint, r_longlong, r_ulonglong] + inttypes = [int, r_uint, int64, r_ulonglong] for inttype in inttypes: c = inttype() def f(): @@ -215,16 +221,16 @@ res = self.interpret(f, [int(-1<<(r_int.BITS-1))]) assert res == 0 - res = self.interpret(f, [r_longlong(-1)]) + res = self.interpret(f, [int64(-1)]) assert res == 1 - res = self.interpret(f, [r_longlong(-1)<<(r_longlong.BITS-1)]) + res = self.interpret(f, [int64(-1)<<(r_longlong.BITS-1)]) assert res == 0 div_mod_iteration_count = 1000 def test_div_mod(self): import random - for inttype in (int, r_longlong): + for inttype in (int, int64): def d(x, y): return x/y @@ -287,7 +293,7 @@ except ZeroDivisionError: return 84 - for inttype in (int, r_longlong): + for inttype in (int, int64): args = [( 5, 2), (-5, 2), ( 5,-2), (-5,-2), ( 6, 2), (-6, 2), ( 6,-2), (-6,-2), From arigo at codespeak.net Tue Sep 29 21:58:03 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 21:58:03 +0200 (CEST) Subject: [pypy-svn] r68003 - pypy/trunk/pypy/jit/backend/x86/test Message-ID: <20090929195803.836A4168007@codespeak.net> Author: arigo Date: Tue Sep 29 21:58:02 2009 New Revision: 68003 Added: pypy/trunk/pypy/jit/backend/x86/test/test_symbolic_x86.py - copied unchanged from r67998, pypy/trunk/pypy/jit/backend/llsupport/test/test_symbolic.py Log: Add this again, with a more explicit name. From arigo at codespeak.net Tue Sep 29 21:58:27 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 21:58:27 +0200 (CEST) Subject: [pypy-svn] r68004 - in pypy/trunk/pypy/jit/backend/llsupport: . test Message-ID: <20090929195827.B4721168007@codespeak.net> Author: arigo Date: Tue Sep 29 21:58:27 2009 New Revision: 68004 Modified: pypy/trunk/pypy/jit/backend/llsupport/symbolic.py pypy/trunk/pypy/jit/backend/llsupport/test/test_symbolic.py Log: Fix symbolic.py and the test to be more general. Modified: pypy/trunk/pypy/jit/backend/llsupport/symbolic.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llsupport/symbolic.py (original) +++ pypy/trunk/pypy/jit/backend/llsupport/symbolic.py Tue Sep 29 21:58:27 2009 @@ -48,7 +48,7 @@ else: before_array_part = 0 carray = ll2ctypes.get_ctypes_type(T) - assert carray.length.size == 4 + assert carray.length.size == WORD ofs_length = before_array_part + carray.length.offset basesize = before_array_part + carray.items.offset carrayitem = ll2ctypes.get_ctypes_type(T.OF) Modified: pypy/trunk/pypy/jit/backend/llsupport/test/test_symbolic.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llsupport/test/test_symbolic.py (original) +++ pypy/trunk/pypy/jit/backend/llsupport/test/test_symbolic.py Tue Sep 29 21:58:27 2009 @@ -2,11 +2,9 @@ from pypy.jit.backend.llsupport.symbolic import * from pypy.rpython.lltypesystem import lltype, rffi -# This test file is here and not in llsupport/test/ because it checks -# that we get correct numbers for a 32-bit machine. -class FakeStats(object): - pass +WORD = rffi.sizeof(lltype.Signed) +PTRWORD = rffi.sizeof(llmemory.GCREF) S = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed), @@ -18,33 +16,32 @@ ofs_y, size_y = get_field_token(S, 'y', False) ofs_z, size_z = get_field_token(S, 'z', False) # ofs_x might be 0 or not, depending on how we count the headers - # but the rest should be as expected for a 386 machine - assert size_x == size_y == size_z == 4 + assert size_x == size_y == size_z == WORD assert ofs_x >= 0 - assert ofs_y == ofs_x + 4 - assert ofs_z == ofs_x + 8 + assert ofs_y == ofs_x + WORD + assert ofs_z == ofs_y + WORD def test_struct_size(): ofs_z, size_z = get_field_token(S, 'z', False) totalsize = get_size(S, False) - assert totalsize == ofs_z + 4 + assert totalsize == ofs_z + WORD def test_primitive_size(): - assert get_size(lltype.Signed, False) == 4 + assert get_size(lltype.Signed, False) == WORD assert get_size(lltype.Char, False) == 1 - assert get_size(lltype.Ptr(S), False) == 4 + assert get_size(lltype.Ptr(S), False) == PTRWORD def test_array_token(): A = lltype.GcArray(lltype.Char) basesize, itemsize, ofs_length = get_array_token(A, False) - assert basesize >= 4 # at least the 'length', maybe some gc headers + assert basesize >= WORD # at least the 'length', maybe some gc headers assert itemsize == 1 - assert ofs_length == basesize - 4 + assert ofs_length == basesize - WORD A = lltype.GcArray(lltype.Signed) basesize, itemsize, ofs_length = get_array_token(A, False) - assert basesize >= 4 # at least the 'length', maybe some gc headers - assert itemsize == 4 - assert ofs_length == basesize - 4 + assert basesize >= WORD # at least the 'length', maybe some gc headers + assert itemsize == WORD + assert ofs_length == basesize - WORD def test_varsized_struct_size(): S1 = lltype.GcStruct('S1', ('parent', S), @@ -54,9 +51,9 @@ ofs_extra, size_extra = get_field_token(S1, 'extra', False) basesize, itemsize, ofs_length = get_array_token(S1, False) assert size_parent == ofs_extra - assert size_extra == 4 - assert ofs_length == ofs_extra + 4 - assert basesize == ofs_length + 4 + assert size_extra == WORD + assert ofs_length == ofs_extra + WORD + assert basesize == ofs_length + WORD assert itemsize == 1 def test_string(): @@ -75,7 +72,3 @@ assert rawbytes[basesize+1] == 'p' assert rawbytes[basesize+2] == 'a' assert rawbytes[basesize+3] == 'm' - assert rawbytes[ofs_length+0] == chr(4) - assert rawbytes[ofs_length+1] == chr(0) - assert rawbytes[ofs_length+2] == chr(0) - assert rawbytes[ofs_length+3] == chr(0) From arigo at codespeak.net Tue Sep 29 22:16:15 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Sep 2009 22:16:15 +0200 (CEST) Subject: [pypy-svn] r68005 - pypy/trunk/pypy/rpython/lltypesystem/test Message-ID: <20090929201615.E2586168007@codespeak.net> Author: arigo Date: Tue Sep 29 22:16:15 2009 New Revision: 68005 Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_llarena.py Log: Fix test for 64 bits. Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_llarena.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/test/test_llarena.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/test/test_llarena.py Tue Sep 29 22:16:15 2009 @@ -100,12 +100,12 @@ def test_address_order(): - a = arena_malloc(20, False) + a = arena_malloc(24, False) assert eq(a, a) assert lt(a, a+1) assert lt(a+5, a+20) - b = arena_malloc(20, False) + b = arena_malloc(24, False) if a > b: a, b = b, a assert lt(a, b) @@ -158,7 +158,7 @@ arena_reserve(b, precomputed_size) def test_partial_arena_reset(): - a = arena_malloc(50, False) + a = arena_malloc(72, False) def reserve(i): b = a + i * llmemory.raw_malloc_usage(precomputed_size) arena_reserve(b, precomputed_size) @@ -224,9 +224,10 @@ STUB = lltype.GcStruct('STUB', ('t', lltype.Char)) gcheaderbuilder = GCHeaderBuilder(HDR) size_gc_header = gcheaderbuilder.size_gc_header + ssize = llmemory.raw_malloc_usage(llmemory.sizeof(S)) - a = arena_malloc(50, True) - hdraddr = a + 12 + a = arena_malloc(13*ssize, True) + hdraddr = a + 3*ssize arena_reserve(hdraddr, size_gc_header + llmemory.sizeof(S)) hdr = llmemory.cast_adr_to_ptr(hdraddr, lltype.Ptr(HDR)) hdr.x = 42 From arigo at codespeak.net Wed Sep 30 11:00:46 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 11:00:46 +0200 (CEST) Subject: [pypy-svn] r68012 - pypy/branch/kill-jumptarget Message-ID: <20090930090046.485E4168025@codespeak.net> Author: arigo Date: Wed Sep 30 11:00:45 2009 New Revision: 68012 Added: pypy/branch/kill-jumptarget/ - copied from r68011, pypy/trunk/ Log: A branch in which to remove the "jump_target" attribute of ResOperation. From fijal at codespeak.net Wed Sep 30 11:16:42 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 11:16:42 +0200 (CEST) Subject: [pypy-svn] r68013 - pypy/extradoc/talk/pycon2010 Message-ID: <20090930091642.3BBA716800D@codespeak.net> Author: fijal Date: Wed Sep 30 11:16:41 2009 New Revision: 68013 Added: pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt - copied unchanged from r68012, pypy/extradoc/talk/pycon2010/how_not_to_write_abstract.txt Removed: pypy/extradoc/talk/pycon2010/how_not_to_write_abstract.txt Log: Make the name less confusing From arigo at codespeak.net Wed Sep 30 11:35:26 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 11:35:26 +0200 (CEST) Subject: [pypy-svn] r68014 - in pypy/branch/kill-jumptarget/pypy/jit: backend/llgraph backend/test metainterp metainterp/test Message-ID: <20090930093526.1845116801B@codespeak.net> Author: arigo Date: Wed Sep 30 11:35:25 2009 New Revision: 68014 Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/llgraph/runner.py pypy/branch/kill-jumptarget/pypy/jit/backend/test/runner_test.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/history.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/resoperation.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/oparser.py Log: Start the refactoring. Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/llgraph/runner.py Wed Sep 30 11:35:25 2009 @@ -104,17 +104,22 @@ llimpl.set_class_size(self.memo_cast, vtable, size) def compile_bridge(self, faildescr, inputargs, operations): - c = self.compile_loop(inputargs, operations) + c = llimpl.compile_start() + self._compile_loop_or_bridge(c, inputargs, operations) old, oldindex = faildescr._compiled_fail llimpl.compile_redirect_fail(old, oldindex, c) - def compile_loop(self, inputargs, operations): + def compile_loop(self, inputargs, operations, loopdescr): """In a real assembler backend, this should assemble the given list of operations. Here we just generate a similar CompiledLoop instance. The code here is RPython, whereas the code in llimpl is not. """ c = llimpl.compile_start() + loopdescr._llgraph_compiled_version = c + self._compile_loop_or_bridge(c, inputargs, operations) + + def _compile_loop_or_bridge(self, c, inputargs, operations): var2index = {} for box in inputargs: if isinstance(box, history.BoxInt): @@ -174,12 +179,10 @@ op = operations[-1] assert op.is_final() if op.opnum == rop.JUMP: - target = op.jump_target - if target is None: - target = c - else: - target = target.executable_token - llimpl.compile_add_jump_target(c, target) + targettoken = op.descr + assert isinstance(targettoken, history.LoopToken) + compiled_version = targettoken._llgraph_compiled_version + llimpl.compile_add_jump_target(c, compiled_version) elif op.opnum == rop.FINISH: llimpl.compile_add_fail(c, len(self.fail_descrs)) faildescr = op.descr @@ -188,10 +191,11 @@ else: assert False, "unknown operation" - def execute_token(self, compiled_version): + def execute_token(self, loop_token): """Calls the assembler generated for the given loop. Returns the ResOperation that failed, of type rop.FAIL. """ + compiled_version = loop_token._llgraph_compiled_version frame = llimpl.new_frame(self.memo_cast, self.is_oo) # setup the frame llimpl.frame_clear(frame, compiled_version) Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/test/runner_test.py Wed Sep 30 11:35:25 2009 @@ -24,7 +24,8 @@ result_type, valueboxes, descr) - executable_token = self.cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + self.cpu.compile_loop(inputargs, operations, looptoken) j = 0 for box in valueboxes: if isinstance(box, BoxInt): @@ -38,7 +39,7 @@ j += 1 else: assert isinstance(box, Const) - res = self.cpu.execute_token(executable_token) + res = self.cpu.execute_token(looptoken) if res is operations[-1].descr: self.guard_failed = False else: @@ -96,9 +97,10 @@ ResOperation(rop.FINISH, [i1], None, descr=faildescr) ] inputargs = [i0] - executable_token = self.cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + self.cpu.compile_loop(inputargs, operations, looptoken) self.cpu.set_future_value_int(0, 2) - fail = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(looptoken) res = self.cpu.get_latest_value_int(0) assert res == 3 assert fail is faildescr @@ -108,19 +110,19 @@ i1 = BoxInt() i2 = BoxInt() faildescr = BasicFailDescr() + looptoken = LoopToken() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr), - ResOperation(rop.JUMP, [i1], None), + ResOperation(rop.JUMP, [i1], None, descr=looptoken), ] inputargs = [i0] operations[2].fail_args = [i1] - operations[-1].jump_target = None - executable_token = self.cpu.compile_loop(inputargs, operations) + self.cpu.compile_loop(inputargs, operations, looptoken) self.cpu.set_future_value_int(0, 2) - fail = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(looptoken) assert fail is faildescr res = self.cpu.get_latest_value_int(0) assert res == 10 @@ -131,19 +133,19 @@ i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() - faildescr = BasicFailDescr() + faildescr = BasicFailDescr() + looptoken = LoopToken() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr), - ResOperation(rop.JUMP, [i1], None), + ResOperation(rop.JUMP, [i1], None, descr=looptoken), ] inputargs = [i0] operations[2].fail_args = [i1] - operations[-1].jump_target = None wr_i1 = weakref.ref(i1) wr_guard = weakref.ref(operations[2]) - executable_token = self.cpu.compile_loop(inputargs, operations) + self.cpu.compile_loop(inputargs, operations, looptoken) del i0, i1, i2 del inputargs del operations @@ -156,33 +158,30 @@ i2 = BoxInt() faildescr1 = BasicFailDescr() faildescr2 = BasicFailDescr() + looptoken = LoopToken() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1), - ResOperation(rop.JUMP, [i1], None), + ResOperation(rop.JUMP, [i1], None, descr=looptoken), ] inputargs = [i0] operations[2].fail_args = [i1] - operations[-1].jump_target = None - executable_token = self.cpu.compile_loop(inputargs, operations) - loop_token = LoopToken() - loop_token.executable_token = executable_token + self.cpu.compile_loop(inputargs, operations, looptoken) i1b = BoxInt() i3 = BoxInt() bridge = [ ResOperation(rop.INT_LE, [i1b, ConstInt(19)], i3), ResOperation(rop.GUARD_TRUE, [i3], None, descr=faildescr2), - ResOperation(rop.JUMP, [i1b], None), + ResOperation(rop.JUMP, [i1b], None, descr=looptoken), ] bridge[1].fail_args = [i1b] - bridge[-1].jump_target = loop_token self.cpu.compile_bridge(faildescr1, [i1b], bridge) self.cpu.set_future_value_int(0, 2) - fail = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(looptoken) assert fail is faildescr2 res = self.cpu.get_latest_value_int(0) assert res == 20 @@ -193,30 +192,33 @@ def __setattr__(self, name, value): py.test.fail("finish descrs should not be touched") faildescr = UntouchableFailDescr() # to check that is not touched + looptoken = LoopToken() operations = [ ResOperation(rop.FINISH, [i0], None, descr=faildescr) ] - executable_token = self.cpu.compile_loop([i0], operations) + self.cpu.compile_loop([i0], operations, looptoken) self.cpu.set_future_value_int(0, 99) - fail = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(looptoken) assert fail is faildescr res = self.cpu.get_latest_value_int(0) assert res == 99 + looptoken = LoopToken() operations = [ ResOperation(rop.FINISH, [ConstInt(42)], None, descr=faildescr) ] - executable_token = self.cpu.compile_loop([], operations) - fail = self.cpu.execute_token(executable_token) + self.cpu.compile_loop([], operations, looptoken) + fail = self.cpu.execute_token(looptoken) assert fail is faildescr res = self.cpu.get_latest_value_int(0) assert res == 42 + looptoken = LoopToken() operations = [ ResOperation(rop.FINISH, [], None, descr=faildescr) ] - executable_token = self.cpu.compile_loop([], operations) - fail = self.cpu.execute_token(executable_token) + self.cpu.compile_loop([], operations, looptoken) + fail = self.cpu.execute_token(looptoken) assert fail is faildescr def test_do_call(self): @@ -406,13 +408,14 @@ ] ops[1].fail_args = [v_res] # - executable_token = self.cpu.compile_loop([v1, v2], ops) + looptoken = LoopToken() + self.cpu.compile_loop([v1, v2], ops, looptoken) for x, y, z in testcases: assert not self.cpu.get_exception() assert not self.cpu.get_exc_value() self.cpu.set_future_value_int(0, x) self.cpu.set_future_value_int(1, y) - fail = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(looptoken) if (z == boom) ^ reversed: assert fail is ops[1].descr else: @@ -1045,15 +1048,14 @@ exc_tp = xtp exc_ptr = xptr loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) + self.cpu.compile_loop(loop.inputargs, loop.operations, loop.token) self.cpu.set_future_value_int(0, 1) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(loop.token) assert self.cpu.get_latest_value_int(0) == 0 assert self.cpu.get_latest_value_ref(1) == xptr self.cpu.clear_exception() self.cpu.set_future_value_int(0, 0) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(loop.token) assert self.cpu.get_latest_value_int(0) == 1 self.cpu.clear_exception() @@ -1069,10 +1071,9 @@ exc_tp = ytp exc_ptr = yptr loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) + self.cpu.compile_loop(loop.inputargs, loop.operations, loop.token) self.cpu.set_future_value_int(0, 1) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(loop.token) assert self.cpu.get_latest_value_int(0) == 1 self.cpu.clear_exception() @@ -1086,14 +1087,13 @@ finish(0) ''' loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) + self.cpu.compile_loop(loop.inputargs, loop.operations, loop.token) self.cpu.set_future_value_int(0, 1) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(loop.token) assert self.cpu.get_latest_value_int(0) == 1 self.cpu.clear_exception() self.cpu.set_future_value_int(0, 0) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(loop.token) assert self.cpu.get_latest_value_int(0) == 0 self.cpu.clear_exception() Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/history.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/history.py Wed Sep 30 11:35:25 2009 @@ -644,16 +644,18 @@ # of operations. Each branch ends in a jump which can go either to # the top of the same loop, or to another TreeLoop; or it ends in a FINISH. -class Base(object): - """Common base class for TreeLoop and History.""" - -class LoopToken(object): - """loop token""" +class LoopToken(AbstractDescr): + """Used for rop.JUMP, giving the target of the jump. + This is different from TreeLoop: the TreeLoop class contains the + whole loop, including 'operations', and goes away after the loop + was compiled; but the LoopDescr remains alive and points to the + generated assembler. + """ terminating = False # see TerminatingLoopToken in compile.py # specnodes # executable_token -class TreeLoop(Base): +class TreeLoop(object): inputargs = None specnodes = None operations = None @@ -764,7 +766,7 @@ # ____________________________________________________________ -class History(Base): +class History(object): def __init__(self, cpu): self.cpu = cpu self.inputargs = None Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/resoperation.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/resoperation.py Wed Sep 30 11:35:25 2009 @@ -5,16 +5,13 @@ """The central ResOperation class, representing one operation.""" # for 'jump': points to the target loop; - jump_target = None + jump_target = property(lambda x: crash, lambda x, y: crash) # XXX temp # for 'guard_*' suboperations = property(lambda x: crash, lambda x, y: crash) # XXX temp optimized = property(lambda x: crash, lambda x, y: crash) # XXX temp fail_args = None - # for x86 backend and guards - inputargs = None - # debug name = "" pc = 0 Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/oparser.py Wed Sep 30 11:35:25 2009 @@ -4,7 +4,7 @@ """ from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ - ConstAddr, ConstObj, ConstPtr, Box, BasicFailDescr + ConstAddr, ConstObj, ConstPtr, Box, BasicFailDescr, LoopToken from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.typesystem import llhelper from pypy.rpython.lltypesystem import lltype, llmemory @@ -49,15 +49,14 @@ class OpParser(object): - def __init__(self, descr, cpu, namespace, type_system, boxkinds, jump_target, invent_fail_descr=default_fail_descr): + def __init__(self, descr, cpu, namespace, type_system, boxkinds, + invent_fail_descr=default_fail_descr): self.descr = descr self.vars = {} self.cpu = cpu self.consts = namespace self.type_system = type_system self.boxkinds = boxkinds or {} - self.jumps = [] - self.jump_target = jump_target self._cache = namespace.setdefault('_CACHE_', {}) self.invent_fail_descr = invent_fail_descr @@ -208,7 +207,7 @@ res = ResOperation(opnum, args, None, descr) res.fail_args = fail_args if opnum == rop.JUMP: - self.jumps.append(res) + assert res.descr is not None return res def parse_next_op(self, line): @@ -240,12 +239,7 @@ if num < len(newlines): raise ParseError("unexpected dedent at line: %s" % newlines[num]) loop = ExtendedTreeLoop("loop") - if len(self.jumps) > 1: - raise ParseError("Multiple jumps??") - if self.jump_target is not None and len(self.jumps) != 1: - raise ParseError("A jump is expected if a jump_target is given") - for jump in self.jumps: - jump.jump_target = self.jump_target + loop.token = LoopToken() loop.operations = ops loop.inputargs = inpargs return loop @@ -276,11 +270,10 @@ return base_indent, inpargs def parse(descr, cpu=None, namespace=None, type_system='lltype', - boxkinds=None, jump_target=None, - invent_fail_descr=default_fail_descr): + boxkinds=None, invent_fail_descr=default_fail_descr): if namespace is None: namespace = {} - return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_target, + return OpParser(descr, cpu, namespace, type_system, boxkinds, invent_fail_descr).parse() def pure_parse(*args, **kwds): From arigo at codespeak.net Wed Sep 30 11:45:35 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 11:45:35 +0200 (CEST) Subject: [pypy-svn] r68015 - in pypy/branch/kill-jumptarget/pypy/jit/metainterp: . test Message-ID: <20090930094535.8ACE716801B@codespeak.net> Author: arigo Date: Wed Sep 30 11:45:34 2009 New Revision: 68015 Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizeopt.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/oparser.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_oparser.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizeopt.py Log: Pass again 'test_o*.py'. Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizeopt.py Wed Sep 30 11:45:34 2009 @@ -1,4 +1,4 @@ -from pypy.jit.metainterp.history import Box, BoxInt +from pypy.jit.metainterp.history import Box, BoxInt, LoopToken from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstObj, REF from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.executor import execute_nonspec @@ -547,18 +547,15 @@ def optimize_JUMP(self, op): orgop = self.loop.operations[-1] exitargs = [] - target = orgop.jump_target - if target is None: - specnodes = self.loop.specnodes - else: - specnodes = target.specnodes + target_loop_token = orgop.descr + assert isinstance(target_loop_token, LoopToken) + specnodes = target_loop_token.specnodes assert len(op.args) == len(specnodes) for i in range(len(specnodes)): value = self.getvalue(op.args[i]) specnodes[i].teardown_virtual_node(self, value, exitargs) op2 = op.clone() op2.args = exitargs - op2.jump_target = op.jump_target self.emit_operation(op2, must_clone=False) def optimize_guard(self, op, constbox): Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/oparser.py Wed Sep 30 11:45:34 2009 @@ -59,6 +59,7 @@ self.boxkinds = boxkinds or {} self._cache = namespace.setdefault('_CACHE_', {}) self.invent_fail_descr = invent_fail_descr + self.looptoken = LoopToken() def box_for_var(self, elem): try: @@ -187,6 +188,9 @@ if opnum == rop.FINISH: if descr is None and self.invent_fail_descr: descr = self.invent_fail_descr() + elif opnum == rop.JUMP: + if descr is None and self.invent_fail_descr: + descr = self.looptoken return opnum, args, descr, fail_args def parse_result_op(self, line): @@ -206,8 +210,6 @@ opnum, args, descr, fail_args = self.parse_op(line) res = ResOperation(opnum, args, None, descr) res.fail_args = fail_args - if opnum == rop.JUMP: - assert res.descr is not None return res def parse_next_op(self, line): @@ -239,7 +241,7 @@ if num < len(newlines): raise ParseError("unexpected dedent at line: %s" % newlines[num]) loop = ExtendedTreeLoop("loop") - loop.token = LoopToken() + loop.token = self.looptoken loop.operations = ops loop.inputargs = inpargs return loop Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_oparser.py Wed Sep 30 11:45:34 2009 @@ -3,7 +3,7 @@ from pypy.jit.metainterp.test.oparser import parse from pypy.jit.metainterp.resoperation import rop -from pypy.jit.metainterp.history import AbstractDescr, BoxInt +from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken def test_basic_parse(): x = """ @@ -118,16 +118,16 @@ jump() ''' loop = parse(x) - assert loop.operations[0].jump_target is None + assert loop.operations[0].descr is loop.token def test_jump_target_other(): + looptoken = LoopToken() x = ''' [] - jump() + jump(descr=looptoken) ''' - obj = object() - loop = parse(x, jump_target=obj) - assert loop.operations[0].jump_target is obj + loop = parse(x, namespace=locals()) + assert loop.operations[0].descr is looptoken def test_debug_merge_point(): x = ''' Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizeopt.py Wed Sep 30 11:45:34 2009 @@ -64,7 +64,8 @@ assert op1.result == remap[op2.result] else: remap[op2.result] = op1.result - assert op1.descr == op2.descr + if op1.opnum != rop.JUMP: # xxx obscure + assert op1.descr == op2.descr if op1.fail_args or op2.fail_args: assert len(op1.fail_args) == len(op2.fail_args) for x, y in zip(op1.fail_args, op2.fail_args): @@ -151,9 +152,7 @@ # for cases where we want to see how optimizeopt behaves with # combinations different from the one computed by optimizefindnode loop.specnodes = self.unpack_specnodes(spectext) - # - assert loop.operations[-1].opnum == rop.JUMP - loop.operations[-1].jump_target = loop + loop.token.specnodes = loop.specnodes # optimize_loop_1(self.cpu, loop) # From fijal at codespeak.net Wed Sep 30 11:54:42 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 11:54:42 +0200 (CEST) Subject: [pypy-svn] r68016 - pypy/extradoc/talk/pycon2010 Message-ID: <20090930095442.287E7168014@codespeak.net> Author: fijal Date: Wed Sep 30 11:54:41 2009 New Revision: 68016 Modified: pypy/extradoc/talk/pycon2010/jit_abstract.txt Log: Add agenda Modified: pypy/extradoc/talk/pycon2010/jit_abstract.txt ============================================================================== --- pypy/extradoc/talk/pycon2010/jit_abstract.txt (original) +++ pypy/extradoc/talk/pycon2010/jit_abstract.txt Wed Sep 30 11:54:41 2009 @@ -6,16 +6,34 @@ The first part of the talk will cover PyPy's speed achievements resulting from the last year's work on the Just-In-Time Compiler. I'll present and discuss a number of benchmarks and compare against other Python-speed -projects. And I'll cover the basics of how the JIT works and what +projects. I'll also cover the basics of how the JIT works and what sort of programs it can greatly speedup (and which ones it can't). Description: PyPy's JIT has been in development for some years now. More recently -it became more practical and begins to be faster than Psyco on some +it became more practical and begins to be `faster than Psyco`_ on some examples. This is the status in September 2009 and currently it's fast-paced -development so we expect to have very interesting results for February 2010, -worth discussing and comparing. If possible a 45 minute talk would be cool -due to the "explaining the JIT" bit of the talk. +development so we expect to have even more interesting results for +February 2010, worth discussing and comparing. If possible +a 45 minute talk would be cool due to the "explaining the JIT" +bit of the talk. -XXX link, review +Proposed talk agenda: + +* Show various benchmarking data and compare different + python interpreters (CPython, PyPy, Jython, IronPython, unladden swallow) + +* A bit of introduction into how PyPy's JIT work (it's tracing JIT, + like tracemonkey JS interpreter, unlike Psyco or JVM). + +* What sorts of programs JITs in general can speed up. What sorts of + programs PyPy's JIT is better at. What similiar python constructs + can yield different performance characteristics while JITting. + +* Future plans for PyPy, especially JIT-wise. + +The main wieght would be put on the point 3 (how can I write my program +so JIT will make it fast). + +.. _`faster than Psyco`: http://morepypy.blogspot.com/2009/09/first-results-of-jit.html From pedronis at codespeak.net Wed Sep 30 12:09:16 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 30 Sep 2009 12:09:16 +0200 (CEST) Subject: [pypy-svn] r68017 - pypy/extradoc/talk/pycon2010 Message-ID: <20090930100916.05A2D168020@codespeak.net> Author: pedronis Date: Wed Sep 30 12:09:15 2009 New Revision: 68017 Modified: pypy/extradoc/talk/pycon2010/jit_abstract.txt Log: be a bit less over-concrete Modified: pypy/extradoc/talk/pycon2010/jit_abstract.txt ============================================================================== --- pypy/extradoc/talk/pycon2010/jit_abstract.txt (original) +++ pypy/extradoc/talk/pycon2010/jit_abstract.txt Wed Sep 30 12:09:15 2009 @@ -21,19 +21,14 @@ Proposed talk agenda: -* Show various benchmarking data and compare different - python interpreters (CPython, PyPy, Jython, IronPython, unladden swallow) +* Show various benchmarking data and compare different Python interpreters -* A bit of introduction into how PyPy's JIT work (it's tracing JIT, - like tracemonkey JS interpreter, unlike Psyco or JVM). +* A bit of introduction into how PyPy's JIT work (it's a generated tracing JIT, + like the tracemonkey JS interpreter, unlike Psyco or JVM JITs). -* What sorts of programs JITs in general can speed up. What sorts of - programs PyPy's JIT is better at. What similiar python constructs - can yield different performance characteristics while JITting. +* Tracing JITs focus on often executed loops. Which kind of programs + will the PyPy JIT speed-up , which constructs we know it is currently poor at. * Future plans for PyPy, especially JIT-wise. -The main wieght would be put on the point 3 (how can I write my program -so JIT will make it fast). - .. _`faster than Psyco`: http://morepypy.blogspot.com/2009/09/first-results-of-jit.html From arigo at codespeak.net Wed Sep 30 12:15:15 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 12:15:15 +0200 (CEST) Subject: [pypy-svn] r68018 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090930101515.7A7C7168020@codespeak.net> Author: arigo Date: Wed Sep 30 12:15:15 2009 New Revision: 68018 Modified: pypy/trunk/pypy/jit/metainterp/optimizefindnode.py pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py Log: Oups. We forgot this find_nodes_FAIL when refactoring the operation name to FINISH, and no test was caring. Modified: pypy/trunk/pypy/jit/metainterp/optimizefindnode.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimizefindnode.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimizefindnode.py Wed Sep 30 12:15:15 2009 @@ -299,7 +299,7 @@ for box in op.args: self.getnode(box).set_unique_nodes() - def find_nodes_FAIL(self, op): + def find_nodes_FINISH(self, op): # only for bridges, and only for the ones that end in a 'return' # or 'raise'; all other cases end with a JUMP. for box in op.args: Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py Wed Sep 30 12:15:15 2009 @@ -1062,6 +1062,9 @@ finish(p1) """ self.find_bridge(ops, 'Not', 'Not') + self.find_bridge(ops, 'Not', + 'Virtual(node_vtable, valuedescr=Not)', + mismatch=True) def test_bridge_array_virtual_1(self): ops = """ From arigo at codespeak.net Wed Sep 30 12:43:14 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 12:43:14 +0200 (CEST) Subject: [pypy-svn] r68019 - in pypy/trunk/pypy: rlib rpython/lltypesystem rpython/lltypesystem/test Message-ID: <20090930104314.3DD52168020@codespeak.net> Author: arigo Date: Wed Sep 30 12:43:13 2009 New Revision: 68019 Modified: pypy/trunk/pypy/rlib/rposix.py pypy/trunk/pypy/rpython/lltypesystem/rffi.py pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Log: "Solve" the ambiguity of rffi.INT versus rffi.LONG in rffi.CExternVariable by requiring an explicit C type. Fix the test to make it pass on both 32- and 64-bits machines. Modified: pypy/trunk/pypy/rlib/rposix.py ============================================================================== --- pypy/trunk/pypy/rlib/rposix.py (original) +++ pypy/trunk/pypy/rlib/rposix.py Wed Sep 30 12:43:13 2009 @@ -24,7 +24,7 @@ _get_errno, _set_errno = CExternVariable(INT, 'errno', errno_eci, CConstantErrno, sandboxsafe=True, - _nowrapper=True) + _nowrapper=True, c_type='int') # the default wrapper for set_errno is not suitable for use in critical places # like around GIL handling logic, so we provide our own wrappers. Modified: pypy/trunk/pypy/rpython/lltypesystem/rffi.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/rffi.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/rffi.py Wed Sep 30 12:43:13 2009 @@ -439,7 +439,8 @@ return lltype.Ptr(COpaque(*args, **kwds)) def CExternVariable(TYPE, name, eci, _CConstantClass=CConstant, - sandboxsafe=False, _nowrapper=False): + sandboxsafe=False, _nowrapper=False, + c_type=None): """Return a pair of functions - a getter and a setter - to access the given global C variable. """ @@ -447,16 +448,17 @@ from pypy.translator.tool.cbuild import ExternalCompilationInfo # XXX we cannot really enumerate all C types here, do it on a case-by-case # basis - if TYPE == CCHARPP: - c_type = 'char **' - elif TYPE == CCHARP: - c_type = 'char *' - elif TYPE == INT: - c_type = 'int' - else: - c_type = PrimitiveType[TYPE] - assert c_type.endswith(' @') - c_type = c_type[:-2] # cut the trailing ' @' + if c_type is None: + if TYPE == CCHARPP: + c_type = 'char **' + elif TYPE == CCHARP: + c_type = 'char *' + elif TYPE == INT or TYPE == LONG: + assert False, "ambiguous type on 32-bit machines: give a c_type" + else: + c_type = PrimitiveType[TYPE] + assert c_type.endswith(' @') + c_type = c_type[:-2] # cut the trailing ' @' getter_name = 'get_' + name setter_name = 'set_' + name Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py ============================================================================== --- pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py (original) +++ pypy/trunk/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Wed Sep 30 12:43:13 2009 @@ -753,6 +753,7 @@ #include static long x = 3; + static int y = 5; char **z = NULL; #endif /* _SOME_H */ @@ -763,7 +764,8 @@ eci = ExternalCompilationInfo(includes=['stdio.h', str(h_file.basename)], include_dirs=[str(udir)]) - get_x, set_x = rffi.CExternVariable(rffi.LONG, 'x', eci) + get_x, set_x = rffi.CExternVariable(rffi.LONG, 'x', eci, c_type='long') + get_y, set_y = rffi.CExternVariable(rffi.INT, 'y', eci, c_type='int') get_z, set_z = rffi.CExternVariable(rffi.CCHARPP, 'z', eci) def f(): @@ -771,6 +773,11 @@ set_x(13) return one + get_x() + def fy(): + one = rffi.cast(lltype.Signed, get_y()) + set_y(rffi.cast(rffi.INT, 13)) + return one + rffi.cast(lltype.Signed, get_y()) + def g(): l = rffi.liststr2charpp(["a", "b", "c"]) try: @@ -781,7 +788,10 @@ res = f() assert res == 16 - assert g() == "c" + res = fy() + assert res == 18 + res = g() + assert res == "c" def test_c_callback(self): c_source = py.code.Source(""" From arigo at codespeak.net Wed Sep 30 13:15:24 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 13:15:24 +0200 (CEST) Subject: [pypy-svn] r68020 - in pypy/branch/kill-jumptarget/pypy/jit/metainterp: . test Message-ID: <20090930111524.7729F168016@codespeak.net> Author: arigo Date: Wed Sep 30 13:15:23 2009 New Revision: 68020 Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/compile.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/graphpage.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/history.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimize.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizefindnode.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizeopt.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/pyjitpl.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/resume.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_compile.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizeopt.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_send.py pypy/branch/kill-jumptarget/pypy/jit/metainterp/warmspot.py Log: Progress. Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/compile.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/compile.py Wed Sep 30 13:15:23 2009 @@ -33,6 +33,11 @@ name = metainterp.staticdata.stats.name_for_new_loop() return TreeLoop(name) +def make_loop_token(nb_args): + loop_token = LoopToken() + loop_token.specnodes = [prebuiltNotSpecNode] * nb_args + return loop_token + # ____________________________________________________________ def compile_new_loop(metainterp, old_loop_tokens, greenkey, start): @@ -50,7 +55,9 @@ loop.operations = history.operations[start:] else: loop.operations = history.operations - loop.operations[-1].jump_target = None + loop_token = make_loop_token(len(loop.inputargs)) + loop.token = loop_token + loop.operations[-1].descr = loop_token # patch the target of the JUMP metainterp_sd = metainterp.staticdata try: old_loop_token = metainterp_sd.state.optimize_loop( @@ -61,12 +68,7 @@ if DEBUG > 0: debug_print("reusing old loop") return old_loop_token - executable_token = send_loop_to_backend(metainterp_sd, loop, "loop") - loop_token = LoopToken() - loop_token.specnodes = loop.specnodes - loop_token.executable_token = executable_token - if not we_are_translated(): - loop.token = loop_token + send_loop_to_backend(metainterp_sd, loop, "loop") insert_loop_token(old_loop_tokens, loop_token) return loop_token @@ -89,8 +91,7 @@ if not we_are_translated(): show_loop(metainterp_sd, loop) loop.check_consistency() - executable_token = metainterp_sd.cpu.compile_loop(loop.inputargs, - loop.operations) + metainterp_sd.cpu.compile_loop(loop.inputargs, loop.operations, loop.token) metainterp_sd.profiler.end_backend() metainterp_sd.stats.add_new_loop(loop) if not we_are_translated(): @@ -103,7 +104,6 @@ from pypy.jit.metainterp.pyjitpl import DEBUG if DEBUG > 0: debug_print("compiled new " + type) - return executable_token def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations): metainterp_sd.options.logger_ops.log_loop(inputargs, operations) @@ -226,21 +226,19 @@ # with completely unoptimized arguments, as in the interpreter. metainterp_sd = metainterp.staticdata metainterp.history.inputargs = self.redkey + new_loop_token = make_loop_token(len(self.redkey)) new_loop.greenkey = self.original_greenkey new_loop.inputargs = self.redkey - executable_token = send_loop_to_backend(metainterp_sd, new_loop, - "entry bridge") + new_loop.token = new_loop_token + send_loop_to_backend(metainterp_sd, new_loop, "entry bridge") # send the new_loop to warmspot.py, to be called directly the next time metainterp_sd.state.attach_unoptimized_bridge_from_interp( self.original_greenkey, - executable_token) + new_loop_token) # store the new loop in compiled_merge_points too glob = metainterp_sd.globaldata greenargs = glob.unpack_greenkey(self.original_greenkey) old_loop_tokens = glob.compiled_merge_points.setdefault(greenargs, []) - new_loop_token = LoopToken() - new_loop_token.specnodes = [prebuiltNotSpecNode] * len(self.redkey) - new_loop_token.executable_token = executable_token # it always goes at the end of the list, as it is the most # general loop token old_loop_tokens.append(new_loop_token) @@ -280,11 +278,11 @@ op = new_loop.operations[-1] if not isinstance(target_loop_token, TerminatingLoopToken): # normal case - op.jump_target = target_loop_token + op.descr = target_loop_token # patch the jump target else: # The target_loop_token is a pseudo loop token, # e.g. loop_tokens_done_with_this_frame_void[0] - # Replace the operation with the real operation we want, i.e. a FAIL. + # Replace the operation with the real operation we want, i.e. a FINISH descr = target_loop_token.finishdescr new_op = ResOperation(rop.FINISH, op.args, None, descr=descr) new_loop.operations[-1] = new_op Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/graphpage.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/graphpage.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/graphpage.py Wed Sep 30 13:15:23 2009 @@ -168,7 +168,7 @@ (graphindex, opindex)) break if op.opnum == rop.JUMP: - tgt = op.jump_target + tgt = op.descr tgt_g = -1 if tgt is None: tgt_g = graphindex Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/history.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/history.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/history.py Wed Sep 30 13:15:23 2009 @@ -652,13 +652,14 @@ generated assembler. """ terminating = False # see TerminatingLoopToken in compile.py - # specnodes - # executable_token + # specnodes = ... + # and more data specified by the backend when the loop is compiled class TreeLoop(object): inputargs = None - specnodes = None operations = None + token = None + specnodes = property(lambda x: crash, lambda x, y: crash) # XXX temp def __init__(self, name): self.name = name @@ -729,7 +730,7 @@ seen[box] = True assert operations[-1].is_final() if operations[-1].opnum == rop.JUMP: - target = operations[-1].jump_target + target = operations[-1].descr if target is not None: assert isinstance(target, LoopToken) @@ -802,6 +803,9 @@ def add_new_loop(self, loop): pass + def view(self, **kwds): + pass + class Stats(object): """For tests.""" Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimize.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimize.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimize.py Wed Sep 30 13:15:23 2009 @@ -9,7 +9,7 @@ finder = PerfectSpecializationFinder(cpu) finder.find_nodes_loop(loop) for old_loop_token in old_loop_tokens: - if equals_specnodes(old_loop_token.specnodes, loop.specnodes): + if equals_specnodes(old_loop_token.specnodes, loop.token.specnodes): return old_loop_token optimize_loop_1(cpu, loop) return None @@ -25,7 +25,7 @@ finder.find_nodes_bridge(bridge) for old_loop_token in old_loop_tokens: if finder.bridge_matches(old_loop_token.specnodes): - bridge.operations[-1].jump_target = old_loop_token + bridge.operations[-1].descr = old_loop_token # patch jump target optimize_bridge_1(cpu, bridge) return old_loop_token return None Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizefindnode.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizefindnode.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizefindnode.py Wed Sep 30 13:15:23 2009 @@ -299,7 +299,7 @@ for box in op.args: self.getnode(box).set_unique_nodes() - def find_nodes_FAIL(self, op): + def find_nodes_FINISH(self, op): # only for bridges, and only for the ones that end in a 'return' # or 'raise'; all other cases end with a JUMP. for box in op.args: @@ -337,7 +337,7 @@ inputnode = self.inputnodes[i] exitnode = self.getnode(op.args[i]) specnodes.append(self.intersect(inputnode, exitnode)) - loop.specnodes = specnodes + loop.token.specnodes = specnodes def intersect(self, inputnode, exitnode): assert inputnode.fromstart Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/optimizeopt.py Wed Sep 30 13:15:23 2009 @@ -458,7 +458,7 @@ def setup_virtuals_and_constants(self): inputargs = self.loop.inputargs - specnodes = self.loop.specnodes + specnodes = self.loop.token.specnodes assert len(inputargs) == len(specnodes) newinputargs = [] for i in range(len(inputargs)): Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/pyjitpl.py Wed Sep 30 13:15:23 2009 @@ -1428,7 +1428,7 @@ residual_args = self.get_residual_args(loop_token.specnodes, gmp.argboxes[num_green_args:]) history.set_future_values(self.cpu, residual_args) - return loop_token.executable_token + return loop_token def prepare_resume_from_failure(self, opnum): if opnum == rop.GUARD_TRUE: # a goto_if_not that jumps only now Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/resume.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/resume.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/resume.py Wed Sep 30 13:15:23 2009 @@ -3,7 +3,7 @@ from pypy.jit.metainterp.resoperation import rop # Logic to encode the chain of frames and the state of the boxes at a -# FAIL operation, and to decode it again. This is a bit advanced, +# guard operation, and to decode it again. This is a bit advanced, # because it needs to support optimize.py which encodes virtuals with # arbitrary cycles. Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_compile.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_compile.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_compile.py Wed Sep 30 13:15:23 2009 @@ -1,6 +1,9 @@ -from pypy.jit.metainterp.history import LoopToken, ConstInt +from pypy.jit.metainterp.history import LoopToken, ConstInt, History, Stats from pypy.jit.metainterp.specnode import NotSpecNode, ConstantSpecNode -from pypy.jit.metainterp.compile import insert_loop_token +from pypy.jit.metainterp.compile import insert_loop_token, compile_new_loop +from pypy.jit.metainterp import optimize, jitprof +from pypy.jit.metainterp.test.oparser import parse +from pypy.jit.metainterp.test.test_optimizefindnode import LLtypeMixin def test_insert_loop_token(): @@ -20,3 +23,71 @@ tok3.specnodes = [ConstantSpecNode(ConstInt(-13))] insert_loop_token(lst, tok3) assert lst == [tok2, tok3, tok1] + + +class FakeCPU: + def __init__(self): + self.seen = [] + def compile_loop(self, inputargs, operations, token): + self.seen.append((inputargs, operations, token)) + +class FakeLogger: + def log_loop(self, inputargs, operations): + pass + +class FakeOptions: + logger_noopt = FakeLogger() + logger_ops = FakeLogger() + +class FakeState: + optimize_loop = staticmethod(optimize.optimize_loop) + +class FakeMetaInterpStaticData: + options = FakeOptions() + state = FakeState() + stats = Stats() + profiler = jitprof.EmptyProfiler() + +class FakeMetaInterp: + pass + +def test_compile_new_loop(): + cpu = FakeCPU() + staticdata = FakeMetaInterpStaticData() + staticdata.cpu = cpu + # + loop = parse(''' + [p1] + i1 = getfield_gc(p1, descr=valuedescr) + i2 = int_add(i1, 1) + p2 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p2, i2, descr=valuedescr) + jump(p2) + ''', namespace=LLtypeMixin.__dict__.copy()) + # + metainterp = FakeMetaInterp() + metainterp.staticdata = staticdata + metainterp.cpu = cpu + metainterp.history = History(metainterp.cpu) + metainterp.history.operations = loop.operations[:] + metainterp.history.inputargs = loop.inputargs[:] + # + loop_tokens = [] + loop_token = compile_new_loop(metainterp, loop_tokens, [], 0) + assert loop_tokens == [loop_token] + # + assert len(cpu.seen) == 1 + assert cpu.seen[0][2] == loop_token + # + del cpu.seen[:] + metainterp = FakeMetaInterp() + metainterp.staticdata = staticdata + metainterp.cpu = cpu + metainterp.history = History(metainterp.cpu) + metainterp.history.operations = loop.operations[:] + metainterp.history.inputargs = loop.inputargs[:] + # + loop_token_2 = compile_new_loop(metainterp, loop_tokens, [], 0) + assert loop_token_2 is loop_token + assert loop_tokens == [loop_token] + assert len(cpu.seen) == 0 Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizefindnode.py Wed Sep 30 13:15:23 2009 @@ -224,7 +224,7 @@ loop = self.parse(ops, boxkinds=boxkinds) perfect_specialization_finder = PerfectSpecializationFinder(self.cpu) perfect_specialization_finder.find_nodes_loop(loop) - self.check_specnodes(loop.specnodes, spectext) + self.check_specnodes(loop.token.specnodes, spectext) return (loop.getboxes(), perfect_specialization_finder.getnode) def test_find_nodes_simple(self): @@ -1062,6 +1062,9 @@ finish(p1) """ self.find_bridge(ops, 'Not', 'Not') + self.find_bridge(ops, 'Not', + 'Virtual(node_vtable, valuedescr=Not)', + mismatch=True) def test_bridge_array_virtual_1(self): ops = """ Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_optimizeopt.py Wed Sep 30 13:15:23 2009 @@ -147,12 +147,11 @@ cpu = self.cpu perfect_specialization_finder = PerfectSpecializationFinder(cpu) perfect_specialization_finder.find_nodes_loop(loop) - self.check_specnodes(loop.specnodes, spectext) + self.check_specnodes(loop.token.specnodes, spectext) else: # for cases where we want to see how optimizeopt behaves with # combinations different from the one computed by optimizefindnode - loop.specnodes = self.unpack_specnodes(spectext) - loop.token.specnodes = loop.specnodes + loop.token.specnodes = self.unpack_specnodes(spectext) # optimize_loop_1(self.cpu, loop) # Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_send.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_send.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/test/test_send.py Wed Sep 30 13:15:23 2009 @@ -586,7 +586,27 @@ self.check_loops(oosend=0) else: self.check_loops(call=0) - + + def test_generalize_loop(self): + myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) + class A: + def __init__(self, n): + self.n = n + def extern(obj): + pass + def fn(i): + obj = A(1) + while i > 0: + myjitdriver.can_enter_jit(i=i, obj=obj) + myjitdriver.jit_merge_point(i=i, obj=obj) + obj = A(obj.n + 1) + if i < 10: + extern(obj) + i -= 1 + return obj.n + res = self.meta_interp(fn, [20], policy=StopAtXPolicy(extern)) + assert res == 21 + class TestOOtype(SendTests, OOJitMixin): pass Modified: pypy/branch/kill-jumptarget/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/metainterp/warmspot.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/metainterp/warmspot.py Wed Sep 30 13:15:23 2009 @@ -696,8 +696,8 @@ # class MachineCodeEntryPoint(object): next = None # linked list - def __init__(self, entry_executable_token, *greenargs): - self.entry_executable_token = entry_executable_token + def __init__(self, entry_loop_token, *greenargs): + self.entry_loop_token = entry_loop_token i = 0 for name in green_args_names: setattr(self, 'green_' + name, greenargs[i]) @@ -825,7 +825,7 @@ return metainterp = MetaInterp(metainterp_sd) try: - executable_token = metainterp.compile_and_run_once(*args) + loop_token = metainterp.compile_and_run_once(*args) except warmrunnerdesc.ContinueRunningNormally: # the trace got too long, reset the counter self.mccounters[argshash] = 0 @@ -837,21 +837,20 @@ cell = self.mcentrypoints[argshash] if not cell.equalkey(*greenargs): # hash collision - executable_token = self.handle_hash_collision(cell, - argshash, - *args) - if executable_token is None: + loop_token = self.handle_hash_collision(cell, argshash, + *args) + if loop_token is None: return else: # get the assembler and fill in the boxes cell.set_future_values(*args[num_green_args:]) - executable_token = cell.entry_executable_token + loop_token = cell.entry_loop_token # ---------- execute assembler ---------- while True: # until interrupted by an exception metainterp_sd.profiler.start_running() - fail_descr = metainterp_sd.cpu.execute_token(executable_token) + fail_descr = metainterp_sd.cpu.execute_token(loop_token) metainterp_sd.profiler.end_running() - executable_token = fail_descr.handle_fail(metainterp_sd) + loop_token = fail_descr.handle_fail(metainterp_sd) maybe_compile_and_run._dont_inline_ = True @@ -867,7 +866,7 @@ nextcell.next = firstcell self.mcentrypoints[argshash] = nextcell nextcell.set_future_values(*args[num_green_args:]) - return nextcell.entry_executable_token + return nextcell.entry_loop_token cell = nextcell # not found at all, do profiling counter = self.mccounters[argshash] @@ -927,9 +926,9 @@ key.counter = 0 def attach_unoptimized_bridge_from_interp(self, greenkey, - entry_executable_token): + entry_loop_token): greenargs = self.unwrap_greenkey(greenkey) - newcell = MachineCodeEntryPoint(entry_executable_token, *greenargs) + newcell = MachineCodeEntryPoint(entry_loop_token, *greenargs) argshash = self.getkeyhash(*greenargs) & self.hashtablemask oldcell = self.mcentrypoints[argshash] newcell.next = oldcell # link From arigo at codespeak.net Wed Sep 30 14:18:23 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 14:18:23 +0200 (CEST) Subject: [pypy-svn] r68021 - in pypy/branch/kill-jumptarget/pypy/jit/backend: . llsupport llsupport/test test Message-ID: <20090930121823.C2C9316801B@codespeak.net> Author: arigo Date: Wed Sep 30 14:18:23 2009 New Revision: 68021 Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/descr.py pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/llmodel.py pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/test/test_runner.py pypy/branch/kill-jumptarget/pypy/jit/backend/model.py pypy/branch/kill-jumptarget/pypy/jit/backend/test/test_random.py Log: Fixes to the interface. Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/descr.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/descr.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/descr.py Wed Sep 30 14:18:23 2009 @@ -1,7 +1,7 @@ from pypy.rpython.lltypesystem import lltype from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr -from pypy.jit.metainterp.history import BasicFailDescr +from pypy.jit.metainterp.history import BasicFailDescr, LoopToken from pypy.jit.metainterp.resoperation import ResOperation, rop # The point of the class organization in this file is to make instances @@ -165,7 +165,7 @@ class BaseCallDescr(AbstractDescr): _clsname = '' - executable_token = None + loop_token = None arg_classes = '' # <-- annotation hack def __init__(self, arg_classes): @@ -186,8 +186,8 @@ raise NotImplementedError def get_token_for_call(self, cpu): - if self.executable_token is not None: - return self.executable_token + if self.loop_token is not None: + return self.loop_token args = [BoxInt()] + self.instantiate_arg_classes() if self.get_result_size(cpu.translate_support_code) == 0: result = None @@ -205,9 +205,10 @@ ResOperation(rop.FINISH, result_list, None, descr=BasicFailDescr())] operations[1].fail_args = [] - executable_token = cpu.compile_loop(args, operations) - self.executable_token = executable_token - return executable_token + loop_token = LoopToken() + cpu.compile_loop(args, operations, loop_token) + self.loop_token = loop_token + return loop_token def repr_of_descr(self): return '<%s>' % self._clsname Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/llmodel.py Wed Sep 30 14:18:23 2009 @@ -409,9 +409,9 @@ if not we_are_translated(): assert (list(calldescr.arg_classes) == [arg.type for arg in args[1:]]) - executable_token = calldescr.get_token_for_call(self) + loop_token = calldescr.get_token_for_call(self) set_future_values(self, args) - self.execute_token(executable_token) + self.execute_token(loop_token) # Note: if an exception is set, the rest of the code does a bit of # nonsense but nothing wrong (the return value should be ignored) if calldescr.returns_a_pointer(): Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/test/test_runner.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/test/test_runner.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/llsupport/test/test_runner.py Wed Sep 30 14:18:23 2009 @@ -7,7 +7,7 @@ pass class MyLLCPU(AbstractLLCPU): - def compile_loop(self, inputargs, operations): + def compile_loop(self, inputargs, operations, looptoken): py.test.skip("llsupport test: cannot compile operations") Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/model.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/model.py Wed Sep 30 14:18:23 2009 @@ -8,17 +8,21 @@ """Called once by the front-end when the program starts.""" pass - def compile_loop(self, inputargs, operations): + def compile_loop(self, inputargs, operations, looptoken): """Assemble the given loop. - Return an opaque token to be consumed by execute_token""" + Extra attributes should be put in the LoopToken to + point to the compiled loop in assembler. + """ raise NotImplementedError def compile_bridge(self, faildescr, inputargs, operations): - """Assemble the bridge""" + """Assemble the bridge. + The FailDescr is the descr of the original guard that failed. + """ raise NotImplementedError - def execute_token(self, executable_token): - """Execute the generated code referenced by the executable_token + def execute_token(self, looptoken): + """Execute the generated code referenced by the looptoken. Returns the ResOperation that failed, of type rop.FAIL. Use set_future_value_xxx() before, and get_latest_value_xxx() after. """ Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/test/test_random.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/test/test_random.py Wed Sep 30 14:18:23 2009 @@ -159,12 +159,13 @@ #print >>s, ' operations[%d].suboperations = [' % i #print >>s, ' ResOperation(rop.FAIL, [%s], None)]' % ( # ', '.join([names[v] for v in op.args])) - print >>s, ' executable_token = cpu.compile_loop(inputargs, operations)' + print >>s, ' looptoken = LoopToken()' + print >>s, ' cpu.compile_loop(inputargs, operations, looptoken)' if hasattr(self.loop, 'inputargs'): for i, v in enumerate(self.loop.inputargs): print >>s, ' cpu.set_future_value_int(%d, %d)' % (i, v.value) - print >>s, ' op = cpu.execute_token(executable_token)' + print >>s, ' op = cpu.execute_token(looptoken)' if self.should_fail_by is None: for i, v in enumerate(self.loop.operations[-1].args): print >>s, ' assert cpu.get_latest_value_int(%d) == %d' % ( @@ -401,13 +402,13 @@ loop = TreeLoop('test_random_function') loop.inputargs = startvars[:] loop.operations = [] + loop.token = LoopToken() builder = builder_factory(cpu, loop, startvars[:]) self.generate_ops(builder, r, loop, startvars) self.builder = builder self.loop = loop - self.executable_token = cpu.compile_loop(loop.inputargs, - loop.operations) + cpu.compile_loop(loop.inputargs, loop.operations, loop.token) def generate_ops(self, builder, r, loop, startvars): block_length = demo_conftest.option.block_length @@ -469,7 +470,7 @@ for i, v in enumerate(self.values): cpu.set_future_value_int(i, v) - fail = cpu.execute_token(self.executable_token) + fail = cpu.execute_token(self.loop.token) assert fail is self.should_fail_by.descr for i, v in enumerate(self.get_fail_args()): value = cpu.get_latest_value_int(i) @@ -536,17 +537,15 @@ args = [x.clonebox() for x in subset] rl = RandomLoop(self.builder.cpu, self.builder.fork, r, args) - executable_token = self.cpu.compile_loop(rl.loop.inputargs, - rl.loop.operations) + self.cpu.compile_loop(rl.loop.inputargs, rl.loop.operations, + rl.loop.token) # done - jump_op = ResOperation(rop.JUMP, subset, None) - jump_op.jump_target = LoopToken() - jump_op.jump_target.executable_token = executable_token self.should_fail_by = rl.should_fail_by self.expected = rl.expected assert len(rl.loop.inputargs) == len(args) # The new bridge's execution will end normally at its FINISH. # Just replace the FINISH with the JUMP to the new loop. + jump_op = ResOperation(rop.JUMP, subset, None, descr=rl.loop.token) subloop.operations[-1] = jump_op self.guard_op = rl.guard_op self.prebuilt_ptr_consts += rl.prebuilt_ptr_consts From fijal at codespeak.net Wed Sep 30 14:30:48 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 14:30:48 +0200 (CEST) Subject: [pypy-svn] r68022 - in pypy/trunk/pypy: jit/metainterp rlib Message-ID: <20090930123048.C9EC4168016@codespeak.net> Author: fijal Date: Wed Sep 30 14:30:48 2009 New Revision: 68022 Modified: pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/dump.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/warmspot.py pypy/trunk/pypy/rlib/jit.py Log: Kill the DEBUG constant and replace it with debug attr on staticdata Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Wed Sep 30 14:30:48 2009 @@ -39,7 +39,6 @@ """Try to compile a new loop by closing the current history back to the first operation. """ - from pypy.jit.metainterp.pyjitpl import DEBUG history = metainterp.history loop = create_empty_loop(metainterp) loop.greenkey = greenkey @@ -58,7 +57,7 @@ except InvalidLoop: return None if old_loop_token is not None: - if DEBUG > 0: + if metainterp.staticdata.debug > 0: debug_print("reusing old loop") return old_loop_token executable_token = send_loop_to_backend(metainterp_sd, loop, "loop") @@ -100,8 +99,7 @@ loop._ignore_during_counting = True log.info("compiled new " + type) else: - from pypy.jit.metainterp.pyjitpl import DEBUG - if DEBUG > 0: + if metainterp_sd.debug > 0: debug_print("compiled new " + type) return executable_token @@ -118,8 +116,7 @@ metainterp_sd.stats.compiled() log.info("compiled new bridge") else: - from pypy.jit.metainterp.pyjitpl import DEBUG - if DEBUG > 0: + if metainterp_sd.debug > 0: debug_print("compiled new bridge") # ____________________________________________________________ Modified: pypy/trunk/pypy/jit/metainterp/dump.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/dump.py (original) +++ pypy/trunk/pypy/jit/metainterp/dump.py Wed Sep 30 14:30:48 2009 @@ -103,7 +103,7 @@ args = [] def wrapper_callback(src, *newargs): args.extend(newargs) - opimpl.argspec(wrapper_callback, 0)(src, 'pc') + opimpl.argspec(wrapper_callback)(src, 'pc') args = map(str, args) Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Wed Sep 30 14:30:48 2009 @@ -14,6 +14,7 @@ from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize +from pypy.rlib.jit import DEBUG_OFF, DEBUG_PROFILE, DEBUG_STEPS, DEBUG_DETAILED # ____________________________________________________________ @@ -21,22 +22,6 @@ for arg in args: assert isinstance(arg, (Box, Const)) -# debug level: 0 off, 1 normal, 2 detailed -DEBUG = 1 - -# translate.py overrides DEBUG with the --jit-debug=xxx option -_DEBUG_LEVEL = {"off": 0, - "profile": 0, - "steps": 1, - "detailed": 2} - -def log(msg, event_kind='info'): - if not we_are_translated(): - getattr(history.log, event_kind)(msg) - elif DEBUG: - debug_print(msg) - - class arguments(object): def __init__(self, *argtypes): self.argtypes = argtypes @@ -51,20 +36,20 @@ return NotImplemented return self.argtypes != other.argtypes - def __call__(self, func, DEBUG=DEBUG): + def __call__(self, func): argtypes = unrolling_iterable(self.argtypes) def wrapped(self, orgpc): args = (self, ) - if DEBUG >= 2: - s = '%s:%d\t%s' % (self.jitcode.name, orgpc, name) - else: - s = '' + #if DEBUG >= DEBUG_DETAILED: + # s = '%s:%d\t%s' % (self.jitcode.name, orgpc, name) + #else: + s = '' for argspec in argtypes: if argspec == "box": box = self.load_arg() args += (box, ) - if DEBUG >= 2: - s += '\t' + box.repr_rpython() + #if DEBUG >= DEBUG_DETAILED: + # s += '\t' + box.repr_rpython() elif argspec == "constbox": args += (self.load_const_arg(), ) elif argspec == "int": @@ -100,12 +85,12 @@ args += (methdescr, ) else: assert 0, "unknown argtype declaration: %r" % (argspec,) - if DEBUG >= 2: - debug_print(s) + #if DEBUG >= DEBUG_DETAILED: + # debug_print(s) val = func(*args) - if DEBUG >= 2: - reprboxes = ' '.join([box.repr_rpython() for box in self.env]) - debug_print(' \x1b[34menv=[%s]\x1b[0m' % (reprboxes,)) + #if DEBUG >= DEBUG_DETAILED: + # reprboxes = ' '.join([box.repr_rpython() for box in self.env]) + # debug_print(' \x1b[34menv=[%s]\x1b[0m' % (reprboxes,)) if val is None: val = False return val @@ -807,7 +792,7 @@ def opimpl_jit_merge_point(self, pc): if not self.metainterp.is_blackholing(): self.generate_merge_point(pc, self.env) - if DEBUG > 0: + if self.metainterp.staticdata.debug > DEBUG_PROFILE: self.debug_merge_point() if self.metainterp.seen_can_enter_jit: self.metainterp.seen_can_enter_jit = False @@ -883,8 +868,9 @@ self.pc = pc self.exception_target = exception_target self.env = env - if DEBUG >= 2: + if self.metainterp.staticdata.debug >= DEBUG_DETAILED: values = ' '.join([box.repr_rpython() for box in self.env]) + log = self.metainterp.staticdata.log log('setup_resume_at_op %s:%d [%s] %d' % (self.jitcode.name, self.pc, values, self.exception_target)) @@ -970,7 +956,7 @@ def __init__(self, portal_graph, graphs, cpu, stats, options, profile=None, warmrunnerdesc=None, - leave_graph=None): + leave_graph=None, debug=DEBUG_STEPS): self.portal_graph = portal_graph self.cpu = cpu self.stats = stats @@ -997,6 +983,7 @@ backendmodule = backendmodule.split('.')[-2] self.jit_starting_line = 'JIT starting (%s)' % backendmodule self.leave_graph = leave_graph + self.debug = debug def _freeze_(self): return True @@ -1018,7 +1005,7 @@ if not self.globaldata.initialized: self._setup_class_sizes() self.cpu.setup_once() - log(self.jit_starting_line) + self.log(self.jit_starting_line) if not self.profiler.initialized: self.profiler.start() self.profiler.initialized = True @@ -1061,6 +1048,14 @@ self._register_opcode(name) return self.opname_to_index[name] + # ---------------- logging ------------------------ + + def log(self, msg, event_kind='info'): + if not we_are_translated(): + getattr(history.log, event_kind)(msg) + elif self.debug: + debug_print(msg) + # ____________________________________________________________ class MetaInterpGlobalData(object): @@ -1280,7 +1275,7 @@ def switch_to_blackhole(self): self.history = None # start blackholing self.staticdata.stats.aborted() - log('~~~ ABORTING TRACING', event_kind='event') + self.staticdata.log('~~~ ABORTING TRACING', event_kind='event') self.staticdata.profiler.end_tracing() self.staticdata.profiler.start_blackhole() @@ -1294,7 +1289,8 @@ # Execute the frames forward until we raise a DoneWithThisFrame, # a ContinueRunningNormally, or a GenerateMergePoint exception. self.staticdata.stats.entered() - log('~~~ ENTER' + self.blackholing_text(), event_kind='event') + self.staticdata.log('~~~ ENTER' + self.blackholing_text(), + event_kind='event') try: while True: self.framestack[-1].run_one_step() @@ -1306,7 +1302,8 @@ self.staticdata.profiler.end_blackhole() else: self.staticdata.profiler.end_tracing() - log('~~~ LEAVE' + self.blackholing_text(), event_kind='event') + self.staticdata.log('~~~ LEAVE' + self.blackholing_text(), + event_kind='event') def interpret(self): if we_are_translated(): @@ -1321,7 +1318,7 @@ raise def compile_and_run_once(self, *args): - log('Switching from interpreter to compiler') + self.staticdata.log('Switching from interpreter to compiler') original_boxes = self.initialize_state_from_start(*args) self.current_merge_points = [(original_boxes, 0)] num_green_args = self.staticdata.num_green_args Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Wed Sep 30 14:30:48 2009 @@ -22,18 +22,18 @@ from pypy.jit.metainterp.policy import JitPolicy from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper from pypy.jit.metainterp.jitprof import Profiler +from pypy.rlib.jit import DEBUG_STEPS, DEBUG_DETAILED, DEBUG_OFF, DEBUG_PROFILE # ____________________________________________________________ # Bootstrapping -def apply_jit(translator, backend_name="auto", debug_level="steps", +def apply_jit(translator, backend_name="auto", debug_level=DEBUG_STEPS, inline=False, **kwds): if 'CPUClass' not in kwds: from pypy.jit.backend.detect_cpu import getcpuclass kwds['CPUClass'] = getcpuclass(backend_name) - pyjitpl.DEBUG = pyjitpl._DEBUG_LEVEL[debug_level] - if debug_level != "off": + if debug_level >= DEBUG_PROFILE: profile = Profiler else: profile = None @@ -69,6 +69,7 @@ warmrunnerdesc.state.set_param_trace_eagerness(2) # for tests warmrunnerdesc.state.set_param_trace_limit(trace_limit) warmrunnerdesc.state.set_param_inlining(inline) + warmrunnerdesc.state.set_param_debug(DEBUG_STEPS) warmrunnerdesc.state.create_tables_now() # for tests if hash_bits: warmrunnerdesc.state.set_param_hash_bits(hash_bits) @@ -228,7 +229,8 @@ really_remove_asserts=True) def build_meta_interp(self, CPUClass, translate_support_code=False, - view="auto", profile=None, no_stats=False, **kwds): + view="auto", profile=None, no_stats=False, debug=2, + **kwds): assert CPUClass is not None opt = history.Options(**kwds) if no_stats: @@ -249,7 +251,8 @@ self.stats, opt, profile=profile, warmrunnerdesc=self, - leave_graph=self.leave_graph) + leave_graph=self.leave_graph, + debug=debug) def make_enter_function(self): WarmEnterState = make_state_class(self) @@ -794,6 +797,9 @@ else: raise ValueError("unknown optimizer") + def set_param_debug(self, value): + metainterp_sd.debug = value + def create_tables_now(self): count = 1 << self.hashbits self.hashtablemask = count - 1 Modified: pypy/trunk/pypy/rlib/jit.py ============================================================================== --- pypy/trunk/pypy/rlib/jit.py (original) +++ pypy/trunk/pypy/rlib/jit.py Wed Sep 30 14:30:48 2009 @@ -83,12 +83,18 @@ OPTIMIZER_SIMPLE = 0 OPTIMIZER_FULL = 1 +DEBUG_OFF = 0 +DEBUG_PROFILE = 1 +DEBUG_STEPS = 2 +DEBUG_DETAILED = 3 + PARAMETERS = {'threshold': 1000, 'trace_eagerness': 200, 'hash_bits': 14, 'trace_limit': 10000, 'inlining': False, 'optimizer': OPTIMIZER_FULL, + 'debug' : DEBUG_STEPS, } unroll_parameters = unrolling_iterable(PARAMETERS.keys()) From pedronis at codespeak.net Wed Sep 30 14:44:08 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 30 Sep 2009 14:44:08 +0200 (CEST) Subject: [pypy-svn] r68023 - pypy/trunk/pypy/jit/backend/test Message-ID: <20090930124408.DC18B168016@codespeak.net> Author: pedronis Date: Wed Sep 30 14:44:07 2009 New Revision: 68023 Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py Log: this is already tested in test_executor Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/runner_test.py (original) +++ pypy/trunk/pypy/jit/backend/test/runner_test.py Wed Sep 30 14:44:07 2009 @@ -259,14 +259,6 @@ 'int', descr=calldescr) assert res.value == 2 * num - def test_executor(self): - cpu = self.cpu - x = execute(cpu, rop.INT_ADD, None, BoxInt(100), ConstInt(42)) - assert x.value == 142 - if self.type_system == 'lltype': - s = execute(cpu, rop.NEWSTR, None, BoxInt(8)) - assert len(s.getref(lltype.Ptr(rstr.STR)).chars) == 8 - def test_lshift(self): res = execute(self.cpu, rop.INT_LSHIFT, None, BoxInt(10), ConstInt(4)) assert res.value == 10 << 4 From arigo at codespeak.net Wed Sep 30 14:50:44 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 14:50:44 +0200 (CEST) Subject: [pypy-svn] r68024 - in pypy/branch/kill-jumptarget/pypy/jit/backend/x86: . test Message-ID: <20090930125044.D6DB3168016@codespeak.net> Author: arigo Date: Wed Sep 30 14:50:43 2009 New Revision: 68024 Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/x86/assembler.py pypy/branch/kill-jumptarget/pypy/jit/backend/x86/regalloc.py pypy/branch/kill-jumptarget/pypy/jit/backend/x86/runner.py pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_recompilation.py pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_regalloc.py pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_regalloc2.py pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_runner.py Log: Fix the interface in the x86 backend. Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/x86/assembler.py Wed Sep 30 14:50:43 2009 @@ -62,12 +62,6 @@ if name.upper() == name: setattr(MachineCodeBlockWrapper, name, _new_method(name)) -class ExecutableToken386(object): - _x86_loop_code = 0 - _x86_bootstrap_code = 0 - _x86_stack_depth = 0 - _x86_arglocs = None - class Assembler386(object): mc = None mc2 = None @@ -123,21 +117,24 @@ self.mc = MachineCodeBlockWrapper() self.mc2 = MachineCodeBlockWrapper() - def assemble_loop(self, inputargs, operations): + def assemble_loop(self, inputargs, operations, looptoken): + """adds the following attributes to looptoken: + _x86_loop_code (an integer giving an address) + _x86_bootstrap_code (an integer giving an address) + _x86_stack_depth + _x86_arglocs + """ self.make_sure_mc_exists() regalloc = RegAlloc(self, self.cpu.translate_support_code) - arglocs = regalloc.prepare_loop(inputargs, operations) - executable_token = ExecutableToken386() - executable_token._x86_arglocs = arglocs - executable_token._x86_bootstrap_code = self.mc.tell() + arglocs = regalloc.prepare_loop(inputargs, operations, looptoken) + looptoken._x86_arglocs = arglocs + looptoken._x86_bootstrap_code = self.mc.tell() adr_stackadjust = self._assemble_bootstrap_code(inputargs, arglocs) - executable_token._x86_loop_code = self.mc.tell() - self._executable_token = executable_token + looptoken._x86_loop_code = self.mc.tell() + looptoken._x86_stack_depth = -1 # temporarily stack_depth = self._assemble(regalloc, operations) - self._executable_token = None self._patch_stackadjust(adr_stackadjust, stack_depth) - executable_token._x86_stack_depth = stack_depth - return executable_token + looptoken._x86_stack_depth = stack_depth def assemble_bridge(self, faildescr, inputargs, operations): self.make_sure_mc_exists() @@ -168,9 +165,9 @@ if we_are_translated() or self.cpu.dont_keepalive_stuff: self._regalloc = None # else keep it around for debugging stack_depth = regalloc.sm.stack_depth - jump_target = regalloc.jump_target - if jump_target is not None: - target_stack_depth = jump_target.executable_token._x86_stack_depth + jump_target_descr = regalloc.jump_target_descr + if jump_target_descr is not None: + target_stack_depth = jump_target_descr._x86_stack_depth stack_depth = max(stack_depth, target_stack_depth) return stack_depth @@ -757,19 +754,11 @@ mark = self._regalloc.get_mark_gc_roots(gcrootmap) gcrootmap.put(rffi.cast(llmemory.Address, self.mc.tell()), mark) - def _get_executable_token(self, loop_token): - if loop_token is not None: - return loop_token.executable_token - assert self._executable_token is not None - return self._executable_token - def target_arglocs(self, loop_token): - executable_token = self._get_executable_token(loop_token) - return executable_token._x86_arglocs + return loop_token._x86_arglocs def closing_jump(self, loop_token): - executable_token = self._get_executable_token(loop_token) - self.mc.JMP(rel32(executable_token._x86_loop_code)) + self.mc.JMP(rel32(loop_token._x86_loop_code)) genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/x86/regalloc.py Wed Sep 30 14:50:43 2009 @@ -3,7 +3,8 @@ """ from pypy.jit.metainterp.history import (Box, Const, ConstInt, ConstPtr, - ResOperation, ConstAddr, BoxPtr) + ResOperation, ConstAddr, BoxPtr, + LoopToken) from pypy.jit.backend.x86.ri386 import * from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi, rstr from pypy.rlib.objectmodel import we_are_translated @@ -59,7 +60,7 @@ self.assembler = assembler self.translate_support_code = translate_support_code # to be read/used by the assembler too - self.jump_target = None + self.jump_target_descr = None def _prepare(self, inputargs, operations): self.sm = X86StackManager() @@ -71,10 +72,10 @@ stack_manager = self.sm, assembler = self.assembler) - def prepare_loop(self, inputargs, operations): + def prepare_loop(self, inputargs, operations, looptoken): self._prepare(inputargs, operations) jump = operations[-1] - loop_consts = self._compute_loop_consts(inputargs, jump) + loop_consts = self._compute_loop_consts(inputargs, jump, looptoken) self.loop_consts = loop_consts return self._process_inputargs(inputargs) @@ -110,8 +111,8 @@ self.rm.possibly_free_vars(inputargs) return locs - def _compute_loop_consts(self, inputargs, jump): - if jump.opnum != rop.JUMP or jump.jump_target is not None: + def _compute_loop_consts(self, inputargs, jump, looptoken): + if jump.opnum != rop.JUMP or jump.descr is not looptoken: loop_consts = {} else: loop_consts = {} @@ -618,9 +619,11 @@ def consider_jump(self, op, ignored): assembler = self.assembler - assert self.jump_target is None - self.jump_target = op.jump_target - arglocs = assembler.target_arglocs(self.jump_target) + assert self.jump_target_descr is None + descr = op.descr + assert isinstance(descr, LoopToken) + self.jump_target_descr = descr + arglocs = assembler.target_arglocs(self.jump_target_descr) # compute 'tmploc' to be all_regs[0] by spilling what is there box = TempBox() tmpreg = X86RegisterManager.all_regs[0] @@ -631,7 +634,7 @@ remap_stack_layout(assembler, src_locations, dst_locations, tmploc) self.rm.possibly_free_var(box) self.rm.possibly_free_vars(op.args) - assembler.closing_jump(self.jump_target) + assembler.closing_jump(self.jump_target_descr) def consider_debug_merge_point(self, op, ignored): pass Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/x86/runner.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/x86/runner.py Wed Sep 30 14:50:43 2009 @@ -33,8 +33,8 @@ def setup_once(self): pass - def compile_loop(self, inputargs, operations): - return self.assembler.assemble_loop(inputargs, operations) + def compile_loop(self, inputargs, operations, looptoken): + self.assembler.assemble_loop(inputargs, operations, looptoken) def compile_bridge(self, faildescr, inputargs, operations): self.assembler.assemble_bridge(faildescr, inputargs, operations) Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_recompilation.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_recompilation.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_recompilation.py Wed Sep 30 14:50:43 2009 @@ -33,7 +33,7 @@ jump(i1) ''' loop = self.interpret(ops, [0]) - previous = loop.executable_token._x86_stack_depth + previous = loop.token._x86_stack_depth assert self.getint(0) == 20 ops = ''' [i1] @@ -47,7 +47,7 @@ finish(i3, i4, i5, i6, i7, i8, i9) ''' bridge = self.attach_bridge(ops, loop, -2) - descr = loop._loop.operations[2].descr + descr = loop.operations[2].descr new = descr._x86_bridge_stack_depth assert new > previous self.cpu.set_future_value_int(0, 0) @@ -73,12 +73,12 @@ ''', [1]) ops = ''' [i3] - jump(i3, 1, 2, 3, 4, 5, 6, 7) + jump(i3, 1, 2, 3, 4, 5, 6, 7, descr=looptoken) ''' - bridge = self.attach_bridge(ops, other_loop, 0, jump_target=loop) + bridge = self.attach_bridge(ops, other_loop, 0, looptoken=loop.token) self.cpu.set_future_value_int(0, 1) fail = self.run(other_loop) - assert fail is loop._loop.operations[2].descr + assert fail is loop.operations[2].descr def test_bridge_jumps_to_self_deeper(self): loop = self.interpret(''' @@ -103,11 +103,11 @@ i7 = int_add(i3, i6) i12 = int_add(i7, i8) i11 = int_add(i12, i6) - jump(i3, i12, i11, i10, i6, i7) + jump(i3, i12, i11, i10, i6, i7, descr=looptoken) ''' - bridge = self.attach_bridge(ops, loop, 5, jump_target=loop) - guard_op = loop._loop.operations[5] - loop_stack_depth = loop.executable_token._x86_stack_depth + bridge = self.attach_bridge(ops, loop, 5, looptoken=loop.token) + guard_op = loop.operations[5] + loop_stack_depth = loop.token._x86_stack_depth assert guard_op.descr._x86_bridge_stack_depth > loop_stack_depth self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) @@ -132,9 +132,9 @@ assert self.getint(1) == 1 ops = ''' [i97, i3] - jump(i3, 0, 1) + jump(i3, 0, 1, descr=looptoken) ''' - bridge = self.attach_bridge(ops, loop, 4, jump_target=loop) + bridge = self.attach_bridge(ops, loop, 4, looptoken=loop.token) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) self.cpu.set_future_value_int(2, 0) Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_regalloc.py Wed Sep 30 14:50:43 2009 @@ -83,16 +83,14 @@ namespace = locals().copy() type_system = 'lltype' - def parse(self, s, boxkinds=None, jump_target=None): + def parse(self, s, boxkinds=None): return parse(s, self.cpu, self.namespace, type_system=self.type_system, - jump_target=jump_target, boxkinds=boxkinds) - def interpret(self, ops, args, jump_target=None, run=True): - loop = self.parse(ops, jump_target=jump_target) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) + def interpret(self, ops, args, run=True): + loop = self.parse(ops) + self.cpu.compile_loop(loop.inputargs, loop.operations, loop.token) for i, arg in enumerate(args): if isinstance(arg, int): self.cpu.set_future_value_int(i, arg) @@ -101,11 +99,8 @@ llgcref = lltype.cast_opaque_ptr(llmemory.GCREF, arg) self.cpu.set_future_value_ref(i, llgcref) if run: - self.cpu.execute_token(executable_token) - loop_token = LoopToken() - loop_token.executable_token = executable_token - loop_token._loop = loop - return loop_token + self.cpu.execute_token(loop.token) + return loop def getint(self, index): return self.cpu.get_latest_value_int(index) @@ -118,16 +113,19 @@ gcref = self.cpu.get_latest_value_ref(index) return lltype.cast_opaque_ptr(T, gcref) - def attach_bridge(self, ops, loop_token, guard_op_index, **kwds): - guard_op = loop_token._loop.operations[guard_op_index] + def attach_bridge(self, ops, loop, guard_op_index, looptoken=None, **kwds): + if looptoken is not None: + self.namespace = self.namespace.copy() + self.namespace['looptoken'] = looptoken + guard_op = loop.operations[guard_op_index] assert guard_op.is_guard() bridge = self.parse(ops, **kwds) faildescr = guard_op.descr self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations) return bridge - def run(self, loop_token): - return self.cpu.execute_token(loop_token.executable_token) + def run(self, loop): + return self.cpu.execute_token(loop.token) class TestRegallocSimple(BaseTestRegalloc): def test_simple_loop(self): @@ -162,9 +160,9 @@ loop2 = self.interpret(ops2, [0]) bridge_ops = ''' [i4] - jump(i4, i4, i4, i4) + jump(i4, i4, i4, i4, descr=looptoken) ''' - bridge = self.attach_bridge(bridge_ops, loop2, 4, jump_target=loop) + bridge = self.attach_bridge(bridge_ops, loop2, 4, looptoken=loop.token) self.cpu.set_future_value_int(0, 0) self.run(loop2) assert self.getint(0) == 31 Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_regalloc2.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_regalloc2.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_regalloc2.py Wed Sep 30 14:50:43 2009 @@ -1,6 +1,6 @@ import py from pypy.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ - BoxPtr, ConstPtr, BasicFailDescr + BoxPtr, ConstPtr, BasicFailDescr, LoopToken from pypy.jit.metainterp.resoperation import rop from pypy.jit.backend.x86.runner import CPU @@ -17,9 +17,10 @@ ResOperation(rop.FINISH, [v4, v3], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) - executable_token = cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + cpu.compile_loop(inputargs, operations, looptoken) cpu.set_future_value_int(0, 9) - cpu.execute_token(executable_token) + cpu.execute_token(looptoken) assert cpu.get_latest_value_int(0) == (9 >> 3) assert cpu.get_latest_value_int(1) == (~18) @@ -38,9 +39,10 @@ ResOperation(rop.FINISH, [v4, v3, tmp5], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) - executable_token = cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + cpu.compile_loop(inputargs, operations, looptoken) cpu.set_future_value_int(0, -10) - cpu.execute_token(executable_token) + cpu.execute_token(looptoken) assert cpu.get_latest_value_int(0) == 0 assert cpu.get_latest_value_int(1) == -1000 assert cpu.get_latest_value_int(2) == 1 @@ -133,7 +135,8 @@ ResOperation(rop.FINISH, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) - executable_token = cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + cpu.compile_loop(inputargs, operations, looptoken) cpu.set_future_value_int(0, -13) cpu.set_future_value_int(1, 10) cpu.set_future_value_int(2, 10) @@ -144,7 +147,7 @@ cpu.set_future_value_int(7, 46) cpu.set_future_value_int(8, -12) cpu.set_future_value_int(9, 26) - cpu.execute_token(executable_token) + cpu.execute_token(looptoken) assert cpu.get_latest_value_int(0) == 0 assert cpu.get_latest_value_int(1) == 0 assert cpu.get_latest_value_int(2) == 0 @@ -246,7 +249,8 @@ ResOperation(rop.FINISH, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) - executable_token = cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + cpu.compile_loop(inputargs, operations, looptoken) cpu.set_future_value_int(0, 17) cpu.set_future_value_int(1, -20) cpu.set_future_value_int(2, -6) @@ -257,7 +261,7 @@ cpu.set_future_value_int(7, 9) cpu.set_future_value_int(8, 49) cpu.set_future_value_int(9, 8) - cpu.execute_token(executable_token) + cpu.execute_token(looptoken) assert cpu.get_latest_value_int(0) == 0 assert cpu.get_latest_value_int(1) == 8 assert cpu.get_latest_value_int(2) == 1 Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_runner.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_runner.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/x86/test/test_runner.py Wed Sep 30 14:50:43 2009 @@ -1,6 +1,6 @@ import py from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr, rclass -from pypy.jit.metainterp.history import ResOperation +from pypy.jit.metainterp.history import ResOperation, LoopToken from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr, Box, BasicFailDescr) from pypy.jit.backend.x86.runner import CPU @@ -73,20 +73,20 @@ z = BoxInt(579) t = BoxInt(455) u = BoxInt(0) # False + looptoken = LoopToken() operations = [ ResOperation(rop.INT_ADD, [x, y], z), ResOperation(rop.INT_SUB, [y, ConstInt(1)], t), ResOperation(rop.INT_EQ, [t, ConstInt(0)], u), ResOperation(rop.GUARD_FALSE, [u], None, descr=BasicFailDescr()), - ResOperation(rop.JUMP, [z, t], None), + ResOperation(rop.JUMP, [z, t], None, descr=looptoken), ] - operations[-1].jump_target = None operations[-2].fail_args = [t, z] - executable_token = cpu.compile_loop([x, y], operations) + cpu.compile_loop([x, y], operations, looptoken) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 10) - res = self.cpu.execute_token(executable_token) + res = self.cpu.execute_token(looptoken) assert self.cpu.get_latest_value_int(0) == 0 assert self.cpu.get_latest_value_int(1) == 55 @@ -327,12 +327,13 @@ descr=BasicFailDescr()), ] ops[-2].fail_args = [i1] - executable_token = self.cpu.compile_loop([b], ops) + looptoken = LoopToken() + self.cpu.compile_loop([b], ops, looptoken) if op == rop.INT_IS_TRUE: self.cpu.set_future_value_int(0, b.value) else: self.cpu.set_future_value_ref(0, b.value) - r = self.cpu.execute_token(executable_token) + r = self.cpu.execute_token(looptoken) result = self.cpu.get_latest_value_int(0) if guard == rop.GUARD_FALSE: assert result == execute(self.cpu, op, None, b).value @@ -374,10 +375,11 @@ ] ops[-2].fail_args = [i1] inputargs = [i for i in (a, b) if isinstance(i, Box)] - executable_token = self.cpu.compile_loop(inputargs, ops) + looptoken = LoopToken() + self.cpu.compile_loop(inputargs, ops, looptoken) for i, box in enumerate(inputargs): self.cpu.set_future_value_int(i, box.value) - r = self.cpu.execute_token(executable_token) + r = self.cpu.execute_token(looptoken) result = self.cpu.get_latest_value_int(0) expected = execute(self.cpu, op, None, a, b).value if guard == rop.GUARD_FALSE: @@ -403,10 +405,11 @@ v = next_v ops.append(ResOperation(rop.FINISH, [v], None, descr=BasicFailDescr())) - executable_token = self.cpu.compile_loop([base_v], ops) + looptoken = LoopToken() + self.cpu.compile_loop([base_v], ops, looptoken) assert self.cpu.assembler.mc != old_mc # overflowed self.cpu.set_future_value_int(0, base_v.value) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(looptoken) assert self.cpu.get_latest_value_int(0) == 1024 finally: MachineCodeBlockWrapper.MC_SIZE = orig_size From pedronis at codespeak.net Wed Sep 30 15:18:20 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 30 Sep 2009 15:18:20 +0200 (CEST) Subject: [pypy-svn] r68025 - in pypy/trunk/pypy/jit: backend/test metainterp/test Message-ID: <20090930131820.A4230168009@codespeak.net> Author: pedronis Date: Wed Sep 30 15:18:20 2009 New Revision: 68025 Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py pypy/trunk/pypy/jit/metainterp/test/test_executor.py Log: refactor int operation execute tests like the float ones, increase executor.py coverage Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/runner_test.py (original) +++ pypy/trunk/pypy/jit/backend/test/runner_test.py Wed Sep 30 15:18:20 2009 @@ -259,95 +259,19 @@ 'int', descr=calldescr) assert res.value == 2 * num - def test_lshift(self): - res = execute(self.cpu, rop.INT_LSHIFT, None, BoxInt(10), ConstInt(4)) - assert res.value == 10 << 4 - res = self.execute_operation(rop.INT_LSHIFT, [BoxInt(10), BoxInt(4)], - 'int') - assert res.value == 10 << 4 - res = self.execute_operation(rop.INT_LSHIFT, [BoxInt(-10), BoxInt(4)], - 'int') - assert res.value == -10 << 4 - - def test_uint_rshift(self): - res = self.execute_operation(rop.UINT_RSHIFT, [BoxInt(-1), BoxInt(4)], - 'int') - assert res.value == intmask(r_uint(-1) >> r_uint(4)) - res = self.execute_operation(rop.UINT_RSHIFT, [BoxInt(1), BoxInt(4)], - 'int') - assert res.value == intmask(r_uint(1) >> r_uint(4)) - - def test_binary_operations(self): - minint = -sys.maxint-1 - for opnum, testcases in [ - (rop.INT_ADD, [(10, -2, 8)]), - (rop.INT_SUB, [(10, -2, 12)]), - (rop.INT_MUL, [(-6, -3, 18)]), - (rop.INT_FLOORDIV, [(110, 3, 36), - (-110, 3, -36), - (110, -3, -36), - (-110, -3, 36), - (-110, -1, 110), - (minint, 1, minint)]), - (rop.INT_MOD, [(11, 3, 2), - (-11, 3, -2), - (11, -3, 2), - (-11, -3, -2)]), - (rop.INT_AND, [(0xFF00, 0x0FF0, 0x0F00)]), - (rop.INT_OR, [(0xFF00, 0x0FF0, 0xFFF0)]), - (rop.INT_XOR, [(0xFF00, 0x0FF0, 0xF0F0)]), - (rop.INT_LSHIFT, [(-5, 2, -20), - (-5, 0, -5)]), - (rop.INT_RSHIFT, [(-17, 2, -5), - (19, 1, 9)]), - ]: - for x, y, z in testcases: - res = self.execute_operation(opnum, [BoxInt(x), BoxInt(y)], - 'int') - assert res.value == z - - def test_compare_operations(self): - random_numbers = [-sys.maxint-1, -1, 0, 1, sys.maxint] - def pick(): - r = random.randrange(-99999, 100000) - if r & 1: - return r + def test_int_operations(self): + from pypy.jit.metainterp.test.test_executor import get_int_tests + for opnum, boxargs, retvalue in get_int_tests(): + if len(boxargs) == 2: + args_variants = [(boxargs[0], boxargs[1]), + (boxargs[0], boxargs[1].constbox()), + (boxargs[0].constbox(), boxargs[1])] else: - return random_numbers[r % len(random_numbers)] - minint = -sys.maxint-1 - for opnum, operation in [ - (rop.INT_LT, lambda x, y: x < y), - (rop.INT_LE, lambda x, y: x <= y), - (rop.INT_EQ, lambda x, y: x == y), - (rop.INT_NE, lambda x, y: x != y), - (rop.INT_GT, lambda x, y: x > y), - (rop.INT_GE, lambda x, y: x >= y), - (rop.UINT_LT, lambda x, y: r_uint(x) < r_uint(y)), - (rop.UINT_LE, lambda x, y: r_uint(x) <= r_uint(y)), - (rop.UINT_GT, lambda x, y: r_uint(x) > r_uint(y)), - (rop.UINT_GE, lambda x, y: r_uint(x) >= r_uint(y)), - ]: - for i in range(20): - x = pick() - y = pick() - res = self.execute_operation(opnum, [BoxInt(x), BoxInt(y)], - 'int') - z = int(operation(x, y)) - assert res.value == z - - def test_unary_operations(self): - minint = -sys.maxint-1 - for opnum, testcases in [ - (rop.INT_IS_TRUE, [(0, 0), (1, 1), (2, 1), (-1, 1), (minint, 1)]), - (rop.INT_NEG, [(0, 0), (123, -123), (-23127, 23127)]), - (rop.INT_INVERT, [(0, ~0), (-1, ~(-1)), (123, ~123)]), - (rop.BOOL_NOT, [(0, 1), (1, 0)]), - ]: - for x, y in testcases: - res = self.execute_operation(opnum, [BoxInt(x)], - 'int') - assert res.value == y - + args_variants = [boxargs] + for argboxes in args_variants: + res = self.execute_operation(opnum, argboxes, 'int') + assert res.value == retvalue + def test_float_operations(self): from pypy.jit.metainterp.test.test_executor import get_float_tests for opnum, boxargs, rettype, retvalue in get_float_tests(self.cpu): Modified: pypy/trunk/pypy/jit/metainterp/test/test_executor.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_executor.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_executor.py Wed Sep 30 15:18:20 2009 @@ -1,4 +1,6 @@ import py +import sys, random +from pypy.rlib.rarithmetic import r_uint, intmask from pypy.jit.metainterp.executor import make_execute_list, execute from pypy.jit.metainterp.executor import execute_varargs, execute_nonspec from pypy.jit.metainterp.resoperation import rop @@ -88,6 +90,93 @@ box = execute_nonspec(cpu, rop.STRSETITEM, [box1, box2, box3]) assert box.args == ('strsetitem', box1, box2, box3) +# ints + +def _int_binary_operations(): + minint = -sys.maxint-1 + for opnum, testcases in [ + (rop.INT_ADD, [(10, -2, 8)]), + (rop.INT_SUB, [(10, -2, 12)]), + (rop.INT_MUL, [(-6, -3, 18)]), + (rop.INT_FLOORDIV, [(110, 3, 36), + (-110, 3, -36), + (110, -3, -36), + (-110, -3, 36), + (-110, -1, 110), + (minint, 1, minint)]), + (rop.INT_MOD, [(11, 3, 2), + (-11, 3, -2), + (11, -3, 2), + (-11, -3, -2)]), + (rop.INT_AND, [(0xFF00, 0x0FF0, 0x0F00)]), + (rop.INT_OR, [(0xFF00, 0x0FF0, 0xFFF0)]), + (rop.INT_XOR, [(0xFF00, 0x0FF0, 0xF0F0)]), + (rop.INT_LSHIFT, [(10, 4, 10<<4), + (-5, 2, -20), + (-5, 0, -5)]), + (rop.INT_RSHIFT, [(-17, 2, -5), + (19, 1, 9)]), + (rop.UINT_RSHIFT, [(-1, 4, intmask(r_uint(-1) >> r_uint(4))), + ( 1, 4, intmask(r_uint(1) >> r_uint(4)))]) + ]: + for x, y, z in testcases: + yield opnum, [x, y], z + +def _int_comparison_operations(): + cpu = FakeCPU() + random_numbers = [-sys.maxint-1, -1, 0, 1, sys.maxint] + def pick(): + r = random.randrange(-99999, 100000) + if r & 1: + return r + else: + return random_numbers[r % len(random_numbers)] + minint = -sys.maxint-1 + for opnum, operation in [ + (rop.INT_LT, lambda x, y: x < y), + (rop.INT_LE, lambda x, y: x <= y), + (rop.INT_EQ, lambda x, y: x == y), + (rop.INT_NE, lambda x, y: x != y), + (rop.INT_GT, lambda x, y: x > y), + (rop.INT_GE, lambda x, y: x >= y), + (rop.UINT_LT, lambda x, y: r_uint(x) < r_uint(y)), + (rop.UINT_LE, lambda x, y: r_uint(x) <= r_uint(y)), + (rop.UINT_GT, lambda x, y: r_uint(x) > r_uint(y)), + (rop.UINT_GE, lambda x, y: r_uint(x) >= r_uint(y)), + ]: + for i in range(20): + x = pick() + y = pick() + res = execute_nonspec(cpu, opnum, [BoxInt(x), BoxInt(y)]) + z = int(operation(x, y)) + yield opnum, [x, y], z + +def _int_unary_operations(): + minint = -sys.maxint-1 + for opnum, testcases in [ + (rop.INT_IS_TRUE, [(0, 0), (1, 1), (2, 1), (-1, 1), (minint, 1)]), + (rop.INT_NEG, [(0, 0), (123, -123), (-23127, 23127)]), + (rop.INT_INVERT, [(0, ~0), (-1, ~(-1)), (123, ~123)]), + (rop.BOOL_NOT, [(0, 1), (1, 0)]), + ]: + for x, y in testcases: + yield opnum, [x], y + +def get_int_tests(): + for opnum, args, retvalue in ( + list(_int_binary_operations()) + + list(_int_comparison_operations()) + + list(_int_unary_operations())): + yield opnum, [BoxInt(x) for x in args], retvalue + + +def test_int_ops(): + cpu = FakeCPU() + for opnum, boxargs, retvalue in get_int_tests(): + box = execute_nonspec(cpu, opnum, boxargs) + assert box.getint() == retvalue + +# floats def _float_binary_operations(): for opnum, testcases in [ From pedronis at codespeak.net Wed Sep 30 15:24:46 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 30 Sep 2009 15:24:46 +0200 (CEST) Subject: [pypy-svn] r68026 - pypy/trunk/pypy/jit/backend/x86/test Message-ID: <20090930132446.33FA1168009@codespeak.net> Author: pedronis Date: Wed Sep 30 15:24:45 2009 New Revision: 68026 Modified: pypy/trunk/pypy/jit/backend/x86/test/test_runner.py Log: kill tests about ops clearly already covered by runner_test Modified: pypy/trunk/pypy/jit/backend/x86/test/test_runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_runner.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_runner.py Wed Sep 30 15:24:45 2009 @@ -28,31 +28,6 @@ def setup_class(cls): cls.cpu = CPU(rtyper=None, stats=FakeStats()) - def test_int_binary_ops(self): - for op, args, res in [ - (rop.INT_SUB, [BoxInt(42), BoxInt(40)], 2), - (rop.INT_SUB, [BoxInt(42), ConstInt(40)], 2), - (rop.INT_SUB, [ConstInt(42), BoxInt(40)], 2), - (rop.INT_ADD, [ConstInt(-3), ConstInt(-5)], -8), - ]: - assert self.execute_operation(op, args, 'int').value == res - - def test_int_unary_ops(self): - for op, args, res in [ - (rop.INT_NEG, [BoxInt(42)], -42), - ]: - assert self.execute_operation(op, args, 'int').value == res - - def test_int_comp_ops(self): - for op, args, res in [ - (rop.INT_LT, [BoxInt(40), BoxInt(39)], 0), - (rop.INT_LT, [BoxInt(40), ConstInt(41)], 1), - (rop.INT_LT, [ConstInt(41), BoxInt(40)], 0), - (rop.INT_LE, [ConstInt(42), BoxInt(42)], 1), - (rop.INT_GT, [BoxInt(40), ConstInt(-100)], 1), - ]: - assert self.execute_operation(op, args, 'int').value == res - def test_execute_ptr_operation(self): cpu = self.cpu u = lltype.malloc(U) @@ -90,21 +65,6 @@ assert self.cpu.get_latest_value_int(0) == 0 assert self.cpu.get_latest_value_int(1) == 55 - def test_misc_int_ops(self): - for op, args, res in [ - (rop.INT_MOD, [BoxInt(7), BoxInt(3)], 1), - (rop.INT_MOD, [ConstInt(0), BoxInt(7)], 0), - (rop.INT_MOD, [BoxInt(13), ConstInt(5)], 3), - (rop.INT_MOD, [ConstInt(33), ConstInt(10)], 3), - (rop.INT_FLOORDIV, [BoxInt(13), BoxInt(3)], 4), - (rop.INT_FLOORDIV, [BoxInt(42), ConstInt(10)], 4), - (rop.INT_FLOORDIV, [ConstInt(42), BoxInt(10)], 4), - (rop.INT_RSHIFT, [ConstInt(3), BoxInt(4)], 3>>4), - (rop.INT_RSHIFT, [BoxInt(3), ConstInt(10)], 3>>10), - #(rop.INT_LSHIFT, [BoxInt(3), BoxInt(1)], 3<<1), - ]: - assert self.execute_operation(op, args, 'int').value == res - def test_unicode(self): ofs = symbolic.get_field_token(rstr.UNICODE, 'chars', False)[0] u = rstr.mallocunicode(13) @@ -292,15 +252,6 @@ c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3 - def test_uint_ops(self): - from pypy.rlib.rarithmetic import r_uint, intmask - - arg0 = BoxInt(intmask(r_uint(sys.maxint + 3))) - arg1 = BoxInt(intmask(r_uint(4))) - - res = self.execute_operation(rop.UINT_GT, [arg0, arg1], 'int') - assert res.value == 1 - def test_nullity_with_guard(self): allops = [rop.OONONNULL, rop.OOISNULL, rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] From fijal at codespeak.net Wed Sep 30 15:32:16 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 15:32:16 +0200 (CEST) Subject: [pypy-svn] r68027 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090930133216.AFE57168010@codespeak.net> Author: fijal Date: Wed Sep 30 15:32:16 2009 New Revision: 68027 Modified: pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/test_basic.py pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py pypy/trunk/pypy/jit/metainterp/warmspot.py Log: Refactor, fix and test Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Wed Sep 30 15:32:16 2009 @@ -57,7 +57,7 @@ except InvalidLoop: return None if old_loop_token is not None: - if metainterp.staticdata.debug > 0: + if metainterp.staticdata.state.debug > 0: debug_print("reusing old loop") return old_loop_token executable_token = send_loop_to_backend(metainterp_sd, loop, "loop") @@ -84,39 +84,41 @@ def send_loop_to_backend(metainterp_sd, loop, type): metainterp_sd.options.logger_ops.log_loop(loop.inputargs, loop.operations) - metainterp_sd.profiler.start_backend() + metainterp_sd.state.profiler.start_backend() if not we_are_translated(): show_loop(metainterp_sd, loop) loop.check_consistency() executable_token = metainterp_sd.cpu.compile_loop(loop.inputargs, loop.operations) - metainterp_sd.profiler.end_backend() + metainterp_sd.state.profiler.end_backend() metainterp_sd.stats.add_new_loop(loop) if not we_are_translated(): if type != "entry bridge": metainterp_sd.stats.compiled() else: loop._ignore_during_counting = True - log.info("compiled new " + type) + if metainterp_sd.state.debug > 0: + log.info("compiled new " + type) else: - if metainterp_sd.debug > 0: + if metainterp_sd.state.debug > 0: debug_print("compiled new " + type) return executable_token def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations): metainterp_sd.options.logger_ops.log_loop(inputargs, operations) - metainterp_sd.profiler.start_backend() + metainterp_sd.state.profiler.start_backend() if not we_are_translated(): show_loop(metainterp_sd) TreeLoop.check_consistency_of(inputargs, operations) pass metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations) - metainterp_sd.profiler.end_backend() + metainterp_sd.state.profiler.end_backend() if not we_are_translated(): - metainterp_sd.stats.compiled() - log.info("compiled new bridge") + if metainterp_sd.state.debug > 0: + metainterp_sd.stats.compiled() + log.info("compiled new bridge") else: - if metainterp_sd.debug > 0: + if metainterp_sd.state.debug > 0: debug_print("compiled new bridge") # ____________________________________________________________ Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Wed Sep 30 15:32:16 2009 @@ -10,7 +10,7 @@ from pypy.jit.metainterp.resoperation import rop from pypy.jit.metainterp import codewriter, executor from pypy.jit.metainterp.logger import Logger -from pypy.jit.metainterp.jitprof import EmptyProfiler, BLACKHOLED_OPS +from pypy.jit.metainterp.jitprof import BLACKHOLED_OPS from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize @@ -792,7 +792,7 @@ def opimpl_jit_merge_point(self, pc): if not self.metainterp.is_blackholing(): self.generate_merge_point(pc, self.env) - if self.metainterp.staticdata.debug > DEBUG_PROFILE: + if self.metainterp.staticdata.state.debug > DEBUG_PROFILE: self.debug_merge_point() if self.metainterp.seen_can_enter_jit: self.metainterp.seen_can_enter_jit = False @@ -868,7 +868,7 @@ self.pc = pc self.exception_target = exception_target self.env = env - if self.metainterp.staticdata.debug >= DEBUG_DETAILED: + if self.metainterp.staticdata.state.debug >= DEBUG_DETAILED: values = ' '.join([box.repr_rpython() for box in self.env]) log = self.metainterp.staticdata.log log('setup_resume_at_op %s:%d [%s] %d' % (self.jitcode.name, @@ -912,7 +912,8 @@ virtualizable_boxes = metainterp.virtualizable_boxes resume.capture_resumedata(metainterp.framestack, virtualizable_boxes, resumedescr) - self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS) # count + self.metainterp.staticdata.state.profiler.count_ops(opnum, GUARDS) + # count metainterp.attach_debug_info(guard_op) self.pc = saved_pc return guard_op @@ -956,7 +957,7 @@ def __init__(self, portal_graph, graphs, cpu, stats, options, profile=None, warmrunnerdesc=None, - leave_graph=None, debug=DEBUG_STEPS): + leave_graph=None): self.portal_graph = portal_graph self.cpu = cpu self.stats = stats @@ -971,11 +972,6 @@ self.opcode_names = [] self.opname_to_index = {} - if profile is not None: - self.profiler = profile() - else: - self.profiler = EmptyProfiler() - self.warmrunnerdesc = warmrunnerdesc self._op_goto_if_not = self.find_opcode('goto_if_not') @@ -983,7 +979,6 @@ backendmodule = backendmodule.split('.')[-2] self.jit_starting_line = 'JIT starting (%s)' % backendmodule self.leave_graph = leave_graph - self.debug = debug def _freeze_(self): return True @@ -1006,12 +1001,9 @@ self._setup_class_sizes() self.cpu.setup_once() self.log(self.jit_starting_line) - if not self.profiler.initialized: - self.profiler.start() - self.profiler.initialized = True self.globaldata.initialized = True self.options.logger_noopt.create_log('.noopt') - self.options.logger_ops.create_log('.ops') + self.options.logger_ops.create_log('.ops') def _setup_class_sizes(self): class_sizes = {} @@ -1051,10 +1043,11 @@ # ---------------- logging ------------------------ def log(self, msg, event_kind='info'): - if not we_are_translated(): - getattr(history.log, event_kind)(msg) - elif self.debug: - debug_print(msg) + if self.state.debug > DEBUG_PROFILE: + if not we_are_translated(): + getattr(history.log, event_kind)(msg) + else: + debug_print(msg) # ____________________________________________________________ @@ -1199,7 +1192,7 @@ history.check_descr(descr) assert opnum != rop.CALL and opnum != rop.OOSEND # execute the operation - profiler = self.staticdata.profiler + profiler = self.staticdata.state.profiler profiler.count_ops(opnum) resbox = executor.execute(self.cpu, opnum, descr, *argboxes) if self.is_blackholing(): @@ -1221,7 +1214,7 @@ if require_attention and not self.is_blackholing(): self.before_residual_call() # execute the operation - profiler = self.staticdata.profiler + profiler = self.staticdata.state.profiler profiler.count_ops(opnum) resbox = executor.execute_varargs(self.cpu, opnum, argboxes, descr) if self.is_blackholing(): @@ -1260,7 +1253,7 @@ def _record_helper_nonpure_varargs(self, opnum, resbox, descr, argboxes): assert resbox is None or isinstance(resbox, Box) # record the operation - profiler = self.staticdata.profiler + profiler = self.staticdata.state.profiler profiler.count_ops(opnum, RECORDED_OPS) op = self.history.record(opnum, argboxes, resbox, descr) self.attach_debug_info(op) @@ -1276,8 +1269,8 @@ self.history = None # start blackholing self.staticdata.stats.aborted() self.staticdata.log('~~~ ABORTING TRACING', event_kind='event') - self.staticdata.profiler.end_tracing() - self.staticdata.profiler.start_blackhole() + self.staticdata.state.profiler.end_tracing() + self.staticdata.state.profiler.start_blackhole() def switch_to_blackhole_if_trace_too_long(self): if not self.is_blackholing(): @@ -1299,9 +1292,9 @@ self.check_recursion_invariant() finally: if self.is_blackholing(): - self.staticdata.profiler.end_blackhole() + self.staticdata.state.profiler.end_blackhole() else: - self.staticdata.profiler.end_tracing() + self.staticdata.state.profiler.end_tracing() self.staticdata.log('~~~ LEAVE' + self.blackholing_text(), event_kind='event') @@ -1520,7 +1513,7 @@ def initialize_state_from_start(self, *args): self.in_recursion = -1 # always one portal around self.staticdata._setup_once() - self.staticdata.profiler.start_tracing() + self.staticdata.state.profiler.start_tracing() self.create_empty_history() num_green_args = self.staticdata.num_green_args original_boxes = [] @@ -1542,9 +1535,9 @@ if must_compile: self.history = history.History(self.cpu) self.history.inputargs = inputargs - self.staticdata.profiler.start_tracing() + self.staticdata.state.profiler.start_tracing() else: - self.staticdata.profiler.start_blackhole() + self.staticdata.state.profiler.start_blackhole() self.history = None # this means that is_blackholing() is true self.rebuild_state_after_failure(resumedescr, inputargs) return resumedescr Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Wed Sep 30 15:32:16 2009 @@ -11,6 +11,7 @@ from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper from pypy.rpython.lltypesystem import lltype from pypy.rpython.ootypesystem import ootype +from pypy.jit.metainterp.jitprof import EmptyProfiler def get_metainterp(func, values, CPUClass, type_system, policy, listops=False, optimizer=OPTIMIZER_FULL): @@ -79,6 +80,8 @@ optimize_bridge = staticmethod(simple_optimize.optimize_bridge) trace_limit = sys.maxint + profiler = EmptyProfiler() + debug = 2 if policy is None: policy = JitPolicy() Modified: pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py Wed Sep 30 15:32:16 2009 @@ -42,7 +42,7 @@ return res * 2 res = self.meta_interp(f, [6, 7]) assert res == 84 - profiler = pyjitpl._warmrunnerdesc.metainterp_sd.profiler + profiler = pyjitpl._warmrunnerdesc.metainterp_sd.state.profiler expected = [ TRACING, BACKEND, @@ -74,7 +74,7 @@ return res * 2 res = self.meta_interp(f, [6, 7]) assert res == 84 - profiler = pyjitpl._warmrunnerdesc.metainterp_sd.profiler + profiler = pyjitpl._warmrunnerdesc.metainterp_sd.state.profiler # calls = (executed, recorded, blackholed) x (inpure, pure) assert profiler.calls == [[1, 0], [1, 0], [0, 0]] @@ -96,6 +96,6 @@ return res * 2 res = self.meta_interp(f, [6, 7, 2]) assert res == 90 - profiler = pyjitpl._warmrunnerdesc.metainterp_sd.profiler + profiler = pyjitpl._warmrunnerdesc.metainterp_sd.state.profiler # calls = (executed, recorded, blackholed) x (inpure, pure) assert profiler.calls == [[0, 1], [0, 0], [0, 1]] Modified: pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py Wed Sep 30 15:32:16 2009 @@ -1,3 +1,4 @@ +import py from pypy.jit.metainterp.warmspot import ll_meta_interp, cast_whatever_to_int from pypy.jit.metainterp.warmspot import get_stats from pypy.rlib.jit import JitDriver, OPTIMIZER_FULL, OPTIMIZER_SIMPLE @@ -151,7 +152,43 @@ assert warmrunnerdescr.state.optimize_loop is optimize.optimize_loop assert warmrunnerdescr.state.optimize_bridge is optimize.optimize_bridge + def test_set_param_debug(self): + from pypy.jit.metainterp.jitprof import Profiler, EmptyProfiler + from pypy.rlib.jit import DEBUG_PROFILE, DEBUG_OFF, DEBUG_STEPS + + myjitdriver = JitDriver(greens = [], reds = ['n']) + def f(n): + while n > 0: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + n -= 1 + return n + def main(n, debug): + myjitdriver.set_param_debug(debug) + print f(n) + + outerr = py.io.StdCaptureFD() + self.meta_interp(f, [10], debug=DEBUG_OFF) + out, errf = outerr.done() + err = errf.read() + assert not 'ENTER' in err + assert not 'LEAVE' in err + assert "Running asm" not in err + outerr = py.io.StdCaptureFD() + self.meta_interp(f, [10], debug=DEBUG_PROFILE) + out, errf = outerr.done() + err = errf.read() + assert not 'ENTER' in err + assert not 'LEAVE' in err + assert "Running asm" in err + outerr = py.io.StdCaptureFD() + self.meta_interp(f, [10], debug=DEBUG_STEPS) + out, errf = outerr.done() + err = errf.read() + assert 'ENTER' in err + assert 'LEAVE' in err + assert "Running asm" in err class TestLLWarmspot(WarmspotTests, LLJitMixin): CPUClass = runner.LLtypeCPU Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Wed Sep 30 15:32:16 2009 @@ -21,7 +21,7 @@ from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData, MetaInterp from pypy.jit.metainterp.policy import JitPolicy from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper -from pypy.jit.metainterp.jitprof import Profiler +from pypy.jit.metainterp.jitprof import Profiler, EmptyProfiler from pypy.rlib.jit import DEBUG_STEPS, DEBUG_DETAILED, DEBUG_OFF, DEBUG_PROFILE # ____________________________________________________________ @@ -33,17 +33,13 @@ if 'CPUClass' not in kwds: from pypy.jit.backend.detect_cpu import getcpuclass kwds['CPUClass'] = getcpuclass(backend_name) - if debug_level >= DEBUG_PROFILE: - profile = Profiler - else: - profile = None warmrunnerdesc = WarmRunnerDesc(translator, translate_support_code=True, listops=True, - profile=profile, no_stats = True, **kwds) - warmrunnerdesc.state.set_param_inlining(inline) + warmrunnerdesc.state.set_param_inlining(inline) + warmrunnerdesc.state.set_param_debug(debug_level) warmrunnerdesc.finish() translator.warmrunnerdesc = warmrunnerdesc # for later debugging @@ -60,7 +56,7 @@ clear_tcache() return jittify_and_run(interp, graph, args, backendopt=backendopt, **kwds) -def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False, trace_limit=sys.maxint, +def jittify_and_run(interp, graph, args, repeat=1, hash_bits=None, backendopt=False, trace_limit=sys.maxint, debug=DEBUG_STEPS, profile=None, inline=False, **kwds): translator = interp.typer.annotator.translator translator.config.translation.gc = "boehm" @@ -69,14 +65,18 @@ warmrunnerdesc.state.set_param_trace_eagerness(2) # for tests warmrunnerdesc.state.set_param_trace_limit(trace_limit) warmrunnerdesc.state.set_param_inlining(inline) - warmrunnerdesc.state.set_param_debug(DEBUG_STEPS) + warmrunnerdesc.state.set_param_debug(debug) + if not we_are_translated() and profile is not None: + # for tests + warmrunnerdesc.state.profiler = profile() + warmrunnerdesc.state.profiler.start() warmrunnerdesc.state.create_tables_now() # for tests if hash_bits: warmrunnerdesc.state.set_param_hash_bits(hash_bits) warmrunnerdesc.finish() res = interp.eval_graph(graph, args) if not kwds.get('translate_support_code', False): - warmrunnerdesc.metainterp_sd.profiler.finish() + warmrunnerdesc.metainterp_sd.state.profiler.finish() print '~~~ return value:', res while repeat > 1: print '~' * 79 @@ -229,7 +229,7 @@ really_remove_asserts=True) def build_meta_interp(self, CPUClass, translate_support_code=False, - view="auto", profile=None, no_stats=False, debug=2, + view="auto", profile=None, no_stats=False, **kwds): assert CPUClass is not None opt = history.Options(**kwds) @@ -249,10 +249,8 @@ self.metainterp_sd = MetaInterpStaticData(self.portal_graph, self.translator.graphs, cpu, self.stats, opt, - profile=profile, warmrunnerdesc=self, - leave_graph=self.leave_graph, - debug=debug) + leave_graph=self.leave_graph) def make_enter_function(self): WarmEnterState = make_state_class(self) @@ -532,8 +530,8 @@ def add_profiler_finish(self): def finish_profiler(): - if self.metainterp_sd.profiler.initialized: - self.metainterp_sd.profiler.finish() + if self.state.profiler.initialized: + self.state.profiler.finish() if self.cpu.translate_support_code: call_final_function(self.translator, finish_profiler, @@ -798,7 +796,14 @@ raise ValueError("unknown optimizer") def set_param_debug(self, value): - metainterp_sd.debug = value + if value >= DEBUG_PROFILE: + self.profiler = Profiler() + else: + self.profiler = EmptyProfiler() + if not self.profiler.initialized: + self.profiler.start() + self.profiler.initialized = True + self.debug = value def create_tables_now(self): count = 1 << self.hashbits @@ -854,9 +859,9 @@ executable_token = cell.entry_executable_token # ---------- execute assembler ---------- while True: # until interrupted by an exception - metainterp_sd.profiler.start_running() + metainterp_sd.state.profiler.start_running() fail_descr = metainterp_sd.cpu.execute_token(executable_token) - metainterp_sd.profiler.end_running() + metainterp_sd.state.profiler.end_running() executable_token = fail_descr.handle_fail(metainterp_sd) maybe_compile_and_run._dont_inline_ = True From pedronis at codespeak.net Wed Sep 30 15:44:32 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 30 Sep 2009 15:44:32 +0200 (CEST) Subject: [pypy-svn] r68028 - in pypy/trunk/pypy/jit/backend: llgraph/test test x86/test Message-ID: <20090930134432.0B5F7168010@codespeak.net> Author: pedronis Date: Wed Sep 30 15:44:32 2009 New Revision: 68028 Modified: pypy/trunk/pypy/jit/backend/llgraph/test/test_llgraph.py pypy/trunk/pypy/jit/backend/test/runner_test.py pypy/trunk/pypy/jit/backend/x86/test/test_runner.py Log: move test, kill irrelevant skipped tests Modified: pypy/trunk/pypy/jit/backend/llgraph/test/test_llgraph.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/test/test_llgraph.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/test/test_llgraph.py Wed Sep 30 15:44:32 2009 @@ -36,33 +36,6 @@ assert getattr(res, key) == value interpret(main, []) - def test_execute_operations_in_env(self): - py.test.skip("Rewrite me") - x = BoxInt(123) - y = BoxInt(456) - z = BoxInt(579) - t = BoxInt(455) - u = BoxInt(0) - operations = [ - ResOperation(rop.MERGE_POINT, [x, y], None), - ResOperation(rop.INT_ADD, [x, y], z), - ResOperation(rop.INT_SUB, [y, ConstInt(1)], t), - ResOperation(rop.INT_EQ, [t, ConstInt(0)], u), - ResOperation(rop.GUARD_FALSE, [u], None), - ResOperation(rop.JUMP, [z, t], None), - ] - operations[-2].liveboxes = [t, z] - operations[-1].jump_target = operations[0] - cpu.compile_operations(operations) - res = cpu.execute_operations_in_new_frame('foo', operations, - [BoxInt(0), BoxInt(10)]) - assert res.value == 42 - gf = cpu.metainterp.gf - assert cpu.metainterp.recordedvalues == [0, 55] - assert gf.guard_op is operations[-2] - assert cpu.stats.exec_counters['int_add'] == 10 - assert cpu.stats.exec_jumps == 9 - def test_cast_adr_to_int_and_back(self): cpu = self.cpu X = lltype.Struct('X', ('foo', lltype.Signed)) @@ -76,14 +49,6 @@ assert cpu.cast_adr_to_int(llmemory.NULL) == 0 assert cpu.cast_int_to_adr(0) == llmemory.NULL - def test_llinterp_simple(self): - py.test.skip("rewrite me") - cpu = self.cpu - self.eval_llinterp(cpu.execute_operation, "int_sub", - [BoxInt(10), BoxInt(2)], "int", - expected_class = BoxInt, - expected_value = 8) - def test_do_operations(self): cpu = self.cpu # Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/runner_test.py (original) +++ pypy/trunk/pypy/jit/backend/test/runner_test.py Wed Sep 30 15:44:32 2009 @@ -11,7 +11,6 @@ from pypy.jit.metainterp.typesystem import deref from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi, rclass from pypy.rpython.ootypesystem import ootype -from pypy.jit.metainterp.executor import execute from pypy.rlib.rarithmetic import r_uint, intmask from pypy.jit.metainterp.test.oparser import parse from pypy.rpython.annlowlevel import llhelper @@ -233,6 +232,30 @@ calldescr) assert x.value == ord('B') + def test_execute_operations_in_env(self): + cpu = self.cpu + x = BoxInt(123) + y = BoxInt(456) + z = BoxInt(579) + t = BoxInt(455) + u = BoxInt(0) # False + operations = [ + ResOperation(rop.INT_ADD, [x, y], z), + ResOperation(rop.INT_SUB, [y, ConstInt(1)], t), + ResOperation(rop.INT_EQ, [t, ConstInt(0)], u), + ResOperation(rop.GUARD_FALSE, [u], None, + descr=BasicFailDescr()), + ResOperation(rop.JUMP, [z, t], None), + ] + operations[-1].jump_target = None + operations[-2].fail_args = [t, z] + executable_token = cpu.compile_loop([x, y], operations) + self.cpu.set_future_value_int(0, 0) + self.cpu.set_future_value_int(1, 10) + res = self.cpu.execute_token(executable_token) + assert self.cpu.get_latest_value_int(0) == 0 + assert self.cpu.get_latest_value_int(1) == 55 + def test_call(self): def func_int(a, b): Modified: pypy/trunk/pypy/jit/backend/x86/test/test_runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_runner.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_runner.py Wed Sep 30 15:44:32 2009 @@ -41,30 +41,6 @@ assert (self.execute_operation(rop.GETFIELD_GC, [u_box], 'int', ofs) .value == 103) - def test_execute_operations_in_env(self): - cpu = self.cpu - x = BoxInt(123) - y = BoxInt(456) - z = BoxInt(579) - t = BoxInt(455) - u = BoxInt(0) # False - operations = [ - ResOperation(rop.INT_ADD, [x, y], z), - ResOperation(rop.INT_SUB, [y, ConstInt(1)], t), - ResOperation(rop.INT_EQ, [t, ConstInt(0)], u), - ResOperation(rop.GUARD_FALSE, [u], None, - descr=BasicFailDescr()), - ResOperation(rop.JUMP, [z, t], None), - ] - operations[-1].jump_target = None - operations[-2].fail_args = [t, z] - executable_token = cpu.compile_loop([x, y], operations) - self.cpu.set_future_value_int(0, 0) - self.cpu.set_future_value_int(1, 10) - res = self.cpu.execute_token(executable_token) - assert self.cpu.get_latest_value_int(0) == 0 - assert self.cpu.get_latest_value_int(1) == 55 - def test_unicode(self): ofs = symbolic.get_field_token(rstr.UNICODE, 'chars', False)[0] u = rstr.mallocunicode(13) From fijal at codespeak.net Wed Sep 30 15:51:11 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 15:51:11 +0200 (CEST) Subject: [pypy-svn] r68029 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090930135111.B0FDC168011@codespeak.net> Author: fijal Date: Wed Sep 30 15:51:11 2009 New Revision: 68029 Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py Log: Fix translation Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/jitprof.py (original) +++ pypy/trunk/pypy/jit/metainterp/jitprof.py Wed Sep 30 15:51:11 2009 @@ -24,7 +24,10 @@ ncounters = len(names) _setup() -class EmptyProfiler(object): +class BaseProfiler(object): + pass + +class EmptyProfiler(BaseProfiler): initialized = True def start(self): @@ -63,7 +66,7 @@ def count_ops(self, opnum, kind=OPS): pass -class Profiler(object): +class Profiler(BaseProfiler): initialized = False timer = time.time starttime = 0 From pedronis at codespeak.net Wed Sep 30 15:51:30 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 30 Sep 2009 15:51:30 +0200 (CEST) Subject: [pypy-svn] r68030 - pypy/trunk/pypy/jit/backend/test Message-ID: <20090930135130.3F038168011@codespeak.net> Author: pedronis Date: Wed Sep 30 15:51:29 2009 New Revision: 68030 Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py Log: kill some misplaced/duplicated do_ testing Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/runner_test.py (original) +++ pypy/trunk/pypy/jit/backend/test/runner_test.py Wed Sep 30 15:51:29 2009 @@ -369,10 +369,6 @@ fielddescr = self.cpu.fielddescrof(self.S, 'value') assert not fielddescr.is_pointer_field() # - self.cpu.do_setfield_gc(t_box, BoxInt(1333), fielddescr) - r = self.cpu.do_getfield_gc(t_box, fielddescr) - assert r.value == 1333 - # res = self.execute_operation(rop.SETFIELD_GC, [t_box, BoxInt(39082)], 'void', descr=fielddescr) assert res is None @@ -497,12 +493,6 @@ arraydescr = self.cpu.arraydescrof(A) assert not arraydescr.is_array_of_pointers() # - r = self.cpu.do_arraylen_gc(a_box, arraydescr) - assert r.value == 342 - self.cpu.do_setarrayitem_gc(a_box, BoxInt(311), BoxInt(170), arraydescr) - r = self.cpu.do_getarrayitem_gc(a_box, BoxInt(311), arraydescr) - assert r.value == 170 - # r = self.execute_operation(rop.ARRAYLEN_GC, [a_box], 'int', descr=arraydescr) assert r.value == 342 From arigo at codespeak.net Wed Sep 30 15:57:15 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 15:57:15 +0200 (CEST) Subject: [pypy-svn] r68031 - pypy/branch/asmgcc-exception/pypy/translator/c/gcc Message-ID: <20090930135715.2DDDF168011@codespeak.net> Author: arigo Date: Wed Sep 30 15:57:14 2009 New Revision: 68031 Modified: pypy/branch/asmgcc-exception/pypy/translator/c/gcc/gccexceptiontransform.py Log: Intermediate check-in. Modified: pypy/branch/asmgcc-exception/pypy/translator/c/gcc/gccexceptiontransform.py ============================================================================== --- pypy/branch/asmgcc-exception/pypy/translator/c/gcc/gccexceptiontransform.py (original) +++ pypy/branch/asmgcc-exception/pypy/translator/c/gcc/gccexceptiontransform.py Wed Sep 30 15:57:14 2009 @@ -1,7 +1,9 @@ -from pypy.rpython.lltypesystem import lltype -from pypy.objspace.flow.model import Constant +from pypy.rpython.lltypesystem import lltype, rffi +from pypy.objspace.flow.model import Block, Link, Constant, Variable +from pypy.objspace.flow.model import SpaceOperation, c_last_exception from pypy.annotation import model as annmodel from pypy.rpython.annlowlevel import MixLevelHelperAnnotator +from pypy.translator.exceptiontransform import error_constant class ExceptionTransformer(object): @@ -27,9 +29,10 @@ def rpyexc_clear(): pass + exit = rffi.llexternal('return', [lltype.Signed], lltype.Void, + _nowrapper=True) def rpyexc_raise(etype, evalue): - # XXX! - pass + exit(0) # XXX! self.rpyexc_occured_ptr = self.build_func( "RPyExceptionOccurred", @@ -72,4 +75,26 @@ return Constant(fn_ptr, lltype.Ptr(FUNC_TYPE)) def create_exception_handling(self, graph): - pass + for block in list(graph.iterblocks()): + self.transform_block(graph, block) + self.transform_except_block(graph, graph.exceptblock) + + def transform_block(self, graph, block): + if block.exitswitch == c_last_exception: + assert block.exits[0].exitcase is None + block.exits = block.exits[:1] + block.exitswitch = None + + def transform_except_block(self, graph, block): + # attach an except block -- let's hope that nobody uses it + graph.exceptblock = Block([Variable('etype'), # exception class + Variable('evalue')]) # exception value + graph.exceptblock.operations = () + graph.exceptblock.closeblock() + + result = Variable() + result.concretetype = lltype.Void + block.operations = [SpaceOperation( + "direct_call", [self.rpyexc_raise_ptr] + block.inputargs, result)] + l = Link([error_constant(graph.returnblock.inputargs[0].concretetype)], graph.returnblock) + block.recloseblock(l) From fijal at codespeak.net Wed Sep 30 15:59:29 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 15:59:29 +0200 (CEST) Subject: [pypy-svn] r68032 - pypy/trunk/pypy/translator Message-ID: <20090930135929.048AF168011@codespeak.net> Author: fijal Date: Wed Sep 30 15:59:29 2009 New Revision: 68032 Modified: pypy/trunk/pypy/translator/driver.py Log: fix translation Modified: pypy/trunk/pypy/translator/driver.py ============================================================================== --- pypy/trunk/pypy/translator/driver.py (original) +++ pypy/trunk/pypy/translator/driver.py Wed Sep 30 15:59:29 2009 @@ -11,6 +11,7 @@ from pypy.annotation import policy as annpolicy from py.compat import optparse from pypy.tool.udir import udir +from pypy.rlib.jit import DEBUG_OFF, DEBUG_DETAILED, DEBUG_PROFILE, DEBUG_STEPS import py from pypy.tool.ansi_print import ansi_log @@ -35,6 +36,13 @@ 'c': 'lltype', } +JIT_DEBUG = { + 'off' : DEBUG_OFF, + 'profile' : DEBUG_PROFILE, + 'steps' : DEBUG_STEPS, + 'detailed' : DEBUG_DETAILED, +} + def backend_to_typesystem(backend): return _BACKEND_TO_TYPESYSTEM.get(backend, 'ootype') @@ -361,7 +369,7 @@ # from pypy.jit.metainterp.warmspot import apply_jit apply_jit(self.translator, policy=self.jitpolicy, - debug_level=self.config.translation.jit_debug, + debug_level=JIT_DEBUG[self.config.translation.jit_debug], backend_name=self.config.translation.jit_backend, inline=True) # self.log.info("the JIT compiler was generated") From fijal at codespeak.net Wed Sep 30 16:06:08 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 16:06:08 +0200 (CEST) Subject: [pypy-svn] r68033 - pypy/trunk/pypy/translator Message-ID: <20090930140608.5880D168010@codespeak.net> Author: fijal Date: Wed Sep 30 16:06:07 2009 New Revision: 68033 Modified: pypy/trunk/pypy/translator/driver.py Log: Fix also here Modified: pypy/trunk/pypy/translator/driver.py ============================================================================== --- pypy/trunk/pypy/translator/driver.py (original) +++ pypy/trunk/pypy/translator/driver.py Wed Sep 30 16:06:07 2009 @@ -384,7 +384,7 @@ # from pypy.jit.metainterp.warmspot import apply_jit apply_jit(self.translator, policy=self.jitpolicy, - debug_level=self.config.translation.jit_debug, + debug_level=JIT_DEBUG[self.config.translation.jit_debug], backend_name='cli', inline=True) #XXX # self.log.info("the JIT compiler was generated") From pedronis at codespeak.net Wed Sep 30 16:07:42 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 30 Sep 2009 16:07:42 +0200 (CEST) Subject: [pypy-svn] r68034 - pypy/trunk/pypy/jit/backend/llgraph/test Message-ID: <20090930140742.43531168010@codespeak.net> Author: pedronis Date: Wed Sep 30 16:07:41 2009 New Revision: 68034 Modified: pypy/trunk/pypy/jit/backend/llgraph/test/test_llgraph.py Log: big cleanup Modified: pypy/trunk/pypy/jit/backend/llgraph/test/test_llgraph.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/test/test_llgraph.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/test/test_llgraph.py Wed Sep 30 16:07:41 2009 @@ -9,33 +9,12 @@ from pypy.jit.metainterp.executor import execute from pypy.jit.backend.test.runner_test import LLtypeBackendTest -NODE = lltype.GcForwardReference() -NODE.become(lltype.GcStruct('NODE', ('value', lltype.Signed), - ('next', lltype.Ptr(NODE)))) - -SUBNODE = lltype.GcStruct('SUBNODE', ('parent', NODE)) - - -class LLGraphTests: +class TestLLTypeLLGraph(LLtypeBackendTest): + from pypy.jit.backend.llgraph.runner import LLtypeCPU as cpu_type def setup_method(self, _): self.cpu = self.cpu_type(None) - def eval_llinterp(self, runme, *args, **kwds): - expected_class = kwds.pop('expected_class', None) - expected_vals = [(name[9:], kwds[name]) - for name in kwds.keys() - if name.startswith('expected_')] - expected_vals = unrolling_iterable(expected_vals) - - def main(): - res = runme(*args) - if expected_class is not None: - assert isinstance(res, expected_class) - for key, value in expected_vals: - assert getattr(res, key) == value - interpret(main, []) - def test_cast_adr_to_int_and_back(self): cpu = self.cpu X = lltype.Struct('X', ('foo', lltype.Signed)) @@ -49,139 +28,6 @@ assert cpu.cast_adr_to_int(llmemory.NULL) == 0 assert cpu.cast_int_to_adr(0) == llmemory.NULL - def test_do_operations(self): - cpu = self.cpu - # - A = lltype.GcArray(lltype.Char) - descr_A = cpu.arraydescrof(A) - a = lltype.malloc(A, 5) - x = cpu.do_arraylen_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, a))], - descr_A) - assert x.value == 5 - # - a[2] = 'Y' - x = cpu.do_getarrayitem_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, a)), BoxInt(2)], - descr_A) - assert x.value == ord('Y') - # - B = lltype.GcArray(lltype.Ptr(A)) - descr_B = cpu.arraydescrof(B) - b = lltype.malloc(B, 4) - b[3] = a - x = cpu.do_getarrayitem_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, b)), BoxInt(3)], - descr_B) - assert isinstance(x, BoxPtr) - assert x.getref(lltype.Ptr(A)) == a - # - s = rstr.mallocstr(6) - x = cpu.do_strlen( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s))]) - assert x.value == 6 - # - s.chars[3] = 'X' - x = cpu.do_strgetitem( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), BoxInt(3)]) - assert x.value == ord('X') - # - S = lltype.GcStruct('S', ('x', lltype.Char), ('y', lltype.Ptr(A))) - descrfld_x = cpu.fielddescrof(S, 'x') - s = lltype.malloc(S) - s.x = 'Z' - x = cpu.do_getfield_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s))], - descrfld_x) - assert x.value == ord('Z') - # - cpu.do_setfield_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), - BoxInt(ord('4'))], - descrfld_x) - assert s.x == '4' - # - descrfld_y = cpu.fielddescrof(S, 'y') - s.y = a - x = cpu.do_getfield_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s))], - descrfld_y) - assert isinstance(x, BoxPtr) - assert x.getref(lltype.Ptr(A)) == a - # - s.y = lltype.nullptr(A) - cpu.do_setfield_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s)), x], - descrfld_y) - assert s.y == a - # - RS = lltype.Struct('S', ('x', lltype.Char), ('y', lltype.Ptr(A))) - descrfld_rx = cpu.fielddescrof(RS, 'x') - rs = lltype.malloc(RS, immortal=True) - rs.x = '?' - x = cpu.do_getfield_raw( - [BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs)))], - descrfld_rx) - assert x.value == ord('?') - # - cpu.do_setfield_raw( - [BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))), - BoxInt(ord('!'))], - descrfld_rx) - assert rs.x == '!' - # - descrfld_ry = cpu.fielddescrof(RS, 'y') - rs.y = a - x = cpu.do_getfield_raw( - [BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs)))], - descrfld_ry) - assert isinstance(x, BoxPtr) - assert x.getref(lltype.Ptr(A)) == a - # - rs.y = lltype.nullptr(A) - cpu.do_setfield_raw( - [BoxInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))), x], - descrfld_ry) - assert rs.y == a - # - descrsize = cpu.sizeof(S) - x = cpu.do_new([], descrsize) - assert isinstance(x, BoxPtr) - x.getref(lltype.Ptr(S)) - # - descrsize2 = cpu.sizeof(rclass.OBJECT) - vtable2 = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) - vtable2_int = cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(vtable2)) - cpu.set_class_sizes({vtable2_int: descrsize2}) - x = cpu.do_new_with_vtable([ConstInt(vtable2_int)]) - assert isinstance(x, BoxPtr) - assert x.getref(rclass.OBJECTPTR).typeptr == vtable2 - # - arraydescr = cpu.arraydescrof(A) - x = cpu.do_new_array([BoxInt(7)], arraydescr) - assert isinstance(x, BoxPtr) - assert len(x.getref(lltype.Ptr(A))) == 7 - # - cpu.do_setarrayitem_gc( - [x, BoxInt(5), BoxInt(ord('*'))], descr_A) - assert x.getref(lltype.Ptr(A))[5] == '*' - # - cpu.do_setarrayitem_gc( - [BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, b)), - BoxInt(1), x], - descr_B) - assert b[1] == x.getref(lltype.Ptr(A)) - # - x = cpu.do_newstr([BoxInt(5)]) - assert isinstance(x, BoxPtr) - assert len(x.getref(lltype.Ptr(rstr.STR)).chars) == 5 - # - cpu.do_strsetitem([x, BoxInt(4), BoxInt(ord('/'))]) - assert x.getref(lltype.Ptr(rstr.STR)).chars[4] == '/' - - -class TestLLTypeLLGraph(LLtypeBackendTest, LLGraphTests): - from pypy.jit.backend.llgraph.runner import LLtypeCPU as cpu_type ## these tests never worked ## class TestOOTypeLLGraph(LLGraphTest): From arigo at codespeak.net Wed Sep 30 16:20:33 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 16:20:33 +0200 (CEST) Subject: [pypy-svn] r68035 - pypy/trunk/pypy/jit/metainterp Message-ID: <20090930142033.09885168011@codespeak.net> Author: arigo Date: Wed Sep 30 16:20:33 2009 New Revision: 68035 Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: Remove the multiple IndirectCallsets and replace them all with a single, global dictionary. Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/codewriter.py Wed Sep 30 16:20:33 2009 @@ -42,35 +42,6 @@ dump.dump_bytecode(self, file=file) print >> file -class IndirectCallset(history.AbstractValue): - def __init__(self, codewriter, graphs): - self.keys = [] - self.values = [] - for graph in graphs: - fnptr = codewriter.rtyper.getcallable(graph) - fnaddress = codewriter.cpu.ts.cast_fnptr_to_root(fnptr) - self.keys.append(fnaddress) - self.values.append(codewriter.get_jitcode(graph)) - self.dict = None - - def bytecode_for_address(self, fnaddress): - if we_are_translated(): - if self.dict is None: - # Build the dictionary at run-time. This is needed - # because the keys are function addresses, so they - # can change from run to run. - self.dict = {} - keys = self.keys - values = self.values - for i in range(len(keys)): - self.dict[keys[i]] = values[i] - return self.dict[fnaddress] - else: - for i in range(len(self.keys)): - if fnaddress == self.keys[i]: - return self.values[i] - raise KeyError(fnaddress) - class SwitchDict(history.AbstractValue): "Get a 'dict' attribute mapping integer values to bytecode positions." @@ -83,7 +54,6 @@ def __init__(self, metainterp_sd, policy): self.all_prebuilt_values = dict_equal_consts() self.all_graphs = {} - self.all_indirectcallsets = {} self.all_methdescrs = {} self.all_listdescs = {} self.unfinished_graphs = [] @@ -173,14 +143,15 @@ calldescr = self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), FUNC.RESULT) return (cfnptr, calldescr) - def get_indirectcallset(self, graphs): - key = tuple(sorted(graphs)) - try: - result = self.all_indirectcallsets[key] - except KeyError: - result = self.all_indirectcallsets[key] = \ - IndirectCallset(self, graphs) - return result + def register_indirect_call_targets(self, op): + targets = self.policy.graphs_from(op, self.cpu.supports_floats) + assert targets is not None + for graph in targets: + fnptr = self.rtyper.getcallable(graph) + fnaddress = self.cpu.ts.cast_fnptr_to_root(fnptr) + jitcode = self.get_jitcode(graph) + self.metainterp_sd._register_indirect_call_target(fnaddress, + jitcode) def get_methdescr(self, SELFTYPE, methname, attach_jitcodes): # use the type where the method is actually defined as a key. This way @@ -1097,13 +1068,9 @@ handle_residual_indirect_call = handle_residual_call def handle_regular_indirect_call(self, op): - targets = self.codewriter.policy.graphs_from(op, - self.codewriter.cpu.supports_floats) - assert targets is not None + self.codewriter.register_indirect_call_targets(op) self.minimize_variables() - indirectcallset = self.codewriter.get_indirectcallset(targets) self.emit('indirect_call') - self.emit(self.get_position(indirectcallset)) self.emit(self.var_position(op.args[0])) self.emit_varargs([x for x in op.args[1:-1] if x.concretetype is not lltype.Void]) Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Wed Sep 30 16:20:33 2009 @@ -73,11 +73,6 @@ args += (bytecode, ) elif argspec == "orgpc": args += (orgpc, ) - elif argspec == "indirectcallset": - indirectcallset = self.load_const_arg() - assert isinstance(indirectcallset, - codewriter.IndirectCallset) - args += (indirectcallset, ) elif argspec == "methdescr": methdescr = self.load_const_arg() assert isinstance(methdescr, @@ -660,13 +655,12 @@ def opimpl_residual_call_pure(self, calldescr, varargs): self.execute_varargs(rop.CALL_PURE, varargs, descr=calldescr, exc=False) - - @arguments("orgpc", "indirectcallset", "box", "varargs") - def opimpl_indirect_call(self, pc, indirectcallset, box, varargs): + @arguments("orgpc", "box", "varargs") + def opimpl_indirect_call(self, pc, box, varargs): box = self.implement_guard_value(pc, box) cpu = self.metainterp.cpu key = cpu.ts.getaddr_for_box(cpu, box) - jitcode = indirectcallset.bytecode_for_address(key) + jitcode = self.metainterp.staticdata.bytecode_for_address(key) f = self.metainterp.newframe(jitcode) f.setup_call(varargs) return True @@ -972,6 +966,9 @@ self.opcode_names = [] self.opname_to_index = {} + self.indirectcall_keys = [] + self.indirectcall_values = [] + self.warmrunnerdesc = warmrunnerdesc self._op_goto_if_not = self.find_opcode('goto_if_not') @@ -1023,6 +1020,26 @@ self.portal_graph) self._class_sizes = self._codewriter.class_sizes + def bytecode_for_address(self, fnaddress): + if we_are_translated(): + d = self.globaldata.indirectcall_dict + if d is None: + # Build the dictionary at run-time. This is needed + # because the keys are function addresses, so they + # can change from run to run. + d = {} + keys = self.indirectcall_keys + values = self.indirectcall_values + for i in range(len(keys)): + d[keys[i]] = values[i] + self.globaldata.indirectcall_dict = d + return d[fnaddress] + else: + for i in range(len(self.indirectcall_keys)): + if fnaddress == self.indirectcall_keys[i]: + return self.indirectcall_values[i] + raise KeyError(fnaddress) + # ---------- construction-time interface ---------- def _register_opcode(self, opname): @@ -1033,6 +1050,10 @@ self.opcode_names.append(opname) self.opcode_implementations.append(getattr(MIFrame, name).im_func) + def _register_indirect_call_target(self, fnaddress, jitcode): + self.indirectcall_keys.append(fnaddress) + self.indirectcall_values.append(jitcode) + def find_opcode(self, name): try: return self.opname_to_index[name] @@ -1054,6 +1075,7 @@ class MetaInterpGlobalData(object): def __init__(self, staticdata): self.initialized = False + self.indirectcall_dict = None # state = staticdata.state if state is not None: From pedronis at codespeak.net Wed Sep 30 16:25:31 2009 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 30 Sep 2009 16:25:31 +0200 (CEST) Subject: [pypy-svn] r68036 - pypy/trunk/pypy/jit/backend/test Message-ID: <20090930142531.0EEC8168011@codespeak.net> Author: pedronis Date: Wed Sep 30 16:25:30 2009 New Revision: 68036 Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py Log: reorg Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/runner_test.py (original) +++ pypy/trunk/pypy/jit/backend/test/runner_test.py Wed Sep 30 16:25:30 2009 @@ -217,20 +217,6 @@ executable_token = self.cpu.compile_loop([], operations) fail = self.cpu.execute_token(executable_token) assert fail is faildescr - - def test_do_call(self): - cpu = self.cpu - # - def func(c): - return chr(ord(c) + 1) - FPTR = self.Ptr(self.FuncType([lltype.Char], lltype.Char)) - func_ptr = llhelper(FPTR, func) - calldescr = cpu.calldescrof(deref(FPTR), (lltype.Char,), lltype.Char) - x = cpu.do_call( - [self.get_funcbox(cpu, func_ptr), - BoxInt(ord('A'))], - calldescr) - assert x.value == ord('B') def test_execute_operations_in_env(self): cpu = self.cpu @@ -256,32 +242,6 @@ assert self.cpu.get_latest_value_int(0) == 0 assert self.cpu.get_latest_value_int(1) == 55 - def test_call(self): - - def func_int(a, b): - return a + b - def func_char(c, c1): - return chr(ord(c) + ord(c1)) - - functions = [ - (func_int, lltype.Signed, 655360), - (func_int, rffi.SHORT, 1213), - (func_char, lltype.Char, 12) - ] - - for func, TP, num in functions: - cpu = self.cpu - # - FPTR = self.Ptr(self.FuncType([TP, TP], TP)) - func_ptr = llhelper(FPTR, func) - FUNC = deref(FPTR) - calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) - funcbox = self.get_funcbox(cpu, func_ptr) - res = self.execute_operation(rop.CALL, - [funcbox, BoxInt(num), BoxInt(num)], - 'int', descr=calldescr) - assert res.value == 2 * num - def test_int_operations(self): from pypy.jit.metainterp.test.test_executor import get_int_tests for opnum, boxargs, retvalue in get_int_tests(): @@ -363,6 +323,46 @@ def test_ovf_operations_reversed(self): self.test_ovf_operations(reversed=True) + + def test_do_call(self): + cpu = self.cpu + # + def func(c): + return chr(ord(c) + 1) + FPTR = self.Ptr(self.FuncType([lltype.Char], lltype.Char)) + func_ptr = llhelper(FPTR, func) + calldescr = cpu.calldescrof(deref(FPTR), (lltype.Char,), lltype.Char) + x = cpu.do_call( + [self.get_funcbox(cpu, func_ptr), + BoxInt(ord('A'))], + calldescr) + assert x.value == ord('B') + + def test_call(self): + + def func_int(a, b): + return a + b + def func_char(c, c1): + return chr(ord(c) + ord(c1)) + + functions = [ + (func_int, lltype.Signed, 655360), + (func_int, rffi.SHORT, 1213), + (func_char, lltype.Char, 12) + ] + + for func, TP, num in functions: + cpu = self.cpu + # + FPTR = self.Ptr(self.FuncType([TP, TP], TP)) + func_ptr = llhelper(FPTR, func) + FUNC = deref(FPTR) + calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) + funcbox = self.get_funcbox(cpu, func_ptr) + res = self.execute_operation(rop.CALL, + [funcbox, BoxInt(num), BoxInt(num)], + 'int', descr=calldescr) + assert res.value == 2 * num def test_field_basic(self): t_box, T_box = self.alloc_instance(self.T) @@ -600,12 +600,13 @@ r = self.execute_operation(rop.STRGETITEM, [s_box, BoxInt(4)], 'int') assert r.value == 153 - def test_unicode_basic(self): + def test_do_unicode_basic(self): u_box = self.cpu.do_newunicode(ConstInt(5)) self.cpu.do_unicodesetitem(u_box, BoxInt(4), BoxInt(123)) r = self.cpu.do_unicodegetitem(u_box, BoxInt(4)) assert r.value == 123 - # + + def test_unicode_basic(self): u_box = self.alloc_unicode(u"hello\u1234") r = self.execute_operation(rop.UNICODELEN, [u_box], 'int') assert r.value == 6 @@ -798,6 +799,114 @@ a = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), r1.value) assert len(a.chars) == 342 + def test_exceptions(self): + exc_tp = None + exc_ptr = None + def func(i): + if i: + raise LLException(exc_tp, exc_ptr) + + ops = ''' + [i0] + i1 = same_as(1) + call(ConstClass(fptr), i0, descr=calldescr) + p0 = guard_exception(ConstClass(xtp)) [i1] + finish(0, p0) + ''' + FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) + fptr = llhelper(FPTR, func) + calldescr = self.cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT) + + xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) + xtp.subclassrange_min = 1 + xtp.subclassrange_max = 3 + X = lltype.GcStruct('X', ('parent', rclass.OBJECT), + hints={'vtable': xtp._obj}) + xptr = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(X)) + + + exc_tp = xtp + exc_ptr = xptr + loop = parse(ops, self.cpu, namespace=locals()) + executable_token = self.cpu.compile_loop(loop.inputargs, + loop.operations) + self.cpu.set_future_value_int(0, 1) + self.cpu.execute_token(executable_token) + assert self.cpu.get_latest_value_int(0) == 0 + assert self.cpu.get_latest_value_ref(1) == xptr + self.cpu.clear_exception() + self.cpu.set_future_value_int(0, 0) + self.cpu.execute_token(executable_token) + assert self.cpu.get_latest_value_int(0) == 1 + self.cpu.clear_exception() + + ytp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) + ytp.subclassrange_min = 2 + ytp.subclassrange_max = 2 + assert rclass.ll_issubclass(ytp, xtp) + Y = lltype.GcStruct('Y', ('parent', rclass.OBJECT), + hints={'vtable': ytp._obj}) + yptr = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(Y)) + + # guard_exception uses an exact match + exc_tp = ytp + exc_ptr = yptr + loop = parse(ops, self.cpu, namespace=locals()) + executable_token = self.cpu.compile_loop(loop.inputargs, + loop.operations) + self.cpu.set_future_value_int(0, 1) + self.cpu.execute_token(executable_token) + assert self.cpu.get_latest_value_int(0) == 1 + self.cpu.clear_exception() + + exc_tp = xtp + exc_ptr = xptr + ops = ''' + [i0] + i1 = same_as(1) + call(ConstClass(fptr), i0, descr=calldescr) + guard_no_exception() [i1] + finish(0) + ''' + loop = parse(ops, self.cpu, namespace=locals()) + executable_token = self.cpu.compile_loop(loop.inputargs, + loop.operations) + self.cpu.set_future_value_int(0, 1) + self.cpu.execute_token(executable_token) + assert self.cpu.get_latest_value_int(0) == 1 + self.cpu.clear_exception() + self.cpu.set_future_value_int(0, 0) + self.cpu.execute_token(executable_token) + assert self.cpu.get_latest_value_int(0) == 0 + self.cpu.clear_exception() + + def test_cond_call_gc_wb(self): + def func_void(a, b): + record.append((a, b)) + record = [] + # + FUNC = self.FuncType([lltype.Signed, lltype.Signed], lltype.Void) + func_ptr = llhelper(lltype.Ptr(FUNC), func_void) + funcbox = self.get_funcbox(self.cpu, func_ptr) + calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) + for cond in [False, True]: + value = random.randrange(-sys.maxint, sys.maxint) + if cond: + value |= 4096 + else: + value &= ~4096 + del record[:] + self.execute_operation(rop.COND_CALL_GC_WB, + [BoxInt(value), ConstInt(4096), + funcbox, BoxInt(655360), BoxInt(-2121)], + 'void', descr=calldescr) + if cond: + assert record == [(655360, -2121)] + else: + assert record == [] + + # pure do_ / descr features + def test_do_operations(self): cpu = self.cpu # @@ -945,113 +1054,6 @@ [value, chr1, chr2]) assert len(dict.fromkeys([value, chr1, chr2]).keys()) == 3 - def test_exceptions(self): - exc_tp = None - exc_ptr = None - def func(i): - if i: - raise LLException(exc_tp, exc_ptr) - - ops = ''' - [i0] - i1 = same_as(1) - call(ConstClass(fptr), i0, descr=calldescr) - p0 = guard_exception(ConstClass(xtp)) [i1] - finish(0, p0) - ''' - FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) - fptr = llhelper(FPTR, func) - calldescr = self.cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT) - - xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) - xtp.subclassrange_min = 1 - xtp.subclassrange_max = 3 - X = lltype.GcStruct('X', ('parent', rclass.OBJECT), - hints={'vtable': xtp._obj}) - xptr = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(X)) - - - exc_tp = xtp - exc_ptr = xptr - loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) - self.cpu.set_future_value_int(0, 1) - self.cpu.execute_token(executable_token) - assert self.cpu.get_latest_value_int(0) == 0 - assert self.cpu.get_latest_value_ref(1) == xptr - self.cpu.clear_exception() - self.cpu.set_future_value_int(0, 0) - self.cpu.execute_token(executable_token) - assert self.cpu.get_latest_value_int(0) == 1 - self.cpu.clear_exception() - - ytp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) - ytp.subclassrange_min = 2 - ytp.subclassrange_max = 2 - assert rclass.ll_issubclass(ytp, xtp) - Y = lltype.GcStruct('Y', ('parent', rclass.OBJECT), - hints={'vtable': ytp._obj}) - yptr = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(Y)) - - # guard_exception uses an exact match - exc_tp = ytp - exc_ptr = yptr - loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) - self.cpu.set_future_value_int(0, 1) - self.cpu.execute_token(executable_token) - assert self.cpu.get_latest_value_int(0) == 1 - self.cpu.clear_exception() - - exc_tp = xtp - exc_ptr = xptr - ops = ''' - [i0] - i1 = same_as(1) - call(ConstClass(fptr), i0, descr=calldescr) - guard_no_exception() [i1] - finish(0) - ''' - loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) - self.cpu.set_future_value_int(0, 1) - self.cpu.execute_token(executable_token) - assert self.cpu.get_latest_value_int(0) == 1 - self.cpu.clear_exception() - self.cpu.set_future_value_int(0, 0) - self.cpu.execute_token(executable_token) - assert self.cpu.get_latest_value_int(0) == 0 - self.cpu.clear_exception() - - def test_cond_call_gc_wb(self): - def func_void(a, b): - record.append((a, b)) - record = [] - # - FUNC = self.FuncType([lltype.Signed, lltype.Signed], lltype.Void) - func_ptr = llhelper(lltype.Ptr(FUNC), func_void) - funcbox = self.get_funcbox(self.cpu, func_ptr) - calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) - for cond in [False, True]: - value = random.randrange(-sys.maxint, sys.maxint) - if cond: - value |= 4096 - else: - value &= ~4096 - del record[:] - self.execute_operation(rop.COND_CALL_GC_WB, - [BoxInt(value), ConstInt(4096), - funcbox, BoxInt(655360), BoxInt(-2121)], - 'void', descr=calldescr) - if cond: - assert record == [(655360, -2121)] - else: - assert record == [] - - class OOtypeBackendTest(BaseBackendTest): type_system = 'ootype' From arigo at codespeak.net Wed Sep 30 16:35:36 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 16:35:36 +0200 (CEST) Subject: [pypy-svn] r68037 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090930143536.BEDCE168011@codespeak.net> Author: arigo Date: Wed Sep 30 16:35:33 2009 New Revision: 68037 Added: pypy/trunk/pypy/jit/metainterp/test/test_blackhole.py (contents, props changed) Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py Log: Argh, indirect calls where not falling back to perform_call(), and so even a blackholing interpreter would always follow the call itself instead of just calling the function. Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Wed Sep 30 16:35:33 2009 @@ -661,9 +661,7 @@ cpu = self.metainterp.cpu key = cpu.ts.getaddr_for_box(cpu, box) jitcode = self.metainterp.staticdata.bytecode_for_address(key) - f = self.metainterp.newframe(jitcode) - f.setup_call(varargs) - return True + return self.perform_call(jitcode, varargs) @arguments("orgpc", "methdescr", "varargs") def opimpl_oosend(self, pc, methdescr, varargs): Added: pypy/trunk/pypy/jit/metainterp/test/test_blackhole.py ============================================================================== --- (empty file) +++ pypy/trunk/pypy/jit/metainterp/test/test_blackhole.py Wed Sep 30 16:35:33 2009 @@ -0,0 +1,87 @@ +from pypy.rlib.jit import JitDriver +from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin +from pypy.jit.metainterp import pyjitpl + + +class BlackholeTests(object): + + def meta_interp(self, *args): + def counting_init(frame, metainterp, jitcode): + previnit(frame, metainterp, jitcode) + self.seen_frames.append(jitcode.name) + # + previnit = pyjitpl.MIFrame.__init__.im_func + try: + self.seen_frames = [] + pyjitpl.MIFrame.__init__ = counting_init + return super(BlackholeTests, self).meta_interp(*args) + finally: + pyjitpl.MIFrame.__init__ = previnit + + def test_calls_not_followed(self): + myjitdriver = JitDriver(greens = [], reds = ['n']) + def h(): + return 42 + def g(): + return h() + def f(n): + while n > 0: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + n -= 1 + return g() + res = self.meta_interp(f, [7]) + assert res == 42 + assert self.seen_frames == ['f', 'f'] + + def test_indirect_calls_not_followed(self): + myjitdriver = JitDriver(greens = [], reds = ['n']) + def h(): + return 42 + def g(): + return h() + def f(n): + while n > 0: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + n -= 1 + if n < 0: + call = h + else: + call = g + return call() + res = self.meta_interp(f, [7]) + assert res == 42 + assert self.seen_frames == ['f', 'f'] + + def test_oosends_not_followed(self): + myjitdriver = JitDriver(greens = [], reds = ['n']) + class A: + def meth(self): + return 42 + class B(A): + def meth(self): + return 45 + class C(A): + def meth(self): + return 64 + def f(n): + while n > 0: + myjitdriver.can_enter_jit(n=n) + myjitdriver.jit_merge_point(n=n) + n -= 1 + if n < 0: + x = B() + else: + x = C() + return x.meth() + res = self.meta_interp(f, [7]) + assert res == 64 + assert self.seen_frames == ['f', 'f'] + + +class TestLLtype(BlackholeTests, LLJitMixin): + pass + +class TestOOtype(BlackholeTests, OOJitMixin): + pass From arigo at codespeak.net Wed Sep 30 17:09:56 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 17:09:56 +0200 (CEST) Subject: [pypy-svn] r68038 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090930150956.6AB93168011@codespeak.net> Author: arigo Date: Wed Sep 30 17:09:55 2009 New Revision: 68038 Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py pypy/trunk/pypy/jit/metainterp/dump.py pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py Log: Oups, we get several times the same graphs in the list. Fix and, to test it, start writing unit tests for the codewriter. Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/codewriter.py Wed Sep 30 17:09:55 2009 @@ -53,6 +53,7 @@ def __init__(self, metainterp_sd, policy): self.all_prebuilt_values = dict_equal_consts() + self.all_indirect_call_targets = {} self.all_graphs = {} self.all_methdescrs = {} self.all_listdescs = {} @@ -147,6 +148,9 @@ targets = self.policy.graphs_from(op, self.cpu.supports_floats) assert targets is not None for graph in targets: + if graph in self.all_indirect_call_targets: + continue + self.all_indirect_call_targets[graph] = True fnptr = self.rtyper.getcallable(graph) fnaddress = self.cpu.ts.cast_fnptr_to_root(fnptr) jitcode = self.get_jitcode(graph) Modified: pypy/trunk/pypy/jit/metainterp/dump.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/dump.py (original) +++ pypy/trunk/pypy/jit/metainterp/dump.py Wed Sep 30 17:09:55 2009 @@ -89,6 +89,8 @@ interpreter = jitcode._metainterp_sd labelpos = jitcode._labelpos print >> file, 'JITCODE %r' % (jitcode.name,) + if interpreter.opcode_implementations is None: + return # for tests src = SourceIterator(jitcode, source, interpreter, labelpos) noblankline = {0: True} Modified: pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py Wed Sep 30 17:09:55 2009 @@ -1,7 +1,74 @@ import py +from pypy.jit.metainterp import support, typesystem +from pypy.jit.metainterp.policy import JitPolicy +from pypy.jit.metainterp.codewriter import CodeWriter from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin +class SomeLabel(object): + def __eq__(self, other): + return repr(other).startswith('label') # :-/ + + +class TestCodeWriter: + type_system = 'lltype' + + def setup_method(self, _): + class FakeMetaInterpSd: + def find_opcode(self, name): + default = len(self.opname_to_index) + return self.opname_to_index.setdefault(name, default) + def _register_indirect_call_target(self, fnaddress, jitcode): + self.indirectcalls.append((fnaddress, jitcode)) + + class FakeCPU: + ts = typesystem.llhelper + supports_floats = False + + self.metainterp_sd = FakeMetaInterpSd() + self.metainterp_sd.opcode_implementations = None + self.metainterp_sd.opname_to_index = {} + self.metainterp_sd.indirectcalls = [] + self.metainterp_sd.cpu = FakeCPU() + + def getgraph(self, func, values): + rtyper = support.annotate(func, values, + type_system=self.type_system) + self.metainterp_sd.cpu.rtyper = rtyper + return rtyper.annotator.translator.graphs[0] + + def test_basic(self): + def f(n): + return n + 10 + graph = self.getgraph(f, [5]) + cw = CodeWriter(self.metainterp_sd, JitPolicy()) + jitcode = cw.make_one_bytecode((graph, None), False) + assert jitcode._source == [ + SomeLabel(), + 'int_add', 0, 1, '# => r1', + 'make_new_vars_1', 2, + 'return'] + + def test_indirect_call_target(self): + def g(m): + return 123 + def h(m): + return 456 + def f(n): + if n > 3: + call = g + else: + call = h + return call(n+1) + call(n+2) + graph = self.getgraph(f, [5]) + cw = CodeWriter(self.metainterp_sd, JitPolicy()) + jitcode = cw.make_one_bytecode((graph, None), False) + assert len(self.metainterp_sd.indirectcalls) == 2 + names = [jitcode.name for (fnaddress, jitcode) + in self.metainterp_sd.indirectcalls] + assert dict.fromkeys(names) == {'g': None, 'h': None} + + class ImmutableFieldsTests: def test_fields(self): From arigo at codespeak.net Wed Sep 30 17:18:19 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 17:18:19 +0200 (CEST) Subject: [pypy-svn] r68039 - pypy/branch/kill-jumptarget/pypy/jit/backend Message-ID: <20090930151819.7DAED168011@codespeak.net> Author: arigo Date: Wed Sep 30 17:18:19 2009 New Revision: 68039 Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/model.py Log: Update docstring of execute_token(). Thanks antocuni. Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/model.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/model.py Wed Sep 30 17:18:19 2009 @@ -23,7 +23,8 @@ def execute_token(self, looptoken): """Execute the generated code referenced by the looptoken. - Returns the ResOperation that failed, of type rop.FAIL. + Returns the descr of the last executed operation: either the one + attached to the failing guard, or the one attached to the FINISH. Use set_future_value_xxx() before, and get_latest_value_xxx() after. """ raise NotImplementedError From arigo at codespeak.net Wed Sep 30 17:30:56 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 17:30:56 +0200 (CEST) Subject: [pypy-svn] r68040 - pypy/branch/kill-jumptarget/pypy/jit/backend Message-ID: <20090930153056.71319168011@codespeak.net> Author: arigo Date: Wed Sep 30 17:30:55 2009 New Revision: 68040 Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/model.py Log: Fix these docstrings too. Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/model.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/model.py Wed Sep 30 17:30:55 2009 @@ -43,17 +43,17 @@ def get_latest_value_int(self, index): """Returns the value for the index'th argument to the - lastest rop.FAIL. Returns an int.""" + last executed operation. Returns an int.""" raise NotImplementedError def get_latest_value_float(self, index): """Returns the value for the index'th argument to the - lastest rop.FAIL. Returns a float.""" + last executed operation. Returns a float.""" raise NotImplementedError def get_latest_value_ref(self, index): """Returns the value for the index'th argument to the - lastest rop.FAIL. Returns a ptr or an obj.""" + last executed operation. Returns a ptr or an obj.""" raise NotImplementedError def get_exception(self): From arigo at codespeak.net Wed Sep 30 17:33:57 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 17:33:57 +0200 (CEST) Subject: [pypy-svn] r68041 - pypy/branch/kill-jumptarget/pypy/jit/backend Message-ID: <20090930153357.D6786168013@codespeak.net> Author: arigo Date: Wed Sep 30 17:33:57 2009 New Revision: 68041 Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/model.py Log: Precision from pedronis. Modified: pypy/branch/kill-jumptarget/pypy/jit/backend/model.py ============================================================================== --- pypy/branch/kill-jumptarget/pypy/jit/backend/model.py (original) +++ pypy/branch/kill-jumptarget/pypy/jit/backend/model.py Wed Sep 30 17:33:57 2009 @@ -43,17 +43,20 @@ def get_latest_value_int(self, index): """Returns the value for the index'th argument to the - last executed operation. Returns an int.""" + last executed operation (from 'fail_args' if it was a guard, + or from 'args' if it was a FINISH). Returns an int.""" raise NotImplementedError def get_latest_value_float(self, index): """Returns the value for the index'th argument to the - last executed operation. Returns a float.""" + last executed operation (from 'fail_args' if it was a guard, + or from 'args' if it was a FINISH). Returns a float.""" raise NotImplementedError def get_latest_value_ref(self, index): """Returns the value for the index'th argument to the - last executed operation. Returns a ptr or an obj.""" + last executed operation (from 'fail_args' if it was a guard, + or from 'args' if it was a FINISH). Returns a ptr or an obj.""" raise NotImplementedError def get_exception(self): From arigo at codespeak.net Wed Sep 30 18:01:55 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 18:01:55 +0200 (CEST) Subject: [pypy-svn] r68042 - in pypy/trunk/pypy/jit: backend backend/llgraph backend/llsupport backend/llsupport/test backend/test backend/x86 backend/x86/test metainterp metainterp/test Message-ID: <20090930160155.E42E3168011@codespeak.net> Author: arigo Date: Wed Sep 30 18:01:53 2009 New Revision: 68042 Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py pypy/trunk/pypy/jit/backend/llsupport/descr.py pypy/trunk/pypy/jit/backend/llsupport/llmodel.py pypy/trunk/pypy/jit/backend/llsupport/test/test_runner.py pypy/trunk/pypy/jit/backend/model.py pypy/trunk/pypy/jit/backend/test/runner_test.py pypy/trunk/pypy/jit/backend/test/test_random.py pypy/trunk/pypy/jit/backend/x86/assembler.py pypy/trunk/pypy/jit/backend/x86/regalloc.py pypy/trunk/pypy/jit/backend/x86/runner.py pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py pypy/trunk/pypy/jit/backend/x86/test/test_regalloc2.py pypy/trunk/pypy/jit/backend/x86/test/test_runner.py pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/graphpage.py pypy/trunk/pypy/jit/metainterp/history.py pypy/trunk/pypy/jit/metainterp/optimize.py pypy/trunk/pypy/jit/metainterp/optimizefindnode.py pypy/trunk/pypy/jit/metainterp/optimizeopt.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/resoperation.py pypy/trunk/pypy/jit/metainterp/resume.py pypy/trunk/pypy/jit/metainterp/test/oparser.py pypy/trunk/pypy/jit/metainterp/test/test_compile.py pypy/trunk/pypy/jit/metainterp/test/test_oparser.py pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py pypy/trunk/pypy/jit/metainterp/test/test_send.py pypy/trunk/pypy/jit/metainterp/warmspot.py Log: Merge the 'kill-jumptarget' branch. Removes jumptarget from JUMP operations, replacing it with a descr. This descr is still the LoopToken, now unified with the executable_token. Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/trunk/pypy/jit/backend/llgraph/runner.py Wed Sep 30 18:01:53 2009 @@ -104,17 +104,22 @@ llimpl.set_class_size(self.memo_cast, vtable, size) def compile_bridge(self, faildescr, inputargs, operations): - c = self.compile_loop(inputargs, operations) + c = llimpl.compile_start() + self._compile_loop_or_bridge(c, inputargs, operations) old, oldindex = faildescr._compiled_fail llimpl.compile_redirect_fail(old, oldindex, c) - def compile_loop(self, inputargs, operations): + def compile_loop(self, inputargs, operations, loopdescr): """In a real assembler backend, this should assemble the given list of operations. Here we just generate a similar CompiledLoop instance. The code here is RPython, whereas the code in llimpl is not. """ c = llimpl.compile_start() + loopdescr._llgraph_compiled_version = c + self._compile_loop_or_bridge(c, inputargs, operations) + + def _compile_loop_or_bridge(self, c, inputargs, operations): var2index = {} for box in inputargs: if isinstance(box, history.BoxInt): @@ -174,12 +179,10 @@ op = operations[-1] assert op.is_final() if op.opnum == rop.JUMP: - target = op.jump_target - if target is None: - target = c - else: - target = target.executable_token - llimpl.compile_add_jump_target(c, target) + targettoken = op.descr + assert isinstance(targettoken, history.LoopToken) + compiled_version = targettoken._llgraph_compiled_version + llimpl.compile_add_jump_target(c, compiled_version) elif op.opnum == rop.FINISH: llimpl.compile_add_fail(c, len(self.fail_descrs)) faildescr = op.descr @@ -188,10 +191,11 @@ else: assert False, "unknown operation" - def execute_token(self, compiled_version): + def execute_token(self, loop_token): """Calls the assembler generated for the given loop. Returns the ResOperation that failed, of type rop.FAIL. """ + compiled_version = loop_token._llgraph_compiled_version frame = llimpl.new_frame(self.memo_cast, self.is_oo) # setup the frame llimpl.frame_clear(frame, compiled_version) Modified: pypy/trunk/pypy/jit/backend/llsupport/descr.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llsupport/descr.py (original) +++ pypy/trunk/pypy/jit/backend/llsupport/descr.py Wed Sep 30 18:01:53 2009 @@ -1,7 +1,7 @@ from pypy.rpython.lltypesystem import lltype from pypy.jit.backend.llsupport import symbolic from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr -from pypy.jit.metainterp.history import BasicFailDescr +from pypy.jit.metainterp.history import BasicFailDescr, LoopToken from pypy.jit.metainterp.resoperation import ResOperation, rop # The point of the class organization in this file is to make instances @@ -165,7 +165,7 @@ class BaseCallDescr(AbstractDescr): _clsname = '' - executable_token = None + loop_token = None arg_classes = '' # <-- annotation hack def __init__(self, arg_classes): @@ -186,8 +186,8 @@ raise NotImplementedError def get_token_for_call(self, cpu): - if self.executable_token is not None: - return self.executable_token + if self.loop_token is not None: + return self.loop_token args = [BoxInt()] + self.instantiate_arg_classes() if self.get_result_size(cpu.translate_support_code) == 0: result = None @@ -205,9 +205,10 @@ ResOperation(rop.FINISH, result_list, None, descr=BasicFailDescr())] operations[1].fail_args = [] - executable_token = cpu.compile_loop(args, operations) - self.executable_token = executable_token - return executable_token + loop_token = LoopToken() + cpu.compile_loop(args, operations, loop_token) + self.loop_token = loop_token + return loop_token def repr_of_descr(self): return '<%s>' % self._clsname Modified: pypy/trunk/pypy/jit/backend/llsupport/llmodel.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llsupport/llmodel.py (original) +++ pypy/trunk/pypy/jit/backend/llsupport/llmodel.py Wed Sep 30 18:01:53 2009 @@ -409,9 +409,9 @@ if not we_are_translated(): assert (list(calldescr.arg_classes) == [arg.type for arg in args[1:]]) - executable_token = calldescr.get_token_for_call(self) + loop_token = calldescr.get_token_for_call(self) set_future_values(self, args) - self.execute_token(executable_token) + self.execute_token(loop_token) # Note: if an exception is set, the rest of the code does a bit of # nonsense but nothing wrong (the return value should be ignored) if calldescr.returns_a_pointer(): Modified: pypy/trunk/pypy/jit/backend/llsupport/test/test_runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/llsupport/test/test_runner.py (original) +++ pypy/trunk/pypy/jit/backend/llsupport/test/test_runner.py Wed Sep 30 18:01:53 2009 @@ -7,7 +7,7 @@ pass class MyLLCPU(AbstractLLCPU): - def compile_loop(self, inputargs, operations): + def compile_loop(self, inputargs, operations, looptoken): py.test.skip("llsupport test: cannot compile operations") Modified: pypy/trunk/pypy/jit/backend/model.py ============================================================================== --- pypy/trunk/pypy/jit/backend/model.py (original) +++ pypy/trunk/pypy/jit/backend/model.py Wed Sep 30 18:01:53 2009 @@ -8,18 +8,23 @@ """Called once by the front-end when the program starts.""" pass - def compile_loop(self, inputargs, operations): + def compile_loop(self, inputargs, operations, looptoken): """Assemble the given loop. - Return an opaque token to be consumed by execute_token""" + Extra attributes should be put in the LoopToken to + point to the compiled loop in assembler. + """ raise NotImplementedError def compile_bridge(self, faildescr, inputargs, operations): - """Assemble the bridge""" + """Assemble the bridge. + The FailDescr is the descr of the original guard that failed. + """ raise NotImplementedError - def execute_token(self, executable_token): - """Execute the generated code referenced by the executable_token - Returns the ResOperation that failed, of type rop.FAIL. + def execute_token(self, looptoken): + """Execute the generated code referenced by the looptoken. + Returns the descr of the last executed operation: either the one + attached to the failing guard, or the one attached to the FINISH. Use set_future_value_xxx() before, and get_latest_value_xxx() after. """ raise NotImplementedError @@ -38,17 +43,20 @@ def get_latest_value_int(self, index): """Returns the value for the index'th argument to the - lastest rop.FAIL. Returns an int.""" + last executed operation (from 'fail_args' if it was a guard, + or from 'args' if it was a FINISH). Returns an int.""" raise NotImplementedError def get_latest_value_float(self, index): """Returns the value for the index'th argument to the - lastest rop.FAIL. Returns a float.""" + last executed operation (from 'fail_args' if it was a guard, + or from 'args' if it was a FINISH). Returns a float.""" raise NotImplementedError def get_latest_value_ref(self, index): """Returns the value for the index'th argument to the - lastest rop.FAIL. Returns a ptr or an obj.""" + last executed operation (from 'fail_args' if it was a guard, + or from 'args' if it was a FINISH). Returns a ptr or an obj.""" raise NotImplementedError def get_exception(self): Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/runner_test.py (original) +++ pypy/trunk/pypy/jit/backend/test/runner_test.py Wed Sep 30 18:01:53 2009 @@ -23,7 +23,8 @@ result_type, valueboxes, descr) - executable_token = self.cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + self.cpu.compile_loop(inputargs, operations, looptoken) j = 0 for box in valueboxes: if isinstance(box, BoxInt): @@ -37,7 +38,7 @@ j += 1 else: assert isinstance(box, Const) - res = self.cpu.execute_token(executable_token) + res = self.cpu.execute_token(looptoken) if res is operations[-1].descr: self.guard_failed = False else: @@ -95,9 +96,10 @@ ResOperation(rop.FINISH, [i1], None, descr=faildescr) ] inputargs = [i0] - executable_token = self.cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + self.cpu.compile_loop(inputargs, operations, looptoken) self.cpu.set_future_value_int(0, 2) - fail = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(looptoken) res = self.cpu.get_latest_value_int(0) assert res == 3 assert fail is faildescr @@ -107,19 +109,19 @@ i1 = BoxInt() i2 = BoxInt() faildescr = BasicFailDescr() + looptoken = LoopToken() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr), - ResOperation(rop.JUMP, [i1], None), + ResOperation(rop.JUMP, [i1], None, descr=looptoken), ] inputargs = [i0] operations[2].fail_args = [i1] - operations[-1].jump_target = None - executable_token = self.cpu.compile_loop(inputargs, operations) + self.cpu.compile_loop(inputargs, operations, looptoken) self.cpu.set_future_value_int(0, 2) - fail = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(looptoken) assert fail is faildescr res = self.cpu.get_latest_value_int(0) assert res == 10 @@ -130,19 +132,19 @@ i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() - faildescr = BasicFailDescr() + faildescr = BasicFailDescr() + looptoken = LoopToken() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr), - ResOperation(rop.JUMP, [i1], None), + ResOperation(rop.JUMP, [i1], None, descr=looptoken), ] inputargs = [i0] operations[2].fail_args = [i1] - operations[-1].jump_target = None wr_i1 = weakref.ref(i1) wr_guard = weakref.ref(operations[2]) - executable_token = self.cpu.compile_loop(inputargs, operations) + self.cpu.compile_loop(inputargs, operations, looptoken) del i0, i1, i2 del inputargs del operations @@ -155,33 +157,30 @@ i2 = BoxInt() faildescr1 = BasicFailDescr() faildescr2 = BasicFailDescr() + looptoken = LoopToken() operations = [ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1), - ResOperation(rop.JUMP, [i1], None), + ResOperation(rop.JUMP, [i1], None, descr=looptoken), ] inputargs = [i0] operations[2].fail_args = [i1] - operations[-1].jump_target = None - executable_token = self.cpu.compile_loop(inputargs, operations) - loop_token = LoopToken() - loop_token.executable_token = executable_token + self.cpu.compile_loop(inputargs, operations, looptoken) i1b = BoxInt() i3 = BoxInt() bridge = [ ResOperation(rop.INT_LE, [i1b, ConstInt(19)], i3), ResOperation(rop.GUARD_TRUE, [i3], None, descr=faildescr2), - ResOperation(rop.JUMP, [i1b], None), + ResOperation(rop.JUMP, [i1b], None, descr=looptoken), ] bridge[1].fail_args = [i1b] - bridge[-1].jump_target = loop_token self.cpu.compile_bridge(faildescr1, [i1b], bridge) self.cpu.set_future_value_int(0, 2) - fail = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(looptoken) assert fail is faildescr2 res = self.cpu.get_latest_value_int(0) assert res == 20 @@ -192,30 +191,33 @@ def __setattr__(self, name, value): py.test.fail("finish descrs should not be touched") faildescr = UntouchableFailDescr() # to check that is not touched + looptoken = LoopToken() operations = [ ResOperation(rop.FINISH, [i0], None, descr=faildescr) ] - executable_token = self.cpu.compile_loop([i0], operations) + self.cpu.compile_loop([i0], operations, looptoken) self.cpu.set_future_value_int(0, 99) - fail = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(looptoken) assert fail is faildescr res = self.cpu.get_latest_value_int(0) assert res == 99 + looptoken = LoopToken() operations = [ ResOperation(rop.FINISH, [ConstInt(42)], None, descr=faildescr) ] - executable_token = self.cpu.compile_loop([], operations) - fail = self.cpu.execute_token(executable_token) + self.cpu.compile_loop([], operations, looptoken) + fail = self.cpu.execute_token(looptoken) assert fail is faildescr res = self.cpu.get_latest_value_int(0) assert res == 42 + looptoken = LoopToken() operations = [ ResOperation(rop.FINISH, [], None, descr=faildescr) ] - executable_token = self.cpu.compile_loop([], operations) - fail = self.cpu.execute_token(executable_token) + self.cpu.compile_loop([], operations, looptoken) + fail = self.cpu.execute_token(looptoken) assert fail is faildescr def test_execute_operations_in_env(self): @@ -225,20 +227,20 @@ z = BoxInt(579) t = BoxInt(455) u = BoxInt(0) # False + looptoken = LoopToken() operations = [ ResOperation(rop.INT_ADD, [x, y], z), ResOperation(rop.INT_SUB, [y, ConstInt(1)], t), ResOperation(rop.INT_EQ, [t, ConstInt(0)], u), ResOperation(rop.GUARD_FALSE, [u], None, descr=BasicFailDescr()), - ResOperation(rop.JUMP, [z, t], None), + ResOperation(rop.JUMP, [z, t], None, descr=looptoken), ] - operations[-1].jump_target = None operations[-2].fail_args = [t, z] - executable_token = cpu.compile_loop([x, y], operations) + cpu.compile_loop([x, y], operations, looptoken) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 10) - res = self.cpu.execute_token(executable_token) + res = self.cpu.execute_token(looptoken) assert self.cpu.get_latest_value_int(0) == 0 assert self.cpu.get_latest_value_int(1) == 55 @@ -305,13 +307,14 @@ ] ops[1].fail_args = [v_res] # - executable_token = self.cpu.compile_loop([v1, v2], ops) + looptoken = LoopToken() + self.cpu.compile_loop([v1, v2], ops, looptoken) for x, y, z in testcases: assert not self.cpu.get_exception() assert not self.cpu.get_exc_value() self.cpu.set_future_value_int(0, x) self.cpu.set_future_value_int(1, y) - fail = self.cpu.execute_token(executable_token) + fail = self.cpu.execute_token(looptoken) if (z == boom) ^ reversed: assert fail is ops[1].descr else: @@ -828,15 +831,14 @@ exc_tp = xtp exc_ptr = xptr loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) + self.cpu.compile_loop(loop.inputargs, loop.operations, loop.token) self.cpu.set_future_value_int(0, 1) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(loop.token) assert self.cpu.get_latest_value_int(0) == 0 assert self.cpu.get_latest_value_ref(1) == xptr self.cpu.clear_exception() self.cpu.set_future_value_int(0, 0) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(loop.token) assert self.cpu.get_latest_value_int(0) == 1 self.cpu.clear_exception() @@ -852,10 +854,9 @@ exc_tp = ytp exc_ptr = yptr loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) + self.cpu.compile_loop(loop.inputargs, loop.operations, loop.token) self.cpu.set_future_value_int(0, 1) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(loop.token) assert self.cpu.get_latest_value_int(0) == 1 self.cpu.clear_exception() @@ -869,14 +870,13 @@ finish(0) ''' loop = parse(ops, self.cpu, namespace=locals()) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) + self.cpu.compile_loop(loop.inputargs, loop.operations, loop.token) self.cpu.set_future_value_int(0, 1) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(loop.token) assert self.cpu.get_latest_value_int(0) == 1 self.cpu.clear_exception() self.cpu.set_future_value_int(0, 0) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(loop.token) assert self.cpu.get_latest_value_int(0) == 0 self.cpu.clear_exception() Modified: pypy/trunk/pypy/jit/backend/test/test_random.py ============================================================================== --- pypy/trunk/pypy/jit/backend/test/test_random.py (original) +++ pypy/trunk/pypy/jit/backend/test/test_random.py Wed Sep 30 18:01:53 2009 @@ -159,12 +159,13 @@ #print >>s, ' operations[%d].suboperations = [' % i #print >>s, ' ResOperation(rop.FAIL, [%s], None)]' % ( # ', '.join([names[v] for v in op.args])) - print >>s, ' executable_token = cpu.compile_loop(inputargs, operations)' + print >>s, ' looptoken = LoopToken()' + print >>s, ' cpu.compile_loop(inputargs, operations, looptoken)' if hasattr(self.loop, 'inputargs'): for i, v in enumerate(self.loop.inputargs): print >>s, ' cpu.set_future_value_int(%d, %d)' % (i, v.value) - print >>s, ' op = cpu.execute_token(executable_token)' + print >>s, ' op = cpu.execute_token(looptoken)' if self.should_fail_by is None: for i, v in enumerate(self.loop.operations[-1].args): print >>s, ' assert cpu.get_latest_value_int(%d) == %d' % ( @@ -401,13 +402,13 @@ loop = TreeLoop('test_random_function') loop.inputargs = startvars[:] loop.operations = [] + loop.token = LoopToken() builder = builder_factory(cpu, loop, startvars[:]) self.generate_ops(builder, r, loop, startvars) self.builder = builder self.loop = loop - self.executable_token = cpu.compile_loop(loop.inputargs, - loop.operations) + cpu.compile_loop(loop.inputargs, loop.operations, loop.token) def generate_ops(self, builder, r, loop, startvars): block_length = demo_conftest.option.block_length @@ -469,7 +470,7 @@ for i, v in enumerate(self.values): cpu.set_future_value_int(i, v) - fail = cpu.execute_token(self.executable_token) + fail = cpu.execute_token(self.loop.token) assert fail is self.should_fail_by.descr for i, v in enumerate(self.get_fail_args()): value = cpu.get_latest_value_int(i) @@ -536,17 +537,15 @@ args = [x.clonebox() for x in subset] rl = RandomLoop(self.builder.cpu, self.builder.fork, r, args) - executable_token = self.cpu.compile_loop(rl.loop.inputargs, - rl.loop.operations) + self.cpu.compile_loop(rl.loop.inputargs, rl.loop.operations, + rl.loop.token) # done - jump_op = ResOperation(rop.JUMP, subset, None) - jump_op.jump_target = LoopToken() - jump_op.jump_target.executable_token = executable_token self.should_fail_by = rl.should_fail_by self.expected = rl.expected assert len(rl.loop.inputargs) == len(args) # The new bridge's execution will end normally at its FINISH. # Just replace the FINISH with the JUMP to the new loop. + jump_op = ResOperation(rop.JUMP, subset, None, descr=rl.loop.token) subloop.operations[-1] = jump_op self.guard_op = rl.guard_op self.prebuilt_ptr_consts += rl.prebuilt_ptr_consts Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/assembler.py (original) +++ pypy/trunk/pypy/jit/backend/x86/assembler.py Wed Sep 30 18:01:53 2009 @@ -62,12 +62,6 @@ if name.upper() == name: setattr(MachineCodeBlockWrapper, name, _new_method(name)) -class ExecutableToken386(object): - _x86_loop_code = 0 - _x86_bootstrap_code = 0 - _x86_stack_depth = 0 - _x86_arglocs = None - class Assembler386(object): mc = None mc2 = None @@ -123,21 +117,24 @@ self.mc = MachineCodeBlockWrapper() self.mc2 = MachineCodeBlockWrapper() - def assemble_loop(self, inputargs, operations): + def assemble_loop(self, inputargs, operations, looptoken): + """adds the following attributes to looptoken: + _x86_loop_code (an integer giving an address) + _x86_bootstrap_code (an integer giving an address) + _x86_stack_depth + _x86_arglocs + """ self.make_sure_mc_exists() regalloc = RegAlloc(self, self.cpu.translate_support_code) - arglocs = regalloc.prepare_loop(inputargs, operations) - executable_token = ExecutableToken386() - executable_token._x86_arglocs = arglocs - executable_token._x86_bootstrap_code = self.mc.tell() + arglocs = regalloc.prepare_loop(inputargs, operations, looptoken) + looptoken._x86_arglocs = arglocs + looptoken._x86_bootstrap_code = self.mc.tell() adr_stackadjust = self._assemble_bootstrap_code(inputargs, arglocs) - executable_token._x86_loop_code = self.mc.tell() - self._executable_token = executable_token + looptoken._x86_loop_code = self.mc.tell() + looptoken._x86_stack_depth = -1 # temporarily stack_depth = self._assemble(regalloc, operations) - self._executable_token = None self._patch_stackadjust(adr_stackadjust, stack_depth) - executable_token._x86_stack_depth = stack_depth - return executable_token + looptoken._x86_stack_depth = stack_depth def assemble_bridge(self, faildescr, inputargs, operations): self.make_sure_mc_exists() @@ -168,9 +165,9 @@ if we_are_translated() or self.cpu.dont_keepalive_stuff: self._regalloc = None # else keep it around for debugging stack_depth = regalloc.sm.stack_depth - jump_target = regalloc.jump_target - if jump_target is not None: - target_stack_depth = jump_target.executable_token._x86_stack_depth + jump_target_descr = regalloc.jump_target_descr + if jump_target_descr is not None: + target_stack_depth = jump_target_descr._x86_stack_depth stack_depth = max(stack_depth, target_stack_depth) return stack_depth @@ -757,19 +754,11 @@ mark = self._regalloc.get_mark_gc_roots(gcrootmap) gcrootmap.put(rffi.cast(llmemory.Address, self.mc.tell()), mark) - def _get_executable_token(self, loop_token): - if loop_token is not None: - return loop_token.executable_token - assert self._executable_token is not None - return self._executable_token - def target_arglocs(self, loop_token): - executable_token = self._get_executable_token(loop_token) - return executable_token._x86_arglocs + return loop_token._x86_arglocs def closing_jump(self, loop_token): - executable_token = self._get_executable_token(loop_token) - self.mc.JMP(rel32(executable_token._x86_loop_code)) + self.mc.JMP(rel32(loop_token._x86_loop_code)) genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST Modified: pypy/trunk/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/regalloc.py Wed Sep 30 18:01:53 2009 @@ -3,7 +3,8 @@ """ from pypy.jit.metainterp.history import (Box, Const, ConstInt, ConstPtr, - ResOperation, ConstAddr, BoxPtr) + ResOperation, ConstAddr, BoxPtr, + LoopToken) from pypy.jit.backend.x86.ri386 import * from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi, rstr from pypy.rlib.objectmodel import we_are_translated @@ -59,7 +60,7 @@ self.assembler = assembler self.translate_support_code = translate_support_code # to be read/used by the assembler too - self.jump_target = None + self.jump_target_descr = None def _prepare(self, inputargs, operations): self.sm = X86StackManager() @@ -71,10 +72,10 @@ stack_manager = self.sm, assembler = self.assembler) - def prepare_loop(self, inputargs, operations): + def prepare_loop(self, inputargs, operations, looptoken): self._prepare(inputargs, operations) jump = operations[-1] - loop_consts = self._compute_loop_consts(inputargs, jump) + loop_consts = self._compute_loop_consts(inputargs, jump, looptoken) self.loop_consts = loop_consts return self._process_inputargs(inputargs) @@ -110,8 +111,8 @@ self.rm.possibly_free_vars(inputargs) return locs - def _compute_loop_consts(self, inputargs, jump): - if jump.opnum != rop.JUMP or jump.jump_target is not None: + def _compute_loop_consts(self, inputargs, jump, looptoken): + if jump.opnum != rop.JUMP or jump.descr is not looptoken: loop_consts = {} else: loop_consts = {} @@ -618,9 +619,11 @@ def consider_jump(self, op, ignored): assembler = self.assembler - assert self.jump_target is None - self.jump_target = op.jump_target - arglocs = assembler.target_arglocs(self.jump_target) + assert self.jump_target_descr is None + descr = op.descr + assert isinstance(descr, LoopToken) + self.jump_target_descr = descr + arglocs = assembler.target_arglocs(self.jump_target_descr) # compute 'tmploc' to be all_regs[0] by spilling what is there box = TempBox() tmpreg = X86RegisterManager.all_regs[0] @@ -631,7 +634,7 @@ remap_stack_layout(assembler, src_locations, dst_locations, tmploc) self.rm.possibly_free_var(box) self.rm.possibly_free_vars(op.args) - assembler.closing_jump(self.jump_target) + assembler.closing_jump(self.jump_target_descr) def consider_debug_merge_point(self, op, ignored): pass Modified: pypy/trunk/pypy/jit/backend/x86/runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/runner.py (original) +++ pypy/trunk/pypy/jit/backend/x86/runner.py Wed Sep 30 18:01:53 2009 @@ -33,8 +33,8 @@ def setup_once(self): pass - def compile_loop(self, inputargs, operations): - return self.assembler.assemble_loop(inputargs, operations) + def compile_loop(self, inputargs, operations, looptoken): + self.assembler.assemble_loop(inputargs, operations, looptoken) def compile_bridge(self, faildescr, inputargs, operations): self.assembler.assemble_bridge(faildescr, inputargs, operations) Modified: pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_recompilation.py Wed Sep 30 18:01:53 2009 @@ -33,7 +33,7 @@ jump(i1) ''' loop = self.interpret(ops, [0]) - previous = loop.executable_token._x86_stack_depth + previous = loop.token._x86_stack_depth assert self.getint(0) == 20 ops = ''' [i1] @@ -47,7 +47,7 @@ finish(i3, i4, i5, i6, i7, i8, i9) ''' bridge = self.attach_bridge(ops, loop, -2) - descr = loop._loop.operations[2].descr + descr = loop.operations[2].descr new = descr._x86_bridge_stack_depth assert new > previous self.cpu.set_future_value_int(0, 0) @@ -73,12 +73,12 @@ ''', [1]) ops = ''' [i3] - jump(i3, 1, 2, 3, 4, 5, 6, 7) + jump(i3, 1, 2, 3, 4, 5, 6, 7, descr=looptoken) ''' - bridge = self.attach_bridge(ops, other_loop, 0, jump_target=loop) + bridge = self.attach_bridge(ops, other_loop, 0, looptoken=loop.token) self.cpu.set_future_value_int(0, 1) fail = self.run(other_loop) - assert fail is loop._loop.operations[2].descr + assert fail is loop.operations[2].descr def test_bridge_jumps_to_self_deeper(self): loop = self.interpret(''' @@ -103,11 +103,11 @@ i7 = int_add(i3, i6) i12 = int_add(i7, i8) i11 = int_add(i12, i6) - jump(i3, i12, i11, i10, i6, i7) + jump(i3, i12, i11, i10, i6, i7, descr=looptoken) ''' - bridge = self.attach_bridge(ops, loop, 5, jump_target=loop) - guard_op = loop._loop.operations[5] - loop_stack_depth = loop.executable_token._x86_stack_depth + bridge = self.attach_bridge(ops, loop, 5, looptoken=loop.token) + guard_op = loop.operations[5] + loop_stack_depth = loop.token._x86_stack_depth assert guard_op.descr._x86_bridge_stack_depth > loop_stack_depth self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) @@ -132,9 +132,9 @@ assert self.getint(1) == 1 ops = ''' [i97, i3] - jump(i3, 0, 1) + jump(i3, 0, 1, descr=looptoken) ''' - bridge = self.attach_bridge(ops, loop, 4, jump_target=loop) + bridge = self.attach_bridge(ops, loop, 4, looptoken=loop.token) self.cpu.set_future_value_int(0, 0) self.cpu.set_future_value_int(1, 0) self.cpu.set_future_value_int(2, 0) Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_regalloc.py Wed Sep 30 18:01:53 2009 @@ -83,16 +83,14 @@ namespace = locals().copy() type_system = 'lltype' - def parse(self, s, boxkinds=None, jump_target=None): + def parse(self, s, boxkinds=None): return parse(s, self.cpu, self.namespace, type_system=self.type_system, - jump_target=jump_target, boxkinds=boxkinds) - def interpret(self, ops, args, jump_target=None, run=True): - loop = self.parse(ops, jump_target=jump_target) - executable_token = self.cpu.compile_loop(loop.inputargs, - loop.operations) + def interpret(self, ops, args, run=True): + loop = self.parse(ops) + self.cpu.compile_loop(loop.inputargs, loop.operations, loop.token) for i, arg in enumerate(args): if isinstance(arg, int): self.cpu.set_future_value_int(i, arg) @@ -101,11 +99,8 @@ llgcref = lltype.cast_opaque_ptr(llmemory.GCREF, arg) self.cpu.set_future_value_ref(i, llgcref) if run: - self.cpu.execute_token(executable_token) - loop_token = LoopToken() - loop_token.executable_token = executable_token - loop_token._loop = loop - return loop_token + self.cpu.execute_token(loop.token) + return loop def getint(self, index): return self.cpu.get_latest_value_int(index) @@ -118,16 +113,19 @@ gcref = self.cpu.get_latest_value_ref(index) return lltype.cast_opaque_ptr(T, gcref) - def attach_bridge(self, ops, loop_token, guard_op_index, **kwds): - guard_op = loop_token._loop.operations[guard_op_index] + def attach_bridge(self, ops, loop, guard_op_index, looptoken=None, **kwds): + if looptoken is not None: + self.namespace = self.namespace.copy() + self.namespace['looptoken'] = looptoken + guard_op = loop.operations[guard_op_index] assert guard_op.is_guard() bridge = self.parse(ops, **kwds) faildescr = guard_op.descr self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations) return bridge - def run(self, loop_token): - return self.cpu.execute_token(loop_token.executable_token) + def run(self, loop): + return self.cpu.execute_token(loop.token) class TestRegallocSimple(BaseTestRegalloc): def test_simple_loop(self): @@ -162,9 +160,9 @@ loop2 = self.interpret(ops2, [0]) bridge_ops = ''' [i4] - jump(i4, i4, i4, i4) + jump(i4, i4, i4, i4, descr=looptoken) ''' - bridge = self.attach_bridge(bridge_ops, loop2, 4, jump_target=loop) + bridge = self.attach_bridge(bridge_ops, loop2, 4, looptoken=loop.token) self.cpu.set_future_value_int(0, 0) self.run(loop2) assert self.getint(0) == 31 Modified: pypy/trunk/pypy/jit/backend/x86/test/test_regalloc2.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_regalloc2.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_regalloc2.py Wed Sep 30 18:01:53 2009 @@ -1,6 +1,6 @@ import py from pypy.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ - BoxPtr, ConstPtr, BasicFailDescr + BoxPtr, ConstPtr, BasicFailDescr, LoopToken from pypy.jit.metainterp.resoperation import rop from pypy.jit.backend.x86.runner import CPU @@ -17,9 +17,10 @@ ResOperation(rop.FINISH, [v4, v3], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) - executable_token = cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + cpu.compile_loop(inputargs, operations, looptoken) cpu.set_future_value_int(0, 9) - cpu.execute_token(executable_token) + cpu.execute_token(looptoken) assert cpu.get_latest_value_int(0) == (9 >> 3) assert cpu.get_latest_value_int(1) == (~18) @@ -38,9 +39,10 @@ ResOperation(rop.FINISH, [v4, v3, tmp5], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) - executable_token = cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + cpu.compile_loop(inputargs, operations, looptoken) cpu.set_future_value_int(0, -10) - cpu.execute_token(executable_token) + cpu.execute_token(looptoken) assert cpu.get_latest_value_int(0) == 0 assert cpu.get_latest_value_int(1) == -1000 assert cpu.get_latest_value_int(2) == 1 @@ -133,7 +135,8 @@ ResOperation(rop.FINISH, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) - executable_token = cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + cpu.compile_loop(inputargs, operations, looptoken) cpu.set_future_value_int(0, -13) cpu.set_future_value_int(1, 10) cpu.set_future_value_int(2, 10) @@ -144,7 +147,7 @@ cpu.set_future_value_int(7, 46) cpu.set_future_value_int(8, -12) cpu.set_future_value_int(9, 26) - cpu.execute_token(executable_token) + cpu.execute_token(looptoken) assert cpu.get_latest_value_int(0) == 0 assert cpu.get_latest_value_int(1) == 0 assert cpu.get_latest_value_int(2) == 0 @@ -246,7 +249,8 @@ ResOperation(rop.FINISH, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None, descr=BasicFailDescr()), ] cpu = CPU(None, None) - executable_token = cpu.compile_loop(inputargs, operations) + looptoken = LoopToken() + cpu.compile_loop(inputargs, operations, looptoken) cpu.set_future_value_int(0, 17) cpu.set_future_value_int(1, -20) cpu.set_future_value_int(2, -6) @@ -257,7 +261,7 @@ cpu.set_future_value_int(7, 9) cpu.set_future_value_int(8, 49) cpu.set_future_value_int(9, 8) - cpu.execute_token(executable_token) + cpu.execute_token(looptoken) assert cpu.get_latest_value_int(0) == 0 assert cpu.get_latest_value_int(1) == 8 assert cpu.get_latest_value_int(2) == 1 Modified: pypy/trunk/pypy/jit/backend/x86/test/test_runner.py ============================================================================== --- pypy/trunk/pypy/jit/backend/x86/test/test_runner.py (original) +++ pypy/trunk/pypy/jit/backend/x86/test/test_runner.py Wed Sep 30 18:01:53 2009 @@ -1,6 +1,6 @@ import py from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr, rclass -from pypy.jit.metainterp.history import ResOperation +from pypy.jit.metainterp.history import ResOperation, LoopToken from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr, Box, BasicFailDescr) from pypy.jit.backend.x86.runner import CPU @@ -254,12 +254,13 @@ descr=BasicFailDescr()), ] ops[-2].fail_args = [i1] - executable_token = self.cpu.compile_loop([b], ops) + looptoken = LoopToken() + self.cpu.compile_loop([b], ops, looptoken) if op == rop.INT_IS_TRUE: self.cpu.set_future_value_int(0, b.value) else: self.cpu.set_future_value_ref(0, b.value) - r = self.cpu.execute_token(executable_token) + r = self.cpu.execute_token(looptoken) result = self.cpu.get_latest_value_int(0) if guard == rop.GUARD_FALSE: assert result == execute(self.cpu, op, None, b).value @@ -301,10 +302,11 @@ ] ops[-2].fail_args = [i1] inputargs = [i for i in (a, b) if isinstance(i, Box)] - executable_token = self.cpu.compile_loop(inputargs, ops) + looptoken = LoopToken() + self.cpu.compile_loop(inputargs, ops, looptoken) for i, box in enumerate(inputargs): self.cpu.set_future_value_int(i, box.value) - r = self.cpu.execute_token(executable_token) + r = self.cpu.execute_token(looptoken) result = self.cpu.get_latest_value_int(0) expected = execute(self.cpu, op, None, a, b).value if guard == rop.GUARD_FALSE: @@ -330,10 +332,11 @@ v = next_v ops.append(ResOperation(rop.FINISH, [v], None, descr=BasicFailDescr())) - executable_token = self.cpu.compile_loop([base_v], ops) + looptoken = LoopToken() + self.cpu.compile_loop([base_v], ops, looptoken) assert self.cpu.assembler.mc != old_mc # overflowed self.cpu.set_future_value_int(0, base_v.value) - self.cpu.execute_token(executable_token) + self.cpu.execute_token(looptoken) assert self.cpu.get_latest_value_int(0) == 1024 finally: MachineCodeBlockWrapper.MC_SIZE = orig_size Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Wed Sep 30 18:01:53 2009 @@ -33,6 +33,11 @@ name = metainterp.staticdata.stats.name_for_new_loop() return TreeLoop(name) +def make_loop_token(nb_args): + loop_token = LoopToken() + loop_token.specnodes = [prebuiltNotSpecNode] * nb_args + return loop_token + # ____________________________________________________________ def compile_new_loop(metainterp, old_loop_tokens, greenkey, start): @@ -49,7 +54,9 @@ loop.operations = history.operations[start:] else: loop.operations = history.operations - loop.operations[-1].jump_target = None + loop_token = make_loop_token(len(loop.inputargs)) + loop.token = loop_token + loop.operations[-1].descr = loop_token # patch the target of the JUMP metainterp_sd = metainterp.staticdata try: old_loop_token = metainterp_sd.state.optimize_loop( @@ -60,12 +67,7 @@ if metainterp.staticdata.state.debug > 0: debug_print("reusing old loop") return old_loop_token - executable_token = send_loop_to_backend(metainterp_sd, loop, "loop") - loop_token = LoopToken() - loop_token.specnodes = loop.specnodes - loop_token.executable_token = executable_token - if not we_are_translated(): - loop.token = loop_token + send_loop_to_backend(metainterp_sd, loop, "loop") insert_loop_token(old_loop_tokens, loop_token) return loop_token @@ -88,8 +90,7 @@ if not we_are_translated(): show_loop(metainterp_sd, loop) loop.check_consistency() - executable_token = metainterp_sd.cpu.compile_loop(loop.inputargs, - loop.operations) + metainterp_sd.cpu.compile_loop(loop.inputargs, loop.operations, loop.token) metainterp_sd.state.profiler.end_backend() metainterp_sd.stats.add_new_loop(loop) if not we_are_translated(): @@ -102,7 +103,6 @@ else: if metainterp_sd.state.debug > 0: debug_print("compiled new " + type) - return executable_token def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations): metainterp_sd.options.logger_ops.log_loop(inputargs, operations) @@ -225,21 +225,19 @@ # with completely unoptimized arguments, as in the interpreter. metainterp_sd = metainterp.staticdata metainterp.history.inputargs = self.redkey + new_loop_token = make_loop_token(len(self.redkey)) new_loop.greenkey = self.original_greenkey new_loop.inputargs = self.redkey - executable_token = send_loop_to_backend(metainterp_sd, new_loop, - "entry bridge") + new_loop.token = new_loop_token + send_loop_to_backend(metainterp_sd, new_loop, "entry bridge") # send the new_loop to warmspot.py, to be called directly the next time metainterp_sd.state.attach_unoptimized_bridge_from_interp( self.original_greenkey, - executable_token) + new_loop_token) # store the new loop in compiled_merge_points too glob = metainterp_sd.globaldata greenargs = glob.unpack_greenkey(self.original_greenkey) old_loop_tokens = glob.compiled_merge_points.setdefault(greenargs, []) - new_loop_token = LoopToken() - new_loop_token.specnodes = [prebuiltNotSpecNode] * len(self.redkey) - new_loop_token.executable_token = executable_token # it always goes at the end of the list, as it is the most # general loop token old_loop_tokens.append(new_loop_token) @@ -279,11 +277,11 @@ op = new_loop.operations[-1] if not isinstance(target_loop_token, TerminatingLoopToken): # normal case - op.jump_target = target_loop_token + op.descr = target_loop_token # patch the jump target else: # The target_loop_token is a pseudo loop token, # e.g. loop_tokens_done_with_this_frame_void[0] - # Replace the operation with the real operation we want, i.e. a FAIL. + # Replace the operation with the real operation we want, i.e. a FINISH descr = target_loop_token.finishdescr new_op = ResOperation(rop.FINISH, op.args, None, descr=descr) new_loop.operations[-1] = new_op Modified: pypy/trunk/pypy/jit/metainterp/graphpage.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/graphpage.py (original) +++ pypy/trunk/pypy/jit/metainterp/graphpage.py Wed Sep 30 18:01:53 2009 @@ -168,7 +168,7 @@ (graphindex, opindex)) break if op.opnum == rop.JUMP: - tgt = op.jump_target + tgt = op.descr tgt_g = -1 if tgt is None: tgt_g = graphindex Modified: pypy/trunk/pypy/jit/metainterp/history.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/history.py (original) +++ pypy/trunk/pypy/jit/metainterp/history.py Wed Sep 30 18:01:53 2009 @@ -644,19 +644,22 @@ # of operations. Each branch ends in a jump which can go either to # the top of the same loop, or to another TreeLoop; or it ends in a FINISH. -class Base(object): - """Common base class for TreeLoop and History.""" - -class LoopToken(object): - """loop token""" +class LoopToken(AbstractDescr): + """Used for rop.JUMP, giving the target of the jump. + This is different from TreeLoop: the TreeLoop class contains the + whole loop, including 'operations', and goes away after the loop + was compiled; but the LoopDescr remains alive and points to the + generated assembler. + """ terminating = False # see TerminatingLoopToken in compile.py - # specnodes - # executable_token + # specnodes = ... + # and more data specified by the backend when the loop is compiled -class TreeLoop(Base): +class TreeLoop(object): inputargs = None - specnodes = None operations = None + token = None + specnodes = property(lambda x: crash, lambda x, y: crash) # XXX temp def __init__(self, name): self.name = name @@ -727,7 +730,7 @@ seen[box] = True assert operations[-1].is_final() if operations[-1].opnum == rop.JUMP: - target = operations[-1].jump_target + target = operations[-1].descr if target is not None: assert isinstance(target, LoopToken) @@ -764,7 +767,7 @@ # ____________________________________________________________ -class History(Base): +class History(object): def __init__(self, cpu): self.cpu = cpu self.inputargs = None @@ -800,6 +803,9 @@ def add_new_loop(self, loop): pass + def view(self, **kwds): + pass + class Stats(object): """For tests.""" Modified: pypy/trunk/pypy/jit/metainterp/optimize.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimize.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimize.py Wed Sep 30 18:01:53 2009 @@ -9,7 +9,7 @@ finder = PerfectSpecializationFinder(cpu) finder.find_nodes_loop(loop) for old_loop_token in old_loop_tokens: - if equals_specnodes(old_loop_token.specnodes, loop.specnodes): + if equals_specnodes(old_loop_token.specnodes, loop.token.specnodes): return old_loop_token optimize_loop_1(cpu, loop) return None @@ -25,7 +25,7 @@ finder.find_nodes_bridge(bridge) for old_loop_token in old_loop_tokens: if finder.bridge_matches(old_loop_token.specnodes): - bridge.operations[-1].jump_target = old_loop_token + bridge.operations[-1].descr = old_loop_token # patch jump target optimize_bridge_1(cpu, bridge) return old_loop_token return None Modified: pypy/trunk/pypy/jit/metainterp/optimizefindnode.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimizefindnode.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimizefindnode.py Wed Sep 30 18:01:53 2009 @@ -337,7 +337,7 @@ inputnode = self.inputnodes[i] exitnode = self.getnode(op.args[i]) specnodes.append(self.intersect(inputnode, exitnode)) - loop.specnodes = specnodes + loop.token.specnodes = specnodes def intersect(self, inputnode, exitnode): assert inputnode.fromstart Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/optimizeopt.py Wed Sep 30 18:01:53 2009 @@ -1,4 +1,4 @@ -from pypy.jit.metainterp.history import Box, BoxInt +from pypy.jit.metainterp.history import Box, BoxInt, LoopToken from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstObj, REF from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.executor import execute_nonspec @@ -458,7 +458,7 @@ def setup_virtuals_and_constants(self): inputargs = self.loop.inputargs - specnodes = self.loop.specnodes + specnodes = self.loop.token.specnodes assert len(inputargs) == len(specnodes) newinputargs = [] for i in range(len(inputargs)): @@ -547,18 +547,15 @@ def optimize_JUMP(self, op): orgop = self.loop.operations[-1] exitargs = [] - target = orgop.jump_target - if target is None: - specnodes = self.loop.specnodes - else: - specnodes = target.specnodes + target_loop_token = orgop.descr + assert isinstance(target_loop_token, LoopToken) + specnodes = target_loop_token.specnodes assert len(op.args) == len(specnodes) for i in range(len(specnodes)): value = self.getvalue(op.args[i]) specnodes[i].teardown_virtual_node(self, value, exitargs) op2 = op.clone() op2.args = exitargs - op2.jump_target = op.jump_target self.emit_operation(op2, must_clone=False) def optimize_guard(self, op, constbox): Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Wed Sep 30 18:01:53 2009 @@ -1438,7 +1438,7 @@ residual_args = self.get_residual_args(loop_token.specnodes, gmp.argboxes[num_green_args:]) history.set_future_values(self.cpu, residual_args) - return loop_token.executable_token + return loop_token def prepare_resume_from_failure(self, opnum): if opnum == rop.GUARD_TRUE: # a goto_if_not that jumps only now Modified: pypy/trunk/pypy/jit/metainterp/resoperation.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resoperation.py (original) +++ pypy/trunk/pypy/jit/metainterp/resoperation.py Wed Sep 30 18:01:53 2009 @@ -5,16 +5,13 @@ """The central ResOperation class, representing one operation.""" # for 'jump': points to the target loop; - jump_target = None + jump_target = property(lambda x: crash, lambda x, y: crash) # XXX temp # for 'guard_*' suboperations = property(lambda x: crash, lambda x, y: crash) # XXX temp optimized = property(lambda x: crash, lambda x, y: crash) # XXX temp fail_args = None - # for x86 backend and guards - inputargs = None - # debug name = "" pc = 0 Modified: pypy/trunk/pypy/jit/metainterp/resume.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/resume.py (original) +++ pypy/trunk/pypy/jit/metainterp/resume.py Wed Sep 30 18:01:53 2009 @@ -3,7 +3,7 @@ from pypy.jit.metainterp.resoperation import rop # Logic to encode the chain of frames and the state of the boxes at a -# FAIL operation, and to decode it again. This is a bit advanced, +# guard operation, and to decode it again. This is a bit advanced, # because it needs to support optimize.py which encodes virtuals with # arbitrary cycles. Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/oparser.py Wed Sep 30 18:01:53 2009 @@ -4,7 +4,7 @@ """ from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ - ConstAddr, ConstObj, ConstPtr, Box, BasicFailDescr + ConstAddr, ConstObj, ConstPtr, Box, BasicFailDescr, LoopToken from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.metainterp.typesystem import llhelper from pypy.rpython.lltypesystem import lltype, llmemory @@ -49,17 +49,17 @@ class OpParser(object): - def __init__(self, descr, cpu, namespace, type_system, boxkinds, jump_target, invent_fail_descr=default_fail_descr): + def __init__(self, descr, cpu, namespace, type_system, boxkinds, + invent_fail_descr=default_fail_descr): self.descr = descr self.vars = {} self.cpu = cpu self.consts = namespace self.type_system = type_system self.boxkinds = boxkinds or {} - self.jumps = [] - self.jump_target = jump_target self._cache = namespace.setdefault('_CACHE_', {}) self.invent_fail_descr = invent_fail_descr + self.looptoken = LoopToken() def box_for_var(self, elem): try: @@ -188,6 +188,9 @@ if opnum == rop.FINISH: if descr is None and self.invent_fail_descr: descr = self.invent_fail_descr() + elif opnum == rop.JUMP: + if descr is None and self.invent_fail_descr: + descr = self.looptoken return opnum, args, descr, fail_args def parse_result_op(self, line): @@ -207,8 +210,6 @@ opnum, args, descr, fail_args = self.parse_op(line) res = ResOperation(opnum, args, None, descr) res.fail_args = fail_args - if opnum == rop.JUMP: - self.jumps.append(res) return res def parse_next_op(self, line): @@ -240,12 +241,7 @@ if num < len(newlines): raise ParseError("unexpected dedent at line: %s" % newlines[num]) loop = ExtendedTreeLoop("loop") - if len(self.jumps) > 1: - raise ParseError("Multiple jumps??") - if self.jump_target is not None and len(self.jumps) != 1: - raise ParseError("A jump is expected if a jump_target is given") - for jump in self.jumps: - jump.jump_target = self.jump_target + loop.token = self.looptoken loop.operations = ops loop.inputargs = inpargs return loop @@ -276,11 +272,10 @@ return base_indent, inpargs def parse(descr, cpu=None, namespace=None, type_system='lltype', - boxkinds=None, jump_target=None, - invent_fail_descr=default_fail_descr): + boxkinds=None, invent_fail_descr=default_fail_descr): if namespace is None: namespace = {} - return OpParser(descr, cpu, namespace, type_system, boxkinds, jump_target, + return OpParser(descr, cpu, namespace, type_system, boxkinds, invent_fail_descr).parse() def pure_parse(*args, **kwds): Modified: pypy/trunk/pypy/jit/metainterp/test/test_compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_compile.py Wed Sep 30 18:01:53 2009 @@ -1,6 +1,9 @@ -from pypy.jit.metainterp.history import LoopToken, ConstInt +from pypy.jit.metainterp.history import LoopToken, ConstInt, History, Stats from pypy.jit.metainterp.specnode import NotSpecNode, ConstantSpecNode -from pypy.jit.metainterp.compile import insert_loop_token +from pypy.jit.metainterp.compile import insert_loop_token, compile_new_loop +from pypy.jit.metainterp import optimize, jitprof +from pypy.jit.metainterp.test.oparser import parse +from pypy.jit.metainterp.test.test_optimizefindnode import LLtypeMixin def test_insert_loop_token(): @@ -20,3 +23,72 @@ tok3.specnodes = [ConstantSpecNode(ConstInt(-13))] insert_loop_token(lst, tok3) assert lst == [tok2, tok3, tok1] + + +class FakeCPU: + def __init__(self): + self.seen = [] + def compile_loop(self, inputargs, operations, token): + self.seen.append((inputargs, operations, token)) + +class FakeLogger: + def log_loop(self, inputargs, operations): + pass + +class FakeOptions: + logger_noopt = FakeLogger() + logger_ops = FakeLogger() + +class FakeState: + optimize_loop = staticmethod(optimize.optimize_loop) + profiler = jitprof.EmptyProfiler() + debug = 0 + +class FakeMetaInterpStaticData: + options = FakeOptions() + state = FakeState() + stats = Stats() + +class FakeMetaInterp: + pass + +def test_compile_new_loop(): + cpu = FakeCPU() + staticdata = FakeMetaInterpStaticData() + staticdata.cpu = cpu + # + loop = parse(''' + [p1] + i1 = getfield_gc(p1, descr=valuedescr) + i2 = int_add(i1, 1) + p2 = new_with_vtable(ConstClass(node_vtable)) + setfield_gc(p2, i2, descr=valuedescr) + jump(p2) + ''', namespace=LLtypeMixin.__dict__.copy()) + # + metainterp = FakeMetaInterp() + metainterp.staticdata = staticdata + metainterp.cpu = cpu + metainterp.history = History(metainterp.cpu) + metainterp.history.operations = loop.operations[:] + metainterp.history.inputargs = loop.inputargs[:] + # + loop_tokens = [] + loop_token = compile_new_loop(metainterp, loop_tokens, [], 0) + assert loop_tokens == [loop_token] + # + assert len(cpu.seen) == 1 + assert cpu.seen[0][2] == loop_token + # + del cpu.seen[:] + metainterp = FakeMetaInterp() + metainterp.staticdata = staticdata + metainterp.cpu = cpu + metainterp.history = History(metainterp.cpu) + metainterp.history.operations = loop.operations[:] + metainterp.history.inputargs = loop.inputargs[:] + # + loop_token_2 = compile_new_loop(metainterp, loop_tokens, [], 0) + assert loop_token_2 is loop_token + assert loop_tokens == [loop_token] + assert len(cpu.seen) == 0 Modified: pypy/trunk/pypy/jit/metainterp/test/test_oparser.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_oparser.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_oparser.py Wed Sep 30 18:01:53 2009 @@ -3,7 +3,7 @@ from pypy.jit.metainterp.test.oparser import parse from pypy.jit.metainterp.resoperation import rop -from pypy.jit.metainterp.history import AbstractDescr, BoxInt +from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken def test_basic_parse(): x = """ @@ -118,16 +118,16 @@ jump() ''' loop = parse(x) - assert loop.operations[0].jump_target is None + assert loop.operations[0].descr is loop.token def test_jump_target_other(): + looptoken = LoopToken() x = ''' [] - jump() + jump(descr=looptoken) ''' - obj = object() - loop = parse(x, jump_target=obj) - assert loop.operations[0].jump_target is obj + loop = parse(x, namespace=locals()) + assert loop.operations[0].descr is looptoken def test_debug_merge_point(): x = ''' Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizefindnode.py Wed Sep 30 18:01:53 2009 @@ -224,7 +224,7 @@ loop = self.parse(ops, boxkinds=boxkinds) perfect_specialization_finder = PerfectSpecializationFinder(self.cpu) perfect_specialization_finder.find_nodes_loop(loop) - self.check_specnodes(loop.specnodes, spectext) + self.check_specnodes(loop.token.specnodes, spectext) return (loop.getboxes(), perfect_specialization_finder.getnode) def test_find_nodes_simple(self): Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py Wed Sep 30 18:01:53 2009 @@ -64,7 +64,8 @@ assert op1.result == remap[op2.result] else: remap[op2.result] = op1.result - assert op1.descr == op2.descr + if op1.opnum != rop.JUMP: # xxx obscure + assert op1.descr == op2.descr if op1.fail_args or op2.fail_args: assert len(op1.fail_args) == len(op2.fail_args) for x, y in zip(op1.fail_args, op2.fail_args): @@ -146,14 +147,11 @@ cpu = self.cpu perfect_specialization_finder = PerfectSpecializationFinder(cpu) perfect_specialization_finder.find_nodes_loop(loop) - self.check_specnodes(loop.specnodes, spectext) + self.check_specnodes(loop.token.specnodes, spectext) else: # for cases where we want to see how optimizeopt behaves with # combinations different from the one computed by optimizefindnode - loop.specnodes = self.unpack_specnodes(spectext) - # - assert loop.operations[-1].opnum == rop.JUMP - loop.operations[-1].jump_target = loop + loop.token.specnodes = self.unpack_specnodes(spectext) # optimize_loop_1(self.cpu, loop) # Modified: pypy/trunk/pypy/jit/metainterp/test/test_send.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_send.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_send.py Wed Sep 30 18:01:53 2009 @@ -586,7 +586,27 @@ self.check_loops(oosend=0) else: self.check_loops(call=0) - + + def test_generalize_loop(self): + myjitdriver = JitDriver(greens=[], reds = ['i', 'obj']) + class A: + def __init__(self, n): + self.n = n + def extern(obj): + pass + def fn(i): + obj = A(1) + while i > 0: + myjitdriver.can_enter_jit(i=i, obj=obj) + myjitdriver.jit_merge_point(i=i, obj=obj) + obj = A(obj.n + 1) + if i < 10: + extern(obj) + i -= 1 + return obj.n + res = self.meta_interp(fn, [20], policy=StopAtXPolicy(extern)) + assert res == 21 + class TestOOtype(SendTests, OOJitMixin): pass Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/warmspot.py Wed Sep 30 18:01:53 2009 @@ -697,8 +697,8 @@ # class MachineCodeEntryPoint(object): next = None # linked list - def __init__(self, entry_executable_token, *greenargs): - self.entry_executable_token = entry_executable_token + def __init__(self, entry_loop_token, *greenargs): + self.entry_loop_token = entry_loop_token i = 0 for name in green_args_names: setattr(self, 'green_' + name, greenargs[i]) @@ -836,7 +836,7 @@ return metainterp = MetaInterp(metainterp_sd) try: - executable_token = metainterp.compile_and_run_once(*args) + loop_token = metainterp.compile_and_run_once(*args) except warmrunnerdesc.ContinueRunningNormally: # the trace got too long, reset the counter self.mccounters[argshash] = 0 @@ -848,21 +848,20 @@ cell = self.mcentrypoints[argshash] if not cell.equalkey(*greenargs): # hash collision - executable_token = self.handle_hash_collision(cell, - argshash, - *args) - if executable_token is None: + loop_token = self.handle_hash_collision(cell, argshash, + *args) + if loop_token is None: return else: # get the assembler and fill in the boxes cell.set_future_values(*args[num_green_args:]) - executable_token = cell.entry_executable_token + loop_token = cell.entry_loop_token # ---------- execute assembler ---------- while True: # until interrupted by an exception metainterp_sd.state.profiler.start_running() - fail_descr = metainterp_sd.cpu.execute_token(executable_token) + fail_descr = metainterp_sd.cpu.execute_token(loop_token) metainterp_sd.state.profiler.end_running() - executable_token = fail_descr.handle_fail(metainterp_sd) + loop_token = fail_descr.handle_fail(metainterp_sd) maybe_compile_and_run._dont_inline_ = True @@ -878,7 +877,7 @@ nextcell.next = firstcell self.mcentrypoints[argshash] = nextcell nextcell.set_future_values(*args[num_green_args:]) - return nextcell.entry_executable_token + return nextcell.entry_loop_token cell = nextcell # not found at all, do profiling counter = self.mccounters[argshash] @@ -938,9 +937,9 @@ key.counter = 0 def attach_unoptimized_bridge_from_interp(self, greenkey, - entry_executable_token): + entry_loop_token): greenargs = self.unwrap_greenkey(greenkey) - newcell = MachineCodeEntryPoint(entry_executable_token, *greenargs) + newcell = MachineCodeEntryPoint(entry_loop_token, *greenargs) argshash = self.getkeyhash(*greenargs) & self.hashtablemask oldcell = self.mcentrypoints[argshash] newcell.next = oldcell # link From fijal at codespeak.net Wed Sep 30 18:23:47 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 18:23:47 +0200 (CEST) Subject: [pypy-svn] r68043 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090930162347.569AF168013@codespeak.net> Author: fijal Date: Wed Sep 30 18:23:46 2009 New Revision: 68043 Modified: pypy/trunk/pypy/jit/metainterp/compile.py pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py Log: A test and a fix Modified: pypy/trunk/pypy/jit/metainterp/compile.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/compile.py (original) +++ pypy/trunk/pypy/jit/metainterp/compile.py Wed Sep 30 18:23:46 2009 @@ -64,7 +64,7 @@ except InvalidLoop: return None if old_loop_token is not None: - if metainterp.staticdata.state.debug > 0: + if metainterp.staticdata.state.debug > 1: debug_print("reusing old loop") return old_loop_token send_loop_to_backend(metainterp_sd, loop, "loop") @@ -98,10 +98,10 @@ metainterp_sd.stats.compiled() else: loop._ignore_during_counting = True - if metainterp_sd.state.debug > 0: + if metainterp_sd.state.debug > 1: log.info("compiled new " + type) else: - if metainterp_sd.state.debug > 0: + if metainterp_sd.state.debug > 1: debug_print("compiled new " + type) def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations): @@ -114,11 +114,11 @@ metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations) metainterp_sd.state.profiler.end_backend() if not we_are_translated(): - if metainterp_sd.state.debug > 0: + if metainterp_sd.state.debug > 1: metainterp_sd.stats.compiled() log.info("compiled new bridge") else: - if metainterp_sd.state.debug > 0: + if metainterp_sd.state.debug > 1: debug_print("compiled new bridge") # ____________________________________________________________ Modified: pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_warmspot.py Wed Sep 30 18:23:46 2009 @@ -181,6 +181,7 @@ err = errf.read() assert not 'ENTER' in err assert not 'LEAVE' in err + assert not 'compiled new' in err assert "Running asm" in err outerr = py.io.StdCaptureFD() self.meta_interp(f, [10], debug=DEBUG_STEPS) From arigo at codespeak.net Wed Sep 30 18:38:19 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 18:38:19 +0200 (CEST) Subject: [pypy-svn] r68044 - in pypy/trunk/pypy/jit/metainterp: . test Message-ID: <20090930163819.E6A37168011@codespeak.net> Author: arigo Date: Wed Sep 30 18:38:17 2009 New Revision: 68044 Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py pypy/trunk/pypy/jit/metainterp/policy.py pypy/trunk/pypy/jit/metainterp/pyjitpl.py pypy/trunk/pypy/jit/metainterp/test/test_basic.py pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py Log: Remove the "call stubs", which were inspired by the old first-generation JIT. Just check in 'indirect_call' if the graph we are about to call has a corresponding jitcode or not. Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/codewriter.py Wed Sep 30 18:38:17 2009 @@ -72,13 +72,16 @@ self.portal_graph = graph graph_key = (graph, None) jitcode = self.make_one_bytecode(graph_key, True) - while self.unfinished_graphs: - graph_key, called_from = self.unfinished_graphs.pop() - self.make_one_bytecode(graph_key, False, called_from) + self.finish_making_bytecodes() log.info("there are %d JitCode instances." % len(self.all_graphs)) self.annotation_hacks(jitcode) return jitcode + def finish_making_bytecodes(self): + while self.unfinished_graphs: + graph_key, called_from = self.unfinished_graphs.pop() + self.make_one_bytecode(graph_key, False, called_from) + def annotation_hacks(self, jitcode): if not self.class_sizes: if self.rtyper.type_system.name == 'lltypesystem': @@ -226,10 +229,8 @@ graph, oosend_methdescr = graph_key self.bytecode = self.codewriter.get_jitcode(graph, oosend_methdescr=oosend_methdescr) - if not codewriter.policy.look_inside_graph(graph, - self.cpu.supports_floats): - assert not portal, "portal has been hidden!" - graph = make_calling_stub(codewriter.rtyper, graph) + assert codewriter.policy.look_inside_graph(graph, + self.cpu.supports_floats) self.graph = graph def assemble(self): @@ -1073,11 +1074,15 @@ def handle_regular_indirect_call(self, op): self.codewriter.register_indirect_call_targets(op) + args = op.args[1:-1] + calldescr, non_void_args = self.codewriter.getcalldescr(op.args[0], + args, + op.result) self.minimize_variables() self.emit('indirect_call') + self.emit(self.get_position(calldescr)) self.emit(self.var_position(op.args[0])) - self.emit_varargs([x for x in op.args[1:-1] - if x.concretetype is not lltype.Void]) + self.emit_varargs(non_void_args) self.register_var(op.result) def handle_regular_oosend(self, op): @@ -1507,24 +1512,6 @@ # ____________________________________________________________ -def make_calling_stub(rtyper, graph): - from pypy.objspace.flow.model import Block, Link, FunctionGraph - from pypy.objspace.flow.model import SpaceOperation - from pypy.translator.unsimplify import copyvar - # - args_v = [copyvar(None, v) for v in graph.getargs()] - v_res = copyvar(None, graph.getreturnvar()) - fnptr = rtyper.getcallable(graph) - v_ptr = Constant(fnptr, lltype.typeOf(fnptr)) - newstartblock = Block(args_v) - newstartblock.operations.append( - SpaceOperation('direct_call', [v_ptr] + args_v, v_res)) - newgraph = FunctionGraph('%s_ts_stub' % (graph.name,), newstartblock) - newgraph.getreturnvar().concretetype = v_res.concretetype - newstartblock.closeblock(Link([v_res], newgraph.returnblock)) - newgraph.ts_stub_for = graph - return newgraph - class VirtualizableArrayField(Exception): def __str__(self): return "using virtualizable array in illegal way in %r" % ( Modified: pypy/trunk/pypy/jit/metainterp/policy.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/policy.py (original) +++ pypy/trunk/pypy/jit/metainterp/policy.py Wed Sep 30 18:38:17 2009 @@ -43,10 +43,13 @@ v_obj = op.args[1].concretetype graphs = v_obj._lookup_graphs(op.args[0].value) if graphs is not None: + result = [] for graph in graphs: if self.look_inside_graph(graph, supports_floats): - return graphs # common case: look inside at - # least one of the graphs + result.append(graph) + if result: + return result # common case: look inside these graphs, + # and ignore the others if there are any # residual call case: we don't need to look into any graph return None Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original) +++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Wed Sep 30 18:38:17 2009 @@ -655,13 +655,19 @@ def opimpl_residual_call_pure(self, calldescr, varargs): self.execute_varargs(rop.CALL_PURE, varargs, descr=calldescr, exc=False) - @arguments("orgpc", "box", "varargs") - def opimpl_indirect_call(self, pc, box, varargs): + @arguments("orgpc", "descr", "box", "varargs") + def opimpl_indirect_call(self, pc, calldescr, box, varargs): box = self.implement_guard_value(pc, box) cpu = self.metainterp.cpu key = cpu.ts.getaddr_for_box(cpu, box) jitcode = self.metainterp.staticdata.bytecode_for_address(key) - return self.perform_call(jitcode, varargs) + if jitcode is not None: + # we should follow calls to this graph + return self.perform_call(jitcode, varargs) + else: + # but we should not follow calls to that graph + return self.execute_varargs(rop.CALL, [box] + varargs, + descr=calldescr, exc=True) @arguments("orgpc", "methdescr", "varargs") def opimpl_oosend(self, pc, methdescr, varargs): @@ -1031,12 +1037,12 @@ for i in range(len(keys)): d[keys[i]] = values[i] self.globaldata.indirectcall_dict = d - return d[fnaddress] + return d.get(fnaddress, None) else: for i in range(len(self.indirectcall_keys)): if fnaddress == self.indirectcall_keys[i]: return self.indirectcall_values[i] - raise KeyError(fnaddress) + return None # ---------- construction-time interface ---------- Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Wed Sep 30 18:38:17 2009 @@ -93,9 +93,7 @@ graph = rtyper.annotator.translator.graphs[0] graph_key = (graph, None) maingraph = cw.make_one_bytecode(graph_key, False) - while cw.unfinished_graphs: - graph_key, called_from = cw.unfinished_graphs.pop() - cw.make_one_bytecode(graph_key, False, called_from) + cw.finish_making_bytecodes() metainterp.staticdata.portal_code = maingraph metainterp.staticdata._class_sizes = cw.class_sizes metainterp.staticdata.state = FakeWarmRunnerDesc() Modified: pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py ============================================================================== --- pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py (original) +++ pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py Wed Sep 30 18:38:17 2009 @@ -1,8 +1,11 @@ import py +from pypy.rlib import jit from pypy.jit.metainterp import support, typesystem from pypy.jit.metainterp.policy import JitPolicy from pypy.jit.metainterp.codewriter import CodeWriter from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin +from pypy.translator.translator import graphof +from pypy.rpython.lltypesystem.rbuiltin import ll_instantiate class SomeLabel(object): @@ -15,6 +18,7 @@ def setup_method(self, _): class FakeMetaInterpSd: + virtualizable_info = None def find_opcode(self, name): default = len(self.opname_to_index) return self.opname_to_index.setdefault(name, default) @@ -24,6 +28,10 @@ class FakeCPU: ts = typesystem.llhelper supports_floats = False + def fielddescrof(self, STRUCT, fieldname): + return ('fielddescr', STRUCT, fieldname) + def calldescrof(self, FUNC, NON_VOID_ARGS, RESULT): + return ('calldescr', FUNC, NON_VOID_ARGS, RESULT) self.metainterp_sd = FakeMetaInterpSd() self.metainterp_sd.opcode_implementations = None @@ -31,16 +39,20 @@ self.metainterp_sd.indirectcalls = [] self.metainterp_sd.cpu = FakeCPU() - def getgraph(self, func, values): + def make_graph(self, func, values): rtyper = support.annotate(func, values, type_system=self.type_system) self.metainterp_sd.cpu.rtyper = rtyper return rtyper.annotator.translator.graphs[0] + def graphof(self, func): + rtyper = self.metainterp_sd.cpu.rtyper + return graphof(rtyper.annotator.translator, func) + def test_basic(self): def f(n): return n + 10 - graph = self.getgraph(f, [5]) + graph = self.make_graph(f, [5]) cw = CodeWriter(self.metainterp_sd, JitPolicy()) jitcode = cw.make_one_bytecode((graph, None), False) assert jitcode._source == [ @@ -60,7 +72,7 @@ else: call = h return call(n+1) + call(n+2) - graph = self.getgraph(f, [5]) + graph = self.make_graph(f, [5]) cw = CodeWriter(self.metainterp_sd, JitPolicy()) jitcode = cw.make_one_bytecode((graph, None), False) assert len(self.metainterp_sd.indirectcalls) == 2 @@ -68,6 +80,47 @@ in self.metainterp_sd.indirectcalls] assert dict.fromkeys(names) == {'g': None, 'h': None} + def test_indirect_look_inside_only_one(self): + def g(m): + return 123 + @jit.dont_look_inside + def h(m): + return 456 + def f(n): + if n > 3: + call = g + else: + call = h + return call(n+1) + call(n+2) + graph = self.make_graph(f, [5]) + cw = CodeWriter(self.metainterp_sd, JitPolicy()) + jitcode = cw.make_one_bytecode((graph, None), False) + assert len(self.metainterp_sd.indirectcalls) == 1 + names = [jitcode.name for (fnaddress, jitcode) + in self.metainterp_sd.indirectcalls] + assert dict.fromkeys(names) == {'g': None} + + def test_instantiate(self): + py.test.skip("in-progress") + class A1: id = 651 + class A2(A1): id = 652 + class B1: id = 661 + class B2(B1): id = 662 + def f(n): + if n > 5: + x, y = A1, B1 + else: + x, y = A2, B2 + n += 1 + return x().id + y().id + n + graph = self.make_graph(f, [5]) + cw = CodeWriter(self.metainterp_sd, JitPolicy()) + cw.make_one_bytecode((graph, None), False) + graph2 = self.graphof(ll_instantiate) + jitcode = cw.make_one_bytecode((graph2, None), False) + assert 'residual_call' not in jitcode._source + xxx + class ImmutableFieldsTests: From fijal at codespeak.net Wed Sep 30 19:14:36 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 19:14:36 +0200 (CEST) Subject: [pypy-svn] r68045 - pypy/trunk/pypy/config Message-ID: <20090930171436.60720168020@codespeak.net> Author: fijal Date: Wed Sep 30 19:14:36 2009 New Revision: 68045 Modified: pypy/trunk/pypy/config/translationoption.py Log: Change the default to 'profile' Modified: pypy/trunk/pypy/config/translationoption.py ============================================================================== --- pypy/trunk/pypy/config/translationoption.py (original) +++ pypy/trunk/pypy/config/translationoption.py Wed Sep 30 19:14:36 2009 @@ -104,7 +104,7 @@ default="auto", cmdline="--jit-backend"), ChoiceOption("jit_debug", "the amount of debugging dumps made by the JIT", ["off", "profile", "steps", "detailed"], - default="steps", # XXX for now + default="profile", # XXX for now cmdline="--jit-debug"), # misc From fijal at codespeak.net Wed Sep 30 19:17:36 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 19:17:36 +0200 (CEST) Subject: [pypy-svn] r68046 - pypy/build/bot2/pypybuildbot Message-ID: <20090930171736.4A94C168023@codespeak.net> Author: fijal Date: Wed Sep 30 19:17:35 2009 New Revision: 68046 Modified: pypy/build/bot2/pypybuildbot/builds.py Log: Make jit lib-python run with steps as jit-debug Modified: pypy/build/bot2/pypybuildbot/builds.py ============================================================================== --- pypy/build/bot2/pypybuildbot/builds.py (original) +++ pypy/build/bot2/pypybuildbot/builds.py Wed Sep 30 19:17:35 2009 @@ -202,7 +202,9 @@ setup_steps(platform, self) - self.addStep(Translate(['-Ojit', '--gc=hybrid','--gcrootfinder=asmgcc'], + self.addStep(Translate(['-Ojit', '--gc=hybrid', + '--gcrootfinder=asmgcc', + '--jit-debug=steps'], ['--withoutmod-thread'])) self.addStep(ShellCmd( From fijal at codespeak.net Wed Sep 30 19:55:59 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 19:55:59 +0200 (CEST) Subject: [pypy-svn] r68051 - in pypy/branch/floats-via-sse2/pypy/jit/backend/x86: . test Message-ID: <20090930175559.07B20168013@codespeak.net> Author: fijal Date: Wed Sep 30 19:55:59 2009 New Revision: 68051 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py Log: * Fix test regalloc * Write a test for XXX test me * Fix various places that lacked correct register management Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Wed Sep 30 19:55:59 2009 @@ -71,7 +71,6 @@ def convert_to_imm(self, c): if self.constant_array_counter >= BASE_CONSTANT_SIZE: - xxx # test me self.constant_arrays.append(self.new_const_array()) self.constant_array_counter = 0 res = self.constant_array_counter @@ -167,9 +166,20 @@ # otherwise we have it saved on stack, so no worry self.rm.free_regs.insert(0, tmpreg) assert tmpreg not in locs - self.rm.possibly_free_vars(inputargs) + for arg in inputargs: + self.possibly_free_var(arg) return locs + def possibly_free_var(self, var): + if var.type == FLOAT: + self.xrm.possibly_free_var(var) + else: + self.rm.possibly_free_var(var) + + def possibly_free_vars(self, vars): + for var in vars: + self.possibly_free_var(var) + def _compute_loop_consts(self, inputargs, jump): if jump.opnum != rop.JUMP or jump.jump_target is not None: loop_consts = {} @@ -219,6 +229,7 @@ def perform_with_guard(self, op, guard_op, arglocs, result_loc): faillocs = self.locs_for_fail(guard_op) self.rm.position += 1 + self.xrm.position += 1 self.assembler.regalloc_perform_with_guard(op, guard_op, faillocs, arglocs, result_loc, self.sm.stack_depth) @@ -263,7 +274,7 @@ while i < len(operations): op = operations[i] self.rm.position = i - # XXX ^^^ and also self.xrm.position = i.... :-( + self.xrm.position = i if op.has_no_side_effect() and op.result not in self.longevity: i += 1 self.rm.possibly_free_vars(op.args) @@ -274,7 +285,7 @@ else: oplist[op.opnum](self, op, None) if op.result is not None: - self.rm.possibly_free_var(op.result) + self.possibly_free_var(op.result) self.rm._check_invariants() self.xrm._check_invariants() i += 1 @@ -329,7 +340,7 @@ locs = [self.loc(arg) for arg in op.args] self.assembler.generate_failure(self.assembler.mc, op.descr, op.args, locs, self.exc) - self.rm.possibly_free_vars(op.args) + self.possibly_free_vars(op.args) consider_finish = consider_fail # for now @@ -461,6 +472,7 @@ loc0 = self.xrm.force_result_in_reg(op.result, op.args[0], op.args) loc1 = self.xrm.loc(op.args[1]) self.Perform(op, [loc0, loc1], loc0) + self.xrm.possibly_free_vars(op.args) def _call(self, op, arglocs, force_store=[]): self.rm.before_call(force_store) Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py Wed Sep 30 19:55:59 2009 @@ -8,7 +8,8 @@ from pypy.jit.metainterp.resoperation import rop, ResOperation from pypy.jit.backend.llsupport.descr import GcCache from pypy.jit.backend.x86.runner import CPU -from pypy.jit.backend.x86.regalloc import RegAlloc, WORD, X86RegisterManager +from pypy.jit.backend.x86.regalloc import RegAlloc, WORD, X86RegisterManager,\ + BASE_CONSTANT_SIZE from pypy.jit.metainterp.test.oparser import parse from pypy.rpython.lltypesystem import lltype, llmemory, rffi from pypy.rpython.annlowlevel import llhelper @@ -515,3 +516,12 @@ ''' self.interpret(ops, [0.1, .2, .3, .4, .5, .6, .7, .8, .9]) assert self.getfloats(9) == [.1+.2, .9+3.5, .3, .4, .5, .6, .7, .8, .9] + + def test_float_overflow_const_list(self): + ops = ['[f0]'] + for i in range(BASE_CONSTANT_SIZE * 2): + ops.append('f%d = float_add(f%d, 3.5)' % (i + 1, i)) + ops.append('fail(f%d)' % (BASE_CONSTANT_SIZE * 2)) + ops = "\n".join(ops) + self.interpret(ops, [0.1]) + assert self.getfloat(0) - (1 + BASE_CONSTANT_SIZE * 2) * 3.5 + 0.1 < 0.00001 From fijal at codespeak.net Wed Sep 30 20:14:48 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 20:14:48 +0200 (CEST) Subject: [pypy-svn] r68052 - pypy/branch/floats-via-sse2/pypy/jit/backend/x86 Message-ID: <20090930181448.EA7B7168014@codespeak.net> Author: fijal Date: Wed Sep 30 20:14:47 2009 New Revision: 68052 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py Log: UCOMISD, a comparison that stores result in processor flags Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py Wed Sep 30 20:14:47 2009 @@ -525,6 +525,9 @@ DIVSD = Instruction() DIVSD.mode2(XMMREG, MODRM64, ['\xF2\x0F\x5E', register(1, 8), modrm(2)]) +UCOMISD = Instruction() +UCOMISD.mode2(XMMREG, MODRM64, ['\x66\x0F\x2E', register(1, 8), modrm(2)]) + # ------------------------------ end of SSE2 ----------------------------- UD2 = Instruction() # reserved as an illegal instruction From fijal at codespeak.net Wed Sep 30 20:33:18 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 20:33:18 +0200 (CEST) Subject: [pypy-svn] r68053 - in pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport: . test Message-ID: <20090930183318.E92E0168024@codespeak.net> Author: fijal Date: Wed Sep 30 20:33:18 2009 New Revision: 68053 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/test/test_regalloc.py Log: A controversial checkin. Const does not go into reg_bindings, but we need to make sure that we don't move stuff after we pass imm_fine=False, because we might override what we have Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py Wed Sep 30 20:33:18 2009 @@ -221,7 +221,7 @@ self.assembler.regalloc_mov(self.convert_to_imm(v), selected_reg) return selected_reg if selected_reg is None and self.free_regs: - loc = self.free_regs.pop() + loc = self.free_regs[-1] self.assembler.regalloc_mov(self.convert_to_imm(v), loc) return loc loc = self._spill_var(v, forbidden_vars, selected_reg) Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/test/test_regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/test/test_regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/test/test_regalloc.py Wed Sep 30 20:33:18 2009 @@ -233,10 +233,11 @@ assert isinstance(loc, ConstInt) for box in boxes[:-1]: rm.force_allocate_reg(box) - assert len(asm.moves) == 4 + assert len(asm.moves) == 3 loc = rm.return_constant(ConstInt(1), imm_fine=False) assert isinstance(loc, FakeReg) - assert len(asm.moves) == 6 + assert len(asm.moves) == 5 + assert len(rm.reg_bindings) == 3 def test_force_result_in_reg_const(self): boxes, longevity = boxes_and_longevity(2) From fijal at codespeak.net Wed Sep 30 21:14:21 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 21:14:21 +0200 (CEST) Subject: [pypy-svn] r68054 - in pypy/branch/floats-via-sse2/pypy/jit/backend/x86: . test Message-ID: <20090930191421.EFA62168010@codespeak.net> Author: fijal Date: Wed Sep 30 21:14:17 2009 New Revision: 68054 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py Log: Start supporting float operations, one by one... Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Wed Sep 30 21:14:17 2009 @@ -318,6 +318,13 @@ getattr(self.mc, 'SET' + cond)(lower_byte(result_loc)) return genop_cmp + def _cmpop_float(cond): + def genop_cmp(self, op, arglocs, result_loc): + self.mc.UCOMISD(arglocs[0], arglocs[1]) + self.mc.MOV(result_loc, imm8(0)) + getattr(self.mc, 'SET' + cond)(lower_byte(result_loc)) + return genop_cmp + def _cmpop_guard(cond, rev_cond, false_cond, false_rev_cond): def genop_cmp_guard(self, op, guard_opnum, addr, arglocs, result_loc): if isinstance(op.args[0], Const): @@ -364,6 +371,9 @@ genop_int_or = _binaryop("OR", True) genop_int_xor = _binaryop("XOR", True) genop_float_add = _binaryop("ADDSD", True) + genop_float_sub = _binaryop('SUBSD') + genop_float_mul = _binaryop('MULSD', True) + genop_float_truediv = _binaryop('DIVSD') genop_int_mul_ovf = genop_int_mul genop_int_sub_ovf = genop_int_sub @@ -378,6 +388,13 @@ genop_int_gt = _cmpop("G", "L") genop_int_ge = _cmpop("GE", "LE") + genop_float_lt = _cmpop_float('B') + genop_float_le = _cmpop_float('BE') + genop_float_eq = _cmpop_float('E') + genop_float_ne = _cmpop_float('NE') + genop_float_gt = _cmpop_float('A') + genop_float_ge = _cmpop_float('AE') + genop_uint_gt = _cmpop("A", "B") genop_uint_lt = _cmpop("B", "A") genop_uint_le = _cmpop("BE", "AE") @@ -399,6 +416,9 @@ # a difference at some point xxx_genop_char_eq = genop_int_eq + def genop_float_neg(self, op, arglocs, resloc): + self.mc.XORPD(arglocs[0], arglocs[1]) + def genop_bool_not(self, op, arglocs, resloc): self.mc.XOR(arglocs[0], imm8(1)) @@ -769,16 +789,19 @@ mc.overwrite(jz_location-1, chr(offset)) def not_implemented_op_discard(self, op, arglocs): - print "not implemented operation: %s" % op.getopname() - raise NotImplementedError + msg = "not implemented operation: %s" % op.getopname() + print msg + raise NotImplementedError(msg) def not_implemented_op(self, op, arglocs, resloc): - print "not implemented operation with res: %s" % op.getopname() - raise NotImplementedError + msg = "not implemented operation with res: %s" % op.getopname() + print msg + raise NotImplementedError(msg) def not_implemented_op_guard(self, op, regalloc, arglocs, resloc, descr): - print "not implemented operation (guard): %s" % op.getopname() - raise NotImplementedError + msg = "not implemented operation (guard): %s" % op.getopname() + print msg + raise NotImplementedError(msg) def mark_gc_roots(self): gcrootmap = self.cpu.gc_ll_descr.gcrootmap Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Wed Sep 30 21:14:17 2009 @@ -52,6 +52,11 @@ BASE_CONSTANT_SIZE = 1000 +# cheat cheat cheat.... +# XXX why not -0.0? People tell me it's platform-dependent +import struct +NEG_ZERO, = struct.unpack('d', struct.pack('ll', 0, -2147483648)) + class X86XMMRegisterManager(RegisterManager): box_types = [FLOAT] @@ -67,7 +72,8 @@ def __init__(self, *args, **kwds): RegisterManager.__init__(self, *args, **kwds) self.constant_arrays = [self.new_const_array()] - self.constant_array_counter = 0 + self.constant_arrays[-1][0] = NEG_ZERO + self.constant_array_counter = 1 def convert_to_imm(self, c): if self.constant_array_counter >= BASE_CONSTANT_SIZE: @@ -77,7 +83,11 @@ self.constant_array_counter += 1 arr = self.constant_arrays[-1] arr[res] = c.getfloat() - return heap64(rffi.cast(lltype.Signed, arr) + res * WORD * 2) + return self.get_addr_of_const_float(-1, res) + + def get_addr_of_const_float(self, num_arr, num_pos): + arr = self.constant_arrays[num_arr] + return heap64(rffi.cast(lltype.Signed, arr) + num_pos * WORD * 2) def after_call(self, v): xxx # test @@ -468,12 +478,48 @@ consider_oois = _consider_compop consider_ooisnot = _consider_compop - def consider_float_add(self, op, ignored): + def _consider_float_op(self, op, ignored): loc0 = self.xrm.force_result_in_reg(op.result, op.args[0], op.args) loc1 = self.xrm.loc(op.args[1]) self.Perform(op, [loc0, loc1], loc0) self.xrm.possibly_free_vars(op.args) + consider_float_add = _consider_float_op + consider_float_sub = _consider_float_op + consider_float_mul = _consider_float_op + consider_float_truediv = _consider_float_op + + def _consider_float_cmp(self, op, ignored): + assert ignored is None + # XXX so far we don't have guards here, but we want them + loc0 = self.xrm.make_sure_var_in_reg(op.args[0], op.args, + imm_fine=False) + loc1 = self.xrm.loc(op.args[1]) + res = self.rm.force_allocate_reg(op.result, need_lower_byte=True) + self.Perform(op, [loc0, loc1], res) + self.xrm.possibly_free_vars(op.args) + + consider_float_lt = _consider_float_cmp + consider_float_le = _consider_float_cmp + consider_float_eq = _consider_float_cmp + consider_float_ne = _consider_float_cmp + consider_float_gt = _consider_float_cmp + consider_float_ge = _consider_float_cmp + + def consider_float_neg(self, op, ignored): + # Following what gcc does... + loc0 = self.xrm.force_result_in_reg(op.result, op.args[0]) + constloc = self.xrm.get_addr_of_const_float(0, 0) + tmpbox = TempBox() + loc1 = self.xrm.force_allocate_reg(tmpbox, op.args) + self.assembler.regalloc_mov(constloc, loc1) + self.Perform(op, [loc0, loc1], loc0) + self.xrm.possibly_free_var(tmpbox) + self.xrm.possibly_free_var(op.args[0]) + + def consider_float_abs(self, op, ignored): + xxx + def _call(self, op, arglocs, force_store=[]): self.rm.before_call(force_store) self.Perform(op, arglocs, eax) @@ -745,8 +791,9 @@ return gcrootmap.compress_callshape(shape) def not_implemented_op(self, op, ignored): - print "[regalloc] Not implemented operation: %s" % op.getopname() - raise NotImplementedError + msg = "[regalloc] Not implemented operation: %s" % op.getopname() + print msg + raise NotImplementedError(msg) oplist = [RegAlloc.not_implemented_op] * rop._LAST Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py Wed Sep 30 21:14:17 2009 @@ -528,6 +528,10 @@ UCOMISD = Instruction() UCOMISD.mode2(XMMREG, MODRM64, ['\x66\x0F\x2E', register(1, 8), modrm(2)]) +XORPD = Instruction() +XORPD.mode2(XMMREG, XMMREG, ['\x66\x0f\x57', register(1, 8), register(2), + '\xC0']) + # ------------------------------ end of SSE2 ----------------------------- UD2 = Instruction() # reserved as an illegal instruction Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/test/test_regalloc.py Wed Sep 30 21:14:17 2009 @@ -525,3 +525,12 @@ ops = "\n".join(ops) self.interpret(ops, [0.1]) assert self.getfloat(0) - (1 + BASE_CONSTANT_SIZE * 2) * 3.5 + 0.1 < 0.00001 + + def test_lt_const(self): + ops = ''' + [f0] + i1 = float_lt(3.5, f0) + fail(i1) + ''' + self.interpret(ops, [0.1]) + assert self.getint(0) == 0 From fijal at codespeak.net Wed Sep 30 21:37:41 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 21:37:41 +0200 (CEST) Subject: [pypy-svn] r68055 - pypy/branch/floats-via-sse2/pypy/jit/backend/x86 Message-ID: <20090930193741.BB4DE168014@codespeak.net> Author: fijal Date: Wed Sep 30 21:37:39 2009 New Revision: 68055 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py Log: float_abs & float_int_is_true, magic thx to gcc Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Wed Sep 30 21:37:39 2009 @@ -419,6 +419,18 @@ def genop_float_neg(self, op, arglocs, resloc): self.mc.XORPD(arglocs[0], arglocs[1]) + def genop_float_abs(self, op, arglocs, resloc): + self.mc.ANDPD(arglocs[0], arglocs[1]) + + def genop_float_is_true(self, op, arglocs, resloc): + loc0, loc1, loc2 = arglocs + self.mc.XORPD(loc0, loc0) + self.mc.UCOMISD(loc1, loc0) + self.mc.SETNE(lower_byte(resloc)) + self.mc.SETP(lower_byte(loc2)) + self.mc.OR(resloc, loc2) + self.mc.MOVZX(resloc, lower_byte(resloc)) + def genop_bool_not(self, op, arglocs, resloc): self.mc.XOR(arglocs[0], imm8(1)) Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Wed Sep 30 21:37:39 2009 @@ -53,9 +53,11 @@ BASE_CONSTANT_SIZE = 1000 # cheat cheat cheat.... -# XXX why not -0.0? People tell me it's platform-dependent +# why not -0.0? People tell me it's platform-dependent +# nan is not portable import struct NEG_ZERO, = struct.unpack('d', struct.pack('ll', 0, -2147483648)) +NAN, = struct.unpack('d', struct.pack('ll', -1, 2147483647)) class X86XMMRegisterManager(RegisterManager): @@ -73,7 +75,8 @@ RegisterManager.__init__(self, *args, **kwds) self.constant_arrays = [self.new_const_array()] self.constant_arrays[-1][0] = NEG_ZERO - self.constant_array_counter = 1 + self.constant_arrays[-1][1] = NAN + self.constant_array_counter = 2 def convert_to_imm(self, c): if self.constant_array_counter >= BASE_CONSTANT_SIZE: @@ -518,6 +521,28 @@ self.xrm.possibly_free_var(op.args[0]) def consider_float_abs(self, op, ignored): + loc0 = self.xrm.force_result_in_reg(op.result, op.args[0]) + constloc = self.xrm.get_addr_of_const_float(0, 1) + tmpbox = TempBox() + loc1 = self.xrm.force_allocate_reg(tmpbox, op.args) + self.assembler.regalloc_mov(constloc, loc1) + self.Perform(op, [loc0, loc1], loc0) + self.xrm.possibly_free_var(tmpbox) + self.xrm.possibly_free_var(op.args[0]) + + def consider_float_is_true(self, op, ignored): + tmpbox0 = TempBox() + tmpbox1 = TempBox() + loc0 = self.xrm.force_allocate_reg(tmpbox0) + loc1 = self.xrm.loc(op.args[0]) + loc2 = self.rm.force_allocate_reg(tmpbox1, need_lower_byte=True) + loc3 = self.rm.force_allocate_reg(op.result, need_lower_byte=True) + self.Perform(op, [loc0, loc1, loc2], loc3) + self.rm.possibly_free_var(tmpbox1) + self.xrm.possibly_free_var(op.args[0]) + self.xrm.possibly_free_var(tmpbox0) + + def consider_cast_float_to_int(self, op, ignored): xxx def _call(self, op, arglocs, force_store=[]): Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py Wed Sep 30 21:37:39 2009 @@ -530,6 +530,10 @@ XORPD = Instruction() XORPD.mode2(XMMREG, XMMREG, ['\x66\x0f\x57', register(1, 8), register(2), + '\xC0']) + +ANDPD = Instruction() +ANDPD.mode2(XMMREG, XMMREG, ['\x66\x0F\x54', register(1, 8), register(2), '\xC0']) # ------------------------------ end of SSE2 ----------------------------- From fijal at codespeak.net Wed Sep 30 21:46:34 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 21:46:34 +0200 (CEST) Subject: [pypy-svn] r68056 - pypy/branch/floats-via-sse2/pypy/jit/backend/x86 Message-ID: <20090930194634.D8B67168014@codespeak.net> Author: fijal Date: Wed Sep 30 21:46:33 2009 New Revision: 68056 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py Log: Wow, pass test_float_operations Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Wed Sep 30 21:46:33 2009 @@ -431,6 +431,12 @@ self.mc.OR(resloc, loc2) self.mc.MOVZX(resloc, lower_byte(resloc)) + def genop_cast_float_to_int(self, op, arglocs, resloc): + self.mc.CVTTSD2SI(resloc, arglocs[0]) + + def genop_cast_int_to_float(self, op, arglocs, resloc): + self.mc.CVTSI2SD(resloc, arglocs[0]) + def genop_bool_not(self, op, arglocs, resloc): self.mc.XOR(arglocs[0], imm8(1)) Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Wed Sep 30 21:46:33 2009 @@ -543,7 +543,16 @@ self.xrm.possibly_free_var(tmpbox0) def consider_cast_float_to_int(self, op, ignored): - xxx + loc0 = self.xrm.make_sure_var_in_reg(op.args[0], imm_fine=False) + loc1 = self.rm.force_allocate_reg(op.result) + self.Perform(op, [loc0], loc1) + self.xrm.possibly_free_var(op.args[0]) + + def consider_cast_int_to_float(self, op, ignored): + loc0 = self.rm.loc(op.args[0]) + loc1 = self.xrm.force_allocate_reg(op.result) + self.Perform(op, [loc0], loc1) + self.rm.possibly_free_var(op.args[0]) def _call(self, op, arglocs, force_store=[]): self.rm.before_call(force_store) Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/ri386setup.py Wed Sep 30 21:46:33 2009 @@ -536,6 +536,13 @@ ANDPD.mode2(XMMREG, XMMREG, ['\x66\x0F\x54', register(1, 8), register(2), '\xC0']) +CVTTSD2SI = Instruction() +CVTTSD2SI.mode2(REG, XMMREG, ['\xF2\x0F\x2C', register(1, 8), register(2), + '\xC0']) + +CVTSI2SD = Instruction() +CVTSI2SD.mode2(XMMREG, MODRM, ['\xF2\x0F\x2A', register(1, 8), modrm(2)]) + # ------------------------------ end of SSE2 ----------------------------- UD2 = Instruction() # reserved as an illegal instruction From fijal at codespeak.net Wed Sep 30 21:48:36 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 21:48:36 +0200 (CEST) Subject: [pypy-svn] r68057 - pypy/branch/floats-via-sse2/pypy/jit/backend/x86 Message-ID: <20090930194836.2F3F3168014@codespeak.net> Author: fijal Date: Wed Sep 30 21:48:35 2009 New Revision: 68057 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Log: oops, fix fix fix Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Wed Sep 30 21:48:35 2009 @@ -867,12 +867,12 @@ return heap(reg_or_imm1.value + offset + (reg_or_imm2.value << scale)) else: - return memSIB(None, reg_or_imm2, scale, reg_or_imm1.value + offset) + return memsib(None, reg_or_imm2, scale, reg_or_imm1.value + offset) else: if isinstance(reg_or_imm2, IMM32): return mem(reg_or_imm1, offset + (reg_or_imm2.value << scale)) else: - return memSIB(reg_or_imm1, reg_or_imm2, scale, offset) + return memsib(reg_or_imm1, reg_or_imm2, scale, offset) return addr_add addr8_add = new_addr_add(heap8, mem8, memSIB8) From fijal at codespeak.net Wed Sep 30 22:22:55 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 22:22:55 +0200 (CEST) Subject: [pypy-svn] r68058 - in pypy/branch/floats-via-sse2/pypy/jit/backend: llsupport test x86 Message-ID: <20090930202255.A889B168013@codespeak.net> Author: fijal Date: Wed Sep 30 22:22:53 2009 New Revision: 68058 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Log: set/get arrayitem for floats, with tests Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/llsupport/regalloc.py Wed Sep 30 22:22:53 2009 @@ -273,6 +273,9 @@ if isinstance(v, Const): loc = self.make_sure_var_in_reg(v, forbidden_vars, imm_fine=False) + # note that calling make_sure_var_in_reg with imm_fine=False + # will not allocate place in reg_bindings, we need to do it + # on our own self.reg_bindings[result_v] = loc self.free_regs = [reg for reg in self.free_regs if reg is not loc] return loc Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py Wed Sep 30 22:22:53 2009 @@ -666,6 +666,22 @@ 'int', descr=arraydescr) assert r.value == 1 + if self.cpu.supports_floats: + a_box, A = self.alloc_array_of(lltype.Float, 31) + arraydescr = self.cpu.arraydescrof(A) + self.execute_operation(rop.SETARRAYITEM_GC, [a_box, BoxInt(1), + BoxFloat(3.5)], + 'void', descr=arraydescr) + self.execute_operation(rop.SETARRAYITEM_GC, [a_box, BoxInt(2), + BoxFloat(4.5)], + 'void', descr=arraydescr) + r = self.execute_operation(rop.GETARRAYITEM_GC, [a_box, BoxInt(1)], + 'float', descr=arraydescr) + assert r.value == 3.5 + r = self.execute_operation(rop.GETARRAYITEM_GC, [a_box, BoxInt(2)], + 'float', descr=arraydescr) + assert r.value == 4.5 + def test_string_basic(self): s_box = self.alloc_string("hello\xfe") r = self.execute_operation(rop.STRLEN, [s_box], 'int') Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Wed Sep 30 22:22:53 2009 @@ -544,15 +544,19 @@ base_loc, ofs_loc, scale, ofs = arglocs assert isinstance(ofs, IMM32) assert isinstance(scale, IMM32) - if scale.value == 0: - self.mc.MOVZX(resloc, addr8_add(base_loc, ofs_loc, ofs.value, - scale.value)) - elif scale.value == 2: - self.mc.MOV(resloc, addr_add(base_loc, ofs_loc, ofs.value, - scale.value)) + if op.result.type == FLOAT: + self.mc.MOVSD(resloc, addr64_add(base_loc, ofs_loc, ofs.value, + scale.value)) else: - print "[asmgen]setarrayitem unsupported size: %d" % scale.value - raise NotImplementedError() + if scale.value == 0: + self.mc.MOVZX(resloc, addr8_add(base_loc, ofs_loc, ofs.value, + scale.value)) + elif scale.value == 2: + self.mc.MOV(resloc, addr_add(base_loc, ofs_loc, ofs.value, + scale.value)) + else: + print "[asmgen]setarrayitem unsupported size: %d" % scale.value + raise NotImplementedError() genop_getfield_raw = genop_getfield_gc genop_getarrayitem_gc_pure = genop_getarrayitem_gc @@ -575,14 +579,18 @@ base_loc, ofs_loc, value_loc, scale_loc, baseofs = arglocs assert isinstance(baseofs, IMM32) assert isinstance(scale_loc, IMM32) - if scale_loc.value == 2: - self.mc.MOV(addr_add(base_loc, ofs_loc, baseofs.value, - scale_loc.value), value_loc) - elif scale_loc.value == 0: - self.mc.MOV(addr8_add(base_loc, ofs_loc, baseofs.value, - scale_loc.value), lower_byte(value_loc)) + if op.args[2].type == FLOAT: + self.mc.MOVSD(addr64_add(base_loc, ofs_loc, baseofs.value, + scale_loc.value), value_loc) else: - raise NotImplementedError("scale = %d" % scale_loc.value) + if scale_loc.value == 2: + self.mc.MOV(addr_add(base_loc, ofs_loc, baseofs.value, + scale_loc.value), value_loc) + elif scale_loc.value == 0: + self.mc.MOV(addr8_add(base_loc, ofs_loc, baseofs.value, + scale_loc.value), lower_byte(value_loc)) + else: + raise NotImplementedError("scale = %d" % scale_loc.value) def genop_discard_strsetitem(self, op, arglocs): base_loc, ofs_loc, val_loc = arglocs Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Wed Sep 30 22:22:53 2009 @@ -193,6 +193,18 @@ for var in vars: self.possibly_free_var(var) + def make_sure_var_in_reg(self, var, forbidden_vars=[], **kwds): + if var.type == FLOAT: + return self.xrm.make_sure_var_in_reg(var, forbidden_vars, **kwds) + else: + return self.rm.make_sure_var_in_reg(var, forbidden_vars, **kwds) + + def force_allocate_reg(self, var, forbidden_vars=[], **kwds): + if var.type == FLOAT: + return self.xrm.force_allocate_reg(var, forbidden_vars, **kwds) + else: + return self.rm.force_allocate_reg(var, forbidden_vars, **kwds) + def _compute_loop_consts(self, inputargs, jump): if jump.opnum != rop.JUMP or jump.jump_target is not None: loop_consts = {} @@ -707,10 +719,10 @@ need_lower_byte = True else: need_lower_byte = False - value_loc = self.rm.make_sure_var_in_reg(op.args[2], op.args, - need_lower_byte=need_lower_byte) + value_loc = self.make_sure_var_in_reg(op.args[2], op.args, + need_lower_byte=need_lower_byte) ofs_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args) - self.rm.possibly_free_vars(op.args) + self.possibly_free_vars(op.args) self.PerformDiscard(op, [base_loc, ofs_loc, value_loc, imm(scale), imm(ofs)]) @@ -730,7 +742,7 @@ base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) ofs_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args) self.rm.possibly_free_vars(op.args) - result_loc = self.rm.force_allocate_reg(op.result) + result_loc = self.force_allocate_reg(op.result) self.Perform(op, [base_loc, ofs_loc, imm(scale), imm(ofs)], result_loc) consider_getfield_raw = consider_getfield_gc From fijal at codespeak.net Wed Sep 30 22:36:51 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 22:36:51 +0200 (CEST) Subject: [pypy-svn] r68060 - pypy/branch/floats-via-sse2/pypy/jit/backend/x86 Message-ID: <20090930203651.09ECC168011@codespeak.net> Author: fijal Date: Wed Sep 30 22:36:50 2009 New Revision: 68060 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Log: Leave comments Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Wed Sep 30 22:36:50 2009 @@ -523,6 +523,8 @@ def consider_float_neg(self, op, ignored): # Following what gcc does... + # XXX we can ignore having constant in a reg, but we need + # to be careful with 128-bit alignment loc0 = self.xrm.force_result_in_reg(op.result, op.args[0]) constloc = self.xrm.get_addr_of_const_float(0, 0) tmpbox = TempBox() @@ -533,6 +535,8 @@ self.xrm.possibly_free_var(op.args[0]) def consider_float_abs(self, op, ignored): + # XXX we can ignore having constant in a reg, but we need + # to be careful with 128-bit alignment loc0 = self.xrm.force_result_in_reg(op.result, op.args[0]) constloc = self.xrm.get_addr_of_const_float(0, 1) tmpbox = TempBox() From arigo at codespeak.net Wed Sep 30 22:39:35 2009 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 30 Sep 2009 22:39:35 +0200 (CEST) Subject: [pypy-svn] r68061 - pypy/branch/floats-via-sse2/pypy/jit/metainterp/test Message-ID: <20090930203935.1B3A7168011@codespeak.net> Author: arigo Date: Wed Sep 30 22:39:35 2009 New Revision: 68061 Modified: pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_executor.py Log: Generic test for bool(-0.0). Modified: pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_executor.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_executor.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_executor.py Wed Sep 30 22:39:35 2009 @@ -115,6 +115,7 @@ yield (rop.FLOAT_ABS, [15.9], 'float', 15.9) yield (rop.FLOAT_IS_TRUE, [-5.9], 'int', 1) yield (rop.FLOAT_IS_TRUE, [0.0], 'int', 0) + yield (rop.FLOAT_IS_TRUE, [-0.0], 'int', 0) yield (rop.CAST_FLOAT_TO_INT, [-5.9], 'int', -5) yield (rop.CAST_FLOAT_TO_INT, [5.9], 'int', 5) yield (rop.CAST_INT_TO_FLOAT, [123], 'float', 123.0) From fijal at codespeak.net Wed Sep 30 22:46:45 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 22:46:45 +0200 (CEST) Subject: [pypy-svn] r68062 - pypy/branch/floats-via-sse2/pypy/jit/metainterp/test Message-ID: <20090930204645.F2B17168011@codespeak.net> Author: fijal Date: Wed Sep 30 22:46:45 2009 New Revision: 68062 Modified: pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_executor.py Log: one more test just in case... Modified: pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_executor.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_executor.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/metainterp/test/test_executor.py Wed Sep 30 22:46:45 2009 @@ -107,6 +107,7 @@ yield (rop.FLOAT_NE, [10.125, y], 'int', 10.125 != y) yield (rop.FLOAT_GT, [10.125, y], 'int', 10.125 > y) yield (rop.FLOAT_GE, [10.125, y], 'int', 10.125 >= y) + yield (rop.FLOAT_EQ, [0.0, -0.0], 'int', 0.0 == -0.0) def _float_unary_operations(): yield (rop.FLOAT_NEG, [-5.9], 'float', 5.9) From fijal at codespeak.net Wed Sep 30 22:50:09 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 22:50:09 +0200 (CEST) Subject: [pypy-svn] r68064 - pypy/branch/floats-via-sse2/pypy/jit/backend/x86 Message-ID: <20090930205009.4187B168011@codespeak.net> Author: fijal Date: Wed Sep 30 22:50:08 2009 New Revision: 68064 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Log: It seems that massively simpler solution works as well... Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Wed Sep 30 22:50:08 2009 @@ -423,12 +423,10 @@ self.mc.ANDPD(arglocs[0], arglocs[1]) def genop_float_is_true(self, op, arglocs, resloc): - loc0, loc1, loc2 = arglocs + loc0, loc1 = arglocs self.mc.XORPD(loc0, loc0) self.mc.UCOMISD(loc1, loc0) self.mc.SETNE(lower_byte(resloc)) - self.mc.SETP(lower_byte(loc2)) - self.mc.OR(resloc, loc2) self.mc.MOVZX(resloc, lower_byte(resloc)) def genop_cast_float_to_int(self, op, arglocs, resloc): Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Wed Sep 30 22:50:08 2009 @@ -548,13 +548,10 @@ def consider_float_is_true(self, op, ignored): tmpbox0 = TempBox() - tmpbox1 = TempBox() loc0 = self.xrm.force_allocate_reg(tmpbox0) loc1 = self.xrm.loc(op.args[0]) - loc2 = self.rm.force_allocate_reg(tmpbox1, need_lower_byte=True) - loc3 = self.rm.force_allocate_reg(op.result, need_lower_byte=True) - self.Perform(op, [loc0, loc1, loc2], loc3) - self.rm.possibly_free_var(tmpbox1) + loc2 = self.rm.force_allocate_reg(op.result, need_lower_byte=True) + self.Perform(op, [loc0, loc1], loc2) self.xrm.possibly_free_var(op.args[0]) self.xrm.possibly_free_var(tmpbox0) From fijal at codespeak.net Wed Sep 30 23:33:44 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 23:33:44 +0200 (CEST) Subject: [pypy-svn] r68067 - in pypy/branch/floats-via-sse2/pypy/jit/backend: test x86 Message-ID: <20090930213344.CD7CF168014@codespeak.net> Author: fijal Date: Wed Sep 30 23:33:44 2009 New Revision: 68067 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Log: getfield/setfield Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py Wed Sep 30 23:33:44 2009 @@ -487,6 +487,14 @@ 'ref', descr=fielddescr2) assert res.value == null_const.value + if self.cpu.supports_floats: + floatdescr = self.cpu.fielddescrof(self.S, 'float') + self.execute_operation(rop.SETFIELD_GC, [t_box, BoxFloat(3.4)], + 'void', descr=floatdescr) + res = self.execute_operation(rop.GETFIELD_GC, [t_box], + 'float', descr=floatdescr) + assert res.value == 3.4 + def test_passing_guards(self): for (opname, args) in [(rop.GUARD_TRUE, [BoxInt(1)]), (rop.GUARD_FALSE, [BoxInt(0)]), @@ -748,7 +756,9 @@ ('chr1', lltype.Char), ('chr2', lltype.Char), ('short', rffi.SHORT), - ('next', lltype.Ptr(S)))) + ('next', lltype.Ptr(S)), + ('float', lltype.Float) + )) T = lltype.GcStruct('T', ('parent', S), ('next', lltype.Ptr(S))) U = lltype.GcStruct('U', ('parent', T), Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Wed Sep 30 23:33:44 2009 @@ -533,6 +533,8 @@ self.mc.MOVZX(resloc, addr_add(base_loc, ofs_loc)) elif size == WORD: self.mc.MOV(resloc, addr_add(base_loc, ofs_loc)) + elif size == 8: + self.mc.MOVSD(resloc, addr64_add(base_loc, ofs_loc)) else: raise NotImplementedError("getfield size = %d" % size) @@ -563,7 +565,9 @@ base_loc, ofs_loc, size_loc, value_loc = arglocs assert isinstance(size_loc, IMM32) size = size_loc.value - if size == WORD: + if size == WORD * 2: + self.mc.MOVSD(addr64_add(base_loc, ofs_loc), value_loc) + elif size == WORD: self.mc.MOV(addr_add(base_loc, ofs_loc), value_loc) elif size == 2: self.mc.MOV16(addr_add(base_loc, ofs_loc), value_loc) Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/regalloc.py Wed Sep 30 23:33:44 2009 @@ -696,9 +696,9 @@ else: need_lower_byte = False base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) - value_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args, + value_loc = self.make_sure_var_in_reg(op.args[1], op.args, need_lower_byte=need_lower_byte) - self.rm.possibly_free_vars(op.args) + self.possibly_free_vars(op.args) self.PerformDiscard(op, [base_loc, ofs_loc, size_loc, value_loc]) consider_setfield_raw = consider_setfield_gc @@ -733,7 +733,7 @@ ofs_loc, size_loc, _ = self._unpack_fielddescr(op.descr) base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args) self.rm.possibly_free_vars(op.args) - result_loc = self.rm.force_allocate_reg(op.result) + result_loc = self.force_allocate_reg(op.result) self.Perform(op, [base_loc, ofs_loc, size_loc], result_loc) consider_getfield_gc_pure = consider_getfield_gc From fijal at codespeak.net Wed Sep 30 23:46:46 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 23:46:46 +0200 (CEST) Subject: [pypy-svn] r68069 - pypy/branch/floats-via-sse2/pypy/jit/backend/x86 Message-ID: <20090930214646.82902168014@codespeak.net> Author: fijal Date: Wed Sep 30 23:46:45 2009 New Revision: 68069 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Log: Refactor calling style so it contains MOVs instead of PUSHes. Gcc does that and besides, it makes it easier to put XMM regs there. Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/x86/assembler.py Wed Sep 30 23:46:45 2009 @@ -771,12 +771,24 @@ size = sizeloc.value nargs = len(op.args)-1 extra_on_stack = self.align_stack_for_call(nargs) - for i in range(nargs+1, 1, -1): - self.mc.PUSH(arglocs[i]) + self.mc.SUB(esp, imm(WORD * extra_on_stack)) if isinstance(op.args[0], Const): x = rel32(op.args[0].getint()) else: x = arglocs[1] + if x is eax: + tmp = ecx + else: + tmp = eax + for i in range(2, nargs + 2): + loc = arglocs[i] + if isinstance(loc, REG): + self.mc.MOV(mem(esp, WORD * (i - 2)), loc) + for i in range(2, nargs + 2): + loc = arglocs[i] + if not isinstance(loc, REG): + self.mc.MOV(tmp, loc) + self.mc.MOV(mem(esp, WORD * (i - 2)), tmp) self.mc.CALL(x) self.mark_gc_roots() self.mc.ADD(esp, imm(WORD * extra_on_stack)) From benjamin at codespeak.net Wed Sep 30 23:52:53 2009 From: benjamin at codespeak.net (benjamin at codespeak.net) Date: Wed, 30 Sep 2009 23:52:53 +0200 (CEST) Subject: [pypy-svn] r68070 - pypy/extradoc/talk/pycon2010 Message-ID: <20090930215253.441BF168011@codespeak.net> Author: benjamin Date: Wed Sep 30 23:52:52 2009 New Revision: 68070 Modified: pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt Log: add some things Modified: pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt ============================================================================== --- pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt (original) +++ pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt Wed Sep 30 23:52:52 2009 @@ -12,4 +12,25 @@ Description: -xXX +Having good tests is the most important component to successful +cross-interpreter programs. This includes having the infrastructure set up to +automatically run them on all supported platforms, runtimes, and versions. + +Try to avoid 3rd party libraries that require C extension modules unless you can +fallback to a pure Python replacement. Implementation specific code, especially +if it's not Python code, is one of the hardest parts to port to other +interpreters. This also applies to libraries that are made available by the +implementation by default but are not part of the stdlib like Java libraries +from Jython and .NET in IronPython. The preferred way to access libraries is +ctypes, since CPython, PyPy, and IronPython support it. + +Mind your bytes and strings! The usual rule is to always decode data as soon as +possible from IO if you need to do processing on it, or always keep it as bytes. +In 2.x, always use unicode for text, and str for byte strings. + +Don't use sys.prefix. Different implementations have different installed +layouts, so it's wrong to assume the CPython one. + +Use all new style classes. Not only does this provide consistency, but it will +avoid surprises in 3.x when all classes are new style and be useful for other +implementations, where new style classes are optimized more. From fijal at codespeak.net Wed Sep 30 23:52:57 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 23:52:57 +0200 (CEST) Subject: [pypy-svn] r68071 - pypy/branch/floats-via-sse2/pypy/jit/backend/llgraph Message-ID: <20090930215257.C0D55168015@codespeak.net> Author: fijal Date: Wed Sep 30 23:52:55 2009 New Revision: 68071 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llgraph/runner.py Log: Missing case in llgraph backend Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/llgraph/runner.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/llgraph/runner.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/llgraph/runner.py Wed Sep 30 23:52:55 2009 @@ -466,9 +466,10 @@ assert isinstance(calldescr, Descr) func = args[0].getint() for arg in args[1:]: - if (isinstance(arg, history.BoxPtr) or - isinstance(arg, history.ConstPtr)): + if arg.type == REF: llimpl.do_call_pushptr(arg.getref_base()) + elif arg.type == FLOAT: + llimpl.do_call_pushfloat(arg.getfloat()) else: llimpl.do_call_pushint(arg.getint()) if calldescr.typeinfo == REF: From fijal at codespeak.net Wed Sep 30 23:53:14 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 23:53:14 +0200 (CEST) Subject: [pypy-svn] r68072 - pypy/branch/floats-via-sse2/pypy/jit/backend/test Message-ID: <20090930215314.A58E7168011@codespeak.net> Author: fijal Date: Wed Sep 30 23:53:09 2009 New Revision: 68072 Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py Log: And a test showing missing case... Modified: pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py ============================================================================== --- pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py (original) +++ pypy/branch/floats-via-sse2/pypy/jit/backend/test/runner_test.py Wed Sep 30 23:53:09 2009 @@ -241,6 +241,19 @@ BoxInt(ord('A'))], calldescr) assert x.value == ord('B') + if cpu.supports_floats: + def func(f, i): + return float(i) + f + FPTR = self.Ptr(self.FuncType([lltype.Float, lltype.Signed], + lltype.Float)) + func_ptr = llhelper(FPTR, func) + FTP = deref(FPTR) + calldescr = cpu.calldescrof(FTP, FTP.ARGS, FTP.RESULT) + x = cpu.do_call( + [self.get_funcbox(cpu, func_ptr), + BoxFloat(3.5), BoxInt(42)], + calldescr) + assert x.value == 42 + 3.5 def test_call(self): From fijal at codespeak.net Wed Sep 30 23:58:24 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 23:58:24 +0200 (CEST) Subject: [pypy-svn] r68073 - pypy/extradoc/talk/pycon2010 Message-ID: <20090930215824.D3472168011@codespeak.net> Author: fijal Date: Wed Sep 30 23:58:24 2009 New Revision: 68073 Modified: pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt pypy/extradoc/talk/pycon2010/jit_abstract.txt Log: Expand a bit Modified: pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt ============================================================================== --- pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt (original) +++ pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt Wed Sep 30 23:58:24 2009 @@ -12,6 +12,9 @@ Description: +The talk will consist mostly out of list of issues what to do and what +not to do. Some examples are given below: + Having good tests is the most important component to successful cross-interpreter programs. This includes having the infrastructure set up to automatically run them on all supported platforms, runtimes, and versions. @@ -22,7 +25,8 @@ interpreters. This also applies to libraries that are made available by the implementation by default but are not part of the stdlib like Java libraries from Jython and .NET in IronPython. The preferred way to access libraries is -ctypes, since CPython, PyPy, and IronPython support it. +ctypes, since CPython and PyPy supports it, while Jython and IronPython are +on the way. Mind your bytes and strings! The usual rule is to always decode data as soon as possible from IO if you need to do processing on it, or always keep it as bytes. @@ -34,3 +38,10 @@ Use all new style classes. Not only does this provide consistency, but it will avoid surprises in 3.x when all classes are new style and be useful for other implementations, where new style classes are optimized more. + +Never use exact string representation of exceptions, they might even +change from one minor revision to other. + +Don't really on exact finalization, especially on files. + +In short: there is no feature obscure enough for people not to rely on. Modified: pypy/extradoc/talk/pycon2010/jit_abstract.txt ============================================================================== --- pypy/extradoc/talk/pycon2010/jit_abstract.txt (original) +++ pypy/extradoc/talk/pycon2010/jit_abstract.txt Wed Sep 30 23:58:24 2009 @@ -27,7 +27,7 @@ like the tracemonkey JS interpreter, unlike Psyco or JVM JITs). * Tracing JITs focus on often executed loops. Which kind of programs - will the PyPy JIT speed-up , which constructs we know it is currently poor at. + will the PyPy JIT speed-up, which constructs we know it is currently poor at. * Future plans for PyPy, especially JIT-wise. From fijal at codespeak.net Wed Sep 30 23:58:57 2009 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 30 Sep 2009 23:58:57 +0200 (CEST) Subject: [pypy-svn] r68074 - pypy/extradoc/talk/pycon2010 Message-ID: <20090930215857.09F79168011@codespeak.net> Author: fijal Date: Wed Sep 30 23:58:56 2009 New Revision: 68074 Modified: pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt Log: cool, IronPython already supports ctypes Modified: pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt ============================================================================== --- pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt (original) +++ pypy/extradoc/talk/pycon2010/abstract_how_to_write_programs.txt Wed Sep 30 23:58:56 2009 @@ -25,8 +25,8 @@ interpreters. This also applies to libraries that are made available by the implementation by default but are not part of the stdlib like Java libraries from Jython and .NET in IronPython. The preferred way to access libraries is -ctypes, since CPython and PyPy supports it, while Jython and IronPython are -on the way. +ctypes, since CPython, PyPy and IronPython supports it, +while Jython is on the way. Mind your bytes and strings! The usual rule is to always decode data as soon as possible from IO if you need to do processing on it, or always keep it as bytes.