40
40
*/
41
41
package com .oracle .graal .python .builtins .objects .thread ;
42
42
43
+ import static com .oracle .graal .python .nodes .SpecialAttributeNames .__DICT__ ;
44
+ import static com .oracle .graal .python .nodes .SpecialMethodNames .__DELATTR__ ;
45
+ import static com .oracle .graal .python .nodes .SpecialMethodNames .__GETATTRIBUTE__ ;
46
+ import static com .oracle .graal .python .nodes .SpecialMethodNames .__INIT__ ;
47
+ import static com .oracle .graal .python .nodes .SpecialMethodNames .__SETATTR__ ;
48
+ import static com .oracle .graal .python .runtime .exception .PythonErrorType .AttributeError ;
49
+
43
50
import java .util .List ;
44
51
45
52
import com .oracle .graal .python .builtins .Builtin ;
46
53
import com .oracle .graal .python .builtins .CoreFunctions ;
47
54
import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
48
55
import com .oracle .graal .python .builtins .PythonBuiltins ;
49
56
import com .oracle .graal .python .builtins .objects .PNone ;
57
+ import com .oracle .graal .python .builtins .objects .common .HashingStorage ;
58
+ import com .oracle .graal .python .builtins .objects .common .HashingStorageLibrary ;
50
59
import com .oracle .graal .python .builtins .objects .dict .PDict ;
51
- import com .oracle .graal .python .builtins .objects .object .PythonObjectLibrary ;
52
- import com .oracle .graal .python .nodes .SpecialAttributeNames ;
53
- import com .oracle .graal .python .nodes .SpecialMethodNames ;
60
+ import com .oracle .graal .python .builtins .objects .object .ObjectBuiltins ;
61
+ import com .oracle .graal .python .builtins .objects .object .ObjectBuiltinsFactory ;
62
+ import com .oracle .graal .python .builtins .objects .type .SpecialMethodSlot ;
63
+ import com .oracle .graal .python .nodes .ErrorMessages ;
64
+ import com .oracle .graal .python .nodes .PGuards ;
65
+ import com .oracle .graal .python .nodes .attributes .LookupAttributeInMRONode ;
66
+ import com .oracle .graal .python .nodes .attributes .LookupCallableSlotInMRONode ;
67
+ import com .oracle .graal .python .nodes .call .special .CallBinaryMethodNode ;
68
+ import com .oracle .graal .python .nodes .call .special .CallTernaryMethodNode ;
54
69
import com .oracle .graal .python .nodes .function .PythonBuiltinBaseNode ;
70
+ import com .oracle .graal .python .nodes .function .builtins .PythonBinaryBuiltinNode ;
71
+ import com .oracle .graal .python .nodes .function .builtins .PythonTernaryBuiltinNode ;
55
72
import com .oracle .graal .python .nodes .function .builtins .PythonUnaryBuiltinNode ;
73
+ import com .oracle .graal .python .nodes .object .GetClassNode ;
74
+ import com .oracle .graal .python .nodes .util .CannotCastException ;
75
+ import com .oracle .graal .python .nodes .util .CastToJavaStringNode ;
76
+ import com .oracle .truffle .api .CompilerDirectives ;
77
+ import com .oracle .truffle .api .CompilerDirectives .CompilationFinal ;
78
+ import com .oracle .truffle .api .dsl .Cached ;
56
79
import com .oracle .truffle .api .dsl .GenerateNodeFactory ;
80
+ import com .oracle .truffle .api .dsl .ImportStatic ;
57
81
import com .oracle .truffle .api .dsl .NodeFactory ;
58
82
import com .oracle .truffle .api .dsl .Specialization ;
83
+ import com .oracle .truffle .api .frame .VirtualFrame ;
59
84
import com .oracle .truffle .api .library .CachedLibrary ;
60
85
61
86
@ CoreFunctions (extendClasses = PythonBuiltinClassType .PThreadLocal )
@@ -65,7 +90,7 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
65
90
return ThreadLocalBuiltinsFactory .getFactories ();
66
91
}
67
92
68
- @ Builtin (name = SpecialMethodNames . __INIT__ , minNumOfPositionalArgs = 1 , maxNumOfPositionalArgs = 1 )
93
+ @ Builtin (name = __INIT__ , minNumOfPositionalArgs = 1 , maxNumOfPositionalArgs = 1 )
69
94
@ GenerateNodeFactory
70
95
abstract static class InitNode extends PythonUnaryBuiltinNode {
71
96
@ Specialization
@@ -74,13 +99,257 @@ PNone repr(@SuppressWarnings("unused") PThreadLocal self) {
74
99
}
75
100
}
76
101
77
- @ Builtin (name = SpecialAttributeNames . __DICT__ , minNumOfPositionalArgs = 1 , isGetter = true )
102
+ @ Builtin (name = __DICT__ , minNumOfPositionalArgs = 1 , isGetter = true )
78
103
@ GenerateNodeFactory
79
104
abstract static class DictNode extends PythonUnaryBuiltinNode {
80
- @ Specialization (limit = "1" )
81
- PDict repr (PThreadLocal self ,
82
- @ CachedLibrary ("self" ) PythonObjectLibrary lib ) {
83
- return lib .getDict (self );
105
+ @ Specialization
106
+ PDict repr (VirtualFrame frame , PThreadLocal self ,
107
+ @ Cached ThreadLocalNodes .GetThreadLocalDict getThreadLocalDict ) {
108
+ return getThreadLocalDict .execute (frame , self );
109
+ }
110
+ }
111
+
112
+ @ ImportStatic (PGuards .class )
113
+ @ Builtin (name = __GETATTRIBUTE__ , minNumOfPositionalArgs = 2 )
114
+ @ GenerateNodeFactory
115
+ public abstract static class GetAttributeNode extends PythonBinaryBuiltinNode {
116
+ @ Child private LookupCallableSlotInMRONode lookupGetNode ;
117
+ @ Child private LookupCallableSlotInMRONode lookupSetNode ;
118
+ @ Child private LookupCallableSlotInMRONode lookupDeleteNode ;
119
+ @ Child private CallTernaryMethodNode dispatchGet ;
120
+ @ Child private HashingStorageLibrary hlib ;
121
+ @ Child private GetClassNode getDescClassNode ;
122
+
123
+ @ Specialization
124
+ protected Object doIt (VirtualFrame frame , PThreadLocal object , Object keyObj ,
125
+ @ Cached ThreadLocalNodes .GetThreadLocalDict getThreadLocalDict ,
126
+ @ Cached LookupAttributeInMRONode .Dynamic lookup ,
127
+ @ Cached GetClassNode getClassNode ,
128
+ @ Cached CastToJavaStringNode castKeyToStringNode ) {
129
+ PDict localDict = getThreadLocalDict .execute (frame , object );
130
+ String key ;
131
+ try {
132
+ key = castKeyToStringNode .execute (keyObj );
133
+ } catch (CannotCastException e ) {
134
+ throw raise (PythonBuiltinClassType .TypeError , ErrorMessages .ATTR_NAME_MUST_BE_STRING , keyObj );
135
+ }
136
+
137
+ Object type = getClassNode .execute (object );
138
+ Object descr = lookup .execute (type , key );
139
+ Object dataDescClass = null ;
140
+ boolean hasDescr = descr != PNone .NO_VALUE ;
141
+ if (hasDescr ) {
142
+ dataDescClass = getDescClass (descr );
143
+ Object delete = PNone .NO_VALUE ;
144
+ Object set = lookupSet (dataDescClass );
145
+ if (set == PNone .NO_VALUE ) {
146
+ delete = lookupDelete (dataDescClass );
147
+ }
148
+ if (set != PNone .NO_VALUE || delete != PNone .NO_VALUE ) {
149
+ Object get = lookupGet (dataDescClass );
150
+ if (PGuards .isCallableOrDescriptor (get )) {
151
+ // Only override if __get__ is defined, too, for compatibility with CPython.
152
+ return dispatch (frame , object , type , descr , get );
153
+ }
154
+ }
155
+ }
156
+ Object value = readAttribute (localDict , key );
157
+ if (value != null ) {
158
+ return value ;
159
+ }
160
+ if (hasDescr ) {
161
+ Object get = lookupGet (dataDescClass );
162
+ if (get == PNone .NO_VALUE ) {
163
+ return descr ;
164
+ } else if (PGuards .isCallableOrDescriptor (get )) {
165
+ return dispatch (frame , object , type , descr , get );
166
+ }
167
+ }
168
+ throw raise (AttributeError , ErrorMessages .OBJ_P_HAS_NO_ATTR_S , object , key );
169
+ }
170
+
171
+ private Object readAttribute (PDict object , Object key ) {
172
+ if (hlib == null ) {
173
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
174
+ hlib = insert (HashingStorageLibrary .getFactory ().createDispatched (3 ));
175
+ }
176
+ return hlib .getItem (object .getDictStorage (), key );
177
+ }
178
+
179
+ private Object dispatch (VirtualFrame frame , Object object , Object type , Object descr , Object get ) {
180
+ if (dispatchGet == null ) {
181
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
182
+ dispatchGet = insert (CallTernaryMethodNode .create ());
183
+ }
184
+ return dispatchGet .execute (frame , get , descr , object , type );
185
+ }
186
+
187
+ private Object getDescClass (Object desc ) {
188
+ if (getDescClassNode == null ) {
189
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
190
+ getDescClassNode = insert (GetClassNode .create ());
191
+ }
192
+ return getDescClassNode .execute (desc );
193
+ }
194
+
195
+ private Object lookupGet (Object dataDescClass ) {
196
+ if (lookupGetNode == null ) {
197
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
198
+ lookupGetNode = insert (LookupCallableSlotInMRONode .create (SpecialMethodSlot .Get ));
199
+ }
200
+ return lookupGetNode .execute (dataDescClass );
201
+ }
202
+
203
+ private Object lookupDelete (Object dataDescClass ) {
204
+ if (lookupDeleteNode == null ) {
205
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
206
+ lookupDeleteNode = insert (LookupCallableSlotInMRONode .create (SpecialMethodSlot .Delete ));
207
+ }
208
+ return lookupDeleteNode .execute (dataDescClass );
209
+ }
210
+
211
+ private Object lookupSet (Object dataDescClass ) {
212
+ if (lookupSetNode == null ) {
213
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
214
+ lookupSetNode = insert (LookupCallableSlotInMRONode .create (SpecialMethodSlot .Set ));
215
+ }
216
+ return lookupSetNode .execute (dataDescClass );
217
+ }
218
+
219
+ public static ObjectBuiltins .GetAttributeNode create () {
220
+ return ObjectBuiltinsFactory .GetAttributeNodeFactory .create ();
221
+ }
222
+ }
223
+
224
+ @ ImportStatic (PGuards .class )
225
+ @ Builtin (name = __SETATTR__ , minNumOfPositionalArgs = 3 )
226
+ @ GenerateNodeFactory
227
+ public abstract static class SetattrNode extends PythonTernaryBuiltinNode {
228
+ @ Child private GetClassNode getDescClassNode ;
229
+ @ Child private LookupCallableSlotInMRONode lookupSetNode ;
230
+ @ Child private CallTernaryMethodNode callSetNode ;
231
+ @ Child private HashingStorageLibrary hlib ;
232
+ @ CompilationFinal private boolean changedStorage ;
233
+
234
+ public abstract PNone execute (VirtualFrame frame , Object object , String key , Object value );
235
+
236
+ @ Specialization
237
+ protected PNone doStringKey (VirtualFrame frame , PThreadLocal object , String keyObject , Object value ,
238
+ @ Cached CastToJavaStringNode castKeyToStringNode ,
239
+ @ Cached ThreadLocalNodes .GetThreadLocalDict getThreadLocalDict ,
240
+ @ Cached GetClassNode getClassNode ,
241
+ @ Cached LookupAttributeInMRONode .Dynamic getExisting ) {
242
+ String key ;
243
+ try {
244
+ key = castKeyToStringNode .execute (keyObject );
245
+ } catch (CannotCastException e ) {
246
+ throw raise (PythonBuiltinClassType .TypeError , ErrorMessages .ATTR_NAME_MUST_BE_STRING , keyObject );
247
+ }
248
+ PDict localDict = getThreadLocalDict .execute (frame , object );
249
+ Object type = getClassNode .execute (object );
250
+ Object descr = getExisting .execute (type , key );
251
+ if (descr != PNone .NO_VALUE ) {
252
+ Object dataDescClass = getDescClass (descr );
253
+ Object set = ensureLookupSetNode ().execute (dataDescClass );
254
+ if (PGuards .isCallableOrDescriptor (set )) {
255
+ ensureCallSetNode ().execute (frame , set , descr , object , value );
256
+ return PNone .NONE ;
257
+ }
258
+ }
259
+ writeAttribute (localDict , key , value );
260
+ return PNone .NONE ;
261
+ }
262
+
263
+ private Object getDescClass (Object desc ) {
264
+ if (getDescClassNode == null ) {
265
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
266
+ getDescClassNode = insert (GetClassNode .create ());
267
+ }
268
+ return getDescClassNode .execute (desc );
269
+ }
270
+
271
+ private LookupCallableSlotInMRONode ensureLookupSetNode () {
272
+ if (lookupSetNode == null ) {
273
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
274
+ lookupSetNode = insert (LookupCallableSlotInMRONode .create (SpecialMethodSlot .Set ));
275
+ }
276
+ return lookupSetNode ;
277
+ }
278
+
279
+ private CallTernaryMethodNode ensureCallSetNode () {
280
+ if (callSetNode == null ) {
281
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
282
+ callSetNode = insert (CallTernaryMethodNode .create ());
283
+ }
284
+ return callSetNode ;
285
+ }
286
+
287
+ private void writeAttribute (PDict dict , Object key , Object value ) {
288
+ if (hlib == null ) {
289
+ hlib = insert (HashingStorageLibrary .getFactory ().createDispatched (3 ));
290
+ }
291
+ HashingStorage storage = dict .getDictStorage ();
292
+ HashingStorage newStorage = hlib .setItem (storage , key , value );
293
+ if (storage != newStorage ) {
294
+ if (!changedStorage ) {
295
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
296
+ changedStorage = true ;
297
+ }
298
+ dict .setDictStorage (newStorage );
299
+ }
300
+ }
301
+ }
302
+
303
+ @ Builtin (name = __DELATTR__ , minNumOfPositionalArgs = 2 )
304
+ @ GenerateNodeFactory
305
+ public abstract static class DelattrNode extends PythonBinaryBuiltinNode {
306
+ @ Child private GetClassNode getDescClassNode ;
307
+
308
+ @ Specialization
309
+ protected PNone doIt (VirtualFrame frame , PThreadLocal object , Object keyObj ,
310
+ @ Cached ThreadLocalNodes .GetThreadLocalDict getThreadLocalDict ,
311
+ @ Cached LookupAttributeInMRONode .Dynamic getExisting ,
312
+ @ Cached GetClassNode getClassNode ,
313
+ @ Cached ("create(__DELETE__)" ) LookupAttributeInMRONode lookupDeleteNode ,
314
+ @ Cached CallBinaryMethodNode callDelete ,
315
+ @ CachedLibrary (limit = "3" ) HashingStorageLibrary hlib ,
316
+ @ Cached CastToJavaStringNode castKeyToStringNode ) {
317
+ String key ;
318
+ try {
319
+ key = castKeyToStringNode .execute (keyObj );
320
+ } catch (CannotCastException e ) {
321
+ throw raise (PythonBuiltinClassType .TypeError , ErrorMessages .ATTR_NAME_MUST_BE_STRING , keyObj );
322
+ }
323
+ PDict localDict = getThreadLocalDict .execute (frame , object );
324
+ Object type = getClassNode .execute (object );
325
+ Object descr = getExisting .execute (type , key );
326
+ if (descr != PNone .NO_VALUE ) {
327
+ Object dataDescClass = getDescClass (descr );
328
+ Object delete = lookupDeleteNode .execute (dataDescClass );
329
+ if (PGuards .isCallable (delete )) {
330
+ callDelete .executeObject (frame , delete , descr , object );
331
+ return PNone .NONE ;
332
+ }
333
+ }
334
+ Object currentValue = hlib .getItem (localDict .getDictStorage (), key );
335
+ if (currentValue != null ) {
336
+ HashingStorage storage = hlib .delItem (localDict .getDictStorage (), key );
337
+ localDict .setDictStorage (storage );
338
+ return PNone .NONE ;
339
+ }
340
+ if (descr != PNone .NO_VALUE ) {
341
+ throw raise (AttributeError , ErrorMessages .ATTR_S_READONLY , key );
342
+ } else {
343
+ throw raise (AttributeError , ErrorMessages .OBJ_P_HAS_NO_ATTR_S , object , key );
344
+ }
345
+ }
346
+
347
+ private Object getDescClass (Object desc ) {
348
+ if (getDescClassNode == null ) {
349
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
350
+ getDescClassNode = insert (GetClassNode .create ());
351
+ }
352
+ return getDescClassNode .execute (desc );
84
353
}
85
354
}
86
355
}
0 commit comments