File: rawbuffer.py

package info (click to toggle)
pypy3 7.3.19%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 212,236 kB
  • sloc: python: 2,098,316; ansic: 540,565; sh: 21,462; asm: 14,419; cpp: 4,451; makefile: 4,209; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 12; awk: 4
file content (134 lines) | stat: -rw-r--r-- 5,238 bytes parent folder | download | duplicates (8)
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
from rpython.rlib.debug import debug_start, debug_stop, debug_print
from rpython.rlib.objectmodel import compute_unique_id, we_are_translated

class InvalidRawOperation(Exception):
    pass

class InvalidRawWrite(InvalidRawOperation):
    pass

class InvalidRawRead(InvalidRawOperation):
    pass

class RawBuffer(object):
    def __init__(self, cpu, logops=None):
        # the following lists represents the writes in the buffer: values[i]
        # is the value of length lengths[i] stored at offset[i].
        #
        # the invariant is that they are ordered by offset, and that
        # offset[i]+length[i] <= offset[i+1], i.e. that the writes never
        # overlaps
        self.cpu = cpu
        self.logops = logops
        self.offsets = []
        self.lengths = []
        self.descrs = []
        self.values = []

    def _get_memory(self):
        """
        NOT_RPYTHON
        for testing only
        """
        return zip(self.offsets, self.lengths, self.descrs, self.values)

    def _repr_of_descr(self, descr):
        if self.logops:
            s = self.logops.repr_of_descr(descr)
        else:
            s = str(descr)
        s += " at %d" % compute_unique_id(descr)
        return s

    def _repr_of_value(self, value):
        if not we_are_translated() and isinstance(value, str):
            return value # for tests
        if self.logops:
            s = self.logops.repr_of_arg(value)
        else:
            s = str(value)
        s += " at %d" % compute_unique_id(value)
        return s

    def _dump_to_log(self):
        debug_print("RawBuffer state")
        debug_print("offset, length, descr, box")
        debug_print("(box == None means that the value is still virtual)")
        for i in range(len(self.offsets)):
            descr = self._repr_of_descr(self.descrs[i])
            box = self._repr_of_value(self.values[i])
            debug_print("%d, %d, %s, %s" % (self.offsets[i], self.lengths[i], descr, box))

    def _invalid_write(self, message, offset, length, descr, value):
        debug_start('jit-log-rawbuffer')
        debug_print('Invalid write: %s' % message)
        debug_print("  offset: %d" % offset)
        debug_print("  length: %d" % length)
        debug_print("  descr:  %s" % self._repr_of_descr(descr))
        debug_print("  value:  %s" % self._repr_of_value(value))
        self._dump_to_log()
        debug_stop('jit-log-rawbuffer')
        raise InvalidRawWrite

    def _invalid_read(self, message, offset, length, descr):
        debug_start('jit-log-rawbuffer')
        debug_print('Invalid read: %s' % message)
        debug_print("  offset: %d" % offset)
        debug_print("  length: %d" % length)
        debug_print("  descr:  %s" % self._repr_of_descr(descr))
        self._dump_to_log()
        debug_stop('jit-log-rawbuffer')
        raise InvalidRawRead

    def _descrs_are_compatible(self, d1, d2):
        # two arraydescrs are compatible if they have the same basesize,
        # itemsize and sign, even if they are not identical
        unpack = self.cpu.unpack_arraydescr_size
        return unpack(d1) == unpack(d2)

    def write_value(self, offset, length, descr, value):
        i = 0
        N = len(self.offsets)
        while i < N:
            if self.offsets[i] == offset:
                if (length != self.lengths[i] or not
                    self._descrs_are_compatible(descr, self.descrs[i])):
                    # in theory we could add support for the cases in which
                    # the length or descr is different, but I don't think we
                    # need it in practice
                    self._invalid_write('length or descr not compatible',
                                        offset, length, descr, value)
                # update the value at this offset
                self.values[i] = value
                return
            elif self.offsets[i] > offset:
                break
            i += 1
        #
        if i < len(self.offsets) and offset+length > self.offsets[i]:
            self._invalid_write("overlap with next bytes",
                                offset, length, descr, value)
        if i > 0 and self.offsets[i-1]+self.lengths[i-1] > offset:
            self._invalid_write("overlap with previous bytes",
                                offset, length, descr, value)
        # insert a new value at offset
        self.offsets.insert(i, offset)
        self.lengths.insert(i, length)
        self.descrs.insert(i, descr)
        self.values.insert(i, value)

    def read_value(self, offset, length, descr):
        i = 0
        N = len(self.offsets)
        while i < N:
            if self.offsets[i] == offset:
                if (length != self.lengths[i] or
                    not self._descrs_are_compatible(descr, self.descrs[i])):
                    self._invalid_read('length or descr not compatible',
                                       offset, length, descr)
                return self.values[i]
            i += 1
        # memory location not found: this means we are reading from
        # uninitialized memory, give up the optimization
        self._invalid_read('uninitialized memory',
                           offset, length, descr)