Skip to content

Commit e6070b4

Browse files
committed
Avoid generic NormalizeIndexWithBoundsCheckNode in fast-paths of PBytecodeDSLRootNode.BinarySubscript; add sequence storage strategies tests
1 parent 31c4643 commit e6070b4

File tree

7 files changed

+166
-20
lines changed

7 files changed

+166
-20
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Copyright (c) 2020, 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+
import sys
40+
41+
42+
if sys.implementation.name == "graalpy":
43+
if not hasattr(__graalpython__, 'get_storage_strategy'):
44+
raise SystemError("This test must run with --python.EnableDebuggingBuiltins=true")
45+
46+
def check_strategy(container, expected):
47+
actual = __graalpython__.get_storage_strategy(container)
48+
assert actual == expected, f"Container '{container}', wrong storage strategy: '{actual}' != '{expected}'"
49+
else:
50+
# For CPython, just to verify other test results
51+
def check_strategy(container, expected):
52+
pass
53+
54+
55+
def test_appending_ints():
56+
l = list()
57+
for i in range(10):
58+
l.append(i)
59+
assert l[5] == 5
60+
check_strategy(l, "IntSequenceStorage")
61+
62+
63+
def test_appending_doubles():
64+
l = list()
65+
for i in range(10):
66+
l.append(i * 0.1)
67+
assert l[5] == 0.5
68+
check_strategy(l, "DoubleSequenceStorage")
69+
70+
71+
def test_generator_int():
72+
l = [x for x in range(10)]
73+
assert l[5] == 5
74+
check_strategy(l, "IntSequenceStorage")
75+
76+
77+
def test_generator_double():
78+
l = [x * 0.1 for x in range(10)]
79+
assert l[5] == 0.5
80+
check_strategy(l, "DoubleSequenceStorage")
81+
82+
83+
# GR-70364
84+
# def test_generator_bool():
85+
# l = [x >= 5 for x in range(10)]
86+
# assert l[5] == True
87+
# check_strategy(l, "BoolSequenceStorage")
88+
89+
90+
def test_literal_int():
91+
l = [1,2,3,4,5]
92+
assert l[4] == 5
93+
check_strategy(l, "IntSequenceStorage")
94+
95+
96+
def test_literal_double():
97+
l = [1.1,2.2,3.3,4.4,0.5]
98+
assert l[4] == 0.5
99+
check_strategy(l, "DoubleSequenceStorage")
100+
101+
102+
def test_literal_mixed():
103+
l = [1,2,3,4,0.5]
104+
assert l[4] == 0.5
105+
check_strategy(l, "ObjectSequenceStorage")

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ public void postInitialize(Python3Core core) {
270270
mod.setAttribute(tsLiteral("dump_truffle_ast"), PNone.NO_VALUE);
271271
mod.setAttribute(tsLiteral("tdebug"), PNone.NO_VALUE);
272272
mod.setAttribute(tsLiteral("set_storage_strategy"), PNone.NO_VALUE);
273+
mod.setAttribute(tsLiteral("get_storage_strategy"), PNone.NO_VALUE);
273274
mod.setAttribute(tsLiteral("storage_to_native"), PNone.NO_VALUE);
274275
mod.setAttribute(tsLiteral("dump_heap"), PNone.NO_VALUE);
275276
mod.setAttribute(tsLiteral("is_native_object"), PNone.NO_VALUE);
@@ -693,7 +694,7 @@ static long doIt(@SuppressWarnings("unused") Object dummy) {
693694
}
694695
}
695696

696-
// Internal builtin used for testing: changes strategy of newly allocated set or map
697+
// Internal builtin used for testing: changes strategy of newly allocated set or map
697698
@Builtin(name = "set_storage_strategy", minNumOfPositionalArgs = 2)
698699
@GenerateNodeFactory
699700
public abstract static class SetStorageStrategyNode extends PythonBinaryBuiltinNode {
@@ -734,6 +735,16 @@ private void validate(HashingStorage dictStorage) {
734735
}
735736
}
736737

