[pypy-svn] r37823 - in pypy/branch/jit-virtual-world/pypy: jit/timeshifter jit/timeshifter/test rpython/lltypesystem

arigo at codespeak.net arigo at codespeak.net
Fri Feb 2 20:59:07 CET 2007


Author: arigo
Date: Fri Feb  2 20:59:02 2007
New Revision: 37823

Modified:
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rcontainer.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rvalue.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_exception.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_promotion.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/vdict.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/vlist.py
   pypy/branch/jit-virtual-world/pypy/rpython/lltypesystem/rclass.py
Log:
(arre, pedronis, arigo)

Add a flag 'known_nonzero' to PtrRedBox.  This allows the propagation of
the fact that some pointers cannot be NULL, which is essential to get
reasonable code out of exception raising.  This keeps exception-raising
paths separate from regular returns - otherwise the compiler would try
to produce code that uses normally the special "-1" value returned in
case of error!



Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py	Fri Feb  2 20:59:02 2007
@@ -1049,26 +1049,52 @@
                                               [v_jitstate,      var  ],
                                               self.s_ConstOrVar)
 
-    def translate_op_split(self, hop):
+    def translate_op_split(self, hop, splitfn=rtimeshift.split,
+                                      reverse=False):
+        if splitfn is rtimeshift.split:
+            nb_fixed_args = 2
+        else:
+            nb_fixed_args = 3
+
         r_switch = self.getredrepr(lltype.Bool)
-        GREENS = [v.concretetype for v in hop.args_v[2:]]
-        greens_r = [self.getgreenrepr(TYPE) for TYPE in GREENS]
-        vlist = hop.inputargs(r_switch, lltype.Signed, *greens_r)
+        GREENS = [v.concretetype for v in hop.args_v[nb_fixed_args:]]
+        extra_r = [self.getgreenrepr(TYPE) for TYPE in GREENS]
+        if splitfn is not rtimeshift.split:
+            TYPE = originalconcretetype(hop.args_s[2])
+            r_ptrbox = self.getredrepr(TYPE)
+            extra_r.insert(0, r_ptrbox)
+        vlist = hop.inputargs(r_switch, lltype.Signed, *extra_r)
 
         v_jitstate = hop.llops.getjitstate()
         v_switch = vlist[0]
         c_resumepoint = vlist[1]
-        greens_v = list(self.wrap_green_vars(hop.llops, vlist[2:]))
+        greens_v = list(self.wrap_green_vars(hop.llops,
+                                             vlist[nb_fixed_args:]))
 
         s_Int = annmodel.SomeInteger(nonneg=True)
         args_s = [self.s_JITState, self.s_RedBox, s_Int]
-        args_s += [self.s_ConstOrVar] * len(greens_v)
         args_v = [v_jitstate, v_switch, c_resumepoint]
+
+        if splitfn is not rtimeshift.split:
+            v_ptrbox = vlist[2]
+            c_reverse = hop.inputconst(lltype.Bool, reverse)
+            args_s += [self.s_PtrRedBox,                 annmodel.s_Bool]
+            args_v += [hop.llops.as_ptrredbox(v_ptrbox), c_reverse      ]
+
+        args_s += [self.s_ConstOrVar] * len(greens_v)
         args_v += greens_v
-        return hop.llops.genmixlevelhelpercall(rtimeshift.split,
+        return hop.llops.genmixlevelhelpercall(splitfn,
                                                args_s, args_v,
                                                annmodel.SomeBool())
 
+    def translate_op_split_ptr_nonzero(self, hop):
+        return self.translate_op_split(hop, rtimeshift.split_ptr_nonzero,
+                                            reverse=False)
+
+    def translate_op_split_ptr_iszero(self, hop):
+        return self.translate_op_split(hop, rtimeshift.split_ptr_nonzero,
+                                            reverse=True)
+
     def translate_op_collect_split(self, hop):
         GREENS = [v.concretetype for v in hop.args_v[1:]]
         greens_r = [self.getgreenrepr(TYPE) for TYPE in GREENS]
@@ -1590,8 +1616,7 @@
                                     typedesc.redirected_fielddescs])
         TYPE = self.original_concretetype
         kind = self.hrtyper.RGenOp.kindToken(TYPE)
-        boxcls = rvalue.ll_redboxcls(TYPE)
-        
+
         def make_arg_redbox(jitstate, inputargs_gv, i):
             box = typedesc.factory()
             jitstate.add_virtualizable(box)
@@ -1601,9 +1626,12 @@
             gv_outside = inputargs_gv[i]
             i += 1
             for name, j in names:
