Skip to content

Commit d3a568b

Browse files
committed
simplify PositionalArgumentsNode and produce fewer nodes for calls
1 parent ff3ceb6 commit d3a568b

File tree

6 files changed

+99
-97
lines changed

6 files changed

+99
-97
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/NodeFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ public PNode createDictionaryConcat(PNode... dictNodes) {
518518
}
519519

520520
public PNode callBuiltin(String string, PNode argument) {
521-
return PythonCallNode.create(getBuiltin(string), new PNode[]{argument}, new PNode[0], EmptyNode.create(), EmptyNode.create());
521+
return PythonCallNode.create(getBuiltin(string), new PNode[]{argument}, new PNode[0], null, null);
522522
}
523523

524524
public PNode createSetAttribute(PNode object, String key, PNode rhs) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/keywords/KeywordArgumentsNode.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,19 @@
2828
import com.oracle.graal.python.builtins.objects.function.PKeyword;
2929
import com.oracle.graal.python.nodes.EmptyNode;
3030
import com.oracle.graal.python.nodes.PNode;
31+
import com.oracle.graal.python.runtime.PythonOptions;
3132
import com.oracle.truffle.api.CompilerAsserts;
3233
import com.oracle.truffle.api.dsl.Cached;
34+
import com.oracle.truffle.api.dsl.ImportStatic;
3335
import com.oracle.truffle.api.dsl.NodeChild;
34-
import com.oracle.truffle.api.dsl.NodeChildren;
3536
import com.oracle.truffle.api.dsl.Specialization;
3637
import com.oracle.truffle.api.frame.VirtualFrame;
3738
import com.oracle.truffle.api.nodes.ExplodeLoop;
39+
import com.oracle.truffle.api.nodes.Node;
3840