738+
@Builtin(name = "get_storage_strategy", minNumOfPositionalArgs = 1)
739+
@GenerateNodeFactory
740+
public abstract static class GetStorageStrategyNode extends PythonUnaryBuiltinNode {
741+
@Specialization
742+
@TruffleBoundary
743+
TruffleString doSet(PSequence seq) {
744+
return PythonUtils.toTruffleStringUncached(seq.getSequenceStorage().getClass().getSimpleName());
745+
}
746+
}
747+
737748
@Builtin(name = "storage_to_native", minNumOfPositionalArgs = 1)
738749
@GenerateNodeFactory
739750
abstract static class StorageToNative extends PythonUnaryBuiltinNode {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/IndexNodes.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@
4444
import com.oracle.graal.python.builtins.objects.common.IndexNodesFactory.NormalizeIndexWithBoundsCheckNodeGen;
4545
import com.oracle.graal.python.builtins.objects.common.IndexNodesFactory.NormalizeIndexWithoutBoundsCheckNodeGen;
4646
import com.oracle.graal.python.builtins.objects.ints.PInt;
47+
import com.oracle.graal.python.builtins.objects.list.PList;
4748
import com.oracle.graal.python.nodes.ErrorMessages;
4849
import com.oracle.graal.python.nodes.PRaiseNode;
50+
import com.oracle.graal.python.runtime.sequence.PTupleListBase;
4951
import com.oracle.graal.python.util.OverflowException;
5052
import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff;
5153
import com.oracle.truffle.api.dsl.Bind;
@@ -159,6 +161,16 @@ public static NormalizeIndexWithBoundsCheckNode getUncached() {
159161
return NormalizeIndexWithBoundsCheckNodeGen.getUncached();
160162
}
161163

164+
public static int normalizeIntIndex(Node inliningTarget, int index, int length, PTupleListBase container,
165+
InlinedConditionProfile negativeIndexProfile, PRaiseNode raiseNode) {
166+
int normalizedIndex = index;
167+
if (negativeIndexProfile.profile(inliningTarget, normalizedIndex < 0)) {
168+
normalizedIndex += length;
169+
}
170+
checkBounds(inliningTarget, raiseNode, container, normalizedIndex, length);
171+
return normalizedIndex;
172+
}
173+
162174
@Specialization
163175
static int doInt(int index, int length, TruffleString errorMessage,
164176
@Bind Node inliningTarget,
@@ -322,6 +334,12 @@ static long doLongLong(long index, long length, @SuppressWarnings("unused") Truf
322334
}
323335
}
324336

337+
public static void checkBounds(Node inliningTarget, PRaiseNode raiseNode, PTupleListBase container, int idx, int length) {
338+
if (idx < 0 || idx >= length) {
339+
raiseIndexError(inliningTarget, container, raiseNode);
340+
}
341+
}
342+
325343
public static void checkBounds(Node inliningTarget, PRaiseNode raiseNode, TruffleString errorMessage, int idx, int length) {
326344
if (idx < 0 || idx >= length) {
327345
raiseIndexError(inliningTarget, errorMessage, raiseNode);
@@ -340,6 +358,12 @@ public static void checkBounds(Node inliningTarget, PRaiseNode raiseNode, Truffl
340358
}
341359
}
342360

361+
@InliningCutoff
362+
private static void raiseIndexError(Node inliningTarget, PTupleListBase container, PRaiseNode raiseNode) {
363+
TruffleString errorMessage = container instanceof PList ? ErrorMessages.LIST_INDEX_OUT_OF_RANGE : ErrorMessages.TUPLE_OUT_OF_BOUNDS;
364+
raiseIndexError(inliningTarget, errorMessage, raiseNode);
365+
}
366+
343367
@InliningCutoff
344368
private static void raiseIndexError(Node inliningTarget, TruffleString errorMessage, PRaiseNode raiseNode) {
345369
throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.IndexError, errorMessage);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/PList.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode;
3535
import com.oracle.graal.python.runtime.GilNode;
3636
import com.oracle.graal.python.runtime.exception.PException;
37-
import com.oracle.graal.python.runtime.sequence.PSequenceWithStorage;
37+
import com.oracle.graal.python.runtime.sequence.PTupleListBase;
3838
import com.oracle.graal.python.runtime.sequence.storage.ArrayBasedSequenceStorage;
3939
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
4040
import com.oracle.graal.python.util.OverflowException;
@@ -57,7 +57,7 @@
5757

5858
@SuppressWarnings("truffle-abstract-export")
5959
@ExportLibrary(InteropLibrary.class)
60-
public final class PList extends PSequenceWithStorage {
60+
public final class PList extends PTupleListBase {
6161
private final ListOrigin origin;
6262

6363
public PList(Object cls, Shape instanceShape, SequenceStorage store) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/PTuple.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
import static com.oracle.graal.python.util.PythonUtils.builtinClassToType;
2929

30-
import com.oracle.graal.python.runtime.sequence.PSequenceWithStorage;
30+
import com.oracle.graal.python.runtime.sequence.PTupleListBase;
3131
import com.oracle.graal.python.runtime.sequence.storage.ObjectSequenceStorage;
3232
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
3333
import com.oracle.truffle.api.CompilerAsserts;
@@ -40,7 +40,7 @@
4040

4141
@SuppressWarnings("truffle-abstract-export")
4242
@ExportLibrary(InteropLibrary.class)
43-
public final class PTuple extends PSequenceWithStorage {
43+
public final class PTuple extends PTupleListBase {
4444

4545
private long hash = -1;
4646

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@
217217
import com.oracle.graal.python.runtime.exception.PythonErrorType;
218218
import com.oracle.graal.python.runtime.object.PFactory;
219219
import com.oracle.graal.python.runtime.sequence.PSequence;
220-
import com.oracle.graal.python.runtime.sequence.PSequenceWithStorage;
220+
import com.oracle.graal.python.runtime.sequence.PTupleListBase;
221221
import com.oracle.graal.python.runtime.sequence.storage.BoolSequenceStorage;
222222
import com.oracle.graal.python.runtime.sequence.storage.DoubleSequenceStorage;
223223
import com.oracle.graal.python.runtime.sequence.storage.EmptySequenceStorage;
@@ -3219,45 +3219,51 @@ public static boolean doObject(long typeFlags, Object value,
32193219
@Operation(storeBytecodeIndex = true)
32203220
@ImportStatic(PGuards.class)
32213221
public static final class BinarySubscript {
3222-
static boolean isBuiltinListOrTuple(PSequenceWithStorage s) {
3222+
static boolean isBuiltinListOrTuple(PTupleListBase s) {
32233223
return PGuards.isBuiltinTuple(s) || PGuards.isBuiltinList(s);
32243224
}
32253225

3226-
public static boolean isIntBuiltinListOrTuple(PSequenceWithStorage s) {
3226+
public static boolean isIntBuiltinListOrTuple(PTupleListBase s) {
32273227
return isBuiltinListOrTuple(s) && s.getSequenceStorage() instanceof IntSequenceStorage;
32283228
}
32293229

32303230
@Specialization(guards = "isIntBuiltinListOrTuple(list)")
3231-
public static int doIntStorage(PSequenceWithStorage list, int index,
3232-
@Shared @Cached NormalizeIndexWithBoundsCheckNode normalizeIndexNode) {
3231+
public static int doIntStorage(PTupleListBase list, int index,
3232+
@Bind Node inliningTarget,
3233+
@Shared @Cached InlinedConditionProfile negativeIndexProfile,
3234+
@Shared @Cached PRaiseNode raiseNode) {
32333235
IntSequenceStorage storage = (IntSequenceStorage) list.getSequenceStorage();
3234-
int normalizedIndex = normalizeIndexNode.execute(index, storage.length(), ErrorMessages.LIST_INDEX_OUT_OF_RANGE);
3236+
int normalizedIndex = NormalizeIndexWithBoundsCheckNode.normalizeIntIndex(inliningTarget, index, storage.length(), list, negativeIndexProfile, raiseNode);
32353237
return storage.getIntItemNormalized(normalizedIndex);
32363238
}
32373239

3238-
public static boolean isDoubleBuiltinListOrTuple(PSequenceWithStorage s) {
3240+
public static boolean isDoubleBuiltinListOrTuple(PTupleListBase s) {
32393241
return isBuiltinListOrTuple(s) && s.getSequenceStorage() instanceof DoubleSequenceStorage;
32403242
}
32413243

32423244
@Specialization(guards = "isDoubleBuiltinListOrTuple(list)")
3243-
public static double doDoubleStorage(PSequenceWithStorage list, int index,
3244-
@Shared @Cached NormalizeIndexWithBoundsCheckNode normalizeIndexNode) {
3245+
public static double doDoubleStorage(PTupleListBase list, int index,
3246+
@Bind Node inliningTarget,
3247+
@Shared @Cached InlinedConditionProfile negativeIndexProfile,
3248+
@Shared @Cached PRaiseNode raiseNode) {
32453249
DoubleSequenceStorage storage = (DoubleSequenceStorage) list.getSequenceStorage();
3246-
int normalizedIndex = normalizeIndexNode.execute(index, storage.length(), ErrorMessages.LIST_INDEX_OUT_OF_RANGE);
3250+
int normalizedIndex = NormalizeIndexWithBoundsCheckNode.normalizeIntIndex(inliningTarget, index, storage.length(), list, negativeIndexProfile, raiseNode);
32473251
return storage.getDoubleItemNormalized(normalizedIndex);
32483252
}
32493253

32503254
@Specialization(replaces = {"doIntStorage", "doDoubleStorage"}, guards = "isBuiltinListOrTuple(list)")
3251-
public static Object doObjectStorage(PSequenceWithStorage list, int index,
3255+
public static Object doGenericStorage(PTupleListBase list, int index,
32523256
@Bind Node inliningTarget,
3253-
@Shared @Cached NormalizeIndexWithBoundsCheckNode normalizeIndexNode,
3257+
@Exclusive @Cached InlinedConditionProfile negativeIndexProfile,
3258+
@Exclusive @Cached PRaiseNode raiseNode,
32543259
@Cached GetItemScalarNode getItemScalarNode) {
32553260
SequenceStorage storage = list.getSequenceStorage();
3256-
int normalizedIndex = normalizeIndexNode.execute(index, storage.length(), ErrorMessages.LIST_INDEX_OUT_OF_RANGE);
3261+
int normalizedIndex = NormalizeIndexWithBoundsCheckNode.normalizeIntIndex(inliningTarget, index, storage.length(), list, negativeIndexProfile, raiseNode);
32573262
return getItemScalarNode.execute(inliningTarget, storage, normalizedIndex);
32583263
}
32593264

32603265
@Fallback
3266+
@InliningCutoff
32613267
public static Object doOther(VirtualFrame frame, Object receiver, Object key,
32623268
@Bind Node inliningTarget,
32633269
@Cached GetObjectSlotsNode getSlotsNode,
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@
4444
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
4545
import com.oracle.truffle.api.object.Shape;
4646

47-
public abstract class PSequenceWithStorage extends PSequence {
47+
public abstract class PTupleListBase extends PSequence {
4848
protected SequenceStorage store;
4949

50-
public PSequenceWithStorage(Object cls, Shape instanceShape) {
50+
public PTupleListBase(Object cls, Shape instanceShape) {
5151
super(cls, instanceShape);
5252
}
5353

0 commit comments

Comments
 (0)