-                content_boxes[j].genvar = inputargs_gv[i]
+                content_boxes[j] = rvalue.PtrRedBox(content_boxes[j].kind,
+                                                    inputargs_gv[i])
                 i += 1
-            content_boxes[-1].genvar = gv_outside
+            content_boxes[-1] = rvalue.PtrRedBox(content_boxes[-1].kind,
+                                                 gv_outside,
+                                                 known_nonzero = True)
             return box
         
         self.make_arg_redbox = make_arg_redbox

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rcontainer.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rcontainer.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rcontainer.py	Fri Feb  2 20:59:02 2007
@@ -178,7 +178,7 @@
         vstruct = self.VirtualStructCls(self)
         vstruct.content_boxes = [desc.makedefaultbox()
                                  for desc in self.fielddescs]
-        box = rvalue.PtrRedBox(self.innermostdesc.ptrkind)
+        box = rvalue.PtrRedBox(self.innermostdesc.ptrkind, known_nonzero=True)
         box.content = vstruct
         vstruct.ownbox = box
         return box
@@ -191,7 +191,8 @@
     gv_size = sizebox.getgenvar(jitstate)
     alloctoken = contdesc.varsizealloctoken
     genvar = jitstate.curbuilder.genop_malloc_varsize(alloctoken, gv_size)
-    return rvalue.PtrRedBox(contdesc.ptrkind, genvar)
+    # XXX MemoryError checking
+    return rvalue.PtrRedBox(contdesc.ptrkind, genvar, known_nonzero=True)
 
 
 class VirtualizableStructTypeDesc(StructTypeDesc):
@@ -353,6 +354,7 @@
     gv_default = None
     canbevirtual = False
     gcref = False
+    fieldnonnull = False
 
     def __init__(self, hrtyper, PTRTYPE, RESTYPE):
         RGenOp = hrtyper.RGenOp
@@ -361,6 +363,7 @@
         if isinstance(RESTYPE, lltype.ContainerType):
             T = RESTYPE
             RESTYPE = lltype.Ptr(RESTYPE)
+            self.fieldnonnull = True
         elif isinstance(RESTYPE, lltype.Ptr):
             T = RESTYPE.TO
             if hasattr(T, '_hints'):
@@ -373,6 +376,7 @@
                     self.canbevirtual = True
             else:
                 T = None
+            self.fieldnonnull = PTRTYPE.TO._hints.get('shouldntbenull', False)
         self.RESTYPE = RESTYPE
         self.ptrkind = RGenOp.kindToken(PTRTYPE)
         self.kind = RGenOp.kindToken(RESTYPE)
@@ -400,7 +404,11 @@
             assert isinstance(content, VirtualizableStruct)
             content.load_from(jitstate, gvar)
             return structbox
-        return self.redboxcls(self.kind, gvar)
+        box = self.redboxcls(self.kind, gvar)
+        if self.fieldnonnull:
+            assert isinstance(box, rvalue.PtrRedBox)
+            box.known_nonzero = True
+        return box
 
     
 class NamedFieldDesc(FieldDesc):
@@ -518,7 +526,7 @@
 
     def setforced(self, gv_forced):
         self.content_boxes = None
-        self.ownbox.genvar = gv_forced
+        self.ownbox.setgenvar_hint(gv_forced, known_nonzero=True)
         self.ownbox.content = None
         
     def force_runtime_container(self, jitstate):
@@ -532,7 +540,7 @@
                     break
             else:
                 gv = typedesc.materialize(builder.rgenop, boxes)
-                self.ownbox.genvar = gv
+                self.ownbox.setgenvar_hint(gv, known_nonzero=True)
                 self.ownbox.content = None
                 return
         debug_print(lltype.Void, "FORCE CONTAINER: "+ typedesc.TYPE._name)
@@ -657,7 +665,10 @@
             assert isinstance(typedesc, VirtualizableStructTypeDesc)
             builder = jitstate.curbuilder
             gv_outside = builder.genop_malloc_fixedsize(typedesc.alloctoken)
-            self.content_boxes[-1].genvar = gv_outside
+            outsidebox = rvalue.PtrRedBox(self.content_boxes[-1].kind,
+                                          gv_outside,
+                                          known_nonzero = True)
+            self.content_boxes[-1] = outsidebox
             jitstate.add_virtualizable(self.ownbox)
             access_token = typedesc.access_desc.fieldtoken            
             gv_access_null = typedesc.access_desc.gv_default
