Skip to content

Commit b77b439

Browse files
committed
make iterables report HAS_SIZE, GET_SIZE, and READ with integer keys
1 parent 1c80d67 commit b77b439

File tree

3 files changed

+149
-17
lines changed

3 files changed

+149
-17
lines changed

graalpython/com.oracle.graal.python.tck/src/com/oracle/graal/python/tck/PythonProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public Collection<? extends Snippet> createExpressions(Context context) {
165165

166166
// dictionaries
167167
addExpressionSnippet(context, snippets, "dict", "lambda: { 'x': 4 }", OBJECT);
168-
addExpressionSnippet(context, snippets, "dict", "lambda: { 'a': 1, 'b': 2, 'c': 3 }", OBJECT, new PDictMemberVerifier(arr("a", "b", "c"), arr("x", "y", "z")));
168+
addExpressionSnippet(context, snippets, "dict", "lambda: { 'a': 1, 'b': 2, 'c': 3 }", OBJECT, new PDictMemberVerifier(arr("get", "keys", "update"), arr("a", "b", "c")));
169169

170170
// @formatter:on
171171
return snippets;

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/interop/JavaInteropTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646

4747
import java.io.ByteArrayOutputStream;
4848
import java.io.IOException;
49-
import java.util.Set;
49+
import java.util.Arrays;
50+
import java.util.List;
5051

5152
import org.graalvm.polyglot.Context;
5253
import org.graalvm.polyglot.Context.Builder;
@@ -227,14 +228,14 @@ public void accessSuitePy() throws IOException {
227228

228229
Value libraries = suite.getMember("libraries");
229230
assertNotNull("libraries found", libraries);
230-
final Set<String> suiteKeys = suite.getMemberKeys();
231+
final List<Object> suiteKeys = Arrays.asList(suite.invokeMember("keys").as(Object[].class));
231232
assertTrue("Libraries found among keys: " + suiteKeys, suiteKeys.contains("libraries"));
232233

233234
Value dacapo = null;
234-
for (String k : libraries.getMemberKeys()) {
235+
for (Object k : libraries.invokeMember("keys").as(List.class)) {
235236
System.err.println("k " + k);
236237
if ("DACAPO".equals(k)) {
237-
dacapo = libraries.getMember(k);
238+
dacapo = libraries.getMember((String) k);
238239
}
239240
}
240241
assertNotNull("Dacapo found", dacapo);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/interop/PythonMessageResolution.java

Lines changed: 143 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,11 @@
7575
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
7676
import com.oracle.graal.python.nodes.attributes.SetAttributeNode;
7777
import com.oracle.graal.python.nodes.call.CallNode;
78+
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
7879
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
7980
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
8081
import com.oracle.graal.python.nodes.datamodel.IsCallableNode;
82+
import com.oracle.graal.python.nodes.datamodel.IsIterableNode;
8183
import com.oracle.graal.python.nodes.datamodel.IsMappingNode;
8284
import com.oracle.graal.python.nodes.datamodel.IsSequenceNode;
8385
import 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

Comments
 (0)