Beispiel #1
0
def effectinfo_from_writeanalyze(effects, cpu,
                                 extraeffect=EffectInfo.EF_CAN_RAISE,
                                 oopspecindex=EffectInfo.OS_NONE,
                                 can_invalidate=False,
                                 call_release_gil_target=
                                     EffectInfo._NO_CALL_RELEASE_GIL_TARGET,
                                 extradescr=None):
    from rpython.translator.backendopt.writeanalyze import top_set
    if effects is top_set or extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
        readonly_descrs_fields = None
        readonly_descrs_arrays = None
        readonly_descrs_interiorfields = None
        write_descrs_fields = None
        write_descrs_arrays = None
        write_descrs_interiorfields = None
        extraeffect = EffectInfo.EF_RANDOM_EFFECTS
    else:
        readonly_descrs_fields = []
        readonly_descrs_arrays = []
        readonly_descrs_interiorfields = []
        write_descrs_fields = []
        write_descrs_arrays = []
        write_descrs_interiorfields = []

        def add_struct(descrs_fields, (_, T, fieldname)):
            T = deref(T)
            if consider_struct(T, fieldname):
                descr = cpu.fielddescrof(T, fieldname)
                descrs_fields.append(descr)

        def add_array(descrs_arrays, (_, T)):
            ARRAY = deref(T)
            if consider_array(ARRAY):
                descr = cpu.arraydescrof(ARRAY)
                descrs_arrays.append(descr)
Beispiel #2
0
def builtin_func_for_spec(rtyper, oopspec_name, ll_args, ll_res,
                          extra=None, extrakey=None):
    assert (extra is None) == (extrakey is None)
    key = (oopspec_name, tuple(ll_args), ll_res, extrakey)
    try:
        return rtyper._builtin_func_for_spec_cache[key]
    except (KeyError, AttributeError):
        pass
    args_s = [lltype_to_annotation(v) for v in ll_args]
    if '.' not in oopspec_name:    # 'newxxx' operations
        LIST_OR_DICT = ll_res
    else:
        LIST_OR_DICT = ll_args[0]
    s_result = lltype_to_annotation(ll_res)
    impl = setup_extra_builtin(rtyper, oopspec_name, len(args_s), extra)
    if getattr(impl, 'need_result_type', False):
        bk = rtyper.annotator.bookkeeper
        args_s.insert(0, annmodel.SomePBC([bk.getdesc(deref(ll_res))]))
    #
    if hasattr(rtyper, 'annotator'):  # regular case
        mixlevelann = MixLevelHelperAnnotator(rtyper)
        c_func = mixlevelann.constfunc(impl, args_s, s_result)
        mixlevelann.finish()
    else:
        # for testing only
        c_func = Constant(oopspec_name,
                          lltype.Ptr(lltype.FuncType(ll_args, ll_res)))
    #
    if not hasattr(rtyper, '_builtin_func_for_spec_cache'):
        rtyper._builtin_func_for_spec_cache = {}
    rtyper._builtin_func_for_spec_cache[key] = (c_func, LIST_OR_DICT)
    #
    return c_func, LIST_OR_DICT
Beispiel #3
0
    def test_immutable_fields_subclass_2(self):
        from rpython.jit.metainterp.typesystem import deref

        class A(object):
            _immutable_fields_ = ["x"]

            def __init__(self, x):
                self.x = x

        class B(A):
            _immutable_fields_ = ["y"]

            def __init__(self, x, y):
                A.__init__(self, x)
                self.y = y

        def f():
            return B(3, 5)

        t, typer, graph = self.gengraph(f, [])
        B_TYPE = deref(graph.getreturnvar().concretetype)
        accessor = B_TYPE._hints["immutable_fields"]
        assert accessor.fields == {
            "inst_x": IR_IMMUTABLE,
            "inst_y": IR_IMMUTABLE
        }
Beispiel #4
0
    def test_quasi_immutable(self):
        from rpython.jit.metainterp.typesystem import deref

        class A(object):
            _immutable_fields_ = ['x', 'y', 'a?', 'b?']

        class B(A):
            pass

        def f():
            a = A()
            a.x = 42
            a.a = 142
            b = B()
            b.x = 43
            b.y = 41
            b.a = 44
            b.b = 45
            return B()

        t, typer, graph = self.gengraph(f, [])
        B_TYPE = deref(graph.getreturnvar().concretetype)
        accessor = B_TYPE._hints["immutable_fields"]
        assert accessor.fields == {
            "inst_y": IR_IMMUTABLE,
            "inst_b": IR_QUASIIMMUTABLE
        }
        found = []
        for op in graph.startblock.operations:
            if op.opname == 'jit_force_quasi_immutable':
                found.append(op.args[1].value)
        assert found == ['mutate_a', 'mutate_a', 'mutate_b']