@@ -677,8 +688,11 @@
     def load_from(self, jitstate, gv_outside):
         typedesc = self.typedesc
         assert isinstance(typedesc, VirtualizableStructTypeDesc)
+        # XXX missing check for gv_outside being NULL
         boxes = self.content_boxes
-        boxes[-1].genvar = gv_outside
+        boxes[-1] = rvalue.PtrRedBox(boxes[-1].kind,
+                                     gv_outside,
+                                     known_nonzero=True)
         builder = jitstate.curbuilder
         builder.genop_call(typedesc.access_is_null_token,
                            typedesc.gv_access_is_null_ptr,

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py	Fri Feb  2 20:59:02 2007
@@ -99,7 +99,8 @@
     gv_size = sizebox.getgenvar(jitstate)
     alloctoken = contdesc.varsizealloctoken
     genvar = jitstate.curbuilder.genop_malloc_varsize(alloctoken, gv_size)
-    return rvalue.PtrRedBox(contdesc.ptrkind, genvar)
+    # XXX MemoryError handling
+    return rvalue.PtrRedBox(contdesc.ptrkind, genvar, known_nonzero=True)
 
 def ll_gengetfield(jitstate, deepfrozen, fielddesc, argbox):
     if (fielddesc.immutable or deepfrozen) and argbox.is_constant():
@@ -167,14 +168,14 @@
         addr = rvalue.ll_getvalue(argbox, llmemory.Address)
         return rvalue.ll_fromvalue(jitstate, bool(addr) ^ reverse)
     builder = jitstate.curbuilder
-    if argbox.content is None:
+    if argbox.known_nonzero:
+        gv_res = builder.rgenop.genconst(True ^ reverse)
+    else:
         gv_addr = argbox.getgenvar(jitstate)
         if reverse:
             gv_res = builder.genop_ptr_iszero(argbox.kind, gv_addr)
         else:
             gv_res = builder.genop_ptr_nonzero(argbox.kind, gv_addr)
-    else:
-        gv_res = builder.rgenop.genconst(True ^ reverse)
     return rvalue.IntRedBox(builder.rgenop.kindToken(lltype.Bool), gv_res)
 
 def ll_genptreq(jitstate, argbox0, argbox1, reverse):
@@ -201,6 +202,7 @@
     linkargs = []
     kinds = []
     for redbox in incoming:
+        assert not redbox.genvar.is_const
         linkargs.append(redbox.genvar)
         kinds.append(redbox.kind)
     newblock = jitstate.curbuilder.enter_next_block(kinds, linkargs)
@@ -270,9 +272,10 @@
         # redboxes from outgoingvarboxes, by making them variables.
         # Then we make a new block based on this new state.
         cleanup_partial_data(memo.partialdatamatch)
+        forget_nonzeroness = memo.forget_nonzeroness
         replace_memo = rvalue.copy_memo()
         for box in outgoingvarboxes:
-            box.forcevar(jitstate, replace_memo)
+            box.forcevar(jitstate, replace_memo, box in forget_nonzeroness)
         if replace_memo.boxes:
             jitstate.replace(replace_memo)
         start_new_block(states_dic, jitstate, key, global_resumer, index=i)
@@ -323,14 +326,49 @@
     if exitgvar.is_const:
         return exitgvar.revealconst(lltype.Bool)
     else:
+        # XXX call another function with list(greens_gv) instead
+        resuming = jitstate.resuming
+        if resuming is not None and resuming.mergesleft == 0:
+            node = resuming.path.pop()
+            assert isinstance(node, PromotionPathSplit)
+            return node.answer
+        false_gv = jitstate.get_locals_gv() # alive gvs on the false path
+        later_builder = jitstate.curbuilder.jump_if_false(exitgvar, false_gv)
+        memo = rvalue.copy_memo()
+        jitstate2 = jitstate.split(later_builder, resumepoint,
+                                   list(greens_gv), memo)
+        if resuming is None:
+            node = jitstate.promotion_path
+            jitstate2.promotion_path = PromotionPathNo(node)
+            jitstate .promotion_path = PromotionPathYes(node)
+        return True
+
+def split_ptr_nonzero(jitstate, switchredbox, resumepoint,
+                      ptrbox, reverse, *greens_gv):
+    exitgvar = switchredbox.getgenvar(jitstate)
+    if exitgvar.is_const:
+        return exitgvar.revealconst(lltype.Bool)
+    else:
+        # XXX call another function with list(greens_gv) instead
         resuming = jitstate.resuming
         if resuming is not None and resuming.mergesleft == 0:
             node = resuming.path.pop()
             assert isinstance(node, PromotionPathSplit)
+            ptrbox.learn_nonzeroness(jitstate,
+                                     nonzeroness = node.answer ^ reverse)
             return node.answer
         false_gv = jitstate.get_locals_gv() # alive gvs on the false path
         later_builder = jitstate.curbuilder.jump_if_false(exitgvar, false_gv)
-        jitstate2 = jitstate.split(later_builder, resumepoint, list(greens_gv))
+        memo = rvalue.copy_memo()
+        jitstate2 = jitstate.split(later_builder, resumepoint,
+                                   list(greens_gv), memo)
+        ptrbox.learn_nonzeroness(jitstate, nonzeroness = True ^ reverse)
+        try:
+            copybox = memo.boxes[ptrbox]
+        except KeyError:
+            pass
+        else:
+            copybox.learn_nonzeroness(jitstate2, nonzeroness = reverse)
         if resuming is None:
             node = jitstate.promotion_path
             jitstate2.promotion_path = PromotionPathNo(node)
@@ -541,6 +579,7 @@
         kinds = [box.kind for box in incoming]
         builder, vars_gv = self.rgenop.replay(self.replayableblock, kinds)
         for i in range(len(incoming)):
+            assert incoming[i].genvar is None
             incoming[i].genvar = vars_gv[i]
         jitstate.curbuilder = builder
         jitstate.greens = self.greens_gv
@@ -682,15 +721,16 @@
             if len(resuming.path) == 0:
                 incoming_gv = pm.incoming_gv
                 for i in range(len(incoming)):
+                    assert not incoming[i].genvar.is_const
                     incoming[i].genvar = incoming_gv[i]
                 flexswitch = pm.flexswitch
-                promotebox.genvar = promotenode.gv_value
+                promotebox.setgenvar(promotenode.gv_value)
                 jitstate.resuming = None
                 node = PromotionPathMergesToSee(promotenode, 0)
                 jitstate.promotion_path = node
             else:
                 resuming.merges_to_see()
-                promotebox.genvar = promotenode.gv_value
+                promotebox.setgenvar(promotenode.gv_value)
                 
             newbuilder = flexswitch.add_case(promotenode.gv_value)
             jitstate.curbuilder = newbuilder
@@ -869,8 +909,7 @@
         if virtualizable_box not in self.virtualizables:
             self.virtualizables.append(virtualizable_box)
 
-    def split(self, newbuilder, newresumepoint, newgreens):
-        memo = rvalue.copy_memo()
+    def split(self, newbuilder, newresumepoint, newgreens, memo):
         virtualizables = []
         for virtualizable_box in self.virtualizables:
             new_virtualizable_box = virtualizable_box.copy(memo)
@@ -1112,6 +1151,8 @@
     resuming = jitstate.resuming
     return_chain = merge_returning_jitstates(jitstate, dispatchqueue,
                                              force_merge=is_portal)
+    if is_portal:
+        assert return_chain is None or return_chain.next is None
     if resuming is not None:
         resuming.leave_call(dispatchqueue)
     jitstate = return_chain

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rvalue.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rvalue.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rvalue.py	Fri Feb  2 20:59:02 2007
@@ -16,6 +16,7 @@
 def exactmatch_memo(force_merge=False):
     memo = Memo()
     memo.partialdatamatch = {}
+    memo.forget_nonzeroness = {}
     memo.force_merge=force_merge
     return memo
 
@@ -50,22 +51,24 @@
     def getgenvar(self, jitstate):
         return self.genvar
 
+    def setgenvar(self, newgenvar):
+        assert not self.is_constant()
+        self.genvar = newgenvar
+
     def enter_block(self, incoming, memo):
         memo = memo.boxes
         if not self.is_constant() and self not in memo:
             incoming.append(self)
             memo[self] = None
 
-    def forcevar(self, jitstate, memo):
-        builder = jitstate.curbuilder
+    def forcevar(self, jitstate, memo, forget_nonzeroness):
         if self.is_constant():
             # cannot mutate constant boxes in-place
+            builder = jitstate.curbuilder
             box = self.copy(memo)
             box.genvar = builder.genop_same_as(self.kind, self.genvar)
             return box
         else:
-            # force virtual containers
-            self.getgenvar(jitstate)
             return self
 
     def replace(self, memo):
@@ -74,15 +77,8 @@
 
 
 def ll_redboxcls(TYPE):
-    if isinstance(TYPE, lltype.Ptr):
-        return PtrRedBox
-    elif TYPE is lltype.Float:
-        return DoubleRedBox
-    else:
-        assert isinstance(TYPE, lltype.Primitive)
-        assert TYPE is not lltype.Void, "cannot make red boxes of voids"
-        # XXX what about long longs?
-        return IntRedBox
+    assert TYPE is not lltype.Void, "cannot make red boxes of voids"
+    return ll_redboxbuilder(TYPE)
 
 def redboxbuilder_void(kind, gv_value):return None
 def redboxbuilder_int(kind, gv_value): return IntRedBox(kind, gv_value)
@@ -181,6 +177,29 @@
 class PtrRedBox(RedBox):
     content = None   # or an AbstractContainer
 
+    def __init__(self, kind, genvar=None, known_nonzero=False):
+        self.kind = kind
+        self.genvar = genvar    # None or a genvar
+        if genvar is not None and genvar.is_const:
+            known_nonzero = bool(genvar.revealconst(llmemory.Address))
+        self.known_nonzero = known_nonzero
+
+    def setgenvar(self, newgenvar):
+        RedBox.setgenvar(self, newgenvar)
+        self.known_nonzero = (newgenvar.is_const and
+                              bool(newgenvar.revealconst(llmemory.Address)))
+
+    def setgenvar_hint(self, newgenvar, known_nonzero):
+        RedBox.setgenvar(self, newgenvar)
+        self.known_nonzero = known_nonzero
+
+    def learn_nonzeroness(self, jitstate, nonzeroness):
+        if nonzeroness:
+            self.known_nonzero = True
+        else:
+            gv_null = jitstate.curbuilder.rgenop.genzeroconst(self.kind)
+            self.setgenvar_hint(gv_null, known_nonzero=False)
+
     def __repr__(self):
         if not self.genvar and self.content is not None:
             return '<virtual %s>' % (self.content,)
@@ -188,6 +207,7 @@
             return RedBox.__repr__(self)
 
     def op_getfield(self, jitstate, fielddesc):
+        self.known_nonzero = True
         if self.content is not None:
             box = self.content.op_getfield(jitstate, fielddesc)
             if box is not None:
@@ -199,6 +219,7 @@
         return box
 
     def op_setfield(self, jitstate, fielddesc, valuebox):
+        self.known_nonzero = True
         gv_ptr = self.genvar
         if gv_ptr:
             fielddesc.generate_set(jitstate, gv_ptr,
@@ -208,6 +229,7 @@
             self.content.op_setfield(jitstate, fielddesc, valuebox)
 
     def op_getsubstruct(self, jitstate, fielddesc):
+        self.known_nonzero = True
         gv_ptr = self.genvar
         if gv_ptr:
             return fielddesc.generate_getsubstruct(jitstate, gv_ptr)
@@ -228,7 +250,7 @@
         try:
             result = boxmemo[self]
         except KeyError:
-            result = PtrRedBox(self.kind, self.genvar)
+            result = PtrRedBox(self.kind, self.genvar, self.known_nonzero)
             boxmemo[self] = result
             if self.content:
                 result.content = self.content.copy(memo)
@@ -263,12 +285,13 @@
             elif self.genvar.is_const:
                 result = FrozenPtrConst(self.kind, self.genvar)
             elif content is None:
-                result = FrozenPtrVar(self.kind)
+                result = FrozenPtrVar(self.kind, self.known_nonzero)
             else:
                 # if self.content is not None, it's a PartialDataStruct
                 from pypy.jit.timeshifter import rcontainer
                 assert isinstance(content, rcontainer.PartialDataStruct)
-                result = FrozenPtrVarWithPartialData(self.kind)
+                result = FrozenPtrVarWithPartialData(self.kind,
+                                                     known_nonzero=True)
                 boxmemo[self] = result
                 result.fz_partialcontent = content.partialfreeze(memo)
                 return result
@@ -286,11 +309,23 @@
             assert self.genvar
         return self.genvar
 
-    def forcevar(self, jitstate, memo):
+    def forcevar(self, jitstate, memo, forget_nonzeroness):
         from pypy.jit.timeshifter import rcontainer
         # xxx
         assert not isinstance(self.content, rcontainer.VirtualizableStruct)
-        return RedBox.forcevar(self, jitstate, memo)
+        if self.is_constant():
+            # cannot mutate constant boxes in-place
+            builder = jitstate.curbuilder
+            box = self.copy(memo)
+            box.genvar = builder.genop_same_as(self.kind, self.genvar)
+        else:
+            # force virtual containers
+            self.getgenvar(jitstate)
+            box = self
+
+        if forget_nonzeroness:
+            box.known_nonzero = False
+        return box
 
     def enter_block(self, incoming, memo):
         if self.genvar:
@@ -412,6 +447,8 @@
     def exactmatch(self, box, outgoingvarboxes, memo):
         assert isinstance(box, PtrRedBox)
         memo.partialdatamatch[box] = None     # could do better
+        if self.is_constant_nullptr():
+            memo.forget_nonzeroness[box] = None
         match = FrozenConst.exactmatch(self, box, outgoingvarboxes, memo)
         if not memo.force_merge and not match:
             from pypy.jit.timeshifter.rcontainer import VirtualContainer
@@ -425,10 +462,18 @@
 
 class FrozenPtrVar(FrozenVar):
 
+    def __init__(self, kind, known_nonzero):
+        self.kind = kind
+        self.known_nonzero = known_nonzero
+
     def exactmatch(self, box, outgoingvarboxes, memo):
         assert isinstance(box, PtrRedBox)
         memo.partialdatamatch[box] = None
+        if not self.known_nonzero:
+            memo.forget_nonzeroness[box] = None
         match = FrozenVar.exactmatch(self, box, outgoingvarboxes, memo)
+        if self.known_nonzero and not box.known_nonzero:
+            match = False
         if not memo.force_merge and not match:
             from pypy.jit.timeshifter.rcontainer import VirtualContainer
             if isinstance(box.content, VirtualContainer):
@@ -438,7 +483,7 @@
     def unfreeze(self, incomingvarboxes, memo):
         memo = memo.boxes
         if self not in memo:
-            newbox = PtrRedBox(self.kind, None)
+            newbox = PtrRedBox(self.kind, None, self.known_nonzero)
             incomingvarboxes.append(newbox)
             memo[self] = newbox
             return newbox

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_exception.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_exception.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_exception.py	Fri Feb  2 20:59:02 2007
@@ -140,26 +140,14 @@
         self.check_insns(malloc=0)
 
     def test_not_segregated_malloc_exception_path(self):
-        py.test.skip("WIP")
-        class E(Exception):
-            def __init__(self, msg):
-                self.msg = msg
-                
         def help(l, x):
-            if x < 0:
-                raise E("x negative: %d" %x)
-            l.append(x)
-            return l
+            l.append("x is %s" % chr(x))
 
         def ll_function(x):
             l = []
-            l = help(l, x)
+            help(l, x)
             return len(l)+x
 
         res = self.timeshift(ll_function, [5], [], policy=P_OOPSPEC)
         res == 6
         self.check_oops(newlist=0)
-            
-
-
-        

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_promotion.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_promotion.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_promotion.py	Fri Feb  2 20:59:02 2007
@@ -302,7 +302,6 @@
         assert res == 22
 
     def test_raise_result_mixup(self):
-        py.test.skip("WIP")
         def w(x):
             pass
         class E(Exception):

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py	Fri Feb  2 20:59:02 2007
@@ -785,14 +785,14 @@
          res = self.timeshift(ll_function, [21, -21, 0], [],
                               policy=P_NOVIRTUAL)
          assert res == 42
-         self.check_insns({'malloc_varsize': 1, 'ptr_iszero': 1,
+         self.check_insns({'malloc_varsize': 1,
                            'setarrayitem': 2, 'getarrayitem': 1,
                            'getarraysize': 1, 'int_mul': 1})
 
          res = self.timeshift(ll_function, [21, -21, 1], [],
                               policy=P_NOVIRTUAL)
          assert res == -42
-         self.check_insns({'malloc_varsize': 1, 'ptr_iszero': 1,
+         self.check_insns({'malloc_varsize': 1,
                            'setarrayitem': 2, 'getarrayitem': 1,
                            'getarraysize': 1, 'int_mul': 1})
 
@@ -808,7 +808,7 @@
          res = self.timeshift(ll_function, [21, -21, 0], [],
                               policy=P_NOVIRTUAL)
          assert res == 42
-         self.check_insns({'malloc_varsize': 1, 'ptr_iszero': 1,
+         self.check_insns({'malloc_varsize': 1,
                            'getarraysubstruct': 3,
                            'setfield': 2, 'getfield': 1,
                            'getarraysize': 1, 'int_mul': 1})
@@ -816,7 +816,7 @@
          res = self.timeshift(ll_function, [21, -21, 1], [],
                               policy=P_NOVIRTUAL)
          assert res == -42
-         self.check_insns({'malloc_varsize': 1, 'ptr_iszero': 1,
+         self.check_insns({'malloc_varsize': 1,
                            'getarraysubstruct': 3,
                            'setfield': 2, 'getfield': 1,
                            'getarraysize': 1, 'int_mul': 1})
@@ -1292,3 +1292,59 @@
 
         res = self.timeshift(f, [3], [], policy=P_NOVIRTUAL)
         assert res == '2'
+
+    def test_known_nonzero(self):
+        S = lltype.GcStruct('s', ('x', lltype.Signed))
+        global_s = lltype.malloc(S, immortal=True)
+        global_s.x = 100
+
+        def h():
+            s = lltype.malloc(S)
+            s.x = 50
+            return s
+        def g(s, y):
+            if s:
+                return s.x * 5
+            else:
+                return -12 + y
+        def f(x, y):
+            x = hint(x, concrete=True)
+            if x == 1:
+                return g(lltype.nullptr(S), y)
+            elif x == 2:
+                return g(global_s, y)
+            elif x == 3:
+                s = lltype.malloc(S)
+                s.x = y
+                return g(s, y)
+            elif x == 4:
+                s = h()
+                return g(s, y)
+            else:
+                s = h()
+                if s:
+                    return g(s, y)
+                else:
+                    return 0
+
+        P = StopAtXPolicy(h)
+
+        res = self.timeshift(f, [1, 10], [0], policy=P)
+        assert res == -2
+        self.check_insns(int_mul=0, int_add=1)
+
+        res = self.timeshift(f, [2, 10], [0], policy=P)
+        assert res == 500
+        self.check_insns(int_mul=1, int_add=0)
+
+        res = self.timeshift(f, [3, 10], [0], policy=P)
+        assert res == 50
+        self.check_insns(int_mul=1, int_add=0)
+
+        res = self.timeshift(f, [4, 10], [0], policy=P)
+        assert res == 250
+        self.check_insns(int_mul=1, int_add=1)
+
+        res = self.timeshift(f, [5, 10], [0], policy=P)
+        assert res == 250
+        self.check_insns(int_mul=1, int_add=0)

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py	Fri Feb  2 20:59:02 2007
@@ -53,6 +53,7 @@
         return self.raise_analyzer.analyze(op)
 
     def transform(self):
+        self.simplify_operations()
         self.compute_merge_points()
         self.insert_save_return()
         self.insert_splits()
@@ -109,6 +110,23 @@
         if startblock in global_merge_blocks:
             self.mergepoint_set[startblock] = 'global'
 
+    def simplify_operations(self):
+        # ptr_eq(x, 0) => ptr_iszero
+        # ptr_ne(x, 0) => ptr_nonzero
+        replace = {'ptr_eq': 'ptr_iszero',
+                   'ptr_ne': 'ptr_nonzero'}
+        for block in self.graph.iterblocks():
+            for op in block.operations:
+                if op.opname in replace:
+                    srcargs = op.args
+                    for v1, v2 in [(srcargs[0], srcargs[1]),
+                                   (srcargs[1], srcargs[0])]:
+                        if isinstance(v2, Constant):
+                            if not v2.value:
+                                op.opname = replace[op.opname]
+                                op.args = [v1]
+                                break
+
     def graph_calling_color(self, tsgraph):
         args_hs, hs_res = self.hannotator.bookkeeper.tsgraphsigs[tsgraph]
         if originalconcretetype(hs_res) is lltype.Void:
@@ -244,51 +262,58 @@
                 if not hs_switch.is_green():
                     self.insert_split_handling(block)
 
+    def trace_back_exitswitch(self, block):
+        """Return the (opname, arguments) that created the exitswitch of
+        the block.  The opname is None if not found.
+        """
+        v = block.exitswitch
+        inverted = False
+        for i in range(len(block.operations)-1, -1, -1):
+            op = block.operations[i]
+            if op.result is v:
+                if op.opname == 'bool_not':
+                    inverted = not inverted
+                    [v] = op.args
+                elif op.opname == 'same_as':
+                    [v] = op.args
+                else:
+                    opname = op.opname
+                    opargs = op.args
+                    if inverted:
+                        opname = {'ptr_nonzero': 'ptr_iszero',
+                                  'ptr_iszero' : 'ptr_nonzero'}.get(opname)
+                    return opname, opargs    # found
+        # not found, comes from earlier block - give up
+        return None, None
+
     def insert_split_handling(self, block):
-        # lots of clever in-line logic commented out
         v_redswitch = block.exitswitch
+
+        # try to look where the v_redswitch comes from
+        split_variant = ''
+        split_extras = []
+        srcopname, srcargs = self.trace_back_exitswitch(block)
+        if srcopname == 'ptr_nonzero':
+            split_variant = '_ptr_nonzero'
+            split_extras = srcargs
+        elif srcopname == 'ptr_iszero':
+            split_variant = '_ptr_iszero'
+            split_extras = srcargs
+
         link_f, link_t = block.exits
         if link_f.exitcase:
             link_f, link_t = link_t, link_f
         assert link_f.exitcase is False
         assert link_t.exitcase is True
 
-##        constant_block = Block([])
-##        nonconstant_block = Block([])
-
-##        v_flag = self.genop(block, 'is_constant', [v_redswitch],
-##                            resulttype = lltype.Bool)
-##        self.genswitch(block, v_flag, true  = constant_block,
-##                                      false = nonconstant_block)
-
-##        v_greenswitch = self.genop(constant_block, 'revealconst',
-##                                   [v_redswitch],
-##                                   resulttype = lltype.Bool)
-##        constant_block.exitswitch = v_greenswitch
-##        constant_block.closeblock(link_f, link_t)
-
         reds, greens = self.sort_by_color(link_f.args, link_f.target.inputargs)
         self.genop(block, 'save_locals', reds)
         resumepoint = self.get_resume_point(link_f.target)
         c_resumepoint = inputconst(lltype.Signed, resumepoint)
-        v_flag = self.genop(block, 'split',
-                            [v_redswitch, c_resumepoint] + greens,
-                            resulttype = lltype.Bool)
-
+        v_flag = self.genop(block, 'split' + split_variant,
+                        [v_redswitch, c_resumepoint] + split_extras + greens,
+                        resulttype = lltype.Bool)
         block.exitswitch = v_flag
-##        true_block = Block([])
-##        true_link  = Link([], true_block)
-##        true_link.exitcase   = True
-##        true_link.llexitcase = True
-##        block.recloseblock(link_f, true_link)
-
-##        reds, greens = self.sort_by_color(link_t.args)
-##        self.genop(true_block, 'save_locals', reds)
-##        self.genop(true_block, 'enter_block', [])
-##        true_block.closeblock(Link(link_t.args, link_t.target))
-
-##        SSA_to_SSI({block     : True,    # reachable from outside
-##                    true_block: False}, self.hannotator)
 
     def get_resume_point_link(self, block):
         try:

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/vdict.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/vdict.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/vdict.py	Fri Feb  2 20:59:02 2007
@@ -133,7 +133,7 @@
 
     def factory(self):
         vdict = self.VirtualDict(self)
-        box = rvalue.PtrRedBox(self.ptrkind)
+        box = rvalue.PtrRedBox(self.ptrkind, known_nonzero=True)
         box.content = vdict
         vdict.ownbox = box
         return box
@@ -208,7 +208,7 @@
         gv_dict = builder.genop_call(typedesc.tok_ll_newdict,
                                      typedesc.gv_ll_newdict,
                                      args_gv)
-        self.ownbox.genvar = gv_dict
+        self.ownbox.setgenvar_hint(gv_dict, known_nonzero=True)
         self.ownbox.content = None
         for gv_key, valuebox, hash in items:
             gv_hash = builder.rgenop.genconst(hash)

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/vlist.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/vlist.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/vlist.py	Fri Feb  2 20:59:02 2007
@@ -75,7 +75,7 @@
 
     def factory(self, length, itembox):
         vlist = VirtualList(self, length, itembox)
-        box = rvalue.PtrRedBox(self.ptrkind)
+        box = rvalue.PtrRedBox(self.ptrkind, known_nonzero=True)
         box.content = vlist
         vlist.ownbox = box
         return box
@@ -154,7 +154,7 @@
 
     def setforced(self, gv_forced):
         self.item_boxes = None
-        self.ownbox.genvar = gv_forced
+        self.ownbox.setgenvar_hint(gv_forced, known_nonzero=True)
         self.ownbox.content = None        
 
     def force_runtime_container(self, jitstate):

Modified: pypy/branch/jit-virtual-world/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/rpython/lltypesystem/rclass.py	Fri Feb  2 20:59:02 2007
@@ -58,7 +58,7 @@
 OBJECT_VTABLE = lltype.ForwardReference()
 CLASSTYPE = Ptr(OBJECT_VTABLE)
 OBJECT = GcStruct('object', ('typeptr', CLASSTYPE),
-                            hints = {'immutable': True})
+                  hints = {'immutable': True, 'shouldntbenull': True})
 OBJECTPTR = Ptr(OBJECT)
 OBJECT_VTABLE.become(Struct('object_vtable',
                             #('parenttypeptr', CLASSTYPE),


More information about the pypy-svn mailing list