Skip to content

Commit cb9ffd3

Browse files
author
Michal Medvecky
committed
[GR-64741] Implement unstar operation just using Variadic annotations
1 parent 3cfc3fc commit cb9ffd3

File tree

4 files changed

+63
-111
lines changed

4 files changed

+63
-111
lines changed

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

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -295,3 +295,30 @@ def foo():
295295
assert foo.__doc__ == 'my doc'
296296
foo2 = type(foo)(foo.__code__, foo.__globals__, foo.__name__, foo.__defaults__, foo.__closure__)
297297
assert foo2.__doc__ == 'my doc'
298+
299+
def test_args_kwargs_eval_order():
300+
l = []
301+
def a1():
302+
nonlocal l
303+
l.append(101)
304+
return 1
305+
def a2():
306+
nonlocal l
307+
l.append(102)
308+
return 1
309+
def k1():
310+
nonlocal l
311+
l.append(201)
312+
return 1
313+
def k2():
314+
nonlocal l
315+
l.append(202)
316+
return 1
317+
def k3():
318+
nonlocal l
319+
l.append(203)
320+
return 1
321+
def f(*args, **kwargs):
322+
pass
323+
f(a1(), a2(), k1=k1(), k2=k2(), k3=k3())
324+
assert l == [101, 102, 201, 202, 203]

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java

