Skip to content

Commit d647e07

Browse files
committed
[GR-54988][GR-54989] Fix repr of recursive foreign array, add getMetaParents
PullRequest: graalpython/3385
2 parents b817122 + 927c314 commit d647e07

File tree

11 files changed

+223
-99
lines changed

11 files changed

+223
-99
lines changed

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@
5050
import java.io.IOException;
5151
import java.io.UnsupportedEncodingException;
5252
import java.math.BigInteger;
53+
import java.util.ArrayList;
5354
import java.util.Arrays;
5455
import java.util.HashMap;
56+
import java.util.List;
5557
import java.util.Map;
5658

5759
import org.graalvm.polyglot.Context;
@@ -772,6 +774,50 @@ public void removeUnsupportedArrayElement() throws IOException {
772774
Value foo = context.eval(suitePy);
773775
foo.execute(new UnsupportedProxyArray());
774776
}
777+
778+
@Test
779+
public void recursiveJavaListRepr() throws IOException {
780+
Source source = Source.newBuilder("python", """
781+
def foo(obj):
782+
return repr(obj)
783+
foo
784+
""", "input").build();
785+
Value foo = context.eval(source);
786+
List<Object> recursiveList = new ArrayList<>();
787+
recursiveList.add(1);
788+
recursiveList.add(recursiveList);
789+
Value result = foo.execute(recursiveList);
790+
assertEquals(result.as(String.class), "[1, [...]]");
791+
}
792+
793+
@Test
794+
public void testMetaParents() throws IOException {
795+
Source source = Source.newBuilder("python", """
796+
class Foo:
797+
pass
798+
class Bar(Foo):
799+
pass
800+
Bar
801+
""", "input").build();
802+
Value bar = context.eval(source);
803+
assertTrue(bar.isMetaObject());
804+
assertEquals(bar.getMetaSimpleName(), "Bar");
805+
assertTrue(bar.hasMetaParents());
806+
Value barParents = bar.getMetaParents();
807+
assertTrue(barParents.hasArrayElements());
808+
assertEquals(barParents.getArraySize(), 1);
809+
Value foo = barParents.getArrayElement(0);
810+
assertTrue(foo.isMetaObject());
811+
assertEquals(foo.getMetaSimpleName(), "Foo");
812+
assertTrue(foo.hasMetaParents());
813+
Value fooParents = foo.getMetaParents();
814+
assertTrue(fooParents.hasArrayElements());
815+
assertEquals(fooParents.getArraySize(), 1);
816+
Value object = fooParents.getArrayElement(0);
817+
assertTrue(object.isMetaObject());
818+
assertEquals(object.getMetaSimpleName(), "object");
819+
assertFalse(object.hasMetaParents());
820+
}
775821
}
776822

777823
@RunWith(Parameterized.class)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@
149149
import com.oracle.graal.python.runtime.PythonContext;
150150
import com.oracle.graal.python.runtime.PythonOptions;
151151
import com.oracle.graal.python.runtime.exception.PException;
152+
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
152153
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
153154
import com.oracle.graal.python.util.OverflowException;
154155
import com.oracle.graal.python.util.PythonUtils;
@@ -1498,6 +1499,41 @@ public Object getMetaObject(
14981499
}
14991500
}
15001501

