forked from nawalgupta/PythonBuddy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrerased.py
More file actions
223 lines (173 loc) · 7.35 KB
/
Copy pathrerased.py
File metadata and controls
223 lines (173 loc) · 7.35 KB
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
""" Contains a mechanism for turning any class instance and any integer into a
pointer-like thing. Gives full control over pointer tagging, i.e. there won't
be tag checks everywhere in the C code.
Usage: erasestuff, unerasestuff = new_erasing_pair('stuff')
An erasestuff(x) object contains a reference to 'x'. Nothing can be done with
this object, except calling unerasestuff(), which returns 'x' again. The point
is that all erased objects can be mixed together, whether they are instances,
lists, strings, etc. As a special case, an erased object can also be an
integer fitting into 31/63 bits, with erase_int() and unerase_int().
Warning: some care is needed to make sure that you call the unerase function
corresponding to the original creator's erase function. Otherwise, segfault.
"""
import sys
from rpython.annotator import model as annmodel
from rpython.rtyper.extregistry import ExtRegistryEntry
from rpython.rtyper.llannotation import lltype_to_annotation
from rpython.rtyper.lltypesystem import lltype, llmemory
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rlib.rarithmetic import is_valid_int
from rpython.rlib.debug import ll_assert
def erase_int(x):
assert is_valid_int(x)
res = 2 * x + 1
if res > sys.maxint or res < -sys.maxint - 1:
raise OverflowError
return Erased(x, _identity_for_ints)
def unerase_int(y):
assert y._identity is _identity_for_ints
assert is_valid_int(y._x)
return y._x
class ErasingPairIdentity(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return 'ErasingPairIdentity(%r)' % self.name
def __deepcopy__(self, memo):
return self
def _getdict(self, bk):
try:
dict = bk._erasing_pairs_tunnel
except AttributeError:
dict = bk._erasing_pairs_tunnel = {}
return dict
def enter_tunnel(self, bookkeeper, s_obj):
dict = self._getdict(bookkeeper)
s_previousobj, reflowpositions = dict.setdefault(
self, (annmodel.s_ImpossibleValue, {}))
s_obj = annmodel.unionof(s_previousobj, s_obj)
if s_obj != s_previousobj:
dict[self] = (s_obj, reflowpositions)
for position in reflowpositions:
bookkeeper.annotator.reflowfromposition(position)
def leave_tunnel(self, bookkeeper):
dict = self._getdict(bookkeeper)
s_obj, reflowpositions = dict.setdefault(
self, (annmodel.s_ImpossibleValue, {}))
reflowpositions[bookkeeper.position_key] = True
return s_obj
def get_input_annotation(self, bookkeeper):
dict = self._getdict(bookkeeper)
s_obj, _ = dict[self]
return s_obj
_identity_for_ints = ErasingPairIdentity("int")
def new_erasing_pair(name):
identity = ErasingPairIdentity(name)
def erase(x):
return Erased(x, identity)
def unerase(y):
assert y._identity is identity
return y._x
class Entry(ExtRegistryEntry):
_about_ = erase
def compute_result_annotation(self, s_obj):
identity.enter_tunnel(self.bookkeeper, s_obj)
return _some_erased()
def specialize_call(self, hop):
bk = hop.rtyper.annotator.bookkeeper
s_obj = identity.get_input_annotation(bk)
hop.exception_cannot_occur()
return _rtype_erase(hop, s_obj)
class Entry(ExtRegistryEntry):
_about_ = unerase
def compute_result_annotation(self, s_obj):
assert _some_erased().contains(s_obj)
return identity.leave_tunnel(self.bookkeeper)
def specialize_call(self, hop):
hop.exception_cannot_occur()
if hop.r_result.lowleveltype is lltype.Void:
return hop.inputconst(lltype.Void, None)
[v] = hop.inputargs(hop.args_r[0])
return _rtype_unerase(hop, v)
return erase, unerase
def new_static_erasing_pair(name):
erase, unerase = new_erasing_pair(name)
return staticmethod(erase), staticmethod(unerase)
# ---------- implementation-specific ----------
class Erased(object):
def __init__(self, x, identity):
self._x = x
self._identity = identity
def __repr__(self):
return "Erased(%r, %r)" % (self._x, self._identity)
def _convert_const_ptr(self, r_self):
value = self
if value._identity is _identity_for_ints:
config = r_self.rtyper.annotator.translator.config
assert config.translation.taggedpointers, "need to enable tagged pointers to use erase_int"
return lltype.cast_int_to_ptr(r_self.lowleveltype, value._x * 2 + 1)
bk = r_self.rtyper.annotator.bookkeeper
s_obj = value._identity.get_input_annotation(bk)
r_obj = r_self.rtyper.getrepr(s_obj)
if r_obj.lowleveltype is lltype.Void:
return lltype.nullptr(r_self.lowleveltype.TO)
v = r_obj.convert_const(value._x)
return lltype.cast_opaque_ptr(r_self.lowleveltype, v)
class Entry(ExtRegistryEntry):
_about_ = erase_int
def compute_result_annotation(self, s_obj):
config = self.bookkeeper.annotator.translator.config
assert config.translation.taggedpointers, "need to enable tagged pointers to use erase_int"
assert annmodel.SomeInteger().contains(s_obj)
return _some_erased()
def specialize_call(self, hop):
return _rtype_erase_int(hop)
class Entry(ExtRegistryEntry):
_about_ = unerase_int
def compute_result_annotation(self, s_obj):
assert _some_erased().contains(s_obj)
return annmodel.SomeInteger()
def specialize_call(self, hop):
[v] = hop.inputargs(hop.args_r[0])
assert isinstance(hop.s_result, annmodel.SomeInteger)
return _rtype_unerase_int(hop, v)
def ll_unerase_int(gcref):
x = llop.cast_ptr_to_int(lltype.Signed, gcref)
ll_assert((x&1) != 0, "unerased_int(): not an integer")
return x >> 1
class Entry(ExtRegistryEntry):
_type_ = Erased
def compute_annotation(self):
identity = self.instance._identity
s_obj = self.bookkeeper.immutablevalue(self.instance._x)
identity.enter_tunnel(self.bookkeeper, s_obj)
return _some_erased()
# annotation and rtyping support
def _some_erased():
return lltype_to_annotation(llmemory.GCREF)
def _rtype_erase(hop, s_obj):
hop.exception_cannot_occur()
r_obj = hop.rtyper.getrepr(s_obj)
if r_obj.lowleveltype is lltype.Void:
return hop.inputconst(llmemory.GCREF,
lltype.nullptr(llmemory.GCREF.TO))
[v_obj] = hop.inputargs(r_obj)
return hop.genop('cast_opaque_ptr', [v_obj],
resulttype=llmemory.GCREF)
def _rtype_unerase(hop, s_obj):
[v] = hop.inputargs(hop.args_r[0])
return hop.genop('cast_opaque_ptr', [v], resulttype=hop.r_result)
def _rtype_unerase_int(hop, v):
hop.exception_cannot_occur()
return hop.gendirectcall(ll_unerase_int, v)
def _rtype_erase_int(hop):
[v_value] = hop.inputargs(lltype.Signed)
c_one = hop.inputconst(lltype.Signed, 1)
hop.exception_is_here()
v2 = hop.genop('int_add_ovf', [v_value, v_value],
resulttype = lltype.Signed)
v2p1 = hop.genop('int_add', [v2, c_one],
resulttype = lltype.Signed)
v_instance = hop.genop('cast_int_to_ptr', [v2p1],
resulttype=llmemory.GCREF)
return v_instance