Lines changed: 27 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,8 +1094,6 @@ public BytecodeDSLCompilerResult visit(ExprTy.ListComp node) {
10941094
return buildComprehensionCodeUnit(node, node.generators, "<listcomp>",
10951095
(statementCompiler) -> {
10961096
statementCompiler.b.beginMakeList();
1097-
// TODO: GR-64741 (do not collect to array manually)
1098-
statementCompiler.b.emitLoadConstant(PythonUtils.EMPTY_OBJECT_ARRAY);
10991097
statementCompiler.b.endMakeList();
11001098
},
11011099
(statementCompiler, collection) -> {
@@ -1127,7 +1125,6 @@ public BytecodeDSLCompilerResult visit(ExprTy.SetComp node) {
11271125
return buildComprehensionCodeUnit(node, node.generators, "<setcomp>",
11281126
(statementCompiler) -> {
11291127
statementCompiler.b.beginMakeSet();
1130-
statementCompiler.b.emitLoadConstant(PythonUtils.EMPTY_OBJECT_ARRAY);
11311128
statementCompiler.b.endMakeSet();
11321129
},
11331130
(statementCompiler, collection) -> {
@@ -1788,7 +1785,9 @@ private void emitCall(ExprTy func, ExprTy[] args, KeywordTy[] keywords) {
17881785
b.emitLoadLocal(function);
17891786
b.endBlock();
17901787

1788+
b.beginCollectToObjectArray();
17911789
emitUnstar(() -> b.emitLoadLocal(receiver), args);
1790+
b.endCollectToObjectArray();
17921791
emitKeywords(keywords, function);
17931792
} else {
17941793
assert len(keywords) == 0;
@@ -1809,7 +1808,9 @@ private void emitCall(ExprTy func, ExprTy[] args, KeywordTy[] keywords) {
18091808
b.emitLoadLocal(function);
18101809
b.endBlock();
18111810

1811+
b.beginCollectToObjectArray();
18121812
emitUnstar(args);
1813+
b.endCollectToObjectArray();
18131814
emitKeywords(keywords, function);
18141815
} else {
18151816
assert len(keywords) == 0;
@@ -2011,12 +2012,9 @@ private void createConstant(ConstantValue value) {
20112012
break;
20122013
case TUPLE:
20132014
b.beginMakeTuple();
2014-
// TODO: GR-64741 (do not collect to array manually)
2015-
b.beginCollectToObjectArray();
20162015
for (ConstantValue cv : value.getTupleElements()) {
20172016
createConstant(cv);
20182017
}
2019-
b.endCollectToObjectArray();
20202018
b.endMakeTuple();
20212019
break;
20222020
case FROZENSET:
@@ -2309,97 +2307,69 @@ private void emitUnstar(Runnable initialElementsProducer, ExprTy[] args) {
23092307
private void emitUnstar(Runnable initialElementsProducer, ExprTy[] args, Runnable finalElementsProducer) {
23102308
boolean noExtraElements = initialElementsProducer == null && finalElementsProducer == null;
23112309
if (noExtraElements && len(args) == 0) {
2312-
b.emitLoadConstant(PythonUtils.EMPTY_OBJECT_ARRAY);
2310+
/**
2311+
* We don't need to emit anything for an empty array.
2312+
*/
23132313
} else if (noExtraElements && len(args) == 1 && args[0] instanceof ExprTy.Starred) {
23142314
// Optimization for single starred argument: we can just upack it. For generic
23152315
// algorithm see the next branch
2316-
b.beginUnpackStarred();
2316+
b.beginUnpackStarredVariadic();
23172317
((ExprTy.Starred) args[0]).value.accept(this);
2318-
b.endUnpackStarred();
2318+
b.endUnpackStarredVariadic();
23192319
} else if (anyIsStarred(args)) {
23202320
/**
2321-
* We emit one or more arrays and concatenate them using Unstar. Each array
2322-
* corresponds to a contiguous sequence of arguments or the result of unpacking a
2323-
* single starred argument.
2321+
* We emit one or more arrays. These are not concatenated directly, but rather
2322+
* expect that the caller is receiving them into @Variadic annotated argument, as that handles
2323+
* the concatenation. Each array corresponds to a contiguous sequence of arguments or the result
2324+
* of unpacking a single starred argument.
23242325
*
23252326
* For example, for the argument list a, b, *c, d, e, *f, g we would emit:
23262327
*
23272328
* @formatter:off
2328-
* Unstar(
2329-
* CollectToObjectArray(a, b),
2330-
* UnpackStarred(c),
2331-
* CollectToObjectArray(d, e),
2332-
* UnpackStarred(f),
2333-
* CollectToObjectArray(g)
2334-
* )
2329+
* a,
2330+
* b,
2331+
* UnpackStarredVariadic(c),
2332+
* d,
2333+
* e,
2334+
* UnpackStarredVariadic(f),
2335+
* g
23352336
* @formatter:on
2337+
*
2338+
* CollectObjectToArray is no longer necessary, as the UnpackStarredVariadic return @Variadic.
23362339
*/
2337-
b.beginUnstar();
2338-
boolean inVariadic = false;
2339-
int numOperands = 0;
2340-
23412340
if (initialElementsProducer != null) {
2342-
b.beginCollectToObjectArray();
23432341
initialElementsProducer.run();
2344-
inVariadic = true;
23452342
}
23462343

23472344
for (int i = 0; i < args.length; i++) {
23482345
if (args[i] instanceof ExprTy.Starred) {
2349-
if (inVariadic) {
2350-
b.endCollectToObjectArray();
2351-
inVariadic = false;
2352-
numOperands++;
2353-
}
2354-
2355-
b.beginUnpackStarred();
2346+
b.beginUnpackStarredVariadic();
23562347
((ExprTy.Starred) args[i]).value.accept(this);
2357-
b.endUnpackStarred();
2358-
numOperands++;
2348+
b.endUnpackStarredVariadic();
23592349
} else {
2360-
if (!inVariadic) {
2361-
b.beginCollectToObjectArray();
2362-
inVariadic = true;
2363-
}
2364-
23652350
args[i].accept(this);
23662351
}
23672352
}
23682353

23692354
if (finalElementsProducer != null) {
2370-
if (!inVariadic) {
2371-
b.beginCollectToObjectArray();
2372-
inVariadic = true;
2373-
}
23742355
finalElementsProducer.run();
23752356
}
2376-
2377-
if (inVariadic) {
2378-
b.endCollectToObjectArray();
2379-
numOperands++;
2380-
}
2381-
2382-
b.endUnstar(numOperands);
23832357
} else {
2384-
b.beginCollectToObjectArray();
23852358
if (initialElementsProducer != null) {
23862359
initialElementsProducer.run();
23872360
}
23882361
visitSequence(args);
23892362
if (finalElementsProducer != null) {
23902363
finalElementsProducer.run();
23912364
}
2392-
b.endCollectToObjectArray();
23932365
}
23942366
}
23952367

23962368
@Override
23972369
public Void visit(ExprTy.Set node) {
23982370
boolean newStatement = beginSourceSection(node, b);
23992371
b.beginMakeSet();
2400-
if (len(node.elements) == 0) {
2401-
b.emitLoadConstant(PythonUtils.EMPTY_OBJECT_ARRAY);
2402-
} else {
2372+
if (len(node.elements) != 0) {
24032373
emitUnstar(node.elements);
24042374
}
24052375
b.endMakeSet();
@@ -2814,12 +2784,9 @@ public void visitTypeParams(TypeParamTy[] typeParams) {
28142784
} else {
28152785
b.beginMakeTuple();
28162786
}
2817-
// TODO: GR-64741 (do not collect to array manually)
2818-
b.beginCollectToObjectArray();
28192787
for (TypeParamTy typeParam : typeParams) {
28202788
typeParam.accept(this);
28212789
}
2822-
b.endCollectToObjectArray();
28232790
if (useList) {
28242791
b.endMakeList();
28252792
} else {
@@ -3348,10 +3315,12 @@ private void emitBuildClass(BytecodeDSLCodeUnit body, ClassDef node) {
33483315
}
33493316

33503317
// positional args
3318+
b.beginCollectToObjectArray();
33513319
emitUnstar(() -> {
33523320
emitMakeFunction(body, node, node.name, null, null);
33533321
emitPythonConstant(toTruffleStringUncached(node.name), b);
33543322
}, node.bases, finalElements);
3323+
b.endCollectToObjectArray();
33553324

33563325
// keyword args
33573326
validateKeywords(node.keywords);

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

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,7 +1493,7 @@ public static Object perform(VirtualFrame frame,
14931493
@Operation
14941494
public static final class MakeList {
14951495
@Specialization
1496-
public static PList perform(Object[] elements,
1496+
public static PList perform(@Variadic Object[] elements,
14971497
@Bind PBytecodeDSLRootNode rootNode) {
14981498
return PFactory.createList(rootNode.getLanguage(), elements);
14991499
}
@@ -1503,14 +1503,14 @@ public static PList perform(Object[] elements,
15031503
@ImportStatic({PBytecodeDSLRootNode.class})
15041504
public static final class MakeSet {
15051505
@Specialization(guards = "elements.length == 0")
1506-
public static PSet doEmpty(VirtualFrame frame, Object[] elements,
1506+
public static PSet doEmpty(VirtualFrame frame, @Variadic Object[] elements,
15071507
@Bind PBytecodeDSLRootNode rootNode) {
15081508
// creates set backed by empty HashingStorage
15091509
return PFactory.createSet(rootNode.getLanguage());
15101510
}
15111511

15121512
@Specialization(guards = "elements.length != 0")
1513-
public static PSet doNonEmpty(VirtualFrame frame, Object[] elements,
1513+
public static PSet doNonEmpty(VirtualFrame frame, @Variadic Object[] elements,
15141514
@Bind PBytecodeDSLRootNode rootNode,
15151515
@Bind Node inliningTarget,
15161516
@Cached MakeSetStorageNode makeSetStorageNode) {
@@ -1539,7 +1539,7 @@ public static PFrozenSet doNonEmpty(VirtualFrame frame, @Variadic Object[] eleme
15391539
@Operation
15401540
public static final class MakeTuple {
15411541
@Specialization
1542-
public static Object perform(Object[] elements,
1542+
public static Object perform(@Variadic Object[] elements,
15431543
@Bind PBytecodeDSLRootNode rootNode) {
15441544
return PFactory.createTuple(rootNode.getLanguage(), elements);
15451545
}
@@ -2510,32 +2510,6 @@ public static PCell[] doMakeCellArray(@Variadic Object[] cells) {
25102510
}
25112511
}
25122512

2513-
/**
2514-
* Flattens an array of arrays. Used for splatting Starred expressions.
2515-
*/
2516-
@Operation
2517-
@ConstantOperand(type = int.class, specifyAtEnd = true)
2518-
public static final class Unstar {
2519-
@Specialization(guards = "length != 1")
2520-
public static Object[] perform(@Variadic Object[] values, int length) {
2521-
// if len <= 1, we should emit load constant "empty array", or emit just unpack starred
2522-
assert length > 1;
2523-
CompilerAsserts.partialEvaluationConstant(length);
2524-
int totalLength = 0;
2525-
for (int i = 0; i < length; i++) {
2526-
totalLength += ((Object[]) values[i]).length;
2527-
}
2528-
Object[] result = new Object[totalLength];
2529-
int idx = 0;
2530-
for (int i = 0; i < length; i++) {
2531-
int nl = ((Object[]) values[i]).length;
2532-
System.arraycopy(values[i], 0, result, idx, nl);
2533-
idx += nl;
2534-
}
2535-
return result;
2536-
}
2537-
}
2538-
25392513
@Operation
25402514
@ConstantOperand(type = LocalAccessor.class)
25412515
public static final class KwargsMerge {
@@ -2565,8 +2539,9 @@ public static PDict doMerge(VirtualFrame frame,
25652539
}
25662540

25672541
@Operation
2542+
@Variadic
25682543
@ImportStatic({PGuards.class})
2569-
public static final class UnpackStarred {
2544+
public static final class UnpackStarredVariadic {
25702545
public static boolean isListOrTuple(PSequence obj, Node inliningTarget, InlinedConditionProfile isListProfile) {
25712546
return isListProfile.profile(inliningTarget, PGuards.isBuiltinList(obj)) || PGuards.isBuiltinTuple(obj);
25722547
}
@@ -2592,7 +2567,7 @@ public static Object[] doUnpackIterable(VirtualFrame virtualFrame, Object collec
25922567
@Cached PyObjectGetIter getIter,
25932568
@Cached PyIterNextNode getNextNode,
25942569
@Cached IsBuiltinObjectProfile notIterableProfile,
2595-
@Exclusive @Cached PRaiseNode raiseNode) {
2570+
@Cached PRaiseNode raiseNode) {
25962571

25972572
Object iterator;
25982573
try {

mx.graalpython/mx_graalpython.py

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,28 +2072,9 @@ def hardcoded_ver_is_behind_major_minor(m):
20722072
return f"Hardcoded version in `{m.group().strip()}` should have {GRAAL_VERSION_MAJ_MIN} as <major>.<minor> version."
20732073

20742074
files_with_versions = {
2075-
"graalpython/graalpy-maven-plugin/pom.xml": {
2076-
r"^ <version>(\d+\.\d+)(?:\.\d+)*</version>" : hardcoded_ver_is_behind_major_minor,
2077-
r'<graalpy.version>(\d+\.\d+)(?:\.\d+)*</graalpy.version>' : hardcoded_ver_is_behind_major_minor
2078-
},
20792075
"graalpython/com.oracle.graal.python.test.integration/pom.xml": {
20802076
r'<com.oracle.graal.python.test.polyglot.version>(\d+\.\d+)(?:\.\d+)*' : hardcoded_ver_is_behind_major_minor,
2081-
},
2082-
"graalpython/graalpy-archetype-polyglot-app/pom.xml": {
2083-
r"^ <version>(\d+\.\d+)(?:\.\d+)*</version>" : hardcoded_ver_is_behind_major_minor,
2084-
},
2085-
"graalpython/graalpy-jbang/examples/hello.java": {
2086-
r"//DEPS org.graalvm.python:jbang[^:]*:\${env.GRAALPY_VERSION:(\d+\.\d+)(?:\.\d+)*" : hardcoded_ver_is_behind_major_minor,
2087-
},
2088-
"graalpython/graalpy-jbang/templates/graalpy-template_local_repo.java.qute": {
2089-
r"//DEPS org.graalvm.python:jbang[^:]*:\${env.GRAALPY_VERSION:(\d+\.\d+)(?:\.\d+)*" : hardcoded_ver_is_behind_major_minor,
2090-
},
2091-
"graalpython/graalpy-jbang/templates/graalpy-template.java.qute": {
2092-
r"//DEPS org.graalvm.python:jbang[^:]*:\${env.GRAALPY_VERSION:(\d+\.\d+)(?:\.\d+)*" : hardcoded_ver_is_behind_major_minor,
2093-
},
2094-
"graalpython/graalpy-archetype-polyglot-app/src/main/resources/archetype-resources/pom.xml": {
2095-
r'<graalpy.version>(\d+\.\d+)(?:\.\d+)*</graalpy.version>' : hardcoded_ver_is_behind_major_minor,
2096-
},
2077+
}
20972078
}
20982079
replacements = set()
20992080
for path, patterns in files_with_versions.items():

0 commit comments

Comments
 (0)