[pypy-commit] pypy default: Merged in force-virtual-state (pull request #478)

sbauman pypy.commits at gmail.com
Tue Sep 13 11:56:48 EDT 2016


Author: Spenser Bauman <sabauma at gmail.com>
Branch: 
Changeset: r87082:cfcbc07174e8
Date: 2016-09-13 11:56 -0400
http://bitbucket.org/pypy/pypy/changeset/cfcbc07174e8/

Log:	Merged in force-virtual-state (pull request #478)

	Ensure make_inputargs fails properly when given arguments with type
	information

diff --git a/rpython/jit/metainterp/optimizeopt/info.py b/rpython/jit/metainterp/optimizeopt/info.py
--- a/rpython/jit/metainterp/optimizeopt/info.py
+++ b/rpython/jit/metainterp/optimizeopt/info.py
@@ -3,7 +3,7 @@
 from rpython.jit.metainterp.resoperation import AbstractValue, ResOperation,\
      rop, OpHelpers
 from rpython.jit.metainterp.history import ConstInt, Const
-from rpython.rtyper.lltypesystem import lltype
+from rpython.rtyper.lltypesystem import lltype, llmemory
 from rpython.jit.metainterp.optimizeopt.rawbuffer import RawBuffer, InvalidRawOperation
 from rpython.jit.metainterp.executor import execute
 from rpython.jit.metainterp.optimize import InvalidLoop
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -11,6 +11,8 @@
 from rpython.jit.metainterp.typesystem import llhelper
 from rpython.rlib.objectmodel import specialize, we_are_translated
 from rpython.rlib.debug import debug_print
+from rpython.rtyper import rclass
+from rpython.rtyper.lltypesystem import llmemory
 from rpython.jit.metainterp.optimize import SpeculativeError
 
 
@@ -799,6 +801,21 @@
         if not (0 <= index < arraylength):
             raise SpeculativeError
 
+    @staticmethod
+    def _check_subclass(vtable1, vtable2): # checks that vtable1 is a subclass of vtable2
+        known_class = llmemory.cast_adr_to_ptr(
+            llmemory.cast_int_to_adr(vtable1),
+            rclass.CLASSTYPE)
+        expected_class = llmemory.cast_adr_to_ptr(
+            llmemory.cast_int_to_adr(vtable2),
+            rclass.CLASSTYPE)
+        # note: the test is for a range including 'max', but 'max'
+        # should never be used for actual classes.  Including it makes
+        # it easier to pass artificial tests.
+        return (expected_class.subclassrange_min
+                <= known_class.subclassrange_min
+                <= expected_class.subclassrange_max)
+
     def is_virtual(self, op):
         if op.type == 'r':
             opinfo = self.getptrinfo(op)
diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py
--- a/rpython/jit/metainterp/optimizeopt/rewrite.py
+++ b/rpython/jit/metainterp/optimizeopt/rewrite.py
@@ -324,40 +324,24 @@
             return
         self.emit_operation(op)
 
-    def _check_subclass(self, vtable1, vtable2):
-        # checks that vtable1 is a subclass of vtable2
-        known_class = llmemory.cast_adr_to_ptr(
-            llmemory.cast_int_to_adr(vtable1),
-            rclass.CLASSTYPE)
-        expected_class = llmemory.cast_adr_to_ptr(
-            llmemory.cast_int_to_adr(vtable2),
-            rclass.CLASSTYPE)
-        # note: the test is for a range including 'max', but 'max'
-        # should never be used for actual classes.  Including it makes
-        # it easier to pass artificial tests.
-        if (expected_class.subclassrange_min
-                <= known_class.subclassrange_min
-                <= expected_class.subclassrange_max):
-            return True
-        return False
-
     def optimize_GUARD_SUBCLASS(self, op):
         info = self.getptrinfo(op.getarg(0))
+        optimizer = self.optimizer
         if info and info.is_constant():
             c = self.get_box_replacement(op.getarg(0))
-            vtable = self.optimizer.cpu.ts.cls_of_box(c).getint()
-            if self._check_subclass(vtable, op.getarg(1).getint()):
+            vtable = optimizer.cpu.ts.cls_of_box(c).getint()
+            if optimizer._check_subclass(vtable, op.getarg(1).getint()):
                 return
             raise InvalidLoop("GUARD_SUBCLASS(const) proven to always fail")
         if info is not None and info.is_about_object():
-            known_class = info.get_known_class(self.optimizer.cpu)
+            known_class = info.get_known_class(optimizer.cpu)
             if known_class:
-                if self._check_subclass(known_class.getint(),
-                                        op.getarg(1).getint()):
+                if optimizer._check_subclass(known_class.getint(),
+                                             op.getarg(1).getint()):
                     return
             elif info.get_descr() is not None:
-                if self._check_subclass(info.get_descr().get_vtable(),
-                                        op.getarg(1).getint()):
+                if optimizer._check_subclass(info.get_descr().get_vtable(),
+                                             op.getarg(1).getint()):
                     return
         self.emit_operation(op)
 
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_unroll.py b/rpython/jit/metainterp/optimizeopt/test/test_unroll.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_unroll.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_unroll.py
@@ -17,12 +17,13 @@
 from rpython.jit.metainterp.optimizeopt.virtualstate import \
      NotVirtualStateInfo, LEVEL_CONSTANT, LEVEL_UNKNOWN, LEVEL_KNOWNCLASS,\
      VirtualStateInfo
-from rpython.jit.metainterp.optimizeopt import info
+from rpython.jit.metainterp.optimizeopt import info, optimizer
 from rpython.jit.codewriter import heaptracker
 from rpython.jit.tool import oparser
 
 class FakeOptimizer(object):
     optearlyforce = None
+    optimizer = optimizer.Optimizer
 
     class cpu:
         remove_gctypeptr = True
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -102,6 +102,8 @@
     node_vtable_adr2 = llmemory.cast_ptr_to_adr(node_vtable2)
     node_vtable3 = lltype.malloc(OBJECT_VTABLE, immortal=True)
     node_vtable3.name = rclass.alloc_array_name('node3')
+    node_vtable3.subclassrange_min = 3
+    node_vtable3.subclassrange_max = 3
     node_vtable_adr3 = llmemory.cast_ptr_to_adr(node_vtable3)
     cpu = runner.LLGraphCPU(None)
 
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
@@ -3,7 +3,8 @@
 from rpython.jit.metainterp.optimizeopt.virtualstate import VirtualStateInfo,\
      VStructStateInfo, LEVEL_CONSTANT,\
      VArrayStateInfo, not_virtual, VirtualState,\
-     GenerateGuardState, VirtualStatesCantMatch, VArrayStructStateInfo
+     GenerateGuardState, VirtualStatesCantMatch, VArrayStructStateInfo,\
+     VirtualStateConstructor
 from rpython.jit.metainterp.history import ConstInt, ConstPtr, TargetToken
 from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef,\
      InputArgFloat
@@ -26,6 +27,7 @@
     def __init__(self, cpu):
         self.cpu = cpu
         self.optearlyforce = None
+        self.optimizer = Optimizer
 
 class BaseTestGenerateGuards(BaseTest):
     def setup_class(self):
@@ -87,6 +89,33 @@
         vs = VirtualState([info0])
         assert vs.make_inputargs(args, optimizer) == []
 
+    def test_make_inputargs_2(self):
+        # Ensure that make_inputargs properly errors with VirtualStatesCantMatch
+        # when the type information for a virtual field conflicts. In practice the
+        # expected and given field always share a common subclass.
+        # This check is needed as not all paths to make_inputargs in unroll.py
+        # are guarded by a call to generate_guards.
+        optimizer = FakeOptimizer(self.cpu)
+        classbox1 = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr))
+        innervalue1 = info.InstancePtrInfo(known_class=classbox1, is_virtual=True, descr=self.valuedescr.get_parent_descr())
+        for field in self.valuedescr.get_parent_descr().get_all_fielddescrs():
+            innervalue1.setfield(field, None, ConstInt(42))
+        classbox2 = self.cpu.ts.cls_of_box(InputArgRef(self.myptr3))
+        innervalue2 = info.InstancePtrInfo(known_class=classbox2, is_virtual=True, descr=self.valuedescr3.get_parent_descr())
+        for field in self.valuedescr3.get_parent_descr().get_all_fielddescrs():
+            innervalue2.setfield(field, None, ConstInt(42))
+
+        nodebox1 = InputArgRef(self.nodeaddr)
+        nodebox2 = InputArgRef(self.myptr3)
+        nodebox1.set_forwarded(innervalue1)
+        nodebox2.set_forwarded(innervalue2)
+
+        constr = VirtualStateConstructor(optimizer)
+        vs = constr.get_virtual_state([nodebox1])
+
+        with py.test.raises(VirtualStatesCantMatch):
+            args = vs.make_inputargs([nodebox2], optimizer, force_boxes=True)
+
     def test_position_generalization(self):
         def postest(info1, info2):
             info1.position = 0
diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py
--- a/rpython/jit/metainterp/optimizeopt/virtualstate.py
+++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py
@@ -177,6 +177,14 @@
     def _generalization_of_structpart(self, other):
         raise NotImplementedError
 
+    @staticmethod
+    def descr_issubclass(descr1, descr2, optimizer):
+        if not descr1.is_object() or not descr2.is_object():
+            return True
+        vtable1 = descr1.get_vtable()
+        vtable2 = descr2.get_vtable()
+        return optimizer._check_subclass(vtable1, vtable2)
+
     def enum_forced_boxes(self, boxes, box, optimizer, force_boxes=False):
         box = optimizer.get_box_replacement(box)
         info = optimizer.getptrinfo(box)
@@ -184,10 +192,14 @@
             raise VirtualStatesCantMatch()
         else:
             assert isinstance(info, AbstractStructPtrInfo)
+
         for i in range(len(self.fielddescrs)):
             state = self.fieldstate[i]
+            descr = self.fielddescrs[i].get_parent_descr()
             if not state:
                 continue
+            if not self.descr_issubclass(info.descr, descr, optimizer.optimizer):
+                raise VirtualStatesCantMatch()
             if state.position > self.position:
                 fieldbox = info._fields[i]
                 state.enum_forced_boxes(boxes, fieldbox, optimizer, force_boxes)


More information about the pypy-commit mailing list