68
68
import com .oracle .graal .python .nodes .attributes .LookupCallableSlotInMRONode ;
69
69
import com .oracle .graal .python .nodes .builtins .ListNodes .FastConstructListNode ;
70
70
import com .oracle .graal .python .nodes .call .special .CallVarargsMethodNode ;
71
- import com .oracle .graal .python .nodes .call .special .LookupAndCallUnaryNode ;
72
71
import com .oracle .graal .python .nodes .object .BuiltinClassProfiles .IsBuiltinObjectProfile ;
73
72
import com .oracle .graal .python .nodes .object .GetClassNode ;
74
73
import com .oracle .graal .python .runtime .ExecutionContext .IndirectCallContext ;
81
80
import com .oracle .truffle .api .dsl .Bind ;
82
81
import com .oracle .truffle .api .dsl .Cached ;
83
82
import com .oracle .truffle .api .dsl .Cached .Exclusive ;
83
+ import com .oracle .truffle .api .dsl .Cached .Shared ;
84
+ import com .oracle .truffle .api .dsl .GenerateCached ;
85
+ import com .oracle .truffle .api .dsl .GenerateInline ;
84
86
import com .oracle .truffle .api .dsl .NeverDefault ;
85
87
import com .oracle .truffle .api .dsl .Specialization ;
86
88
import com .oracle .truffle .api .frame .VirtualFrame ;
@@ -157,16 +159,12 @@ static HashingStorage doNoBuiltinKeysAttr(VirtualFrame frame, PHashingCollection
157
159
@ Bind ("this" ) Node inliningTarget ,
158
160
@ SuppressWarnings ("unused" ) @ Exclusive @ Cached GetClassNode getClassNode ,
159
161
@ SuppressWarnings ("unused" ) @ Exclusive @ Cached (parameters = "Iter" ) LookupCallableSlotInMRONode lookupIter ,
160
- @ Exclusive @ Cached PyObjectGetIter getIter ,
161
- @ Exclusive @ Cached HashingStorageSetItem setHashingStorageItem ,
162
- @ Exclusive @ Cached HashingStorageAddAllToOther addAllToOther ,
163
- @ Exclusive @ Cached ("create(T_KEYS)" ) LookupAndCallUnaryNode callKeysNode ,
164
- @ Exclusive @ Cached PyObjectGetItem getItemNode ,
165
- @ Exclusive @ Cached GetNextNode nextNode ,
166
- @ Exclusive @ Cached IsBuiltinObjectProfile errorProfile ) {
167
- HashingStorage curStorage = PDict .createNewStorage (0 );
168
- Object keysIterable = callKeysNode .executeObject (frame , col );
169
- return copyToStorage (frame , col , kwargs , curStorage , inliningTarget , keysIterable , getItemNode , getIter , nextNode , errorProfile , setHashingStorageItem , addAllToOther );
162
+ @ Exclusive @ Cached PyObjectLookupAttr lookupKeysAttributeNode ,
163
+ @ Exclusive @ Cached ObjectToArrayPairNode toArrayPair ,
164
+ @ Exclusive @ Cached HashingStorageSetItem setHasihngStorageItem ,
165
+ @ Exclusive @ Cached HashingStorageAddAllToOther addAllToOther ) {
166
+ return updateArg (frame , col , kwargs , inliningTarget , lookupKeysAttributeNode ,
167
+ toArrayPair , setHasihngStorageItem , addAllToOther );
170
168
}
171
169
172
170
protected static boolean hasIterAttrButNotBuiltin (Node inliningTarget , PHashingCollection col , GetClassNode getClassNode , LookupCallableSlotInMRONode lookupIter ) {
@@ -177,34 +175,16 @@ protected static boolean hasIterAttrButNotBuiltin(Node inliningTarget, PHashingC
177
175
@ Specialization (guards = {"!isNoValue(arg)" , "!isPDict(arg)" })
178
176
static HashingStorage updateArg (VirtualFrame frame , Object arg , PKeyword [] kwargs ,
179
177
@ Bind ("this" ) Node inliningTarget ,
180
- @ Cached PyObjectLookupAttr lookupKeysAttributeNode ,
181
- @ Cached CallVarargsMethodNode callKeysMethod ,
178
+ @ Exclusive @ Cached PyObjectLookupAttr lookupKeysAttributeNode ,
179
+ @ Exclusive @ Cached ObjectToArrayPairNode toArrayPair ,
182
180
@ Exclusive @ Cached HashingStorageSetItem setHasihngStorageItem ,
183
- @ Exclusive @ Cached HashingStorageAddAllToOther addAllToOther ,
184
- @ Exclusive @ Cached PyObjectGetIter getIter ,
185
- @ Cached PRaiseNode .Lazy raise ,
186
- @ Exclusive @ Cached GetNextNode nextNode ,
187
- @ Cached FastConstructListNode createListNode ,
188
- @ Exclusive @ Cached PyObjectGetItem getItemNode ,
189
- @ Cached SequenceNodes .LenNode seqLenNode ,
190
- @ Cached InlinedConditionProfile lengthTwoProfile ,
191
- @ Cached InlinedConditionProfile hasKeyProfile ,
192
- @ Exclusive @ Cached IsBuiltinObjectProfile errorProfile ,
193
- @ Exclusive @ Cached IsBuiltinObjectProfile isTypeErrorProfile ) {
181
+ @ Exclusive @ Cached HashingStorageAddAllToOther addAllToOther ) {
194
182
Object keyAttr = lookupKeysAttributeNode .execute (frame , inliningTarget , arg , T_KEYS );
195
- if (hasKeyProfile .profile (inliningTarget , keyAttr != PNone .NO_VALUE )) {
196
- HashingStorage curStorage = PDict .createNewStorage (0 );
197
- // We don't need to pass self as the attribute object has it already.
198
- Object keysIterable = callKeysMethod .execute (frame , keyAttr , EMPTY_OBJECT_ARRAY , EMPTY_KEYWORDS );
199
- return copyToStorage (frame , arg , kwargs , curStorage ,
200
- inliningTarget , keysIterable , getItemNode , getIter , nextNode ,
201
- errorProfile , setHasihngStorageItem , addAllToOther );
202
- } else {
203
- return addSequenceToStorage (frame , arg , kwargs ,
204
- inliningTarget , PDict ::createNewStorage , getIter , nextNode , createListNode ,
205
- seqLenNode , lengthTwoProfile , raise , getItemNode , isTypeErrorProfile ,
206
- errorProfile , setHasihngStorageItem , addAllToOther );
207
- }
183
+ ArrayBuilder <KeyValue > elements = toArrayPair .execute (frame , arg , keyAttr );
184
+ HashingStorage storage = PDict .createNewStorage (elements .size () + kwargs .length );
185
+ storage = addKeyValuesToStorage (frame , elements , storage , inliningTarget , setHasihngStorageItem );
186
+ storage = addKeywordsToStorage (frame , kwargs , storage , inliningTarget , addAllToOther );
187
+ return storage ;
208
188
}
209
189
210
190
@ NeverDefault
@@ -227,90 +207,120 @@ public final HashingStorage unionCached(HashingStorage other, HashingStorageCopy
227
207
return addAllToOther .executeCached (null , other , newStore );
228
208
}
229
209
230
- /**
231
- * Adds all items from the given mapping object to storage. It is the caller responsibility to
232
- * ensure, that mapping has the 'keys' attribute.
233
- */
234
- public static HashingStorage copyToStorage (VirtualFrame frame , Object mapping , PKeyword [] kwargs , HashingStorage storage ,
210
+ public static HashingStorage addKeywordsToStorage (VirtualFrame frame , PKeyword [] kwargs , HashingStorage storage ,
235
211
Node inliningTarget ,
236
- Object keysIterable ,
237
- PyObjectGetItem callGetItemNode ,
238
- PyObjectGetIter getIter ,
239
- GetNextNode nextNode ,
240
- IsBuiltinObjectProfile errorProfile ,
241
- HashingStorageSetItem setHashingStorageItem ,
242
- HashingStorageAddAllToOther addAllToOtherNode ) {
243
- Object keysIt = getIter .execute (frame , inliningTarget , keysIterable );
244
- HashingStorage curStorage = storage ;
245
- while (true ) {
246
- try {
247
- Object keyObj = nextNode .execute (frame , keysIt );
248
- Object valueObj = callGetItemNode .execute (frame , inliningTarget , mapping , keyObj );
212
+ HashingStorageAddAllToOther addAllToOther ) {
213
+ if (kwargs .length > 0 ) {
214
+ return addAllToOther .execute (frame , inliningTarget , new KeywordsStorage (kwargs ), storage );
215
+ }
216
+ return storage ;
217
+ }
249
218
250
- curStorage = setHashingStorageItem .execute (frame , inliningTarget , curStorage , keyObj , valueObj );
251
- } catch (PException e ) {
252
- e .expectStopIteration (inliningTarget , errorProfile );
253
- break ;
254
- }
219
+ protected static final class KeyValue {
220
+ final Object key ;
221
+ final Object value ;
222
+
223
+ private KeyValue (Object key , Object value ) {
224
+ this .key = key ;
225
+ this .value = value ;
255
226
}
256
- if (kwargs .length > 0 ) {
257
- curStorage = addAllToOtherNode .execute (frame , inliningTarget , new KeywordsStorage (kwargs ), curStorage );
227
+ }
228
+
229
+ public static HashingStorage addKeyValuesToStorage (VirtualFrame frame , ArrayBuilder <KeyValue > elements , HashingStorage storage ,
230
+ Node inliningTarget ,
231
+ HashingStorageSetItem setHashingStorageItem ) {
232
+ for (int i = 0 ; i < elements .size (); i ++) {
233
+ Object key = elements .get (i ).key ;
234
+ Object value = elements .get (i ).value ;
235
+ storage = setHashingStorageItem .execute (frame , inliningTarget , storage , key , value );
258
236
}
259
- return curStorage ;
237
+ return storage ;
260
238
}
261
239
262
- @ FunctionalInterface
263
- public interface StorageSupplier {
264
- HashingStorage get (int length );
240
+ public static HashingStorage addKeyValuesToStorage (VirtualFrame frame , PDict self , Object other , Object keyAttr ,
241
+ Node inliningTarget ,
242
+ ObjectToArrayPairNode toArrayPair ,
243
+ HashingStorageSetItem setHashingStorageItem ) {
244
+ ArrayBuilder <KeyValue > elements = toArrayPair .execute (frame , other , keyAttr );
245
+ HashingStorage storage = self .getDictStorage ();
246
+ return addKeyValuesToStorage (frame , elements , storage , inliningTarget , setHashingStorageItem );
265
247
}
266
248
267
- public static HashingStorage addSequenceToStorage (VirtualFrame frame , Object iterable , PKeyword [] kwargs , Node inliningTarget ,
268
- StorageSupplier storageSupplier ,
269
- PyObjectGetIter getIter ,
270
- GetNextNode nextNode ,
271
- FastConstructListNode createListNode ,
272
- LenNode seqLenNode ,
273
- InlinedConditionProfile lengthTwoProfile ,
274
- PRaiseNode .Lazy raise ,
275
- PyObjectGetItem getItemNode ,
276
- IsBuiltinObjectProfile isTypeErrorProfile ,
277
- IsBuiltinObjectProfile errorProfile ,
278
- HashingStorageSetItem setHashingStorageItem ,
279
- HashingStorageAddAllToOther addAllToOther ) throws PException {
280
- Object it = getIter .execute (frame , inliningTarget , iterable );
281
- ArrayBuilder <PSequence > elements = new ArrayBuilder <>();
282
- try {
283
- while (true ) {
284
- Object next = nextNode .execute (frame , it );
285
- PSequence element = createListNode .execute (frame , inliningTarget , next );
286
- assert element != null ;
287
- // This constructs a new list using the builtin type. So, the object cannot
288
- // be subclassed and we can directly call 'len()'.
289
- int len = seqLenNode .execute (inliningTarget , element );
249
+ // partial impl dict_update_arg
250
+ @ GenerateCached
251
+ @ GenerateInline (false )
252
+ public abstract static class ObjectToArrayPairNode extends PNodeWithContext {
253
+ public abstract ArrayBuilder <KeyValue > execute (VirtualFrame frame , Object mapping , Object keyAttr );
290
254
291
- if (lengthTwoProfile .profile (inliningTarget , len != 2 )) {
292
- throw raise .get (inliningTarget ).raise (ValueError , ErrorMessages .DICT_UPDATE_SEQ_ELEM_HAS_LENGTH_2_REQUIRED , elements .size (), len );
255
+ /**
256
+ * Adds all items from the given mapping object to storage. It is the caller responsibility
257
+ * to ensure, that mapping has the 'keys' attribute.
258
+ */
259
+ // partial impl PyDict_Merge
260
+ @ Specialization (guards = "!isNoValue(keyAttr)" )
261
+ static ArrayBuilder <KeyValue > partialMerge (VirtualFrame frame , Object mapping , Object keyAttr ,
262
+ @ Bind ("this" ) Node inliningTarget ,
263
+ @ Shared @ Cached PyObjectGetIter getIter ,
264
+ @ Shared @ Cached GetNextNode nextNode ,
265
+ @ Shared @ Cached PyObjectGetItem getItemNode ,
266
+ @ Shared @ Cached IsBuiltinObjectProfile errorProfile ,
267
+ @ Cached CallVarargsMethodNode callKeysMethod ) {
268
+ // We don't need to pass self as the attribute object has it already.
269
+ Object keysIterable = callKeysMethod .execute (frame , keyAttr , EMPTY_OBJECT_ARRAY , EMPTY_KEYWORDS );
270
+ Object keysIt = getIter .execute (frame , inliningTarget , keysIterable );
271
+ ArrayBuilder <KeyValue > elements = new ArrayBuilder <>();
272
+ while (true ) {
273
+ try {
274
+ Object keyObj = nextNode .execute (frame , keysIt );
275
+ Object valueObj = getItemNode .execute (frame , inliningTarget , mapping , keyObj );
276
+ elements .add (new KeyValue (keyObj , valueObj ));
277
+ } catch (PException e ) {
278
+ e .expectStopIteration (inliningTarget , errorProfile );
279
+ break ;
293
280
}
294
-
295
- elements .add (element );
296
281
}
297
- } catch (PException e ) {
298
- if (isTypeErrorProfile .profileException (inliningTarget , e , TypeError )) {
299
- throw raise .get (inliningTarget ).raise (TypeError , ErrorMessages .CANNOT_CONVERT_DICT_UPDATE_SEQ , elements .size ());
300
- } else {
301
- e .expectStopIteration (inliningTarget , errorProfile );
302
- }
303
- }
304
- HashingStorage storage = storageSupplier .get (elements .size () + kwargs .length );
305
- for (int j = 0 ; j < elements .size (); j ++) {
306
- PSequence element = elements .get (j );
307
- Object key = getItemNode .execute (frame , inliningTarget , element , 0 );
308
- Object value = getItemNode .execute (frame , inliningTarget , element , 1 );
309
- storage = setHashingStorageItem .execute (frame , inliningTarget , storage , key , value );
282
+ return elements ;
310
283
}
311
- if (kwargs .length > 0 ) {
312
- storage = addAllToOther .execute (frame , inliningTarget , new KeywordsStorage (kwargs ), storage );
284
+
285
+ // partial impl PyDict_MergeFromSeq2
286
+ @ Specialization
287
+ static ArrayBuilder <KeyValue > partialMergeFromSeq2 (VirtualFrame frame , Object iterable , @ SuppressWarnings ("unused" ) PNone keyAttr ,
288
+ @ Bind ("this" ) Node inliningTarget ,
289
+ @ Shared @ Cached PyObjectGetIter getIter ,
290
+ @ Shared @ Cached GetNextNode nextNode ,
291
+ @ Shared @ Cached PyObjectGetItem getItemNode ,
292
+ @ Shared @ Cached IsBuiltinObjectProfile errorProfile ,
293
+ @ Cached FastConstructListNode createListNode ,
294
+ @ Cached LenNode seqLenNode ,
295
+ @ Cached PRaiseNode .Lazy raise ,
296
+ @ Cached InlinedConditionProfile lengthTwoProfile ,
297
+ @ Exclusive @ Cached IsBuiltinObjectProfile isTypeErrorProfile ) throws PException {
298
+ Object it = getIter .execute (frame , inliningTarget , iterable );
299
+ ArrayBuilder <KeyValue > elements = new ArrayBuilder <>();
300
+ try {
301
+ while (true ) {
302
+ Object next = nextNode .execute (frame , it );
303
+ PSequence element = createListNode .execute (frame , inliningTarget , next );
304
+ assert element != null ;
305
+ // This constructs a new list using the builtin type. So, the object cannot
306
+ // be subclassed and we can directly call 'len()'.
307
+ int len = seqLenNode .execute (inliningTarget , element );
308
+
309
+ if (lengthTwoProfile .profile (inliningTarget , len != 2 )) {
310
+ throw raise .get (inliningTarget ).raise (ValueError , ErrorMessages .DICT_UPDATE_SEQ_ELEM_HAS_LENGTH_2_REQUIRED , elements .size (), len );
311
+ }
312
+ Object key = getItemNode .execute (frame , inliningTarget , element , 0 );
313
+ Object value = getItemNode .execute (frame , inliningTarget , element , 1 );
314
+ elements .add (new KeyValue (key , value ));
315
+ }
316
+ } catch (PException e ) {
317
+ if (isTypeErrorProfile .profileException (inliningTarget , e , TypeError )) {
318
+ throw raise .get (inliningTarget ).raise (TypeError , ErrorMessages .CANNOT_CONVERT_DICT_UPDATE_SEQ , elements .size ());
319
+ } else {
320
+ e .expectStopIteration (inliningTarget , errorProfile );
321
+ }
322
+ }
323
+ return elements ;
313
324
}
314
- return storage ;
315
325
}
316
326
}
0 commit comments