Beispiel #5
0
 def test_quasi_immutable(self):
     from rpython.jit.metainterp.typesystem import deref
     class A(object):
         _immutable_fields_ = ['x', 'y', 'a?', 'b?']
     class B(A):
         pass
     def f():
         a = A()
         a.x = 42
         a.a = 142
         b = B()
         b.x = 43
         b.y = 41
         b.a = 44
         b.b = 45
         return B()
     t, typer, graph = self.gengraph(f, [])
     B_TYPE = deref(graph.getreturnvar().concretetype)
     accessor = B_TYPE._hints["immutable_fields"]
     assert accessor.fields == {"inst_y": IR_IMMUTABLE,
                                "inst_b": IR_QUASIIMMUTABLE}
     found = []
     for op in graph.startblock.operations:
         if op.opname == 'jit_force_quasi_immutable':
             found.append(op.args[1].value)
     assert found == ['mutate_a', 'mutate_a', 'mutate_b']
Beispiel #6
0
 def test_immutable_subclass_2(self):
     from rpython.jit.metainterp.typesystem import deref
     class A(object):
         pass
     class B(A):
         _immutable_ = True
     def f():
         A()
         B().v = 123
         return B()
     t, typer, graph = self.gengraph(f, [])
     B_TYPE = deref(graph.getreturnvar().concretetype)
     assert B_TYPE._hints["immutable"]
Beispiel #7
0
def effectinfo_from_writeanalyze(
        effects,
        cpu,
        extraeffect=EffectInfo.EF_CAN_RAISE,
        oopspecindex=EffectInfo.OS_NONE,
        can_invalidate=False,
        call_release_gil_target=EffectInfo._NO_CALL_RELEASE_GIL_TARGET,
        extradescr=None,
        can_collect=True):
    from rpython.translator.backendopt.writeanalyze import top_set
    if effects is top_set or extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
        readonly_descrs_fields = None
        readonly_descrs_arrays = None
        readonly_descrs_interiorfields = None
        write_descrs_fields = None
        write_descrs_arrays = None
        write_descrs_interiorfields = None
        extraeffect = EffectInfo.EF_RANDOM_EFFECTS
    else:
        readonly_descrs_fields = []
        readonly_descrs_arrays = []
        readonly_descrs_interiorfields = []
        write_descrs_fields = []
        write_descrs_arrays = []
        write_descrs_interiorfields = []

        def add_struct(descrs_fields, (_, T, fieldname)):
            T = deref(T)
            if consider_struct(T, fieldname):
                descr = cpu.fielddescrof(T, fieldname)
                descrs_fields.append(descr)

        def add_array(descrs_arrays, (_, T)):
            ARRAY = deref(T)
            if consider_array(ARRAY):
                descr = cpu.arraydescrof(ARRAY)
                descrs_arrays.append(descr)
Beispiel #8
0
def builtin_func_for_spec(rtyper,
                          oopspec_name,
                          ll_args,
                          ll_res,
                          extra=None,
                          extrakey=None):
    assert (extra is None) == (extrakey is None)
    key = (oopspec_name, tuple(ll_args), ll_res, extrakey)
    try:
        return rtyper._builtin_func_for_spec_cache[key]
    except (KeyError, AttributeError):
        pass
    args_s = [lltype_to_annotation(v) for v in ll_args]
    if '.' not in oopspec_name:  # 'newxxx' operations
        LIST_OR_DICT = ll_res
    else:
        LIST_OR_DICT = ll_args[0]
    s_result = lltype_to_annotation(ll_res)
    impl = setup_extra_builtin(rtyper, oopspec_name, len(args_s), extra)
    if getattr(impl, 'need_result_type', False):
        if hasattr(rtyper, 'annotator'):
            bk = rtyper.annotator.bookkeeper
            ll_restype = ll_res
            if impl.need_result_type != 'exact':
                ll_restype = deref(ll_restype)
            desc = bk.getdesc(ll_restype)
        else:

            class TestingDesc(object):
                knowntype = int
                pyobj = None

            desc = TestingDesc()
        args_s.insert(0, annmodel.SomePBC([desc]))
    #
    if hasattr(rtyper, 'annotator'):  # regular case
        mixlevelann = MixLevelHelperAnnotator(rtyper)
        c_func = mixlevelann.constfunc(impl, args_s, s_result)
        mixlevelann.finish()
    else:
        # for testing only
        c_func = Constant(oopspec_name,
                          lltype.Ptr(lltype.FuncType(ll_args, ll_res)))
    #
    if not hasattr(rtyper, '_builtin_func_for_spec_cache'):
        rtyper._builtin_func_for_spec_cache = {}
    rtyper._builtin_func_for_spec_cache[key] = (c_func, LIST_OR_DICT)
    #
    return c_func, LIST_OR_DICT
