File: quasiimmut.py

package info (click to toggle)
pypy 5.6.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 97,040 kB
  • ctags: 185,069
  • sloc: python: 1,147,862; ansic: 49,642; cpp: 5,245; asm: 5,169; makefile: 529; sh: 481; xml: 232; lisp: 45
file content (152 lines) | stat: -rw-r--r-- 5,720 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
from rpython.rtyper.lltypesystem import lltype, llmemory
from rpython.rtyper import rclass
from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
from rpython.jit.metainterp.history import AbstractDescr, ConstPtr, ConstInt,\
     ConstFloat
from rpython.rlib.objectmodel import we_are_translated


def get_mutate_field_name(fieldname):
    if fieldname.startswith('inst_'):    # lltype
        return 'mutate_' + fieldname[5:]
    else:
        raise AssertionError(fieldname)

def get_current_qmut_instance(cpu, gcref, mutatefielddescr):
    """Returns the current QuasiImmut instance in the field,
    possibly creating one.
    """
    qmut_gcref = cpu.bh_getfield_gc_r(gcref, mutatefielddescr)
    if qmut_gcref:
        qmut = QuasiImmut.show(cpu, qmut_gcref)
    else:
        qmut = QuasiImmut(cpu)
        cpu.bh_setfield_gc_r(gcref, qmut.hide(), mutatefielddescr)
    return qmut

def make_invalidation_function(STRUCT, mutatefieldname):
    #
    def _invalidate_now(p):
        qmut_ptr = getattr(p, mutatefieldname)
        setattr(p, mutatefieldname, lltype.nullptr(rclass.OBJECT))
        qmut = cast_base_ptr_to_instance(QuasiImmut, qmut_ptr)
        qmut.invalidate()
    _invalidate_now._dont_inline_ = True
    #
    def invalidation(p):
        if getattr(p, mutatefieldname):
            _invalidate_now(p)
    #
    return invalidation

def do_force_quasi_immutable(cpu, p, mutatefielddescr):
    qmut_ref = cpu.bh_getfield_gc_r(p, mutatefielddescr)
    if qmut_ref:
        cpu.bh_setfield_gc_r(p, cpu.ts.NULLREF, mutatefielddescr)
        qmut_ptr = lltype.cast_opaque_ptr(rclass.OBJECTPTR, qmut_ref)
        qmut = cast_base_ptr_to_instance(QuasiImmut, qmut_ptr)
        qmut.invalidate()


class QuasiImmut(object):
    llopaque = True
    compress_limit = 30
    looptokens_wrefs = None

    def __init__(self, cpu):
        self.cpu = cpu
        # list of weakrefs to the LoopTokens that must be invalidated if
        # this value ever changes
        self.looptokens_wrefs = []

    def hide(self):
        qmut_ptr = self.cpu.ts.cast_instance_to_base_ref(self)
        return self.cpu.ts.cast_to_ref(qmut_ptr)

    @staticmethod
    def show(cpu, qmut_gcref):
        qmut_ptr = cpu.ts.cast_to_baseclass(qmut_gcref)
        return cast_base_ptr_to_instance(QuasiImmut, qmut_ptr)

    def register_loop_token(self, wref_looptoken):
        if len(self.looptokens_wrefs) > self.compress_limit:
            self.compress_looptokens_list()
        self.looptokens_wrefs.append(wref_looptoken)

    def compress_looptokens_list(self):
        self.looptokens_wrefs = [wref for wref in self.looptokens_wrefs
                                      if wref() is not None]
        # NB. we must keep around the looptokens_wrefs that are
        # already invalidated; see below
        self.compress_limit = (len(self.looptokens_wrefs) + 15) * 2

    def invalidate(self):
        # When this is called, all the loops that we record become
        # invalid: all GUARD_NOT_INVALIDATED in these loops (and
        # in attached bridges) must now fail.
        if self.looptokens_wrefs is None:
            # can't happen, but helps compiled tests
            return
        wrefs = self.looptokens_wrefs
        self.looptokens_wrefs = []
        for wref in wrefs:
            looptoken = wref()
            if looptoken is not None:
                looptoken.invalidated = True
                self.cpu.invalidate_loop(looptoken)
                # NB. we must call cpu.invalidate_loop() even if
                # looptoken.invalidated was already set to True.
                # It's possible to invalidate several times the
                # same looptoken; see comments in jit.backend.model
                # in invalidate_loop().
                if not we_are_translated():
                    self.cpu.stats.invalidated_token_numbers.add(
                        looptoken.number)


class QuasiImmutDescr(AbstractDescr):
    # those fields are necessary for translation without quasi immutable
    # fields
    struct = lltype.nullptr(llmemory.GCREF.TO)
    fielddescr = None
    
    def __init__(self, cpu, struct, fielddescr, mutatefielddescr):
        self.cpu = cpu
        self.struct = struct
        self.fielddescr = fielddescr
        self.mutatefielddescr = mutatefielddescr
        self.qmut = get_current_qmut_instance(cpu, struct, mutatefielddescr)
        self.constantfieldbox = self.get_current_constant_fieldvalue()

    def get_parent_descr(self):
        if self.fielddescr is not None:
            return self.fielddescr.get_parent_descr()

    def get_index(self):
        if self.fielddescr is not None:
            return self.fielddescr.get_index()
        return 0 # annotation hint

    def get_current_constant_fieldvalue(self):
        struct = self.struct
        fielddescr = self.fielddescr
        if self.fielddescr.is_pointer_field():
            return ConstPtr(self.cpu.bh_getfield_gc_r(struct, fielddescr))
        elif self.fielddescr.is_float_field():
            return ConstFloat(self.cpu.bh_getfield_gc_f(struct, fielddescr))
        else:
            return ConstInt(self.cpu.bh_getfield_gc_i(struct, fielddescr))

    def is_still_valid_for(self, structconst):
        assert self.struct
        if self.struct != structconst.getref_base():
            return False
        cpu = self.cpu
        qmut = get_current_qmut_instance(cpu, self.struct,
                                         self.mutatefielddescr)
        if qmut is not self.qmut:
            return False
        else:
            currentbox = self.get_current_constant_fieldvalue()
            assert self.constantfieldbox.same_constant(currentbox)
            return True