Skip to content

Commit de882cf

Browse files
committed
[GR-40038][GR-39992] Improve compilation in bytecode interpreter
PullRequest: graalpython/2360
2 parents b09cd98 + f5f1a45 commit de882cf

File tree

12 files changed

+426
-171
lines changed

12 files changed

+426
-171
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ public enum PythonBuiltinClassType implements TruffleObject {
382382
Capsule("PyCapsule"),
383383

384384
// A marker for @Builtin that is not a class. Must always come last.
385-
nil(null);
385+
nil("nil");
386386

387387
private static class Flags {
388388

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import org.graalvm.polyglot.io.ByteSequence;
7272

7373
import com.oracle.graal.python.PythonLanguage;
74+
import com.oracle.graal.python.annotations.ArgumentClinic;
7475
import com.oracle.graal.python.builtins.Builtin;
7576
import com.oracle.graal.python.builtins.CoreFunctions;
7677
import com.oracle.graal.python.builtins.Python3Core;
@@ -112,8 +113,10 @@
112113
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
113114
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
114115
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
116+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryClinicBuiltinNode;
115117
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
116118
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
119+
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
117120
import com.oracle.graal.python.nodes.object.GetClassNode;
118121
import com.oracle.graal.python.nodes.statement.AbstractImportNode;
119122
import com.oracle.graal.python.nodes.subscript.GetItemNode;
@@ -650,33 +653,40 @@ protected static boolean isType(Object obj, Env env, InteropLibrary lib) {
650653

651654
}
652655

653-
@Builtin(name = "dis", minNumOfPositionalArgs = 1, doc = "Helper to disassemble code objects if running with the bytecode interpreter")
656+
@Builtin(name = "dis", minNumOfPositionalArgs = 1, parameterNames = {"obj", "quickened"}, doc = "Helper to disassemble code objects if running with the bytecode interpreter")
657+
@ArgumentClinic(name = "quickened", conversion = ArgumentClinic.ClinicConversion.Boolean, defaultValue = "false")
654658
@GenerateNodeFactory
655-
public abstract static class BCIDisNode extends PythonUnaryBuiltinNode {
659+
public abstract static class BCIDisNode extends PythonBinaryClinicBuiltinNode {
656660
@Specialization
657-
Object doMethod(PMethod method) {
661+
Object doMethod(PMethod method, boolean quickened) {
658662
final Object function = method.getFunction();
659663
if (function instanceof PFunction) {
660-
return doFunction((PFunction) function);
664+
return doFunction((PFunction) function, quickened);
661665
}
662666
return PNone.NONE;
663667
}
664668

665669
@Specialization
666-
Object doFunction(PFunction function) {
667-
return doCode(function.getCode());
670+
Object doFunction(PFunction function, boolean quickened) {
671+
return doCode(function.getCode(), quickened);
668672
}
669673

670674
@Specialization
671675
@TruffleBoundary
672-
Object doCode(PCode code) {
673-
return toTruffleStringUncached(code.toDisassembledString());
676+
Object doCode(PCode code, boolean quickened) {
677+
return toTruffleStringUncached(code.toDisassembledString(quickened));
674678
}
675679

676-
@Specialization(guards = {"!isCode(value)", "!isPFunction(value)", "!isMethod(value)"})
677-
Object doObject(@SuppressWarnings("unused") Object value) {
680+
@Fallback
681+
@SuppressWarnings("unused")
682+
Object doObject(Object value, Object quickened) {
678683
return PNone.NONE;
679684
}
685+
686+
@Override
687+
protected ArgumentClinicProvider getArgumentClinic() {
688+
return GraalPythonModuleBuiltinsClinicProviders.BCIDisNodeClinicProviderGen.INSTANCE;
689+
}
680690
}
681691

682692
@Builtin(name = "super", minNumOfPositionalArgs = 1, doc = "Returns HostAdapter instance of the object or None")

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -746,16 +746,26 @@ public boolean hasSourceLocation(@Exclusive @Cached GilNode gil) {
746746
@TruffleBoundary
747747
public String toString() {
748748
String codeName = this.getName() == null ? "None" : this.getName().toJavaStringUncached();
749-
String codeFilename = this.getFilename() == null ? "None" : this.getFilename().toJavaStringUncached();
749+
/*
750+
* This might be called without an active context (i.e. when dumping graphs), we cannot use
751+
* getFilename
752+
*/
753+
String codeFilename = getSourceSectionFileName(rootNodeForExtraction(getRootNode()).getSourceSection());
754+
if (codeFilename == null) {
755+
codeFilename = "None";
756+
}
750757
int codeFirstLineNo = this.getFirstLineNo() == 0 ? -1 : this.getFirstLineNo();
751758
return String.format("<code object %s, file \"%s\", line %d>", codeName, codeFilename, codeFirstLineNo);
752759
}
753760

754761
@TruffleBoundary
755-
public String toDisassembledString() {
762+
public String toDisassembledString(boolean quickened) {
756763
final RootNode rootNode = getRootCallTarget().getRootNode();
757764
if (rootNode instanceof PBytecodeRootNode) {
758765
CodeUnit code = ((PBytecodeRootNode) rootNode).getCodeUnit();
766+
if (quickened) {
767+
return code.toString(((PBytecodeRootNode) rootNode).getBytecode());
768+
}
759769
return code.toString();
760770
}
761771
return J_EMPTY_STRING;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/CompilationUnit.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ public CodeUnit assemble() {
206206
}
207207
int[] boxingMetric = new int[varCount];
208208
byte[] shouldUnboxVariable = new byte[varCount];
209+
Arrays.fill(shouldUnboxVariable, (byte) 0xff);
209210

210211
SortedSet<int[]> finishedExceptionHandlerRanges = new TreeSet<>(Comparator.comparingInt(a -> a[0]));
211212

@@ -243,7 +244,6 @@ public CodeUnit assemble() {
243244
if (i.opcode == OpCodes.STORE_FAST) {
244245
variableStores.get(i.arg).add(i);
245246
} else if (i.opcode == OpCodes.LOAD_FAST) {
246-
shouldUnboxVariable[i.arg] |= i.quickenOutput;
247247
boxingMetric[i.arg] += i.quickenOutput != 0 ? 1 : -1;
248248
}
249249
i.bci = buf.size();
@@ -296,14 +296,24 @@ public CodeUnit assemble() {
296296
}
297297
}
298298
}
299-
for (int i = 0; i < varCount; i++) {
300-
List<Instruction> stores = variableStores.get(i);
301-
finishedGeneralizeVarsMap[i] = new int[stores.size()];
302-
for (int j = 0; j < stores.size(); j++) {
303-
finishedGeneralizeVarsMap[i][j] = stores.get(j).bci;
304-
}
305-
if (boxingMetric[i] <= 0) {
306-
shouldUnboxVariable[i] = 0;
299+
if (!scope.isGenerator()) {
300+
/*
301+
* We do an optimization in the interpreter that we don't unbox variables that would
302+
* mostly get boxed again. This helps for interpreter performance, but for compiled code
303+
* we have to unbox all variables otherwise the compiler is not always able to prove the
304+
* variable was initialized. In generators, transferring the variables between the two
305+
* modes of usage (boxed vs unboxed) would be too complex, so we skip the optimization
306+
* there and unbox all variables.
307+
*/
308+
for (int i = 0; i < varCount; i++) {
309+
List<Instruction> stores = variableStores.get(i);
310+
finishedGeneralizeVarsMap[i] = new int[stores.size()];
311+
for (int j = 0; j < stores.size(); j++) {
312+
finishedGeneralizeVarsMap[i][j] = stores.get(j).bci;
313+
}
314+
if (boxingMetric[i] <= 0) {
315+
shouldUnboxVariable[i] = 0;
316+
}
307317
}
308318
}
309319
return new CodeUnit(toTruffleStringUncached(name), toTruffleStringUncached(qualName),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/OpCodes.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,8 +681,10 @@ public enum OpCodes {
681681
LOAD_FAST_B(LOAD_FAST, 0, QuickeningTypes.BOOLEAN, LOAD_FAST_B_BOX),
682682
STORE_FAST_O(STORE_FAST, QuickeningTypes.OBJECT, 0),
683683
STORE_FAST_UNBOX_I(STORE_FAST, QuickeningTypes.OBJECT, 0),
684+
STORE_FAST_BOXED_I(STORE_FAST, QuickeningTypes.OBJECT, 0),
684685
STORE_FAST_I(STORE_FAST, QuickeningTypes.INT, 0),
685686
STORE_FAST_UNBOX_B(STORE_FAST, QuickeningTypes.OBJECT, 0),
687+
STORE_FAST_BOXED_B(STORE_FAST, QuickeningTypes.OBJECT, 0),
686688
STORE_FAST_B(STORE_FAST, QuickeningTypes.BOOLEAN, 0),
687689
UNARY_OP_O_O(UNARY_OP, QuickeningTypes.OBJECT, QuickeningTypes.OBJECT),
688690
UNARY_OP_I_O(UNARY_OP, QuickeningTypes.INT, QuickeningTypes.OBJECT),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/QuickeningTypes.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,43 @@
4040
*/
4141
package com.oracle.graal.python.compiler;
4242

43+
import com.oracle.truffle.api.CompilerDirectives;
44+
import com.oracle.truffle.api.frame.FrameSlotKind;
45+
4346
public abstract class QuickeningTypes {
4447
public static final byte OBJECT = 1;
4548
public static final byte INT = 2;
4649
public static final byte LONG = 4;
4750
public static final byte DOUBLE = 8;
4851
public static final byte BOOLEAN = 16;
52+
53+
public static byte fromFrameSlotTag(byte tag) {
54+
if (tag == FrameSlotKind.Object.tag) {
55+
return OBJECT;
56+
} else if (tag == FrameSlotKind.Int.tag) {
57+
return INT;
58+
} else if (tag == FrameSlotKind.Long.tag) {
59+
return LONG;
60+
} else if (tag == FrameSlotKind.Double.tag) {
61+
return DOUBLE;
62+
} else if (tag == FrameSlotKind.Boolean.tag) {
63+
return BOOLEAN;
64+
} else {
65+
throw CompilerDirectives.shouldNotReachHere("Unknown stack item type");
66+
}
67+
}
68+
69+
public static byte fromObjectType(Object object) {
70+
if (object instanceof Integer) {
71+
return INT;
72+
} else if (object instanceof Long) {
73+
return LONG;
74+
} else if (object instanceof Double) {
75+
return DOUBLE;
76+
} else if (object instanceof Boolean) {
77+
return BOOLEAN;
78+
} else {
79+
return OBJECT;
80+
}
81+
}
4982
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/ForIterINode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
import com.oracle.truffle.api.dsl.Specialization;
5959
import com.oracle.truffle.api.frame.Frame;
6060
import com.oracle.truffle.api.frame.VirtualFrame;
61-
import com.oracle.truffle.api.profiles.ConditionProfile;
61+
import com.oracle.truffle.api.profiles.LoopConditionProfile;
6262

6363
/**
6464
* Obtains the next value of an iterator. When the iterator is exhausted it returns {@code null}. It
@@ -70,7 +70,7 @@ public abstract class ForIterINode extends PNodeWithContext {
7070

7171
@Specialization
7272
boolean doIntRange(VirtualFrame frame, PIntRangeIterator iterator, int stackTop,
73-
@Cached("createCountingProfile()") ConditionProfile conditionProfile) {
73+
@Cached("createCountingProfile()") LoopConditionProfile conditionProfile) {
7474
if (conditionProfile.profile(iterator.hasNextInt())) {
7575
frame.setInt(stackTop, iterator.nextInt());
7676
return true;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/ForIterONode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
import com.oracle.truffle.api.dsl.Specialization;
5757
import com.oracle.truffle.api.frame.Frame;
5858
import com.oracle.truffle.api.frame.VirtualFrame;
59-
import com.oracle.truffle.api.profiles.ConditionProfile;
59+
import com.oracle.truffle.api.profiles.LoopConditionProfile;
6060

6161
/**
6262
* Obtains the next value of an iterator. When the iterator is exhausted it returns {@code null}. It
@@ -68,7 +68,7 @@ public abstract class ForIterONode extends PNodeWithContext {
6868

6969
@Specialization
7070
boolean doIntRange(VirtualFrame frame, PIntRangeIterator iterator, int stackTop,
71-
@Cached("createCountingProfile()") ConditionProfile conditionProfile) {
71+
@Cached("createCountingProfile()") LoopConditionProfile conditionProfile) {
7272
if (conditionProfile.profile(iterator.hasNextInt())) {
7373
frame.setObject(stackTop, iterator.nextInt());
7474
return true;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2022, 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.bytecode;
42+
43+
import com.oracle.graal.python.builtins.objects.PNone;
44+
import com.oracle.graal.python.builtins.objects.generator.ThrowData;
45+
import com.oracle.graal.python.nodes.PNodeWithContext;
46+
import com.oracle.graal.python.runtime.exception.PException;
47+
import com.oracle.truffle.api.dsl.Fallback;
48+
import com.oracle.truffle.api.dsl.GenerateUncached;
49+
import com.oracle.truffle.api.dsl.Specialization;
50+
51+
@GenerateUncached
52+
public abstract class GetSendValueNode extends PNodeWithContext {
53+
public abstract Object execute(Object specialArgument);
54+
55+
@Specialization(guards = "specialArgument == null")
56+
Object doNext(@SuppressWarnings("unused") Object specialArgument) {
57+
return PNone.NONE;
58+
}
59+
60+
@Specialization
61+
Object doThrow(ThrowData throwData) {
62+
throw PException.fromObject(throwData.pythonException, this, throwData.withJavaStacktrace);
63+
}
64+
65+
@Fallback
66+
Object doSend(Object obj) {
67+
return obj;
68+
}
69+
70+
public static GetSendValueNode create() {
71+
return GetSendValueNodeGen.create();
72+
}
73+
74+
public static GetSendValueNode getUncached() {
75+
return GetSendValueNodeGen.getUncached();
76+
}
77+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/OSRInterpreterState.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,8 @@
4242

4343
final class OSRInterpreterState {
4444
public final int stackTop;
45-
public final int loopEndBci;
4645

47-
public OSRInterpreterState(int stackTop, int loopEndBci) {
46+
public OSRInterpreterState(int stackTop) {
4847
this.stackTop = stackTop;
49-
this.loopEndBci = loopEndBci;
5048
}
5149
}

0 commit comments

Comments
 (0)