Skip to content

Commit 0d1fd42

Browse files
committed
isIterator() -> iterator
1 parent 0e7e292 commit 0d1fd42

File tree

5 files changed

+128
-87
lines changed

5 files changed

+128
-87
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_interop.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,43 @@ def test_java_map(self):
964964
with self.assertRaisesRegex(TypeError, 'invalid instantiation of foreign object'):
965965
type(h).fromkeys(['a', 'b'], 42)
966966

967+
def test_java_iterator(self):
968+
from java.util import ArrayList, LinkedHashSet
969+
970+
s = LinkedHashSet() # not hasArrayElements() and not hasHashEntries()
971+
s.add(1)
972+
s.add(2)
973+
itr1 = s.iterator()
974+
itr2 = iter(s)
975+
976+
l = ArrayList()
977+
l.extend([1, 2])
978+
itr3 = l.iterator() # call Java iterator(), iter(l) would call list.__iter__() and return a Python iterator
979+
980+
for itr in [itr1, itr2, itr3]:
981+
iterator_type = type(iter([]))
982+
assert isinstance(itr, iterator_type)
983+
assert iterator_type in type(itr).mro()
984+
self.assertEqual(['ForeignIterator', 'iterator', 'foreign', 'object'], [t.__name__ for t in type(itr).mro()])
985+
assert '<polyglot.ForeignIterator object at 0x' in repr(itr), repr(itr)
986+
assert '<polyglot.ForeignIterator object at 0x' in str(itr), str(itr)
987+
assert bool(itr) == True
988+
989+
assert iter(itr) is itr
990+
991+
assert itr.__length_hint__() == 1
992+
assert next(itr) == 1
993+
assert next(itr) == 2
994+
self.assertRaises(StopIteration, lambda: next(itr))
995+
self.assertRaises(StopIteration, lambda: next(itr))
996+
assert itr.__length_hint__() == 0
997+
998+
with self.assertRaisesRegex(TypeError, "descriptor requires a 'iterator' object but received a 'ForeignIterator'"):
999+
itr.__reduce__()
1000+
1001+
with self.assertRaisesRegex(TypeError, "descriptor requires a 'iterator' object but received a 'ForeignIterator'"):
1002+
itr.__setstate__(0)
1003+
9671004
def test_java_map_as_keywords(self):
9681005
from java.util import HashMap, LinkedHashMap
9691006

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LE__;
5050
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LT__;
5151
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEW__;
52-
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEXT__;
5352
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___OR__;
5453
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RAND__;
5554
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___RDIVMOD__;
@@ -65,7 +64,6 @@
6564
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___XOR__;
6665
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___INSTANCECHECK__;
6766
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___LEN__;
68-
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEXT__;
6967
import static com.oracle.graal.python.nodes.StringLiterals.T_NONE;
7068
import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING;
7169

@@ -154,7 +152,6 @@
154152
import com.oracle.truffle.api.library.CachedLibrary;
155153
import com.oracle.truffle.api.nodes.Node;
156154
import com.oracle.truffle.api.profiles.InlinedBranchProfile;
157-
import com.oracle.truffle.api.profiles.InlinedConditionProfile;
158155
import com.oracle.truffle.api.strings.TruffleString;
159156

160157
@CoreFunctions(extendClasses = PythonBuiltinClassType.ForeignObject)
@@ -830,35 +827,6 @@ static Object doGeneric(Object object,
830827
}
831828
}
832829

833-
@Builtin(name = J___NEXT__, minNumOfPositionalArgs = 1)
834-
@GenerateNodeFactory
835-
public abstract static class NextNode extends PythonUnaryBuiltinNode {
836-
837-
@Specialization(limit = "getCallSiteInlineCacheMaxDepth()")
838-
static Object doForeignArray(Object iterator,
839-
@Bind("this") Node inliningTarget,
840-
@Cached InlinedConditionProfile notIterator,
841-
@Cached PRaiseNode raiseNode,
842-
@CachedLibrary("iterator") InteropLibrary lib,
843-
@Cached PForeignToPTypeNode convertNode,
844-
@Cached GilNode gil) {
845-
if (notIterator.profile(inliningTarget, lib.isIterator(iterator))) {
846-
gil.release(true);
847-
try {
848-
return convertNode.executeConvert(lib.getIteratorNextElement(iterator));
849-
} catch (StopIterationException e) {
850-
throw raiseNode.raiseStopIteration();
851-
} catch (UnsupportedMessageException e) {
852-
throw CompilerDirectives.shouldNotReachHere("iterator claimed to be iterator but wasn't");
853-
} finally {
854-
gil.acquire();
855-
}
856-
} else {
857-
throw raiseNode.raise(AttributeError, ErrorMessages.FOREIGN_OBJ_HAS_NO_ATTR_S, T___NEXT__);
858-
}
859-
}
860-
}
861-
862830
@Builtin(name = J___NEW__, minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true)
863831
@GenerateNodeFactory
864832
abstract static class NewNode extends PythonBuiltinNode {
@@ -940,7 +908,8 @@ public static CallNode create() {
940908
}
941909
}
942910