1502+
@ExportMessage
1503+
public boolean hasMetaParents(
1504+
@Bind("$node") Node inliningTarget,
1505+
@Exclusive @Cached TypeNodes.IsTypeNode isTypeNode,
1506+
@Exclusive @Cached TypeNodes.GetBaseClassesNode getBaseClassNode,
1507+
@Exclusive @Cached GilNode gil) {
1508+
boolean mustRelease = gil.acquire();
1509+
try {
1510+
return isTypeNode.execute(inliningTarget, this) && getBaseClassNode.execute(inliningTarget, this).length > 0;
1511+
} finally {
1512+
gil.release(mustRelease);
1513+
}
1514+
}
1515+
1516+
@ExportMessage
1517+
public Object getMetaParents(
1518+
@Bind("$node") Node inliningTarget,
1519+
@Exclusive @Cached PythonObjectFactory factory,
1520+
@Exclusive @Cached TypeNodes.IsTypeNode isTypeNode,
1521+
@Exclusive @Cached TypeNodes.GetBaseClassesNode getBaseClassNode,
1522+
@Exclusive @Cached GilNode gil) throws UnsupportedMessageException {
1523+
boolean mustRelease = gil.acquire();
1524+
try {
1525+
if (isTypeNode.execute(inliningTarget, this)) {
1526+
var bases = getBaseClassNode.execute(inliningTarget, this);
1527+
if (bases.length > 0) {
1528+
return factory.createTuple(bases);
1529+
}
1530+
}
1531+
throw UnsupportedMessageException.create();
1532+
} finally {
1533+
gil.release(mustRelease);
1534+
}
1535+
}
1536+
15011537
@ExportMessage
15021538
public int identityHashCode(
15031539
@Bind("$node") Node inliningTarget,

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

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@
7272
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___INSTANCECHECK__;
7373
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___LEN__;
7474
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEXT__;
75+
import static com.oracle.graal.python.nodes.StringLiterals.T_COMMA_SPACE;
76+
import static com.oracle.graal.python.nodes.StringLiterals.T_ELLIPSIS_IN_BRACKETS;
77+
import static com.oracle.graal.python.nodes.StringLiterals.T_EMPTY_BRACKETS;
78+
import static com.oracle.graal.python.nodes.StringLiterals.T_LBRACKET;
79+
import static com.oracle.graal.python.nodes.StringLiterals.T_NONE;
80+
import static com.oracle.graal.python.nodes.StringLiterals.T_RBRACKET;
7581
import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING;
7682

7783
import java.math.BigInteger;
@@ -90,11 +96,9 @@
9096
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
9197
import com.oracle.graal.python.builtins.objects.function.PKeyword;
9298
import com.oracle.graal.python.builtins.objects.ints.PInt;
93-
import com.oracle.graal.python.builtins.objects.iterator.PForeignArrayIterator;
9499
import com.oracle.graal.python.builtins.objects.object.ObjectBuiltins;
95100
import com.oracle.graal.python.builtins.objects.object.ObjectNodes;
96101
import com.oracle.graal.python.builtins.objects.str.StringBuiltins;
97-
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
98102
import com.oracle.graal.python.builtins.objects.type.TpSlots;
99103
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.MpSubscriptBuiltinNode;
100104
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotGetAttr.GetAttrBuiltinNode;
@@ -103,18 +107,18 @@
103107
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSetAttr.SetAttrBuiltinNode;
104108
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotSizeArgFun.SqItemBuiltinNode;
105109
import com.oracle.graal.python.lib.PyNumberAsSizeNode;
110+
import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode;
106111
import com.oracle.graal.python.lib.PyObjectRichCompareBool;
112+
import com.oracle.graal.python.lib.PyObjectStrAsTruffleStringNode;
107113
import com.oracle.graal.python.nodes.ErrorMessages;
108114
import com.oracle.graal.python.nodes.PGuards;
109115
import com.oracle.graal.python.nodes.PRaiseNode;
110-
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
111116
import com.oracle.graal.python.nodes.expression.BinaryArithmetic;
112117
import com.oracle.graal.python.nodes.expression.BinaryArithmetic.BitAndNode;
113118
import com.oracle.graal.python.nodes.expression.BinaryArithmetic.BitOrNode;
114119
import com.oracle.graal.python.nodes.expression.BinaryArithmetic.BitXorNode;
115120
import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
116121
import com.oracle.graal.python.nodes.expression.BinaryOpNode;
117-
import com.oracle.graal.python.nodes.expression.CastToListExpressionNode.CastToListNode;
118122
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
119123
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
120124
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
@@ -162,6 +166,7 @@
162166
import com.oracle.truffle.api.profiles.InlinedBranchProfile;
163167
import com.oracle.truffle.api.profiles.InlinedConditionProfile;
164168
import com.oracle.truffle.api.strings.TruffleString;
169+
import com.oracle.truffle.api.strings.TruffleStringBuilder;
165170

166171
@CoreFunctions(extendClasses = PythonBuiltinClassType.ForeignObject)
167172
public final class ForeignObjectBuiltins extends PythonBuiltins {
@@ -1190,27 +1195,25 @@ protected static Object doIt(Object object,
11901195
@Builtin(name = J___STR__, minNumOfPositionalArgs = 1)
11911196
@GenerateNodeFactory
11921197
abstract static class StrNode extends PythonUnaryBuiltinNode {
1193-
@Child private LookupAndCallUnaryNode callStrNode;
1194-
@Child private CastToListNode castToListNode;
11951198
@Child private TruffleString.SwitchEncodingNode switchEncodingNode;
11961199

11971200
@Specialization
11981201
Object str(VirtualFrame frame, Object object,
11991202
@Bind("this") Node inliningTarget,
12001203
@CachedLibrary(limit = "3") InteropLibrary lib,
12011204
@Cached GilNode gil,
1205+
@Cached PyObjectStrAsTruffleStringNode strNode,
1206+
@Cached StrForeignArrayNode strForeignArrayNode,
12021207
@Cached InlinedBranchProfile isNull,
12031208
@Cached InlinedBranchProfile isBoolean,
12041209
@Cached InlinedBranchProfile isString,
12051210
@Cached InlinedBranchProfile isLong,
12061211
@Cached InlinedBranchProfile isDouble,
1207-
@Cached InlinedBranchProfile isArray,
1208-
@Cached InlinedBranchProfile defaultCase,
1209-
@Cached PythonObjectFactory.Lazy factory) {
1212+
@Cached InlinedBranchProfile defaultCase) {
12101213
try {
12111214
if (lib.isNull(object)) {
12121215
isNull.enter(inliningTarget);
1213-
return getCallStrNode().executeObject(frame, PNone.NONE);
1216+
return T_NONE;
12141217
} else if (lib.isBoolean(object)) {
12151218
isBoolean.enter(inliningTarget);
12161219
boolean value;
@@ -1220,7 +1223,7 @@ Object str(VirtualFrame frame, Object object,
12201223
} finally {
12211224
gil.acquire();
12221225
}
1223-
return getCallStrNode().executeObject(frame, value);
1226+
return strNode.execute(frame, inliningTarget, value);
12241227
} else if (lib.isString(object)) {
12251228
isString.enter(inliningTarget);
12261229
TruffleString value;
@@ -1230,7 +1233,7 @@ Object str(VirtualFrame frame, Object object,
12301233
} finally {
12311234
gil.acquire();
12321235
}
1233-
return getCallStrNode().executeObject(frame, getSwitchEncodingNode().execute(value, TS_ENCODING));
1236+
return strNode.execute(frame, inliningTarget, getSwitchEncodingNode().execute(value, TS_ENCODING));
12341237
} else if (lib.fitsInLong(object)) {
12351238
isLong.enter(inliningTarget);
12361239
long value;
@@ -1240,7 +1243,7 @@ Object str(VirtualFrame frame, Object object,
12401243
} finally {
12411244
gil.acquire();
12421245
}
1243-
return getCallStrNode().executeObject(frame, value);
1246+
return strNode.execute(frame, inliningTarget, value);
12441247
} else if (lib.fitsInDouble(object)) {
12451248
isDouble.enter(inliningTarget);
12461249
double value;
@@ -1250,20 +1253,9 @@ Object str(VirtualFrame frame, Object object,
12501253
} finally {
12511254
gil.acquire();
12521255
}
1253-
return getCallStrNode().executeObject(frame, value);
1256+
return strNode.execute(frame, inliningTarget, value);
12541257
} else if (lib.hasArrayElements(object)) {
1255-
isArray.enter(inliningTarget);
1256-
long size;
1257-
gil.release(true);
1258-
try {
1259-
size = lib.getArraySize(object);
1260-
} finally {
1261-
gil.acquire();
1262-
}
1263-
if (size <= Integer.MAX_VALUE && size >= 0) {
1264-
PForeignArrayIterator iterable = factory.get(inliningTarget).createForeignArrayIterator(object);
1265-
return getCallStrNode().executeObject(frame, getCastToListNode().execute(frame, iterable));
1266-
}
1258+
return strForeignArrayNode.execute(frame, object, lib);
12671259
}
12681260
} catch (UnsupportedMessageException e) {
12691261
// Fall back to the generic impl
@@ -1272,22 +1264,6 @@ Object str(VirtualFrame frame, Object object,
12721264
return defaultConversion(frame, lib, object);
12731265
}
12741266

1275-
private LookupAndCallUnaryNode getCallStrNode() {
1276-
if (callStrNode == null) {
1277-
CompilerDirectives.transferToInterpreterAndInvalidate();
1278-
callStrNode = insert(LookupAndCallUnaryNode.create(SpecialMethodSlot.Str));
1279-
}
1280-
return callStrNode;
1281-
}
1282-
1283-
private CastToListNode getCastToListNode() {
1284-
if (castToListNode == null) {
1285-
CompilerDirectives.transferToInterpreterAndInvalidate();
1286-
castToListNode = insert(CastToListNode.create());
1287-
}
1288-
return castToListNode;
1289-
}
1290-
12911267
protected TruffleString.SwitchEncodingNode getSwitchEncodingNode() {
12921268
if (switchEncodingNode == null) {
12931269
CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -1305,6 +1281,60 @@ protected TruffleString defaultConversion(@SuppressWarnings("unused") VirtualFra
13051281
}
13061282
}
13071283

1284+
@GenerateInline(false) // Uncommon path
1285+
abstract static class StrForeignArrayNode extends Node {
1286+
abstract TruffleString execute(VirtualFrame frame, Object object, InteropLibrary lib) throws UnsupportedMessageException;
1287+
1288+
@Specialization
1289+
static TruffleString str(VirtualFrame frame, Object object, InteropLibrary lib,
1290+
@Bind("this") Node inliningTarget,
1291+
@Cached GilNode gil,
1292+
@Cached PyObjectReprAsTruffleStringNode reprNode,
1293+
@Cached TruffleStringBuilder.AppendStringNode appendStringNode,
1294+
@Cached TruffleStringBuilder.ToStringNode toStringNode) throws UnsupportedMessageException {
1295+
if (!PythonContext.get(inliningTarget).reprEnter(object)) {
1296+
return T_ELLIPSIS_IN_BRACKETS;
1297+
}
1298+
try {
1299+
long length;
1300+
gil.release(true);
1301+
try {
1302+
length = lib.getArraySize(object);
1303+
} finally {
1304+
gil.acquire();
1305+
}
1306+
if (length == 0) {
1307+
return T_EMPTY_BRACKETS;
1308+
}
1309+
TruffleStringBuilder buf = TruffleStringBuilder.create(TS_ENCODING);
1310+
appendStringNode.execute(buf, T_LBRACKET);
1311+
boolean initial = true;
1312+
for (int index = 0; index < length; index++) {
1313+
if (initial) {
1314+
initial = false;
1315+
} else {
1316+
appendStringNode.execute(buf, T_COMMA_SPACE);
1317+
}
1318+
Object value;
1319+
gil.release(true);
1320+
try {
1321+
value = lib.readArrayElement(object, index);
1322+
} catch (InvalidArrayIndexException e) {
1323+
// Concurrent modification?
1324+
break;
1325+
} finally {
1326+
gil.acquire();
1327+
}
1328+
appendStringNode.execute(buf, reprNode.execute(frame, inliningTarget, value));
1329+
}
1330+
appendStringNode.execute(buf, T_RBRACKET);
1331+
return toStringNode.execute(buf);
1332+
} finally {
1333+
PythonContext.get(inliningTarget).reprLeave(object);
1334+
}
1335+
}
1336+
}
1337+
13081338
@Builtin(name = J___REPR__, minNumOfPositionalArgs = 1)
13091339
@GenerateNodeFactory
13101340
abstract static class ReprNode extends StrNode {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,8 @@ private PythonOptions() {
355355
@Option(category = OptionCategory.EXPERT, usageSyntax = "true|false", help = "If native memory tracing is enabled, also capture stack.") //
356356
public static final OptionKey<Boolean> TraceNativeMemoryCalls = new OptionKey<>(false);
357357

358-
@Option(category = OptionCategory.EXPERT, usageSyntax = "<bytes>", help = "Max native memory heap size (default: 2 GB).") //
359-
public static final OptionKey<Long> MaxNativeMemory = new OptionKey<>(1L << 31);
358+
@Option(category = OptionCategory.EXPERT, usageSyntax = "<bytes>", help = "Max native memory heap size (default: 8 GB).") //
359+
public static final OptionKey<Long> MaxNativeMemory = new OptionKey<>(1L << 33);
360360

361361
@Option(category = OptionCategory.EXPERT, usageSyntax = "<bytes>", help = "Initial native memory heap size that triggers a GC (default: 256 MB).") //
362362
public static final OptionKey<Long> InitialNativeMemory = new OptionKey<>(1L << 28);

graalpython/lib-graalpython/patches/Cython/Cython-3.0.10.patch

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ index 0a50bc5..f93b3cc 100644
303303
#else
304304
if (s1 == s2) {
305305
diff --git a/Cython/Utility/arrayarray.h b/Cython/Utility/arrayarray.h
306-
index a9e4923..cf704c9 100644
306+
index a9e4923..be07e56 100644
307307
--- a/Cython/Utility/arrayarray.h
308308
+++ b/Cython/Utility/arrayarray.h
309309
@@ -32,30 +32,31 @@ typedef struct arraydescr {
@@ -329,7 +329,7 @@ index a9e4923..cf704c9 100644
329329
+ unsigned short *as_ushorts;
330330
+ Py_UNICODE *as_pyunicodes;
331331
+ void *as_voidptr;
332-
+} __data_union
332+
+} __data_union;
333333

334334
struct arrayobject {
335335
PyObject_HEAD
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
[[rules]]
2-
version = '== 2.5.1.post0'
3-
patch = 'category-encoders-2.5.1.post0.patch'
2+
patch = 'category-encoders.patch'

0 commit comments

Comments
 (0)