7575import com .oracle .graal .python .nodes .attributes .ReadAttributeFromObjectNode ;
7676import com .oracle .graal .python .nodes .attributes .SetAttributeNode ;
7777import com .oracle .graal .python .nodes .call .CallNode ;
78+ import com .oracle .graal .python .nodes .call .special .CallUnaryMethodNode ;
7879import com .oracle .graal .python .nodes .call .special .LookupAndCallBinaryNode ;
7980import com .oracle .graal .python .nodes .call .special .LookupAndCallUnaryNode ;
8081import com .oracle .graal .python .nodes .datamodel .IsCallableNode ;
82+ import com .oracle .graal .python .nodes .datamodel .IsIterableNode ;
8183import com .oracle .graal .python .nodes .datamodel .IsMappingNode ;
8284import com .oracle .graal .python .nodes .datamodel .IsSequenceNode ;
8385import com .oracle .graal .python .nodes .expression .CastToListNode ;
@@ -183,45 +185,119 @@ private static final class KeyForItemAccess extends KeyForForcedAccess {
183185 private static final class ReadNode extends Node {
184186 private static final Object NONEXISTING_IDENTIFIER = new Object ();
185187
186- @ Child private IsSequenceNode isSequence = IsSequenceNode .create ();
187- @ Child private LookupAndCallBinaryNode readNode = LookupAndCallBinaryNode .create (__GETATTRIBUTE__ );
188- @ Child private GetItemNode getItemNode = GetItemNode .create ();
189188 @ Child private KeyForAttributeAccess getAttributeKey = new KeyForAttributeAccess ();
190- @ Child private KeyForItemAccess getItemKey = new KeyForItemAccess ();
191- final ConditionProfile strProfile = ConditionProfile .createBinaryProfile ();
192189 @ Child private PTypeToForeignNode toForeign = PTypeToForeignNodeGen .create ();
193190
191+ @ Child private LookupAndCallBinaryNode readNode ;
192+ @ Child private KeyForItemAccess getItemKey ;
193+ @ Child private GetItemNode getItemNode ;
194+ @ Child private IsSequenceNode isSequence ;
195+ @ Child private IsIterableNode isIterableNode ;
196+ @ Child private LookupAndCallUnaryNode getIter ;
197+ @ Child private LookupAndCallUnaryNode callNext ;
198+
199+ final ConditionProfile strProfile = ConditionProfile .createBinaryProfile ();
200+
201+ private LookupAndCallBinaryNode getReadNode () {
202+ if (readNode == null ) {
203+ CompilerDirectives .transferToInterpreterAndInvalidate ();
204+ readNode = insert (LookupAndCallBinaryNode .create (__GETATTRIBUTE__ ));
205+ }
206+ return readNode ;
207+ }
208+
209+ private KeyForItemAccess getGetItemKey () {
210+ if (getItemKey == null ) {
211+ CompilerDirectives .transferToInterpreterAndInvalidate ();
212+ getItemKey = insert (new KeyForItemAccess ());
213+ }
214+ return getItemKey ;
215+ }
216+
217+ private GetItemNode getGetItemNode () {
218+ if (getItemNode == null ) {
219+ CompilerDirectives .transferToInterpreterAndInvalidate ();
220+ getItemNode = insert (GetItemNode .create ());
221+ }
222+ return getItemNode ;
223+ }
224+
225+ private IsSequenceNode getIsSequenceNode () {
226+ if (isSequence == null ) {
227+ CompilerDirectives .transferToInterpreterAndInvalidate ();
228+ isSequence = insert (IsSequenceNode .create ());
229+ }
230+ return isSequence ;
231+ }
232+
233+ private IsIterableNode getIsIterableNode () {
234+ if (isIterableNode == null ) {
235+ CompilerDirectives .transferToInterpreterAndInvalidate ();
236+ isIterableNode = insert (IsIterableNode .create ());
237+ }
238+ return isIterableNode ;
239+ }
240+
194241 public Object execute (Object object , Object key ) {
195242 String attrKey = getAttributeKey .execute (key );
196243 if (attrKey != null ) {
197244 try {
198- return toForeign .executeConvert (readNode .executeObject (object , attrKey ));
245+ return toForeign .executeConvert (getReadNode () .executeObject (object , attrKey ));
199246 } catch (PException e ) {
200247 // pass, we might be reading an item that starts with "@"
201248 }
202249 }
203250
204- String itemKey = getItemKey .execute (key );
251+ String itemKey = getGetItemKey () .execute (key );
205252 if (itemKey != null ) {
206- return toForeign .executeConvert (getItemNode .execute (object , itemKey ));
253+ return toForeign .executeConvert (getGetItemNode () .execute (object , itemKey ));
207254 }
208255
209256 if (strProfile .profile (key instanceof String )) {
210257 try {
211- return toForeign .executeConvert (readNode .executeObject (object , key ));
258+ return toForeign .executeConvert (getReadNode () .executeObject (object , key ));
212259 } catch (PException e ) {
213260 // pass
214261 }
215262 }
216- if (isSequence .execute (object )) {
263+
264+ if (getIsSequenceNode ().execute (object )) {
217265 try {
218- return toForeign .executeConvert (getItemNode .execute (object , key ));
266+ return toForeign .executeConvert (getGetItemNode () .execute (object , key ));
219267 } catch (PException e ) {
220268 // pass
221269 }
222270 }
271+
272+ if (key instanceof Integer ) {
273+ int intKey = (int ) key ;
274+ if (getIsIterableNode ().execute (object )) {
275+ if (getIter == null ) {
276+ CompilerDirectives .transferToInterpreterAndInvalidate ();
277+ getIter = insert (LookupAndCallUnaryNode .create (SpecialMethodNames .__ITER__ ));
278+ }
279+ Object iter = getIter .executeObject (object );
280+ if (iter != object ) {
281+ // there is a separate iterator for this object, should be safe to consume
282+ return iterateToKey (iter , intKey );
283+ }
284+ }
285+ }
286+
223287 return NONEXISTING_IDENTIFIER ;
224288 }
289+
290+ private Object iterateToKey (Object iter , int key ) {
291+ if (callNext == null ) {
292+ CompilerDirectives .transferToInterpreterAndInvalidate ();
293+ callNext = insert (LookupAndCallUnaryNode .create (SpecialMethodNames .__NEXT__ ));
294+ }
295+ Object value = NONEXISTING_IDENTIFIER ;
296+ for (int i = 0 ; i <= key ; i ++) {
297+ value = callNext .executeObject (iter );
298+ }
299+ return value ;
300+ }
225301 }
226302
227303 private static final class KeysNode extends Node {
@@ -534,6 +610,7 @@ public Object access(Object object) {
534610 @ Resolve (message = "HAS_SIZE" )
535611 abstract static class PForeignHasSizeNode extends Node {
536612 @ Child private IsSequenceNode isSequenceNode ;
613+ @ Child private IsIterableNode isIterableNode ;
537614 @ Child private IsMappingNode isMappingNode ;
538615 @ Child private BuiltinFunctions .LenNode lenNode ;
539616 @ Child private PTypeUnboxNode unboxNode ;
@@ -543,7 +620,10 @@ abstract static class PForeignHasSizeNode extends Node {
543620
544621 public Object access (Object object ) {
545622 Object profiled = profile .profile (object );
546- if (getIsSequenceNode ().execute (profiled ) && !getIsMappingNode ().execute (profiled )) {
623+ boolean isMapping = getIsMappingNode ().execute (profiled );
624+ if (isMapping ) {
625+ return false ;
626+ } else if (getIsSequenceNode ().execute (profiled )) {
547627 // also try to access using an integer index
548628 int len = (int ) getUnboxNode ().execute (getLenNode ().executeWith (profiled ));
549629 if (len > 0 ) {
@@ -555,6 +635,8 @@ public Object access(Object object) {
555635 }
556636 }
557637 return true ;
638+ } else if (getIsIterableNode ().execute (profiled )) {
639+ return true ;
558640 }
559641 return false ;
560642 }
@@ -583,6 +665,14 @@ private LookupAndCallBinaryNode getCallGetItemNode() {
583665 return callGetItemNode ;
584666 }
585667
668+ private IsIterableNode getIsIterableNode () {
669+ if (isIterableNode == null ) {
670+ CompilerDirectives .transferToInterpreterAndInvalidate ();
671+ isIterableNode = insert (IsIterableNode .create ());
672+ }
673+ return isIterableNode ;
674+ }
675+
586676 private IsSequenceNode getIsSequenceNode () {
587677 if (isSequenceNode == null ) {
588678 CompilerDirectives .transferToInterpreterAndInvalidate ();
@@ -605,10 +695,47 @@ abstract static class PForeignGetSizeNode extends Node {
605695 @ Child IsSequenceNode isSeq = IsSequenceNode .create ();
606696 @ Child private BuiltinFunctions .LenNode lenNode = BuiltinFunctionsFactory .LenNodeFactory .create ();
607697 @ Child private PTypeUnboxNode unboxNode = PTypeUnboxNode .create ();
698+ @ Child private IsIterableNode isIter ;
699+ @ Child private LookupInheritedAttributeNode getLenHint ;
700+ @ Child private CallUnaryMethodNode callNode ;
701+ @ Child private CastToListNode castToList ;
702+ @ Child private LookupAndCallUnaryNode getIter ;
608703
609704 public Object access (Object object ) {
610705 if (isSeq .execute (object )) {
611706 return unboxNode .execute (lenNode .executeWith (object ));
707+ } else {
708+ if (isIter == null ) {
709+ CompilerDirectives .transferToInterpreterAndInvalidate ();
710+ isIter = insert (IsIterableNode .create ());
711+ }
712+ if (isIter .execute (object )) {
713+ if (getLenHint == null ) {
714+ CompilerDirectives .transferToInterpreterAndInvalidate ();
715+ getLenHint = insert (LookupInheritedAttributeNode .create (SpecialMethodNames .__LENGTH_HINT__ ));
716+ }
717+ Object lenHint = getLenHint .execute (object );
718+ if (lenHint != PNone .NO_VALUE ) {
719+ if (callNode == null ) {
720+ CompilerDirectives .transferToInterpreterAndInvalidate ();
721+ callNode = insert (CallUnaryMethodNode .create ());
722+ }
723+ return unboxNode .execute (callNode .executeObject (lenHint , object ));
724+ }
725+ if (getIter == null ) {
726+ CompilerDirectives .transferToInterpreterAndInvalidate ();
727+ getIter = insert (LookupAndCallUnaryNode .create (SpecialMethodNames .__ITER__ ));
728+ }
729+ Object iter = getIter .executeObject (object );
730+ if (iter != object ) {
731+ if (castToList == null ) {
732+ CompilerDirectives .transferToInterpreterAndInvalidate ();
733+ castToList = insert (CastToListNode .create ());
734+ }
735+ // there is a separate iterator for this object, should be safe to consume
736+ return unboxNode .execute (lenNode .executeWith (castToList .executeWith (iter )));
737+ }
738+ }
612739 }
613740 throw UnsupportedMessageException .raise (Message .GET_SIZE );
614741 }
@@ -633,6 +760,10 @@ abstract static class PKeyInfoNode extends Node {
633760 @ Child private KeyForItemAccess itemKey = new KeyForItemAccess ();
634761
635762 public int access (Object object , Object fieldName ) {
763+ if (fieldName instanceof Integer ) {
764+ return KeyInfo .READABLE | KeyInfo .READ_SIDE_EFFECTS ;
765+ }
766+
636767 String itemFieldName = itemKey .execute (fieldName );
637768 if (itemFieldName != null ) {
638769 return KeyInfo .READABLE | KeyInfo .MODIFIABLE | KeyInfo .REMOVABLE | KeyInfo .REMOVABLE ;
0 commit comments