Skip to content

Commit fdcf508

Browse files
committed
Use PyTuple nodes during string formatting as CPython does
1 parent 740cb40 commit fdcf508

File tree

7 files changed

+60
-26
lines changed

7 files changed

+60
-26
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
def test_platform_uname():
41+
import platform
42+
assert repr(platform.uname()), "should not raise"

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@
9696
import com.oracle.graal.python.builtins.objects.iterator.PSequenceIterator;
9797
import com.oracle.graal.python.builtins.objects.list.PList;
9898
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
99-
import com.oracle.graal.python.builtins.objects.tuple.TupleBuiltins;
10099
import com.oracle.graal.python.builtins.objects.type.TpSlots;
101100
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.SqConcatBuiltinNode;
102101
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryOp.BinaryOpBuiltinNode;
@@ -356,13 +355,12 @@ static Object mod(VirtualFrame frame, Object self, Object right,
356355
@Cached("createFor(this)") IndirectCallData indirectCallData,
357356
@CachedLibrary(limit = "3") PythonBufferAcquireLibrary acquireLib,
358357
@CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib,
359-
@Cached BytesNodes.CreateBytesNode create,
360-
@Cached TupleBuiltins.GetItemNode getTupleItemNode) {
358+
@Cached BytesNodes.CreateBytesNode create) {
361359
Object buffer = acquireLib.acquireReadonly(self, frame, indirectCallData);
362360
try {
363361
byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer);
364362
int bytesLen = bufferLib.getBufferLength(buffer);
365-
BytesFormatProcessor formatter = new BytesFormatProcessor(PythonContext.get(inliningTarget), getTupleItemNode, bytes, bytesLen, inliningTarget);
363+
BytesFormatProcessor formatter = new BytesFormatProcessor(PythonContext.get(inliningTarget), bytes, bytesLen, inliningTarget);
366364
Object savedState = IndirectCallContext.enter(frame, inliningTarget, indirectCallData);
367365
try {
368366
byte[] data = formatter.format(right);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@
117117
import com.oracle.graal.python.builtins.objects.str.StringNodes.StringReplaceNode;
118118
import com.oracle.graal.python.builtins.objects.str.StringUtils.StripKind;
119119
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
120-
import com.oracle.graal.python.builtins.objects.tuple.TupleBuiltins;
121120
import com.oracle.graal.python.builtins.objects.type.TpSlots;
122121
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
123122
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotBinaryFunc.MpSubscriptBuiltinNode;
@@ -1871,14 +1870,13 @@ static Object doGeneric(VirtualFrame frame, Object self, Object right,
18711870
@SuppressWarnings("unused") @Cached PyUnicodeCheckNode check,
18721871
@Cached("createFor(this)") IndirectCallData indirectCallData,
18731872
@Cached CastToJavaStringCheckedNode castSelfNode,
1874-
@Cached TupleBuiltins.GetItemNode getTupleItemNode,
18751873
@Cached TruffleString.FromJavaStringNode fromJavaStringNode) {
18761874
String selfStr = castSelfNode.cast(inliningTarget, self, ErrorMessages.REQUIRES_STR_OBJECT_BUT_RECEIVED_P, T___MOD__, self);
18771875
PythonContext context = PythonContext.get(inliningTarget);
18781876
PythonLanguage language = context.getLanguage(inliningTarget);
18791877
Object state = IndirectCallContext.enter(frame, language, context, indirectCallData);
18801878
try {
1881-
return fromJavaStringNode.execute(new StringFormatProcessor(context, getTupleItemNode, selfStr, inliningTarget).format(assertNoJavaString(right)), TS_ENCODING);
1879+
return fromJavaStringNode.execute(new StringFormatProcessor(context, selfStr, inliningTarget).format(assertNoJavaString(right)), TS_ENCODING);
18821880
} finally {
18831881
IndirectCallContext.exit(frame, language, context, state);
18841882
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyTupleSizeNode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@
6767
@GenerateInline
6868
@GenerateCached(false)
6969
public abstract class PyTupleSizeNode extends PNodeWithContext {
70+
public static int executeUncached(Object tuple) {
71+
return PyTupleSizeNodeGen.getUncached().execute(null, tuple);
72+
}
73+
7074
public abstract int execute(Node inliningTarget, Object tuple);
7175

7276
@Specialization

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/formatting/BytesFormatProcessor.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
import com.oracle.graal.python.builtins.objects.ints.PInt;
6262
import com.oracle.graal.python.builtins.objects.str.PString;
6363
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
64-
import com.oracle.graal.python.builtins.objects.tuple.TupleBuiltins;
6564
import com.oracle.graal.python.lib.PyMappingCheckNode;
6665
import com.oracle.graal.python.lib.PyObjectAsciiNode;
6766
import com.oracle.graal.python.nodes.ErrorMessages;
@@ -78,8 +77,8 @@ public class BytesFormatProcessor extends FormatProcessor<byte[]> {
7877
private final byte[] formatBytes;
7978
private final int bytesLength;
8079

81-
public BytesFormatProcessor(Python3Core core, TupleBuiltins.GetItemNode getTupleItemNode, byte[] formatBytes, int bytesLength, Node raisingNode) {
82-
super(core, getTupleItemNode, new BytesFormattingBuffer(), raisingNode);
80+
public BytesFormatProcessor(Python3Core core, byte[] formatBytes, int bytesLength, Node raisingNode) {
81+
super(core, new BytesFormattingBuffer(), raisingNode);
8382
this.formatBytes = formatBytes;
8483
this.bytesLength = bytesLength;
8584
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/formatting/FormatProcessor.java

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
2121
import com.oracle.graal.python.builtins.objects.function.PKeyword;
2222
import com.oracle.graal.python.builtins.objects.ints.PInt;
23-
import com.oracle.graal.python.builtins.objects.tuple.TupleBuiltins;
2423
import com.oracle.graal.python.lib.PyFloatAsDoubleNode;
2524
import com.oracle.graal.python.lib.PyNumberCheckNode;
2625
import com.oracle.graal.python.lib.PyNumberIndexNode;
2726
import com.oracle.graal.python.lib.PyNumberLongNode;
2827
import com.oracle.graal.python.lib.PyObjectGetItem;
29-
import com.oracle.graal.python.lib.PyObjectSizeNode;
28+
import com.oracle.graal.python.lib.PyTupleGetItem;
29+
import com.oracle.graal.python.lib.PyTupleSizeNode;
3030
import com.oracle.graal.python.nodes.ErrorMessages;
3131
import com.oracle.graal.python.nodes.PGuards;
3232
import com.oracle.graal.python.nodes.PRaiseNode;
@@ -58,17 +58,15 @@ abstract class FormatProcessor<T> {
5858
/** see {@link #getArg()} for the meaning of this value. */
5959
private int argIndex = -1;
6060
private Object args;
61-
private final TupleBuiltins.GetItemNode getTupleItemNode;
6261

6362
protected int index;
6463
protected final Python3Core core;
6564
protected final Node raisingNode;
6665
protected final FormattingBuffer buffer;
6766

68-
public FormatProcessor(Python3Core core, TupleBuiltins.GetItemNode getTupleItemNode, FormattingBuffer buffer, Node raisingNode) {
67+
public FormatProcessor(Python3Core core, FormattingBuffer buffer, Node raisingNode) {
6968
this.core = core;
7069
this.raisingNode = raisingNode;
71-
this.getTupleItemNode = getTupleItemNode;
7270
this.buffer = buffer;
7371
index = 0;
7472
}
@@ -101,10 +99,6 @@ static Object call(Object callable, Object... args) {
10199
return CallNode.executeUncached(callable, args, PKeyword.EMPTY_KEYWORDS);
102100
}
103101

104-
Object getItem(Object arg, Object arg2) {
105-
return PyObjectGetItem.executeUncached(arg, arg2);
106-
}
107-
108102
Object getArg() {
109103
Object ret = null;
110104
switch (argIndex) {
@@ -121,7 +115,7 @@ Object getArg() {
121115
// directly, so the only error can be IndexError, which we ignore and transform into
122116
// the TypeError below.
123117
try {
124-
ret = getTupleItemNode.execute(null, args, argIndex++);
118+
ret = PyTupleGetItem.executeUncached(args, argIndex++);
125119
} catch (PException e) {
126120
// fall through
127121
}
@@ -174,7 +168,7 @@ private static boolean useIndexMagicMethod(char specType) {
174168
return specType == 'x' || specType == 'X' || specType == 'o' || specType == 'c';
175169
}
176170

177-
protected final Object asNumber(Object arg, char specType) {
171+
protected static Object asNumber(Object arg, char specType) {
178172
if (arg instanceof Integer || arg instanceof Long || arg instanceof PInt) {
179173
// arg is already acceptable
180174
return arg;
@@ -328,7 +322,7 @@ private T formatImpl(Object args1) {
328322
Object tmp = parseMappingKey(keyStart, index - 1);
329323
// Look it up using this extent as the (right type of) key. The caller must have
330324
// pushed the frame.
331-
this.args = getItem(mapping, tmp);
325+
this.args = PyObjectGetItem.executeUncached(mapping, tmp);
332326
} else {
333327
// Not a mapping key: next clause will re-read c.
334328
push();
@@ -489,7 +483,7 @@ private T formatImpl(Object args1) {
489483
* of range; if a special value, it would be wrong if it were -1, indicating a single item
490484
* that has not yet been used.
491485
*/
492-
if (argIndex == -1 || (argIndex >= 0 && PyObjectSizeNode.executeUncached(args1) >= argIndex + 1)) {
486+
if (argIndex == -1 || (argIndex >= 0 && PyTupleSizeNode.executeUncached(args1) >= argIndex + 1)) {
493487
throw PRaiseNode.raiseStatic(raisingNode, TypeError, ErrorMessages.NOT_ALL_ARGS_CONVERTED_DURING_FORMATTING, getFormatType());
494488
}
495489

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/formatting/StringFormatProcessor.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import com.oracle.graal.python.builtins.Python3Core;
1616
import com.oracle.graal.python.builtins.objects.str.PString;
1717
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
18-
import com.oracle.graal.python.builtins.objects.tuple.TupleBuiltins;
1918
import com.oracle.graal.python.lib.PyMappingCheckNode;
2019
import com.oracle.graal.python.lib.PyObjectAsciiNode;
2120
import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode;
@@ -29,8 +28,8 @@
2928
public final class StringFormatProcessor extends FormatProcessor<String> {
3029
private final String formatText;
3130

32-
public StringFormatProcessor(Python3Core core, TupleBuiltins.GetItemNode getTupleItemNode, String format, Node raisingNode) {
33-
super(core, getTupleItemNode, new FormattingBuffer.StringFormattingBuffer(format.length() + 100), raisingNode);
31+
public StringFormatProcessor(Python3Core core, String format, Node raisingNode) {
32+
super(core, new FormattingBuffer.StringFormattingBuffer(format.length() + 100), raisingNode);
3433
index = 0;
3534
this.formatText = format;
3635
}

0 commit comments

Comments
 (0)