Beispiel #9
0
 def test_immutable_subclass_void(self):
     from rpython.jit.metainterp.typesystem import deref
     class A(object):
         pass
     class B(A):
         _immutable_ = True
     def myfunc():
         pass
     def f():
         A().f = myfunc    # it's ok to add Void attributes to A
         B().v = 123       # even though only B is declared _immutable_
         return B()
     t, typer, graph = self.gengraph(f, [])
     B_TYPE = deref(graph.getreturnvar().concretetype)
     assert B_TYPE._hints["immutable"]
Beispiel #10
0
    def test_immutable_fields(self):
        from rpython.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": IR_IMMUTABLE,
                                   "inst_y": IR_IMMUTABLE_ARRAY}
Beispiel #11
0
 def test_immutable_ok_inheritance_2(self):
     from rpython.jit.metainterp.typesystem import deref
     class A(object):
         _immutable_fields_ = ['v']
     class B(A):
         _immutable_ = True
     def f():
         A().v = 123
         B().w = 456
         return B()
     t, typer, graph = self.gengraph(f, [])
     B_TYPE = deref(graph.getreturnvar().concretetype)
     assert B_TYPE._hints["immutable"]
     A_TYPE = B_TYPE.super
     accessor = A_TYPE._hints["immutable_fields"]
     assert accessor.fields == {"inst_v": IR_IMMUTABLE}
Beispiel #12
0
    def test_immutable_subclass_2(self):
        from rpython.jit.metainterp.typesystem import deref

        class A(object):
            pass

        class B(A):
            _immutable_ = True

        def f():
            A()
            B().v = 123
            return B()

        t, typer, graph = self.gengraph(f, [])
        B_TYPE = deref(graph.getreturnvar().concretetype)
        assert B_TYPE._hints["immutable"]
Beispiel #13
0
    def test_immutable_fields_only_in_subclass(self):
        from rpython.jit.metainterp.typesystem import deref
        class A(object):
            def __init__(self, x):
                self.x = x
        class B(A):
            _immutable_fields_ = ["y"]
            def __init__(self, x, y):
                A.__init__(self, x)
                self.y = y

        def f():
            return B(3, 5)
        t, typer, graph = self.gengraph(f, [])
        B_TYPE = deref(graph.getreturnvar().concretetype)
        accessor = B_TYPE._hints["immutable_fields"]
        assert accessor.fields == {"inst_y": IR_IMMUTABLE}
Beispiel #14
0
 def test_quasi_immutable_array(self):
     from rpython.jit.metainterp.typesystem import deref
     class A(object):
         _immutable_fields_ = ['c?[*]']
     class B(A):
         pass
     def f():
         a = A()
         a.c = [3, 4, 5]
         return A()
     t, typer, graph = self.gengraph(f, [])
     A_TYPE = deref(graph.getreturnvar().concretetype)
     accessor = A_TYPE._hints["immutable_fields"]
     assert accessor.fields == {"inst_c": IR_QUASIIMMUTABLE_ARRAY}
     found = []
     for op in graph.startblock.operations:
         if op.opname == 'jit_force_quasi_immutable':
             found.append(op.args[1].value)
     assert found == ['mutate_c']
Beispiel #15
0
    def test_immutable_ok_inheritance_2(self):
        from rpython.jit.metainterp.typesystem import deref

        class A(object):
            _immutable_fields_ = ['v']

        class B(A):
            _immutable_ = True

        def f():
            A().v = 123
            B().w = 456
            return B()

        t, typer, graph = self.gengraph(f, [])
        B_TYPE = deref(graph.getreturnvar().concretetype)
        assert B_TYPE._hints["immutable"]
        A_TYPE = B_TYPE.super
        accessor = A_TYPE._hints["immutable_fields"]
        assert accessor.fields == {"inst_v": IR_IMMUTABLE}
Beispiel #16
0
    def test_immutable_subclass_void(self):
        from rpython.jit.metainterp.typesystem import deref

        class A(object):
            pass

        class B(A):
            _immutable_ = True

        def myfunc():
            pass

        def f():
            A().f = myfunc  # it's ok to add Void attributes to A
            B().v = 123  # even though only B is declared _immutable_
            return B()

        t, typer, graph = self.gengraph(f, [])
        B_TYPE = deref(graph.getreturnvar().concretetype)
        assert B_TYPE._hints["immutable"]
Beispiel #17
0
    def test_immutable_fields(self):
        from rpython.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": IR_IMMUTABLE,
            "inst_y": IR_IMMUTABLE_ARRAY
        }
Beispiel #18
0
    def test_quasi_immutable_array(self):
        from rpython.jit.metainterp.typesystem import deref

        class A(object):
            _immutable_fields_ = ['c?[*]']

        class B(A):
            pass

        def f():
            a = A()
            a.c = [3, 4, 5]
            return A()

        t, typer, graph = self.gengraph(f, [])
        A_TYPE = deref(graph.getreturnvar().concretetype)
        accessor = A_TYPE._hints["immutable_fields"]
        assert accessor.fields == {"inst_c": IR_QUASIIMMUTABLE_ARRAY}
        found = []
        for op in graph.startblock.operations:
            if op.opname == 'jit_force_quasi_immutable':
                found.append(op.args[1].value)
        assert found == ['mutate_c']
