Skip to content

Commit ef596d3

Browse files
committed
[GR-14177] function builtins: move getCode logic to own node, add support for caching of code when not changed.
PullRequest: graalpython/436
2 parents 2d3358e + 966bd7e commit ef596d3

File tree

7 files changed

+189
-43
lines changed

7 files changed

+189
-43
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ public abstract static class GetCodeNode extends PythonBuiltinNode {
162162
protected Object get(PCode self) {
163163
byte[] codestring = self.getCodestring();
164164
if (codestring == null) {
165-
// TODO: this is for the moment undefined
166165
codestring = new byte[0];
167166
}
168167
return factory().createBytes(codestring);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/FunctionBuiltins.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
5454
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
5555
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
56+
import com.oracle.graal.python.nodes.code.GetFunctionCodeNode;
5657
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
5758
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
5859
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
@@ -245,8 +246,9 @@ Object doGeneric(Object object) {
245246
@GenerateNodeFactory
246247
public abstract static class GetCodeNode extends PythonBinaryBuiltinNode {
247248
@Specialization(guards = {"isNoValue(none)"})
248-
Object getCode(PFunction self, @SuppressWarnings("unused") PNone none) {
249-
return self.getCode();
249+
Object getCodeU(PFunction self, @SuppressWarnings("unused") PNone none,
250+
@Cached("create()") GetFunctionCodeNode getFunctionCodeNode) {
251+
return getFunctionCodeNode.execute(self);
250252
}
251253

252254
@SuppressWarnings("unused")

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PFunction.java

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ public class PFunction extends PythonObject {
5656
private final PCell[] closure;
5757
private final boolean isStatic;
5858
@CompilationFinal private PCode code;
59-
private PCode uncachedCode;
6059
@CompilationFinal(dimensions = 1) private Object[] defaultValues;
6160
private Object[] uncachedDefaultValues;
6261
@CompilationFinal(dimensions = 1) private PKeyword[] kwDefaultValues;
@@ -70,7 +69,7 @@ public PFunction(LazyPythonClass clazz, String name, String enclosingClassName,
7069
PCell[] closure) {
7170
super(clazz);
7271
this.name = name;
73-
this.code = this.uncachedCode = new PCode(PythonBuiltinClassType.PCode, callTarget);
72+
this.code = new PCode(PythonBuiltinClassType.PCode, callTarget);
7473
this.isStatic = name.equals(SpecialMethodNames.__NEW__);
7574
this.enclosingClassName = enclosingClassName;
7675
this.globals = globals;
@@ -145,22 +144,12 @@ public final String toString() {
145144
}
146145

147146
public PCode getCode() {
148-
Assumption assumption = this.codeStableAssumption;
149-
if (CompilerDirectives.isCompilationConstant(this) && CompilerDirectives.isCompilationConstant(assumption)) {
150-
if (assumption.isValid()) {
151-
return code;
152-
}
153-
}
154-
return uncachedCode;
155-
}
156-
157-
public PCode getUncachedCode() {
158-
return uncachedCode;
147+
return code;
159148
}
160149

161150
public void setCode(PCode code) {
162151
codeStableAssumption.invalidate("code changed for function " + getName());
163-
this.code = this.uncachedCode = code;
152+
this.code = code;
164153
}
165154

166155
public String getEnclosingClassName() {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/CreateArgumentsNode.java

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@
4343
import java.util.Arrays;
4444

4545
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
46-
import com.oracle.graal.python.builtins.objects.function.Signature;
4746
import com.oracle.graal.python.builtins.objects.function.PArguments;
4847
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
4948
import com.oracle.graal.python.builtins.objects.function.PFunction;
5049
import com.oracle.graal.python.builtins.objects.function.PKeyword;
50+
import com.oracle.graal.python.builtins.objects.function.Signature;
5151
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
5252
import com.oracle.graal.python.builtins.objects.method.PMethod;
5353
import com.oracle.graal.python.builtins.objects.module.PythonModule;
@@ -60,6 +60,7 @@
6060
import com.oracle.graal.python.nodes.argument.CreateArgumentsNodeGen.FillKwDefaultsNodeGen;
6161
import com.oracle.graal.python.nodes.argument.CreateArgumentsNodeGen.FindKwDefaultNodeGen;
6262
import com.oracle.graal.python.nodes.argument.CreateArgumentsNodeGen.HandleTooManyArgumentsNodeGen;
63+
import com.oracle.graal.python.nodes.code.GetSignatureNode;
6364
import com.oracle.graal.python.runtime.PythonOptions;
6465
import com.oracle.graal.python.runtime.exception.PException;
6566
import com.oracle.truffle.api.CompilerDirectives;
@@ -79,11 +80,12 @@ public static CreateArgumentsNode create() {
7980
@Specialization(guards = {"isMethod(method)", "method == cachedMethod"}, limit = "getVariableArgumentInlineCacheLimit()")
8081
Object[] doMethodCached(PythonObject method, Object[] userArguments, PKeyword[] keywords,
8182
@Cached("create()") CreateAndCheckArgumentsNode createAndCheckArgumentsNode,
83+
@Cached("create()") GetSignatureNode getSignatureNode,
8284
@Cached("method") @SuppressWarnings("unused") PythonObject cachedMethod) {
8385

8486
// We do not directly cache these objects because they are compilation final anyway and the
8587
// getter check the appropriate assumptions.
86-
Signature signature = getSignature(cachedMethod);
88+
Signature signature = getSignatureNode.execute(cachedMethod);
8789
Object[] defaults = getDefaults(cachedMethod);
8890
PKeyword[] kwdefaults = getKwDefaults(cachedMethod);
8991
Object self = getSelf(cachedMethod);
@@ -95,11 +97,12 @@ Object[] doMethodCached(PythonObject method, Object[] userArguments, PKeyword[]
9597
Object[] doMethodFunctionAndSelfCached(PythonObject method, Object[] userArguments, PKeyword[] keywords,
9698
@Cached("create()") CreateAndCheckArgumentsNode createAndCheckArgumentsNode,
9799
@Cached("getFunction(method)") @SuppressWarnings("unused") Object cachedFunction,
100+
@Cached("create()") GetSignatureNode getSignatureNode,
98101
@Cached("getSelf(method)") Object cachedSelf) {
99102

100103
// We do not directly cache these objects because they are compilation final anyway and the
101104
// getter check the appropriate assumptions.
102-
Signature signature = getSignature(cachedFunction);
105+
Signature signature = getSignatureNode.execute(cachedFunction);
103106
Object[] defaults = getDefaults(cachedFunction);
104107
PKeyword[] kwdefaults = getKwDefaults(cachedFunction);
105108
return createAndCheckArgumentsNode.execute(method, userArguments, keywords, signature, cachedSelf, defaults, kwdefaults, isMethodCall(cachedSelf));
@@ -108,11 +111,12 @@ Object[] doMethodFunctionAndSelfCached(PythonObject method, Object[] userArgumen
108111
@Specialization(guards = {"isMethod(method)", "getFunction(method) == cachedFunction"}, limit = "getVariableArgumentInlineCacheLimit()", replaces = "doMethodFunctionAndSelfCached")
109112
Object[] doMethodFunctionCached(PythonObject method, Object[] userArguments, PKeyword[] keywords,
110113
@Cached("create()") CreateAndCheckArgumentsNode createAndCheckArgumentsNode,
114+
@Cached("create()") GetSignatureNode getSignatureNode,
111115
@Cached("getFunction(method)") @SuppressWarnings("unused") Object cachedFunction) {
112116

113117
// We do not directly cache these objects because they are compilation final anyway and the
114118
// getter check the appropriate assumptions.
115-
Signature signature = getSignature(cachedFunction);
119+
Signature signature = getSignatureNode.execute(cachedFunction);
116120
Object[] defaults = getDefaults(cachedFunction);
117121
PKeyword[] kwdefaults = getKwDefaults(cachedFunction);
118122
Object self = getSelf(method);
@@ -122,11 +126,12 @@ Object[] doMethodFunctionCached(PythonObject method, Object[] userArguments, PKe
122126
@Specialization(guards = {"isFunction(callable)", "callable == cachedCallable"}, limit = "getVariableArgumentInlineCacheLimit()")
123127
Object[] doFunctionCached(PythonObject callable, Object[] userArguments, PKeyword[] keywords,
124128
@Cached("create()") CreateAndCheckArgumentsNode createAndCheckArgumentsNode,
129+
@Cached("create()") GetSignatureNode getSignatureNode,
125130
@Cached("callable") @SuppressWarnings("unused") PythonObject cachedCallable) {
126131

127132
// We do not directly cache these objects because they are compilation final anyway and the
128133
// getter check the appropriate assumptions.
129-
Signature signature = getSignature(cachedCallable);
134+
Signature signature = getSignatureNode.execute(cachedCallable);
130135
Object[] defaults = getDefaults(cachedCallable);
131136
PKeyword[] kwdefaults = getKwDefaults(cachedCallable);
132137
return createAndCheckArgumentsNode.execute(callable, userArguments, keywords, signature, null, defaults, kwdefaults, false);
@@ -584,10 +589,6 @@ protected static PKeyword[] getKwDefaultsUncached(Object callable) {
584589
return getProperty(callable, UncachedKwDefaultsGetter.INSTANCE);
585590
}
586591

587-
protected static Signature getSignature(Object callable) {
588-
return getProperty(callable, SignatureGetter.INSTANCE);
589-
}
590-
591592
protected static Object[] getDefaults(Object callable) {
592593
return getProperty(callable, DefaultsGetter.INSTANCE);
593594
}
@@ -652,20 +653,6 @@ private abstract static class Getter<T> {
652653
public abstract T fromPBuiltinFunction(PBuiltinFunction fun);
653654
}
654655

655-
private static final class SignatureGetter extends Getter<Signature> {
656-
private static final SignatureGetter INSTANCE = new SignatureGetter();
657-
658-
@Override
659-
public Signature fromPFunction(PFunction fun) {
660-
return fun.getSignature();
661-
}
662-
663-
@Override
664-
public Signature fromPBuiltinFunction(PBuiltinFunction fun) {
665-
return fun.getSignature();
666-
}
667-
}
668-
669656
private static final class DefaultsGetter extends Getter<Object[]> {
670657
private static final DefaultsGetter INSTANCE = new DefaultsGetter();
671658

@@ -699,7 +686,7 @@ private static final class UncachedSignatureGetter extends Getter<Signature> {
699686

700687
@Override
701688
public Signature fromPFunction(PFunction fun) {
702-
return fun.getUncachedCode().getSignature();
689+
return fun.getCode().getSignature();
703690
}
704691

705692
@Override

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.oracle.graal.python.builtins.objects.code.PCode;
3030
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
3131
import com.oracle.graal.python.builtins.objects.function.PFunction;
32+
import com.oracle.graal.python.nodes.code.GetFunctionCodeNode;
3233
import com.oracle.graal.python.runtime.PythonOptions;
3334
import com.oracle.truffle.api.Assumption;
3435
import com.oracle.truffle.api.RootCallTarget;
@@ -85,10 +86,15 @@ protected Object callFunctionCached(VirtualFrame frame, @SuppressWarnings("unuse
8586

8687
// We only have a single context and this function changed its code before, but now it's
8788
// constant
88-
@Specialization(guards = {"callee == cachedCallee", "callee.getCode() == cachedCode"}, limit = "getCallSiteInlineCacheMaxDepth()", assumptions = {"singleContextAssumption()"})
89+
protected PCode getCode(GetFunctionCodeNode getFunctionCodeNode, PFunction function) {
90+
return getFunctionCodeNode.execute(function);
91+
}
92+
93+
@Specialization(guards = {"callee == cachedCallee", "getCode(getFunctionCodeNode, callee) == cachedCode"}, limit = "getCallSiteInlineCacheMaxDepth()", assumptions = {"singleContextAssumption()"})
8994
protected Object callFunctionCachedCode(VirtualFrame frame, @SuppressWarnings("unused") PFunction callee, Object[] arguments,
9095
@SuppressWarnings("unused") @Cached("callee") PFunction cachedCallee,
91-
@SuppressWarnings("unused") @Cached("callee.getCode()") PCode cachedCode,
96+
@SuppressWarnings("unused") @Cached("create()") GetFunctionCodeNode getFunctionCodeNode,
97+
@SuppressWarnings("unused") @Cached("getCode(getFunctionCodeNode, callee)") PCode cachedCode,
9298
@Cached("createInvokeNode(cachedCallee)") InvokeNode invoke) {
9399
return invoke.execute(frame, arguments);
94100
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.nodes.code;
42+
43+
import com.oracle.graal.python.builtins.objects.code.PCode;
44+
import com.oracle.graal.python.builtins.objects.function.PFunction;
45+
import com.oracle.graal.python.nodes.PNodeWithContext;
46+
import com.oracle.truffle.api.Assumption;
47+
import com.oracle.truffle.api.dsl.Cached;
48+
import com.oracle.truffle.api.dsl.Specialization;
49+
50+
public abstract class GetFunctionCodeNode extends PNodeWithContext {
51+
public abstract PCode execute(PFunction function);
52+
53+
@Specialization(guards = {"self == cachedSelf"}, assumptions = {"codeStableAssumption"})
54+
PCode getCodeCached(@SuppressWarnings("unused") PFunction self,
55+
@SuppressWarnings("unused") @Cached("self") PFunction cachedSelf,
56+
@Cached("self.getCode()") PCode cachedCode,
57+
@SuppressWarnings("unused") @Cached("self.getCodeStableAssumption()") Assumption codeStableAssumption) {
58+
return cachedCode;
59+
}
60+
61+
@Specialization
62+
PCode getCodeUncached(PFunction self) {
63+
return self.getCode();
64+
}
65+
66+
public static GetFunctionCodeNode create() {
67+
return GetFunctionCodeNodeGen.create();
68+
}
69+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.nodes.code;
42+
43+
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
44+
import com.oracle.graal.python.builtins.objects.function.PFunction;
45+
import com.oracle.graal.python.builtins.objects.function.Signature;
46+
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
47+
import com.oracle.graal.python.builtins.objects.method.PMethod;
48+
import com.oracle.graal.python.nodes.PNodeWithContext;
49+
import com.oracle.truffle.api.dsl.Cached;
50+
import com.oracle.truffle.api.dsl.Specialization;
51+
52+
public abstract class GetSignatureNode extends PNodeWithContext {
53+
private static Signature doFunctionInternal(GetFunctionCodeNode getFunctionCodeNode, PFunction function) {
54+
return getFunctionCodeNode.execute(function).getSignature();
55+
}
56+
57+
private static Signature doMethodInternal(GetFunctionCodeNode getFunctionCodeNode, Object function) {
58+
if (function instanceof PFunction) {
59+
return doFunctionInternal(getFunctionCodeNode, (PFunction) function);
60+
} else if (function instanceof PBuiltinFunction) {
61+
return ((PBuiltinFunction) function).getSignature();
62+
}
63+
return null;
64+
}
65+
66+
public abstract Signature execute(Object function);
67+
68+
@Specialization
69+
Signature doFunction(PFunction function,
70+
@Cached("create()") GetFunctionCodeNode getFunctionCodeNode) {
71+
return doFunctionInternal(getFunctionCodeNode, function);
72+
}
73+
74+
@Specialization
75+
Signature doBuiltinFunction(PBuiltinFunction builtinFunction) {
76+
return builtinFunction.getSignature();
77+
}
78+
79+
@Specialization
80+
Signature doMethod(PMethod method,
81+
@Cached("create()") GetFunctionCodeNode getFunctionCodeNode) {
82+
return doMethodInternal(getFunctionCodeNode, method.getFunction());
83+
}
84+
85+
@Specialization
86+
Signature doBuiltinMethod(PBuiltinMethod builtinMethod,
87+
@Cached("create()") GetFunctionCodeNode getFunctionCodeNode) {
88+
return doMethodInternal(getFunctionCodeNode, builtinMethod.getFunction());
89+
}
90+
91+
public static GetSignatureNode create() {
92+
return GetSignatureNodeGen.create();
93+
}
94+
}

0 commit comments

Comments
 (0)