File: rawstorage.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 (159 lines) | stat: -rw-r--r-- 5,961 bytes parent folder | download
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
153
154
155
156
157
158
159
from rpython.rlib.objectmodel import we_are_translated
from rpython.rtyper.extregistry import ExtRegistryEntry
from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
from rpython.annotator import model as annmodel
from rpython.rtyper.llannotation import lltype_to_annotation
from rpython.rlib.rgc import lltype_is_gc
from rpython.rlib.objectmodel import specialize

RAW_STORAGE = rffi.CCHARP.TO
RAW_STORAGE_PTR = rffi.CCHARP

@specialize.arg(1, 2)
def alloc_raw_storage(size, track_allocation=True, zero=False):
    return lltype.malloc(RAW_STORAGE, size, flavor='raw',
                         add_memory_pressure=True,
                         track_allocation=track_allocation,
                         zero=zero)

def raw_storage_getitem(TP, storage, index):
    "NOT_RPYTHON"
    _check_alignment(TP, index)
    return _raw_storage_getitem_unchecked(TP, storage, index)

def _raw_storage_getitem_unchecked(TP, storage, index):
    "NOT_RPYTHON"
    return rffi.cast(rffi.CArrayPtr(TP), rffi.ptradd(storage, index))[0]

def raw_storage_setitem(storage, index, item):
    "NOT_RPYTHON"
    TP = lltype.typeOf(item)
    _check_alignment(TP, index)
    _raw_storage_setitem_unchecked(storage, index, item)

def _raw_storage_setitem_unchecked(storage, index, item):
    "NOT_RPYTHON"
    TP = lltype.typeOf(item)
    rffi.cast(rffi.CArrayPtr(TP), rffi.ptradd(storage, index))[0] = item

@specialize.arg(1)
def free_raw_storage(storage, track_allocation=True):
    lltype.free(storage, flavor='raw', track_allocation=track_allocation)

# ____________________________________________________________
#
# Support for possibly-unaligned accesses

from rpython.jit.backend import detect_cpu
try:
    cpuname = detect_cpu.autodetect()
    misaligned_is_fine = cpuname.startswith('x86') or \
                         cpuname.startswith('s390x') or \
                         cpuname.startswith('ppc')
    del cpuname
except detect_cpu.ProcessorAutodetectError:
    misaligned_is_fine = False


class AlignmentError(NotImplementedError):
    "Means that raw_storage_{get,set}item was used on unaligned memory"

# Tweak?  It seems a reasonable value for any system out there: requiring
# an aligned access to be up to 8-bytes-aligned, even for 64-bit data
# types on 32-bit systems.
MAXIMUM_ALIGNMENT = 8

@specialize.memo()
def _get_alignment_mask(TP):
    size = rffi.sizeof(TP)
    alignment = 1
    while (size & alignment) == 0 and alignment < MAXIMUM_ALIGNMENT:
        alignment *= 2
    return alignment - 1

def _check_alignment(TP, index):
    """Check that the 'index' does indeed have the maximum alignment
    for the given type."""
    mask = _get_alignment_mask(TP)
    if (index & mask) != 0:
        raise AlignmentError

@specialize.ll()
def raw_storage_getitem_unaligned(TP, storage, index):
    if misaligned_is_fine:
        if we_are_translated():
            return raw_storage_getitem(TP, storage, index)
        else:
            return _raw_storage_getitem_unchecked(TP, storage, index)
    mask = _get_alignment_mask(TP)
    if (index & mask) == 0:
        if we_are_translated():
            return raw_storage_getitem(TP, storage, index)
        else:
            return _raw_storage_getitem_unchecked(TP, storage, index)
    ptr = rffi.ptradd(storage, index)
    with lltype.scoped_alloc(rffi.CArray(TP), 1) as s_array:
        rffi.c_memcpy(rffi.cast(rffi.VOIDP, s_array),
                      rffi.cast(rffi.VOIDP, ptr),
                      rffi.sizeof(TP))
        return rffi.cast(rffi.CArrayPtr(TP), s_array)[0]

@specialize.ll()
def raw_storage_setitem_unaligned(storage, index, item):
    if misaligned_is_fine:
        if we_are_translated():
            raw_storage_setitem(storage, index, item)
        else:
            _raw_storage_setitem_unchecked(storage, index, item)
        return
    TP = lltype.typeOf(item)
    mask = _get_alignment_mask(TP)
    if (index & mask) == 0:
        if we_are_translated():
            raw_storage_setitem(storage, index, item)
        else:
            _raw_storage_setitem_unchecked(storage, index, item)
        return
    ptr = rffi.ptradd(storage, index)
    with lltype.scoped_alloc(rffi.CArray(TP), 1) as s_array:
        rffi.cast(rffi.CArrayPtr(TP), s_array)[0] = item
        rffi.c_memcpy(rffi.cast(rffi.VOIDP, ptr),
                      rffi.cast(rffi.VOIDP, s_array),
                      rffi.sizeof(TP))

# ____________________________________________________________


class RawStorageGetitemEntry(ExtRegistryEntry):
    _about_ = raw_storage_getitem

    def compute_result_annotation(self, s_TP, s_storage, s_index):
        assert s_TP.is_constant()
        return lltype_to_annotation(s_TP.const)

    def specialize_call(self, hop):
        assert hop.args_r[1].lowleveltype == RAW_STORAGE_PTR
        v_storage = hop.inputarg(hop.args_r[1], arg=1)
        v_index   = hop.inputarg(lltype.Signed, arg=2)
        hop.exception_cannot_occur()
        v_addr = hop.genop('cast_ptr_to_adr', [v_storage],
                           resulttype=llmemory.Address)
        return hop.genop('raw_load', [v_addr, v_index],
                         resulttype=hop.r_result.lowleveltype)

class RawStorageSetitemEntry(ExtRegistryEntry):
    _about_ = raw_storage_setitem

    def compute_result_annotation(self, s_storage, s_index, s_item):
        assert annmodel.SomeInteger().contains(s_index)

    def specialize_call(self, hop):
        assert not lltype_is_gc(hop.args_r[2].lowleveltype)
        assert hop.args_r[0].lowleveltype == RAW_STORAGE_PTR
        v_storage, v_index, v_item = hop.inputargs(hop.args_r[0],
                                                   lltype.Signed,
                                                   hop.args_r[2])
        hop.exception_cannot_occur()
        v_addr = hop.genop('cast_ptr_to_adr', [v_storage],
                           resulttype=llmemory.Address)
        return hop.genop('raw_store', [v_addr, v_index, v_item])