Beispiel #19
0
    def __init__(self, warmrunnerdesc, VTYPEPTR):
        self.warmrunnerdesc = warmrunnerdesc
        cpu = warmrunnerdesc.cpu
        self.cpu = cpu
        #
        VTYPEPTR1 = VTYPEPTR
        while 'virtualizable_accessor' not in deref(VTYPEPTR)._hints:
            VTYPEPTR = cpu.ts.get_superclass(VTYPEPTR)
            assert VTYPEPTR is not None, (
                "%r is listed in the jit driver's 'virtualizables', "
                "but that class doesn't have a '_virtualizable_' attribute "
                "(if it has _virtualizable2_, rename it to _virtualizable_)" %
                (VTYPEPTR1, ))
        self.VTYPEPTR = VTYPEPTR
        self.VTYPE = VTYPE = deref(VTYPEPTR)
        self.vable_token_descr = cpu.fielddescrof(VTYPE, 'vable_token')
        #
        accessor = VTYPE._hints['virtualizable_accessor']
        all_fields = accessor.fields
        static_fields = []
        array_fields = []
        for name, tp in all_fields.iteritems():
            if tp == IR_IMMUTABLE_ARRAY:
                array_fields.append(name)
            elif tp == IR_IMMUTABLE:
                static_fields.append(name)
            else:
                raise Exception("unknown type: %s" % tp)
        self.static_fields = static_fields
        self.array_fields = array_fields
        #
        FIELDTYPES = [fieldType(VTYPE, name) for name in static_fields]
        ARRAYITEMTYPES = []
        for name in array_fields:
            ARRAYPTR = fieldType(VTYPE, name)
            ARRAY = deref(ARRAYPTR)
            assert isinstance(ARRAYPTR, lltype.Ptr)
            if not isinstance(ARRAY, lltype.GcArray):
                raise Exception(
                    "The virtualizable field '%s' is not an array (found %r)."
                    " It usually means that you must try harder to ensure that"
                    " the list is not resized at run-time. You can do that by"
                    " using rpython.rlib.debug.make_sure_not_resized()." %
                    (name, ARRAY))
            ARRAYITEMTYPES.append(arrayItem(ARRAY))
        self.array_descrs = [
            cpu.arraydescrof(deref(fieldType(VTYPE, name)))
            for name in array_fields
        ]
        #
        self.num_static_extra_boxes = len(static_fields)
        self.num_arrays = len(array_fields)
        self.static_field_to_extra_box = dict([
            (name, i) for (i, name) in enumerate(static_fields)
        ])
        self.array_field_counter = dict([
            (name, i) for (i, name) in enumerate(array_fields)
        ])
        self.static_extra_types = [
            history.getkind(TYPE) for TYPE in FIELDTYPES
        ]
        self.arrayitem_extra_types = [
            history.getkind(ITEM) for ITEM in ARRAYITEMTYPES
        ]
        self.static_field_descrs = [
            cpu.fielddescrof(VTYPE, name) for name in static_fields
        ]
        self.array_field_descrs = [
            cpu.fielddescrof(VTYPE, name) for name in array_fields
        ]

        for descr in self.static_field_descrs:
            descr.vinfo = self
        for descr in self.array_field_descrs:
            descr.vinfo = self

        self.static_field_by_descrs = dict([
            (descr, i) for (i, descr) in enumerate(self.static_field_descrs)
        ])
        self.array_field_by_descrs = dict([
            (descr, i) for (i, descr) in enumerate(self.array_field_descrs)
        ])
        #
        getlength = cpu.ts.getlength
        getarrayitem = cpu.ts.getarrayitem
        setarrayitem = cpu.ts.setarrayitem

        def read_boxes(cpu, virtualizable):
            assert lltype.typeOf(virtualizable) == llmemory.GCREF
            virtualizable = cast_gcref_to_vtype(virtualizable)
            boxes = []
            for _, fieldname in unroll_static_fields:
                x = getattr(virtualizable, fieldname)
                boxes.append(wrap(cpu, x))
            for _, fieldname in unroll_array_fields:
                lst = getattr(virtualizable, fieldname)
                for i in range(getlength(lst)):
                    boxes.append(wrap(cpu, getarrayitem(lst, i)))
            return boxes

        def write_boxes(virtualizable, boxes):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            i = 0
            for FIELDTYPE, fieldname in unroll_static_fields:
                x = unwrap(FIELDTYPE, boxes[i])
                setattr(virtualizable, fieldname, x)
                i = i + 1
            for ARRAYITEMTYPE, fieldname in unroll_array_fields:
                lst = getattr(virtualizable, fieldname)
                for j in range(getlength(lst)):
                    x = unwrap(ARRAYITEMTYPE, boxes[i])
                    setarrayitem(lst, j, x)
                    i = i + 1
            assert len(boxes) == i + 1

        def get_total_size(virtualizable):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            size = 0
            for _, fieldname in unroll_array_fields:
                lst = getattr(virtualizable, fieldname)
                size += getlength(lst)
            for _, fieldname in unroll_static_fields:
                size += 1
            return size

        def write_from_resume_data_partial(virtualizable, reader):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            # Load values from the reader (see resume.py) described by
            # the list of numbers 'nums', and write them in their proper
            # place in the 'virtualizable'.
            for FIELDTYPE, fieldname in unroll_static_fields:
                x = reader.load_next_value_of_type(FIELDTYPE)
                setattr(virtualizable, fieldname, x)
            for ARRAYITEMTYPE, fieldname in unroll_array_fields:
                lst = getattr(virtualizable, fieldname)
                for j in range(getlength(lst)):
                    x = reader.load_next_value_of_type(ARRAYITEMTYPE)
                    setarrayitem(lst, j, x)

        def load_list_of_boxes(virtualizable, reader, vable_box):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            # Uses 'virtualizable' only to know the length of the arrays;
            # does not write anything into it.  The returned list is in
            # the format expected of virtualizable_boxes, so it ends in
            # the virtualizable itself.
            boxes = []
            for FIELDTYPE, fieldname in unroll_static_fields:
                box = reader.next_box_of_type(FIELDTYPE)
                boxes.append(box)
            for ARRAYITEMTYPE, fieldname in unroll_array_fields:
                lst = getattr(virtualizable, fieldname)
                for j in range(getlength(lst)):
                    box = reader.next_box_of_type(ARRAYITEMTYPE)
                    boxes.append(box)
            boxes.append(vable_box)
            return boxes

        def check_boxes(virtualizable, boxes):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            # for debugging
            i = 0
            for FIELDTYPE, fieldname in unroll_static_fields:
                x = unwrap(FIELDTYPE, boxes[i])
                assert getattr(virtualizable, fieldname) == x
                i = i + 1
            for ARRAYITEMTYPE, fieldname in unroll_array_fields:
                lst = getattr(virtualizable, fieldname)
                for j in range(getlength(lst)):
                    x = unwrap(ARRAYITEMTYPE, boxes[i])
                    assert getarrayitem(lst, j) == x
                    i = i + 1
            assert len(boxes) == i + 1

        def get_index_in_array(virtualizable, arrayindex, index):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            index += self.num_static_extra_boxes
            j = 0
            for _, fieldname in unroll_array_fields:
                if arrayindex == j:
                    return index
                lst = getattr(virtualizable, fieldname)
                index += getlength(lst)
                j = j + 1
            assert False, "invalid arrayindex"

        def get_array_length(virtualizable, arrayindex):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            j = 0
            for _, fieldname in unroll_array_fields:
                if arrayindex == j:
                    lst = getattr(virtualizable, fieldname)
                    return getlength(lst)
                j += 1
            assert False, "invalid arrayindex"

        unroll_static_fields = unrolling_iterable(
            zip(FIELDTYPES, static_fields))
        unroll_array_fields = unrolling_iterable(
            zip(ARRAYITEMTYPES, array_fields))
        unroll_static_fields_rev = unrolling_iterable(
            reversed(list(unroll_static_fields)))
        unroll_array_fields_rev = unrolling_iterable(
            reversed(list(unroll_array_fields)))
        self.read_boxes = read_boxes
        self.write_boxes = write_boxes
        self.write_from_resume_data_partial = write_from_resume_data_partial
        self.load_list_of_boxes = load_list_of_boxes
        self.check_boxes = check_boxes
        self.get_index_in_array = get_index_in_array
        self.get_array_length = get_array_length
        self.get_total_size = get_total_size

        def cast_to_vtype(virtualizable):
            return self.cpu.ts.cast_to_instance_maybe(VTYPEPTR, virtualizable)

        self.cast_to_vtype = cast_to_vtype

        def cast_gcref_to_vtype(virtualizable):
            assert lltype.typeOf(virtualizable) == llmemory.GCREF
            return lltype.cast_opaque_ptr(VTYPEPTR, virtualizable)

        self.cast_gcref_to_vtype = cast_gcref_to_vtype

        def clear_vable_token(virtualizable):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            if virtualizable.vable_token:
                force_now(virtualizable)
                assert not virtualizable.vable_token

        self.clear_vable_token = clear_vable_token

        def tracing_before_residual_call(virtualizable):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            assert not virtualizable.vable_token
            virtualizable.vable_token = TOKEN_TRACING_RESCALL

        self.tracing_before_residual_call = tracing_before_residual_call

        def tracing_after_residual_call(virtualizable):
            """
            Returns whether or not the virtualizable was forced during a
            CALL_MAY_FORCE.
            """
            virtualizable = cast_gcref_to_vtype(virtualizable)
            if virtualizable.vable_token:
                # not modified by the residual call; assert that it is still
                # set to TOKEN_TRACING_RESCALL and clear it.
                assert virtualizable.vable_token == TOKEN_TRACING_RESCALL
                virtualizable.vable_token = TOKEN_NONE
                return False
            else:
                # marker "modified during residual call" set.
                return True

        self.tracing_after_residual_call = tracing_after_residual_call

        def force_now(virtualizable):
            token = virtualizable.vable_token
            if token == TOKEN_TRACING_RESCALL:
                # The values in the virtualizable are always correct during
                # tracing.  We only need to reset vable_token to TOKEN_NONE
                # as a marker for the tracing, to tell it that this
                # virtualizable escapes.
                virtualizable.vable_token = TOKEN_NONE
            else:
                from rpython.jit.metainterp.compile import ResumeGuardForcedDescr
                ResumeGuardForcedDescr.force_now(cpu, token)
                assert virtualizable.vable_token == TOKEN_NONE

        force_now._dont_inline_ = True
        self.force_now = force_now

        def is_token_nonnull_gcref(virtualizable):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            return bool(virtualizable.vable_token)

        self.is_token_nonnull_gcref = is_token_nonnull_gcref

        def reset_token_gcref(virtualizable):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            virtualizable.vable_token = TOKEN_NONE

        self.reset_token_gcref = reset_token_gcref

        def reset_vable_token(virtualizable):
            virtualizable.vable_token = TOKEN_NONE

        self.reset_vable_token = reset_vable_token