39-
@NodeChildren({@NodeChild(value = "splat", type = ExecuteKeywordStarargsNode.class)})
40-
public abstract class KeywordArgumentsNode extends PNode {
41+
@NodeChild(value = "splat", type = ExecuteKeywordStarargsNode.class)
42+
@ImportStatic(PythonOptions.class)
43+
public abstract class KeywordArgumentsNode extends Node {
4144
@Children private final PNode[] arguments;
4245
@Child private CompactKeywordsNode compactNode = CompactKeywordsNodeGen.create();
4346

@@ -49,7 +52,6 @@ public static KeywordArgumentsNode create(PNode[] arguments, PNode starargs) {
4952
this.arguments = arguments;
5053
}
5154

52-
@Override
5355
public abstract PKeyword[] execute(VirtualFrame frame);
5456

5557
@Specialization(guards = "starargs.length == cachedLen", limit = "getVariableArgumentInlineCacheLimit()")

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/positional/PositionalArgumentsNode.java

Lines changed: 29 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -25,93 +25,39 @@
2525
*/
2626
package com.oracle.graal.python.nodes.argument.positional;
2727

28-
import com.oracle.graal.python.nodes.EmptyNode;
2928
import com.oracle.graal.python.nodes.PNode;
3029
import com.oracle.truffle.api.CompilerAsserts;
31-
import com.oracle.truffle.api.dsl.Cached;
32-
import com.oracle.truffle.api.dsl.NodeChild;
33-
import com.oracle.truffle.api.dsl.NodeChildren;
34-
import com.oracle.truffle.api.dsl.Specialization;
3530
import com.oracle.truffle.api.frame.VirtualFrame;
3631
import com.oracle.truffle.api.nodes.ExplodeLoop;
32+
import com.oracle.truffle.api.nodes.Node;
33+
import com.oracle.truffle.api.profiles.PrimitiveValueProfile;
3734

38-
@NodeChildren({@NodeChild(value = "primary"), @NodeChild(value = "splat", type = ExecutePositionalStarargsNode.class)})
39-
public abstract class PositionalArgumentsNode extends PNode {
40-
@Children private final PNode[] arguments;
35+
public final class PositionalArgumentsNode extends Node {
4136

42-
public static PositionalArgumentsNode create(PNode[] arguments, PNode starargs) {
43-
return PositionalArgumentsNodeGen.create(arguments, EmptyNode.create(), ExecutePositionalStarargsNode.create(starargs == null ? EmptyNode.create() : starargs));
37+
public static PositionalArgumentsNode create(PNode[] arguments, PNode starArgs) {
38+
assert starArgs != null;
39+
return new PositionalArgumentsNode(arguments, ExecutePositionalStarargsNode.create(starArgs));
4440
}
4541

46-
public static PositionalArgumentsNode create() {
47-
return PositionalArgumentsNodeGen.create(new PNode[0], EmptyNode.create(), ExecutePositionalStarargsNode.create(EmptyNode.create()));
48-
}
49-
50-
PositionalArgumentsNode(PNode[] arguments) {
51-
this.arguments = arguments;
52-
}
53-
54-
public int getArgumentLength() {
55-
return arguments.length;
56-
}
42+
@Children protected final PNode[] arguments;
43+
@Child private ExecutePositionalStarargsNode starArgs;
5744

58-
@Override
59-
public final Object[] execute(VirtualFrame frame) {
60-
return execute(frame, null);
61-
}
62-
63-
public abstract Object[] execute(VirtualFrame frame, Object primary);
64-
65-
protected abstract Object[] executeWithArguments(VirtualFrame frame, Object primary, Object[] starargs);
45+
private final PrimitiveValueProfile starArgsLengthProfile = PrimitiveValueProfile.createEqualityProfile();
6646

67-
public final Object[] executeWithArguments(Object primary, Object[] starargs) {
68-
assert arguments.length == 0;
69-
return executeWithArguments(null, primary, starargs);
47+
public PositionalArgumentsNode(PNode[] arguments, ExecutePositionalStarargsNode starArgs) {
48+
this.arguments = arguments;
49+
this.starArgs = starArgs;
7050
}
7151

72-
@Specialization(guards = {"starargs.length == starLen", "(primary == null) == primaryWasNull"}, limit = "getVariableArgumentInlineCacheLimit()")
7352
@ExplodeLoop
74-
Object[] argumentsCached(VirtualFrame frame, Object primary, Object[] starargs,
75-
@Cached("starargs.length") int starLen,
76-
@Cached("primary == null") boolean primaryWasNull) {
77-
final int argLen = arguments.length;
78-
CompilerAsserts.partialEvaluationConstant(primaryWasNull);
79-
int offset = 0;
80-
if (!primaryWasNull) {
81-
offset = 1;
82-
}
83-
CompilerAsserts.partialEvaluationConstant(offset);
84-
final int length = argLen + starLen + offset;
85-
CompilerAsserts.partialEvaluationConstant(length);
86-
final Object[] values = new Object[length];
87-
if (!primaryWasNull) {
88-
values[0] = primary;
89-
}
90-
for (int i = 0; i < argLen; i++) {
91-
values[offset + i] = arguments[i].execute(frame);
92-
}
93-
for (int i = 0; i < starLen; i++) {
94-
values[offset + argLen + i] = starargs[i];
95-
}
96-
return values;
97-
}
98-
99-
@Specialization(replaces = "argumentsCached")
100-
Object[] arguments(VirtualFrame frame, Object primary, Object[] starargs) {
101-
final int argLen = arguments.length;
102-
final int starLen = starargs.length;
103-
int offset = primary == null ? 0 : 1;
104-
final int length = argLen + starLen + offset;
105-
final Object[] values = new Object[length];
106-
if (primary != null) {
107-
values[0] = primary;
108-
}
109-
for (int i = 0; i < argLen; i++) {
110-
values[offset + i] = arguments[i].execute(frame);
111-
}
112-
for (int i = 0; i < starLen; i++) {
113-
values[offset + argLen + i] = starargs[i];
53+
public Object[] execute(VirtualFrame frame) {
54+
Object[] starArgsArray = starArgs.execute(frame);
55+
int starArgsLength = starArgsLengthProfile.profile(starArgsArray.length);
56+
Object[] values = new Object[arguments.length + starArgsLength];
57+
for (int i = 0; i < arguments.length; i++) {
58+
values[i] = arguments[i].execute(frame);
11459
}
60+
System.arraycopy(starArgsArray, 0, values, arguments.length, starArgsLength);
11561
return values;
11662
}
11763

@@ -121,4 +67,14 @@ public static Object[] prependArgument(Object primary, Object[] arguments, int a
12167
System.arraycopy(arguments, 0, result, 1, argumentsLength);
12268
return result;
12369
}
70+
71+
@ExplodeLoop
72+
public static Object[] evaluateArguments(VirtualFrame frame, PNode[] arguments) {
73+
CompilerAsserts.compilationConstant(arguments);
74+
Object[] values = new Object[arguments.length];
75+
for (int i = 0; i < arguments.length; i++) {
76+
values[i] = arguments[i].execute(frame);
77+
}
78+
return values;
79+
}
12480
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/PythonCallNode.java

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,22 @@
2727

2828
import com.oracle.graal.python.builtins.objects.function.PKeyword;
2929
import com.oracle.graal.python.nodes.BuiltinNames;
30+
import com.oracle.graal.python.nodes.EmptyNode;
3031
import com.oracle.graal.python.nodes.PNode;
3132
import com.oracle.graal.python.nodes.argument.keywords.KeywordArgumentsNode;
3233
import com.oracle.graal.python.nodes.argument.positional.PositionalArgumentsNode;
3334
import com.oracle.graal.python.nodes.attributes.GetAttributeNode;
3435
import com.oracle.graal.python.nodes.call.PythonCallNodeGen.GetCallAttributeNodeGen;
3536
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
3637
import com.oracle.graal.python.nodes.frame.ReadGlobalOrBuiltinNode;
38+
import com.oracle.graal.python.nodes.literal.StringLiteralNode;
3739
import com.oracle.graal.python.runtime.exception.PythonErrorType;
3840
import com.oracle.truffle.api.debug.DebuggerTags;
3941
import com.oracle.truffle.api.dsl.Cached;
4042
import com.oracle.truffle.api.dsl.Fallback;
4143
import com.oracle.truffle.api.dsl.NodeChild;
42-
import com.oracle.truffle.api.dsl.NodeChildren;
4344
import com.oracle.truffle.api.dsl.Specialization;
45+
import com.oracle.truffle.api.frame.VirtualFrame;
4446
import com.oracle.truffle.api.instrumentation.StandardTags;
4547
import com.oracle.truffle.api.instrumentation.Tag;
4648
import com.oracle.truffle.api.interop.ArityException;
@@ -53,39 +55,65 @@
5355
import com.oracle.truffle.api.nodes.Node;
5456
import com.oracle.truffle.api.profiles.BranchProfile;
5557

56-
@NodeChildren({@NodeChild("calleeNode"), @NodeChild(value = "arguments", type = PositionalArgumentsNode.class), @NodeChild(value = "keywords", type = KeywordArgumentsNode.class)})
58+
@NodeChild("calleeNode")
5759
public abstract class PythonCallNode extends PNode {
60+
5861
@Child private CallNode callNode = CallNode.create();
5962

63+
/*
64+
* Either "argument" or "positionalArgument" needs to be non-null (but not both), and
65+
* "keywordArguments" may be null.
66+
*/
67+
@Children private final PNode[] argumentNodes;
68+
@Child private PositionalArgumentsNode positionalArguments;
69+
@Child private KeywordArgumentsNode keywordArguments;
70+
6071
protected final String calleeName;
6172

62-
PythonCallNode(String calleeName) {
73+
PythonCallNode(String calleeName, PNode[] argumentNodes, PositionalArgumentsNode positionalArguments, KeywordArgumentsNode keywordArguments) {
6374
this.calleeName = calleeName;
75+
this.argumentNodes = argumentNodes;
76+
this.positionalArguments = positionalArguments;
77+
this.keywordArguments = keywordArguments;
6478
}
6579

66-
public static PythonCallNode create(PNode calleeNode, PNode[] argumentNodes, PNode[] keywords, PNode starargs, PNode kwargs) {
80+
public static PythonCallNode create(PNode calleeNode, PNode[] argumentNodes, PNode[] keywords, PNode starArgs, PNode kwArgs) {
81+
assert !(starArgs instanceof EmptyNode) : "pass null instead";
82+
assert !(kwArgs instanceof EmptyNode) : "pass null instead";
83+
6784
String calleeName = "~unknown";
6885
PNode getCallableNode = calleeNode;
6986

7087
if (calleeNode instanceof ReadGlobalOrBuiltinNode) {
7188
calleeName = ((ReadGlobalOrBuiltinNode) calleeNode).getAttributeId();
7289
} else if (calleeNode instanceof GetAttributeNode) {
73-
getCallableNode = GetCallAttributeNodeGen.create(((GetAttributeNode) calleeNode).getObject(), ((GetAttributeNode) calleeNode).getKey());
90+
PNode key = ((GetAttributeNode) calleeNode).getKey();
91+
getCallableNode = GetCallAttributeNodeGen.create(((StringLiteralNode) key).getValue(), ((GetAttributeNode) calleeNode).getObject());
92+
}
93+
KeywordArgumentsNode keywordArgumentsNode = kwArgs == null && keywords.length == 0 ? null : KeywordArgumentsNode.create(keywords, kwArgs);
94+
if (starArgs == null) {
95+
return PythonCallNodeGen.create(calleeName, argumentNodes, null, keywordArgumentsNode, getCallableNode);
96+
} else {
97+
return PythonCallNodeGen.create(calleeName, null, PositionalArgumentsNode.create(argumentNodes, starArgs), keywordArgumentsNode, getCallableNode);
7498
}
75-
76-
return PythonCallNodeGen.create(calleeName, getCallableNode, PositionalArgumentsNode.create(argumentNodes, starargs), KeywordArgumentsNode.create(keywords, kwargs));
7799
}
78100

79-
@NodeChildren({@NodeChild("object"), @NodeChild("key")})
101+
@NodeChild("object")
80102
protected abstract static class GetCallAttributeNode extends PNode {
81103

104+
private final String key;
105+
106+
protected GetCallAttributeNode(String key) {
107+
this.key = key;
108+
}
109+
82110
@Specialization(guards = "isForeignObject(object)")
83-
Object getForeignInvoke(TruffleObject object, String key) {
111+
Object getForeignInvoke(TruffleObject object) {
84112
return new ForeignInvoke(object, key);
85113
}
86114

87115
@Specialization(guards = "!isForeignObject(object)")
88-
Object getCallAttribute(Object object, Object key,
116+
Object getCallAttribute(Object object,
89117
@Cached("create(__GETATTRIBUTE__)") LookupAndCallBinaryNode getAttributeNode) {
90118
return getAttributeNode.executeObject(object, key);
91119
}
@@ -110,18 +138,28 @@ public boolean hasSideEffectAsAnExpression() {
110138
return true;
111139
}
112140

141+
private Object[] evaluateArguments(VirtualFrame frame) {
142+
return argumentNodes != null ? PositionalArgumentsNode.evaluateArguments(frame, argumentNodes) : positionalArguments.execute(frame);
143+
}
144+
145+
private PKeyword[] evaluateKeywords(VirtualFrame frame) {
146+
return keywordArguments == null ? PKeyword.EMPTY_KEYWORDS : keywordArguments.execute(frame);
147+
}
148+
113149
protected static Node createInvoke() {
114150
return Message.createInvoke(0).createNode();
115151
}
116152

117153
@Specialization
118-
Object call(ForeignInvoke callable, Object[] arguments, PKeyword[] keywords,
154+
Object call(VirtualFrame frame, ForeignInvoke callable,
119155
@Cached("create()") BranchProfile keywordsError,
120156
@Cached("create()") BranchProfile nameError,
121157
@Cached("create()") BranchProfile typeError,
122158
@Cached("create()") BranchProfile invokeError,
123159
@Cached("create(__GETATTRIBUTE__)") LookupAndCallBinaryNode getAttrNode,
124160
@Cached("createInvoke()") Node invokeNode) {
161+
Object[] arguments = evaluateArguments(frame);
162+
PKeyword[] keywords = evaluateKeywords(frame);
125163
if (keywords.length != 0) {
126164
keywordsError.enter();
127165
throw raise(PythonErrorType.TypeError, "foreign invocation does not support keyword arguments");
@@ -143,7 +181,9 @@ Object call(ForeignInvoke callable, Object[] arguments, PKeyword[] keywords,
143181
}
144182

145183
@Fallback
146-
Object call(Object callable, Object[] arguments, PKeyword[] keywords) {
184+
Object call(VirtualFrame frame, Object callable) {
185+
Object[] arguments = evaluateArguments(frame);
186+
PKeyword[] keywords = evaluateKeywords(frame);
147187
return callNode.execute(callable, arguments, keywords);
148188
}
149189

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/literal/StringLiteralNode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public Object execute(VirtualFrame frame) {
4040
return value;
4141
}
4242

43+
public String getValue() {
44+
return value;
45+
}
46+
4347
public static StringLiteralNode create(String string) {
4448
return new StringLiteralNode(string);
4549
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/PythonBaseTreeTranslator.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,8 @@ private PNode visitTrailerFrom(PNode owner, Python3Parser.TrailerContext t) {
248248
}
249249

250250
private void visitCallArglist(Python3Parser.ArglistContext arglist, List<PNode> argumentNodes, List<PNode> keywords, PNode[] splatArguments) {
251-
PNode starargs = EmptyNode.create();
252-
PNode kwargs = EmptyNode.create();
251+
PNode starargs = null;
252+
PNode kwargs = null;
253253
if (arglist != null) {
254254
for (Python3Parser.ArgumentContext argctx : arglist.argument()) {
255255
PNode defaultarg = getDefaultarg(argctx);
@@ -263,16 +263,16 @@ private void visitCallArglist(Python3Parser.ArglistContext arglist, List<PNode>
263263
arg = (PNode) argctx.accept(this);
264264
}
265265
if (isKwarg(argctx)) {
266-
if (!EmptyNode.isEmpty(kwargs)) {
266+
if (kwargs != null) {
267267
kwargs = factory.createDictionaryConcat(kwargs, arg);
268268
} else {
269269
kwargs = arg;
270270
}
271271
} else if (isStararg(argctx)) {
272-
if (!EmptyNode.isEmpty(kwargs)) {
272+
if (kwargs != null) {
273273
throw core.raise(SyntaxError, "iterable argument unpacking follows keyword argument unpacking");
274274
}
275-
if (!EmptyNode.isEmpty(starargs)) {
275+
if (starargs != null) {
276276
starargs = factory.createBinaryOperation("+", starargs, arg);
277277
} else {
278278
starargs = arg;
@@ -281,7 +281,7 @@ private void visitCallArglist(Python3Parser.ArglistContext arglist, List<PNode>
281281
if (!keywords.isEmpty()) {
282282
throw core.raise(SyntaxError, "positional argument follows keyword argument");
283283
}
284-
if (!EmptyNode.isEmpty(kwargs)) {
284+
if (kwargs != null) {
285285
throw core.raise(SyntaxError, "positional argument follows keyword argument unpacking");
286286
}
287287
argumentNodes.add(arg);
@@ -836,7 +836,7 @@ public Object visitDecorated(Python3Parser.DecoratedContext ctx) {
836836
definition = ((WriteNode) definition).getRhs();
837837
}
838838
for (PNode decorator : decorators) {
839-
definition = PythonCallNode.create(decorator, new PNode[]{definition}, new PNode[]{}, EmptyNode.create(), EmptyNode.create());
839+
definition = PythonCallNode.create(decorator, new PNode[]{definition}, new PNode[]{}, null, null);
840840
definition.assignSourceSection(decorator.getSourceSection());
841841
}
842842
return environment.findVariable(definitionName).makeWriteNode(definition);

0 commit comments

Comments
 (0)