6868import com .oracle .graal .python .nodes .attributes .LookupCallableSlotInMRONode ;
6969import com .oracle .graal .python .nodes .builtins .ListNodes .FastConstructListNode ;
7070import com .oracle .graal .python .nodes .call .special .CallVarargsMethodNode ;
71- import com .oracle .graal .python .nodes .call .special .LookupAndCallUnaryNode ;
7271import com .oracle .graal .python .nodes .object .BuiltinClassProfiles .IsBuiltinObjectProfile ;
7372import com .oracle .graal .python .nodes .object .GetClassNode ;
7473import com .oracle .graal .python .runtime .ExecutionContext .IndirectCallContext ;
8180import com .oracle .truffle .api .dsl .Bind ;
8281import com .oracle .truffle .api .dsl .Cached ;
8382import 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 ;
8486import com .oracle .truffle .api .dsl .NeverDefault ;
8587import com .oracle .truffle .api .dsl .Specialization ;
8688import com .oracle .truffle .api .frame .VirtualFrame ;
@@ -157,16 +159,12 @@ static HashingStorage doNoBuiltinKeysAttr(VirtualFrame frame, PHashingCollection
157159 @ Bind ("this" ) Node inliningTarget ,
158160 @ SuppressWarnings ("unused" ) @ Exclusive @ Cached GetClassNode getClassNode ,
159161 @ 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 );
170168 }
171169
172170 protected static boolean hasIterAttrButNotBuiltin (Node inliningTarget , PHashingCollection col , GetClassNode getClassNode , LookupCallableSlotInMRONode lookupIter ) {
@@ -177,34 +175,16 @@ protected static boolean hasIterAttrButNotBuiltin(Node inliningTarget, PHashingC
177175 @ Specialization (guards = {"!isNoValue(arg)" , "!isPDict(arg)" })
178176 static HashingStorage updateArg (VirtualFrame frame , Object arg , PKeyword [] kwargs ,
179177 @ Bind ("this" ) Node inliningTarget ,
180- @ Cached PyObjectLookupAttr lookupKeysAttributeNode ,
181- @ Cached CallVarargsMethodNode callKeysMethod ,
178+ @ Exclusive @ Cached PyObjectLookupAttr lookupKeysAttributeNode ,
179+ @ Exclusive @ Cached ObjectToArrayPairNode toArrayPair ,
182180 @ 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 ) {
194182 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 ;
208188 }
209189
210190 @ NeverDefault
@@ -227,90 +207,120 @@ public final HashingStorage unionCached(HashingStorage other, HashingStorageCopy
227207 return addAllToOther .executeCached (null , other , newStore );
228208 }
229209
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 ,
235211 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+ }
249218
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 ;
255226 }
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 );
258236 }
259- return curStorage ;
237+ return storage ;
260238 }
261239
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 );
265247 }
266248
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 );
290254
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 ;
293280 }
294-
295- elements .add (element );
296281 }
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 ;
310283 }
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 ;
313324 }
314- return storage ;
315325 }
316326}
0 commit comments