Beispiel #20
0
        write_descrs_interiorfields = []

        def add_struct(descrs_fields, (_, T, fieldname)):
            T = deref(T)
            if consider_struct(T, fieldname):
                descr = cpu.fielddescrof(T, fieldname)
                descrs_fields.append(descr)

        def add_array(descrs_arrays, (_, T)):
            ARRAY = deref(T)
            if consider_array(ARRAY):
                descr = cpu.arraydescrof(ARRAY)
                descrs_arrays.append(descr)

        def add_interiorfield(descrs_interiorfields, (_, T, fieldname)):
            T = deref(T)
            if not isinstance(T, lltype.Array):
                return  # let's not consider structs for now
            if not consider_array(T):
                return
            if getattr(T.OF, fieldname) is lltype.Void:
                return
            try:
                descr = cpu.interiorfielddescrof(T, fieldname)
            except UnsupportedFieldExc:
                return
            descrs_interiorfields.append(descr)

        # a read or a write to an interiorfield, inside an array of
        # structs, is additionally recorded as a read or write of
        # the array itself
Beispiel #21
0
        write_descrs_interiorfields = []

        def add_struct(descrs_fields, (_, T, fieldname)):
            T = deref(T)
            if consider_struct(T, fieldname):
                descr = cpu.fielddescrof(T, fieldname)
                descrs_fields.append(descr)

        def add_array(descrs_arrays, (_, T)):
            ARRAY = deref(T)
            if consider_array(ARRAY):
                descr = cpu.arraydescrof(ARRAY)
                descrs_arrays.append(descr)

        def add_interiorfield(descrs_interiorfields, (_, T, fieldname)):
            T = deref(T)
            if not isinstance(T, lltype.Array):
                return # let's not consider structs for now
            if not consider_array(T):
                return
            if getattr(T.OF, fieldname) is lltype.Void:
                return
            descr = cpu.interiorfielddescrof(T, fieldname)
            descrs_interiorfields.append(descr)

        # a read or a write to an interiorfield, inside an array of
        # structs, is additionally recorded as a read or write of
        # the array itself
        extraef = set()
        for tup in effects:
            if tup[0] == "interiorfield" or tup[0] == "readinteriorfield":