943-
// TODO: PySequenceCheckNode can be removed once this is no longer defined
911+
// TODO: PySequenceCheckNode special foreign handling can be removed once this is no longer
912+
// defined
944913
@Slot(value = SlotKind.sq_item, isComplex = true)
945914
@GenerateNodeFactory
946915
abstract static class ForeignSqItemNode extends SqItemBuiltinNode {
@@ -1196,11 +1165,13 @@ Object str(VirtualFrame frame, Object object,
11961165
@CachedLibrary(limit = "3") InteropLibrary lib,
11971166
@Cached GilNode gil,
11981167
@Cached PyObjectStrAsTruffleStringNode strNode,
1168+
@Cached ObjectNodes.DefaultObjectReprNode defaultReprNode,
11991169
@Cached InlinedBranchProfile isNull,
12001170
@Cached InlinedBranchProfile isBoolean,
12011171
@Cached InlinedBranchProfile isString,
12021172
@Cached InlinedBranchProfile isLong,
12031173
@Cached InlinedBranchProfile isDouble,
1174+
@Cached InlinedBranchProfile isIterator,
12041175
@Cached InlinedBranchProfile defaultCase) {
12051176
// Check if __repr__ is defined before foreign, if so call that, like object.__str__
12061177
// would do
@@ -1255,6 +1226,9 @@ Object str(VirtualFrame frame, Object object,
12551226
gil.acquire();
12561227
}
12571228
return strNode.execute(frame, inliningTarget, value);
1229+
} else if (lib.isIterator(object)) {
1230+
isIterator.enter(inliningTarget);
1231+
return defaultReprNode.execute(frame, inliningTarget, object);
12581232
}
12591233
} catch (UnsupportedMessageException e) {
12601234
// Fall back to the generic impl

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/IteratorBuiltins.java

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
package com.oracle.graal.python.builtins.objects.iterator;
2727

2828
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeError;
29+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
2930
import static com.oracle.graal.python.nodes.BuiltinNames.T_ITER;
31+
import static com.oracle.graal.python.nodes.ErrorMessages.DESCRIPTOR_REQUIRES_S_OBJ_RECEIVED_P;
3032
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__;
3133
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___LENGTH_HINT__;
3234
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEXT__;
@@ -64,32 +66,43 @@
6466
import com.oracle.graal.python.lib.PyObjectSizeNode;
6567
import com.oracle.graal.python.lib.PySequenceGetItemNode;
6668
import com.oracle.graal.python.nodes.ErrorMessages;
69+
import com.oracle.graal.python.nodes.PNodeWithContext;
6770
import com.oracle.graal.python.nodes.PRaiseNode;
6871
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
6972
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
7073
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
74+
import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode;
7175
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile;
76+
import com.oracle.graal.python.nodes.object.IsForeignObjectNode;
7277
import com.oracle.graal.python.nodes.util.CastToJavaBigIntegerNode;
78+
import com.oracle.graal.python.runtime.GilNode;
7379
import com.oracle.graal.python.runtime.PythonContext;
7480
import com.oracle.graal.python.runtime.exception.PException;
7581
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
7682
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
83+
import com.oracle.truffle.api.CompilerDirectives;
7784
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
7885
import com.oracle.truffle.api.dsl.Bind;
7986
import com.oracle.truffle.api.dsl.Cached;
8087
import com.oracle.truffle.api.dsl.Cached.Exclusive;
8188
import com.oracle.truffle.api.dsl.Cached.Shared;
89+
import com.oracle.truffle.api.dsl.Fallback;
8290
import com.oracle.truffle.api.dsl.GenerateCached;
8391
import com.oracle.truffle.api.dsl.GenerateInline;
8492
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
8593
import com.oracle.truffle.api.dsl.NodeFactory;
8694
import com.oracle.truffle.api.dsl.Specialization;
8795
import com.oracle.truffle.api.frame.VirtualFrame;
96+
import com.oracle.truffle.api.interop.InteropLibrary;
97+
import com.oracle.truffle.api.interop.StopIterationException;
98+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
99+
import com.oracle.truffle.api.library.CachedLibrary;
88100
import com.oracle.truffle.api.nodes.Node;
89101
import com.oracle.truffle.api.profiles.InlinedConditionProfile;
90102
import com.oracle.truffle.api.profiles.InlinedExactClassProfile;
91103
import com.oracle.truffle.api.strings.TruffleString;
92104

105+
/** NOTE: self can either be a PBuiltinIterator or a foreign iterator (isIterator()). */
93106
@CoreFunctions(extendClasses = {PythonBuiltinClassType.PIterator, PythonBuiltinClassType.PArrayIterator,
94107
PythonBuiltinClassType.PDictItemIterator, PythonBuiltinClassType.PDictReverseItemIterator,
95108
PythonBuiltinClassType.PDictKeyIterator, PythonBuiltinClassType.PDictReverseKeyIterator,
@@ -111,7 +124,7 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
111124
public abstract static class NextNode extends PythonUnaryBuiltinNode {
112125

113126
@Specialization
114-
static Object exhausted(VirtualFrame frame, PBuiltinIterator self,
127+
static Object exhausted(VirtualFrame frame, Object self,
115128
@Bind("this") Node inliningTarget,
116129
@Cached NextHelperNode nextHelperNode) {
117130
return nextHelperNode.execute(frame, inliningTarget, self, true);
@@ -120,11 +133,11 @@ static Object exhausted(VirtualFrame frame, PBuiltinIterator self,
120133

121134
@GenerateInline
122135
@GenerateCached(false)
123-
public abstract static class NextHelperNode extends Node {
136+
public abstract static class NextHelperNode extends PNodeWithContext {
124137

125138
public static final Object STOP_MARKER = new Object();
126139

127-
public abstract Object execute(VirtualFrame frame, Node inliningTarget, PBuiltinIterator iterator, boolean throwStopIteration);
140+
public abstract Object execute(VirtualFrame frame, Node inliningTarget, Object iterator, boolean throwStopIteration);
128141

129142
private static Object stopIteration(Node inliningTarget, PBuiltinIterator self, boolean throwStopIteration, PRaiseNode.Lazy raiseNode) {
130143
self.setExhausted();
@@ -135,6 +148,14 @@ private static Object stopIteration(Node inliningTarget, PBuiltinIterator self,
135148
}
136149
}
137150

151+
private static Object stopIterationForeign(Node inliningTarget, boolean throwStopIteration, PRaiseNode.Lazy raiseNode) {
152+
if (throwStopIteration) {
153+
throw raiseNode.get(inliningTarget).raiseStopIteration();
154+
} else {
155+
return STOP_MARKER;
156+
}
157+
}
158+
138159
@Specialization(guards = "self.isExhausted()")
139160
static Object exhausted(Node inliningTarget, @SuppressWarnings("unused") PBuiltinIterator self, boolean throwStopIteration,
140161
@Exclusive @Cached PRaiseNode.Lazy raiseNode) {
@@ -277,6 +298,29 @@ static Object next(VirtualFrame frame, Node inliningTarget, PSequenceIterator se
277298
}
278299
}
279300

301+
@Specialization(guards = {"isForeignObjectNode.execute(inliningTarget, self)", "interop.isIterator(self)"}, limit = "1")
302+
static Object foreign(Node inliningTarget, Object self, boolean throwStopIteration,
303+
@Cached IsForeignObjectNode isForeignObjectNode,
304+
@CachedLibrary(limit = "getCallSiteInlineCacheMaxDepth()") InteropLibrary interop,
305+
@Cached(inline = false) GilNode gil,
306+
@Cached(inline = false) PForeignToPTypeNode toPythonNode,
307+
@Exclusive @Cached PRaiseNode.Lazy raiseNode) {
308+
final Object element;
309+
310+
gil.release(true);
311+
try {
312+
element = interop.getIteratorNextElement(self);
313+
} catch (StopIterationException e) {
314+
return stopIterationForeign(inliningTarget, throwStopIteration, raiseNode);
315+
} catch (UnsupportedMessageException e) {
316+
throw CompilerDirectives.shouldNotReachHere("iterator claimed to be iterator but wasn't");
317+
} finally {
318+
gil.acquire();
319+
}
320+
321+
return toPythonNode.executeConvert(element);
322+
}
323+
280324
@GenerateInline
281325
@GenerateCached(false)
282326
abstract static class PHashingStorageIteratorNextValue extends Node {
@@ -415,6 +459,22 @@ static int lengthHint(VirtualFrame frame, PSequenceIterator self,
415459
int len = sizeNode.execute(frame, inliningTarget, self.getObject()) - self.getIndex();
416460
return len < 0 ? 0 : len;
417461
}
462+
463+
@Specialization(guards = {"isForeignObjectNode.execute(inliningTarget, self)", "interop.isIterator(self)"}, limit = "1")
464+
static int foreign(Object self,
465+
@Bind("this") Node inliningTarget,
466+
@Cached IsForeignObjectNode isForeignObjectNode,
467+
@CachedLibrary(limit = "getCallSiteInlineCacheMaxDepth()") InteropLibrary interop,
468+
@Cached(inline = false) GilNode gil) {
469+
gil.release(true);
470+
try {
471+
return interop.hasIteratorNextElement(self) ? 1 : 0;
472+
} catch (UnsupportedMessageException e) {
473+
throw CompilerDirectives.shouldNotReachHere("iterator claimed to be iterator but wasn't");
474+
} finally {
475+
gil.acquire();
476+
}
477+
}
418478
}
419479

420480
@Builtin(name = J___REDUCE__, minNumOfPositionalArgs = 1)
@@ -538,6 +598,13 @@ Object reduceNonSeq(@SuppressWarnings({"unused"}) VirtualFrame frame, PSequenceI
538598
}
539599
}
540600

601+
@Fallback
602+
static int other(Object self,
603+
@Bind("this") Node inliningTarget,
604+
@Cached PRaiseNode.Lazy raiseNode) {
605+
throw raiseNode.get(inliningTarget).raise(TypeError, DESCRIPTOR_REQUIRES_S_OBJ_RECEIVED_P, "iterator", self);
606+
}
607+
541608
private static PTuple reduceInternal(VirtualFrame frame, Node inliningTarget, Object arg, PythonContext context, PyObjectGetAttr getAttrNode, PythonObjectFactory factory) {
542609
return reduceInternal(frame, inliningTarget, arg, null, context, getAttrNode, factory);
543610
}
@@ -560,7 +627,7 @@ private static PTuple reduceInternal(VirtualFrame frame, Node inliningTarget, Ob
560627
public abstract static class SetStateNode extends PythonBinaryBuiltinNode {
561628
@Specialization
562629
@TruffleBoundary
563-
public static Object reduce(PBigRangeIterator self, Object index,
630+
static Object setstate(PBigRangeIterator self, Object index,
564631
@Bind("this") Node inliningTarget,
565632
@Cached CastToJavaBigIntegerNode castToJavaBigIntegerNode) {
566633
BigInteger idx = castToJavaBigIntegerNode.execute(inliningTarget, index);
@@ -572,7 +639,7 @@ public static Object reduce(PBigRangeIterator self, Object index,
572639
}
573640

574641
@Specialization(guards = "!isPBigRangeIterator(self)")
575-
public static Object reduce(VirtualFrame frame, PBuiltinIterator self, Object index,
642+
static Object setstate(VirtualFrame frame, PBuiltinIterator self, Object index,
576643
@Bind("this") Node inliningTarget,
577644
@Cached PyNumberAsSizeNode asSizeNode) {
578645
int idx = asSizeNode.executeExact(frame, inliningTarget, index);
@@ -583,6 +650,13 @@ public static Object reduce(VirtualFrame frame, PBuiltinIterator self, Object in
583650
return PNone.NONE;
584651
}
585652

653+
@Fallback
654+
static Object other(Object self, Object index,
655+
@Bind("this") Node inliningTarget,
656+
@Cached PRaiseNode.Lazy raiseNode) {
657+
throw raiseNode.get(inliningTarget).raise(TypeError, DESCRIPTOR_REQUIRES_S_OBJ_RECEIVED_P, "iterator", self);
658+
}
659+
586660
protected static boolean isPBigRangeIterator(Object obj) {
587661
return obj instanceof PBigRangeIterator;
588662
}

0 commit comments

Comments
 (0)