Beispiel #22
0
    def __init__(self, warmrunnerdesc, VTYPEPTR):
        self.warmrunnerdesc = warmrunnerdesc
        cpu = warmrunnerdesc.cpu
        self.cpu = cpu
        self.BoxArray = cpu.ts.BoxRef
        #
        while 'virtualizable2_accessor' not in deref(VTYPEPTR)._hints:
            VTYPEPTR = cpu.ts.get_superclass(VTYPEPTR)
        self.VTYPEPTR = VTYPEPTR
        self.VTYPE = VTYPE = deref(VTYPEPTR)
        self.vable_token_descr = cpu.fielddescrof(VTYPE, 'vable_token')
        #
        accessor = VTYPE._hints['virtualizable2_accessor']
        all_fields = accessor.fields
        static_fields = []
        array_fields = []
        for name, tp in all_fields.iteritems():
            if tp == IR_IMMUTABLE_ARRAY:
                array_fields.append(name)
            elif tp == IR_IMMUTABLE:
                static_fields.append(name)
            else:
                raise Exception("unknown type: %s" % tp)
        self.static_fields = static_fields
        self.array_fields = array_fields
        #
        FIELDTYPES = [fieldType(VTYPE, name) for name in static_fields]
        ARRAYITEMTYPES = []
        for name in array_fields:
            ARRAYPTR = fieldType(VTYPE, name)
            ARRAY = deref(ARRAYPTR)
            assert isinstance(ARRAYPTR, lltype.Ptr)
            assert isinstance(ARRAY, lltype.GcArray)
            ARRAYITEMTYPES.append(arrayItem(ARRAY))
        self.array_descrs = [cpu.arraydescrof(deref(fieldType(VTYPE, name)))
                             for name in array_fields]
        #
        self.num_static_extra_boxes = len(static_fields)
        self.num_arrays = len(array_fields)
        self.static_field_to_extra_box = dict(
            [(name, i) for (i, name) in enumerate(static_fields)])
        self.array_field_counter = dict(
            [(name, i) for (i, name) in enumerate(array_fields)])
        self.static_extra_types = [history.getkind(TYPE)
                                   for TYPE in FIELDTYPES]
        self.arrayitem_extra_types = [history.getkind(ITEM)
                                      for ITEM in ARRAYITEMTYPES]
        self.static_field_descrs = [cpu.fielddescrof(VTYPE, name)
                                    for name in static_fields]
        self.array_field_descrs = [cpu.fielddescrof(VTYPE, name)
                                   for name in array_fields]
        self.static_field_by_descrs = dict(
            [(descr, i) for (i, descr) in enumerate(self.static_field_descrs)])
        self.array_field_by_descrs = dict(
            [(descr, i) for (i, descr) in enumerate(self.array_field_descrs)])
        #
        getlength = cpu.ts.getlength
        getarrayitem = cpu.ts.getarrayitem
        setarrayitem = cpu.ts.setarrayitem

        def read_boxes(cpu, virtualizable):
            assert lltype.typeOf(virtualizable) == llmemory.GCREF
            virtualizable = cast_gcref_to_vtype(virtualizable)
            boxes = []
            for _, fieldname in unroll_static_fields:
                x = getattr(virtualizable, fieldname)
                boxes.append(wrap(cpu, x))
            for _, fieldname in unroll_array_fields:
                lst = getattr(virtualizable, fieldname)
                for i in range(getlength(lst)):
                    boxes.append(wrap(cpu, getarrayitem(lst, i)))
            return boxes

        def write_boxes(virtualizable, boxes):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            i = 0
            for FIELDTYPE, fieldname in unroll_static_fields:
                x = unwrap(FIELDTYPE, boxes[i])
                setattr(virtualizable, fieldname, x)
                i = i + 1
            for ARRAYITEMTYPE, fieldname in unroll_array_fields:
                lst = getattr(virtualizable, fieldname)
                for j in range(getlength(lst)):
                    x = unwrap(ARRAYITEMTYPE, boxes[i])
                    setarrayitem(lst, j, x)
                    i = i + 1
            assert len(boxes) == i + 1

        def write_from_resume_data_partial(virtualizable, reader, numb):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            # Load values from the reader (see resume.py) described by
            # the list of numbers 'nums', and write them in their proper
            # place in the 'virtualizable'.  This works from the end of
            # the list and returns the index in 'nums' of the start of
            # the virtualizable data found, allowing the caller to do
            # further processing with the start of the list.
            i = len(numb.nums) - 1
            assert i >= 0
            for ARRAYITEMTYPE, fieldname in unroll_array_fields_rev:
                lst = getattr(virtualizable, fieldname)
                for j in range(getlength(lst) - 1, -1, -1):
                    i -= 1
                    assert i >= 0
                    x = reader.load_value_of_type(ARRAYITEMTYPE, numb.nums[i])
                    setarrayitem(lst, j, x)
            for FIELDTYPE, fieldname in unroll_static_fields_rev:
                i -= 1
                assert i >= 0
                x = reader.load_value_of_type(FIELDTYPE, numb.nums[i])
                setattr(virtualizable, fieldname, x)
            return i

        def load_list_of_boxes(virtualizable, reader, numb):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            # Uses 'virtualizable' only to know the length of the arrays;
            # does not write anything into it.  The returned list is in
            # the format expected of virtualizable_boxes, so it ends in
            # the virtualizable itself.
            i = len(numb.nums) - 1
            assert i >= 0
            boxes = [reader.decode_box_of_type(self.VTYPEPTR, numb.nums[i])]
            for ARRAYITEMTYPE, fieldname in unroll_array_fields_rev:
                lst = getattr(virtualizable, fieldname)
                for j in range(getlength(lst) - 1, -1, -1):
                    i -= 1
                    assert i >= 0
                    box = reader.decode_box_of_type(ARRAYITEMTYPE, numb.nums[i])
                    boxes.append(box)
            for FIELDTYPE, fieldname in unroll_static_fields_rev:
                i -= 1
                assert i >= 0
                box = reader.decode_box_of_type(FIELDTYPE, numb.nums[i])
                boxes.append(box)
            boxes.reverse()
            return boxes

        def check_boxes(virtualizable, boxes):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            # for debugging
            i = 0
            for FIELDTYPE, fieldname in unroll_static_fields:
                x = unwrap(FIELDTYPE, boxes[i])
                assert getattr(virtualizable, fieldname) == x
                i = i + 1
            for ARRAYITEMTYPE, fieldname in unroll_array_fields:
                lst = getattr(virtualizable, fieldname)
                for j in range(getlength(lst)):
                    x = unwrap(ARRAYITEMTYPE, boxes[i])
                    assert getarrayitem(lst, j) == x
                    i = i + 1
            assert len(boxes) == i + 1

        def get_index_in_array(virtualizable, arrayindex, index):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            index += self.num_static_extra_boxes
            j = 0
            for _, fieldname in unroll_array_fields:
                if arrayindex == j:
                    return index
                lst = getattr(virtualizable, fieldname)
                index += getlength(lst)
                j = j + 1
            assert False, "invalid arrayindex"

        def get_array_length(virtualizable, arrayindex):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            j = 0
            for _, fieldname in unroll_array_fields:
                if arrayindex == j:
                    lst = getattr(virtualizable, fieldname)
                    return getlength(lst)
                j += 1
            assert False, "invalid arrayindex"

        unroll_static_fields = unrolling_iterable(zip(FIELDTYPES,
                                                      static_fields))
        unroll_array_fields = unrolling_iterable(zip(ARRAYITEMTYPES,
                                                     array_fields))
        unroll_static_fields_rev = unrolling_iterable(
                                          reversed(list(unroll_static_fields)))
        unroll_array_fields_rev = unrolling_iterable(
                                          reversed(list(unroll_array_fields)))
        self.read_boxes = read_boxes
        self.write_boxes = write_boxes
        self.write_from_resume_data_partial = write_from_resume_data_partial
        self.load_list_of_boxes = load_list_of_boxes
        self.check_boxes = check_boxes
        self.get_index_in_array = get_index_in_array
        self.get_array_length = get_array_length

        def cast_to_vtype(virtualizable):
            return self.cpu.ts.cast_to_instance_maybe(VTYPEPTR, virtualizable)
        self.cast_to_vtype = cast_to_vtype

        def cast_gcref_to_vtype(virtualizable):
            assert lltype.typeOf(virtualizable) == llmemory.GCREF
            return lltype.cast_opaque_ptr(VTYPEPTR, virtualizable)
        self.cast_gcref_to_vtype = cast_gcref_to_vtype

        def reset_vable_token(virtualizable):
            virtualizable.vable_token = TOKEN_NONE
        self.reset_vable_token = reset_vable_token

        def clear_vable_token(virtualizable):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            if virtualizable.vable_token:
                force_now(virtualizable)
                assert not virtualizable.vable_token
        self.clear_vable_token = clear_vable_token

        def tracing_before_residual_call(virtualizable):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            assert not virtualizable.vable_token
            virtualizable.vable_token = TOKEN_TRACING_RESCALL
        self.tracing_before_residual_call = tracing_before_residual_call

        def tracing_after_residual_call(virtualizable):
            """
            Returns whether or not the virtualizable was forced during a
            CALL_MAY_FORCE.
            """
            virtualizable = cast_gcref_to_vtype(virtualizable)
            if virtualizable.vable_token:
                # not modified by the residual call; assert that it is still
                # set to TOKEN_TRACING_RESCALL and clear it.
                assert virtualizable.vable_token == TOKEN_TRACING_RESCALL
                virtualizable.vable_token = TOKEN_NONE
                return False
            else:
                # marker "modified during residual call" set.
                return True
        self.tracing_after_residual_call = tracing_after_residual_call

        def force_now(virtualizable):
            token = virtualizable.vable_token
            if token == TOKEN_TRACING_RESCALL:
                # The values in the virtualizable are always correct during
                # tracing.  We only need to reset vable_token to TOKEN_NONE
                # as a marker for the tracing, to tell it that this
                # virtualizable escapes.
                virtualizable.vable_token = TOKEN_NONE
            else:
                from rpython.jit.metainterp.compile import ResumeGuardForcedDescr
                ResumeGuardForcedDescr.force_now(cpu, token)
                assert virtualizable.vable_token == TOKEN_NONE
        force_now._dont_inline_ = True
        self.force_now = force_now

        def is_token_nonnull_gcref(virtualizable):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            return bool(virtualizable.vable_token)
        self.is_token_nonnull_gcref = is_token_nonnull_gcref

        def reset_token_gcref(virtualizable):
            virtualizable = cast_gcref_to_vtype(virtualizable)
            virtualizable.vable_token = TOKEN_NONE
        self.reset_token_gcref = reset_token_gcref