Skip to content

Commit 386c8c6

Browse files
committed
[GR-71028][GR-71094] Eliminate unnecessary frame syncs
PullRequest: graalpython/4079
2 parents e744d36 + 6b1fdfd commit 386c8c6

File tree

53 files changed

+1065
-934
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1065
-934
lines changed

graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/Builtin.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@
7777
boolean needsFrame() default false;
7878

7979
/**
80-
* By default the caller frame bit is set on-demand, but for some builtins it might be useful to
81-
* always force passing the caller frame.
80+
* By default the callerFlags bits are set on-demand, but for some builtins it might be useful
81+
* to pre-set them.
8282
*/
83-
boolean alwaysNeedsCallerFrame() default false;
83+
int callerFlags() default 0;
8484

8585
/**
8686
* Module functions should be bound to their module, meaning they would take the module itself

graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/Slot.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
* The slot node either needs frame for execution (e.g., may call Python code) and/or is complex
5757
* enough that indirect call to partially evaluated code is preferred over uncached execution
5858
* without frame and without setting up indirect call context.
59-
*
59+
*
6060
* The slot call nodes AST inline slot nodes, but if the inline cache overflows or in the
6161
* uncached case, they need to either call uncached slot node or do indirect call if
6262
* {@code isComplex} is {@code true}.
@@ -97,7 +97,7 @@
9797

9898
boolean needsFrame() default false;
9999

100-
boolean alwaysNeedsCallerFrame() default false;
100+
int callerFlags() default 0;
101101
}
102102

103103
/** See <a href="https://docs.python.org/3/c-api/typeobj.html">slot documentation</a> */

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/ConversionNodeTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public boolean isPythonInternal() {
101101
PArguments.setException(arguments, PException.NO_EXCEPTION);
102102
PArguments.setArgument(arguments, 0, arg);
103103
PythonThreadState threadState = pythonContext.getThreadState(language);
104-
Object state = IndirectCalleeContext.enter(threadState, arguments, callTarget);
104+
Object state = IndirectCalleeContext.enter(threadState, arguments);
105105
try {
106106
return CallDispatchers.SimpleIndirectInvokeNode.executeUncached(callTarget, arguments);
107107
} finally {

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,35 @@ def test_clearing_globals():
246246
junk = globals().clear()
247247
assert "foo" not in globals().keys()
248248
assert "junk" in globals().keys()
249+
250+
251+
def test_frame_from_another_thread():
252+
import sys, threading
253+
event1 = threading.Event()
254+
event2 = threading.Event()
255+
event3 = threading.Event()
256+
event4 = threading.Event()
257+
frame = None
258+
def target():
259+
# Mind the line numbers
260+
nonlocal frame
261+
frame = sys._getframe()
262+
a = 1
263+
event1.set()
264+
event2.wait(timeout=60)
265+
b = 2
266+
event3.set()
267+
event4.wait(timeout=60)
268+
thread = threading.Thread(target=target)
269+
thread.start()
270+
event1.wait(timeout=60)
271+
firstlineno = target.__code__.co_firstlineno
272+
assert 5 <= frame.f_lineno - firstlineno <= 6
273+
assert frame.f_locals['a'] == 1
274+
assert 'b' not in frame.f_locals
275+
event2.set()
276+
event3.wait(timeout=60)
277+
assert 8 <= frame.f_lineno - firstlineno <= 9
278+
assert frame.f_locals['b'] == 2
279+
event4.set()
280+
thread.join(timeout=60)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ def test_java_class(self):
482482
assert isinstance(l, ArrayList)
483483
self.assertEqual(getattr(ArrayList, 'class'), l.getClass())
484484

485-
with self.assertRaisesRegex(TypeError, "__call__\(\) got an unexpected keyword argument 'kwarg'"):
485+
with self.assertRaisesRegex(TypeError, r"__call__\(\) got an unexpected keyword argument 'kwarg'"):
486486
ArrayList(kwarg=42)
487487

488488
def test_java_exceptions(self):
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
test.test_profile.ProfileTest.test_output_file_when_changing_directory @ linux-x86_64
22
test.test_profile.ProfileTest.test_run @ linux-x86_64
3-
test.test_profile.ProfileTest.test_run_profile_as_module @ linux-x86_64
43
test.test_profile.ProfileTest.test_runctx @ linux-x86_64

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -785,9 +785,8 @@ public ExecutableNode parse(InlineParsingRequest request) {
785785
@Override
786786
public Object execute(VirtualFrame frame) {
787787
Object[] arguments = PArguments.create();
788-
// escape?
789788
PFrame pFrame = materializeFrameNode.execute(this, false, true, frame);
790-
Object pLocals = getFrameLocalsNode.executeCached(pFrame);
789+
Object pLocals = getFrameLocalsNode.executeCached(frame, pFrame, true);
791790
PArguments.setSpecialArgument(arguments, pLocals);
792791
PArguments.setGlobals(arguments, PArguments.getGlobals(frame));
793792
boolean wasAcquired = gilNode.acquire();

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

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@
235235
import com.oracle.graal.python.nodes.call.special.SpecialMethodNotFound;
236236
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
237237
import com.oracle.graal.python.nodes.frame.GetFrameLocalsNode;
238-
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode;
238+
import com.oracle.graal.python.nodes.frame.ReadFrameNode;
239239
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
240240
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
241241
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
@@ -261,6 +261,7 @@
261261
import com.oracle.graal.python.pegparser.ParserCallbacks;
262262
import com.oracle.graal.python.pegparser.sst.ModTy;
263263
import com.oracle.graal.python.pegparser.tokenizer.SourceRange;
264+
import com.oracle.graal.python.runtime.CallerFlags;
264265
import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext;
265266
import com.oracle.graal.python.runtime.GilNode;
266267
import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData;
@@ -314,7 +315,6 @@
314315
import com.oracle.truffle.api.nodes.LoopNode;
315316
import com.oracle.truffle.api.nodes.Node;
316317
import com.oracle.truffle.api.nodes.RootNode;
317-
import com.oracle.truffle.api.profiles.ConditionProfile;
318318
import com.oracle.truffle.api.profiles.InlinedBranchProfile;
319319
import com.oracle.truffle.api.profiles.InlinedConditionProfile;
320320
import com.oracle.truffle.api.profiles.InlinedCountingConditionProfile;
@@ -804,24 +804,25 @@ abstract static class CreateEvalExecArgumentsNode extends Node {
804804

805805
@Specialization
806806
static Object[] inheritGlobals(VirtualFrame frame, Node inliningTarget, @SuppressWarnings("unused") PNone globals, Object locals, TruffleString mode,
807-
@Exclusive @Cached ReadCallerFrameNode readCallerFrameNode,
807+
@Exclusive @Cached ReadFrameNode readFrameNode,
808808
@Exclusive @Cached GetOrCreateDictNode getOrCreateDictNode,
809809
@Exclusive @Cached InlinedConditionProfile haveCallerFrameProfile,
810-
@Exclusive @Cached InlinedConditionProfile haveLocals,
810+
@Exclusive @Cached InlinedConditionProfile inheritLocalsProfile,
811811
@Exclusive @Cached PyMappingCheckNode mappingCheckNode,
812812
@Exclusive @Cached GetFrameLocalsNode getFrameLocalsNode,
813813
@Exclusive @Cached PRaiseNode raiseNode) {
814-
PFrame callerFrame = readCallerFrameNode.executeWith(frame, 0);
814+
boolean inheritLocals = inheritLocalsProfile.profile(inliningTarget, locals instanceof PNone);
815+
PFrame callerFrame = readFrameNode.getCurrentPythonFrame(frame, inheritLocals ? CallerFlags.NEEDS_LOCALS : 0);
815816
Object[] args = PArguments.create();
816817
boolean haveCallerFrame = haveCallerFrameProfile.profile(inliningTarget, callerFrame != null);
817818
if (haveCallerFrame) {
818819
PArguments.setGlobals(args, callerFrame.getGlobals());
819820
} else {
820821
PArguments.setGlobals(args, getOrCreateDictNode.execute(inliningTarget, PythonContext.get(inliningTarget).getMainModule()));
821822
}
822-
if (haveLocals.profile(inliningTarget, locals instanceof PNone)) {
823+
if (inheritLocals) {
823824
if (haveCallerFrame) {
824-
Object callerLocals = getFrameLocalsNode.execute(inliningTarget, callerFrame);
825+
Object callerLocals = getFrameLocalsNode.execute(frame, inliningTarget, callerFrame, true);
825826
setCustomLocals(args, callerLocals);
826827
} else {
827828
setCustomLocals(args, PArguments.getGlobals(args));
@@ -838,7 +839,7 @@ static Object[] inheritGlobals(VirtualFrame frame, Node inliningTarget, @Suppres
838839
@Specialization
839840
static Object[] customGlobals(VirtualFrame frame, Node inliningTarget, PDict globals, Object locals, TruffleString mode,
840841
@Bind PythonContext context,
841-
@Exclusive @Cached InlinedConditionProfile haveLocals,
842+
@Exclusive @Cached InlinedConditionProfile inheritLocalsProfile,
842843
@Exclusive @Cached PyMappingCheckNode mappingCheckNode,
843844
@Exclusive @Cached GetOrCreateDictNode getOrCreateDictNode,
844845
@Exclusive @Cached HashingCollectionNodes.SetItemNode setBuiltins,
@@ -851,7 +852,7 @@ static Object[] customGlobals(VirtualFrame frame, Node inliningTarget, PDict glo
851852
setBuiltins.execute(frame, inliningTarget, globals, T___BUILTINS__, builtinsDict);
852853
}
853854
PArguments.setGlobals(args, globals);
854-
if (haveLocals.profile(inliningTarget, locals instanceof PNone)) {
855+
if (inheritLocalsProfile.profile(inliningTarget, locals instanceof PNone)) {
855856
setCustomLocals(args, globals);
856857
} else {
857858
if (!mappingCheckNode.execute(inliningTarget, locals)) {
@@ -979,8 +980,8 @@ public final PCode compile(VirtualFrame frame, Object source, TruffleString file
979980
protected abstract Object executeInternal(VirtualFrame frame, Object source, TruffleString filename, TruffleString mode, int flags, boolean dontInherit, int optimize,
980981
int featureVersion);
981982

982-
private int inheritFlags(VirtualFrame frame, int flags, ReadCallerFrameNode readCallerFrame) {
983-
PFrame fr = readCallerFrame.executeWith(frame, 0);
983+
private int inheritFlags(VirtualFrame frame, int flags, ReadFrameNode readCallerFrame) {
984+
PFrame fr = readCallerFrame.getCurrentPythonFrame(frame);
984985
if (fr != null) {
985986
PCode code = PFactory.createCode(PythonLanguage.get(this), fr.getTarget());
986987
flags |= code.getFlags() & PyCF_MASK;
@@ -991,7 +992,7 @@ private int inheritFlags(VirtualFrame frame, int flags, ReadCallerFrameNode read
991992
@Specialization
992993
Object doCompile(VirtualFrame frame, TruffleString expression, TruffleString filename, TruffleString mode, int flags, boolean dontInherit, int optimize,
993994
int featureVersion,
994-
@Shared @Cached ReadCallerFrameNode readCallerFrame,
995+
@Shared @Cached ReadFrameNode readCallerFrame,
995996
@Exclusive @Cached("createFor($node)") BoundaryCallData boundaryCallData) {
996997
if (!dontInherit) {
997998
flags = inheritFlags(frame, flags, readCallerFrame);
@@ -1082,7 +1083,7 @@ Object generic(VirtualFrame frame, Object wSource, Object wFilename, TruffleStri
10821083
@CachedLibrary("wSource") InteropLibrary interopLib,
10831084
@Cached PyUnicodeFSDecoderNode asPath,
10841085
@Cached TruffleString.SwitchEncodingNode switchEncodingNode,
1085-
@Shared @Cached ReadCallerFrameNode readCallerFrame,
1086+
@Shared @Cached ReadFrameNode readCallerFrame,
10861087
@Cached PRaiseNode raiseNode) {
10871088
if (wSource instanceof PCode) {
10881089
return wSource;
@@ -2252,26 +2253,19 @@ private static long maybeInt(Node inliningTarget, InlinedConditionProfile result
22522253
}
22532254
}
22542255

2255-
@Builtin(name = "globals", needsFrame = true, alwaysNeedsCallerFrame = true)
2256+
@Builtin(name = "globals", needsFrame = true, callerFlags = CallerFlags.NEEDS_PFRAME)
22562257
@GenerateNodeFactory
22572258
abstract static class GlobalsNode extends PythonBuiltinNode {
2258-
private final ConditionProfile condProfile = ConditionProfile.create();
22592259

22602260
@Specialization
22612261
public Object globals(VirtualFrame frame,
22622262
@Bind Node inliningTarget,
2263-
@Cached PyEvalGetGlobals getGlobals,
2264-
@Cached GetOrCreateDictNode getDict) {
2265-
Object globals = getGlobals.execute(frame, inliningTarget);
2266-
if (condProfile.profile(globals instanceof PythonModule)) {
2267-
return getDict.execute(inliningTarget, globals);
2268-
} else {
2269-
return globals;
2270-
}
2263+
@Cached PyEvalGetGlobals getGlobals) {
2264+
return getGlobals.execute(frame, inliningTarget);
22712265
}
22722266
}
22732267

2274-
@Builtin(name = "locals", needsFrame = true, alwaysNeedsCallerFrame = true)
2268+
@Builtin(name = "locals", needsFrame = true, callerFlags = CallerFlags.NEEDS_LOCALS)
22752269
@GenerateNodeFactory
22762270
abstract static class LocalsNode extends PythonBuiltinNode {
22772271

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ private void runFile(PythonContext context, TruffleString inputFilePath) {
391391
PArguments.setSpecialArgument(arguments, mainDict);
392392
PArguments.setException(arguments, PException.NO_EXCEPTION);
393393
context.initializeMainModule(inputFilePath);
394-
Object state = ExecutionContext.IndirectCalleeContext.enterIndirect(language, context, arguments, callTarget);
394+
Object state = ExecutionContext.IndirectCalleeContext.enter(context.getThreadState(language), arguments);
395395
try {
396396
callTarget.call(arguments);
397397
} finally {

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

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@
175175
import com.oracle.graal.python.builtins.objects.exception.ExceptionNodes;
176176
import com.oracle.graal.python.builtins.objects.exception.GetEscapedExceptionNode;
177177
import com.oracle.graal.python.builtins.objects.frame.PFrame;
178-
import com.oracle.graal.python.builtins.objects.frame.PFrame.Reference;
179178
import com.oracle.graal.python.builtins.objects.function.PArguments;
180179
import com.oracle.graal.python.builtins.objects.function.PKeyword;
181180
import com.oracle.graal.python.builtins.objects.ints.PInt;
@@ -218,18 +217,18 @@
218217
import com.oracle.graal.python.nodes.call.CallNode;
219218
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
220219
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode.NoAttributeHandler;
221-
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode;
220+
import com.oracle.graal.python.nodes.frame.ReadFrameNode;
222221
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
223222
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
224223
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
225-
import com.oracle.graal.python.nodes.function.builtins.PythonClinicBuiltinNode;
226224
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
227225
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode;
228226
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
229227
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile;
230228
import com.oracle.graal.python.nodes.object.GetClassNode;
231229
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
232230
import com.oracle.graal.python.nodes.util.ExceptionStateNodes.GetCaughtExceptionNode;
231+
import com.oracle.graal.python.runtime.CallerFlags;
233232
import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext;
234233
import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData;
235234
import com.oracle.graal.python.runtime.PosixSupportLibrary;
@@ -259,7 +258,6 @@
259258
import com.oracle.truffle.api.frame.VirtualFrame;
260259
import com.oracle.truffle.api.nodes.Node;
261260
import com.oracle.truffle.api.profiles.BranchProfile;
262-
import com.oracle.truffle.api.profiles.InlinedConditionProfile;
263261
import com.oracle.truffle.api.strings.TruffleString;
264262

265263
@CoreFunctions(defineModule = "sys", isEager = true)
@@ -852,37 +850,27 @@ static Object run(VirtualFrame frame,
852850
}
853851
}
854852

855-
// ATTENTION: this is intentionally a PythonBuiltinNode and not PythonUnaryBuiltinNode,
856-
// because we need a guarantee that this builtin will get its own stack frame in order to
857-
// be able to count how many frames down the call stack we need to walk
858-
@Builtin(name = "_getframe", parameterNames = "depth", minNumOfPositionalArgs = 0, needsFrame = true, alwaysNeedsCallerFrame = true)
853+
@Builtin(name = "_getframe", parameterNames = "depth", minNumOfPositionalArgs = 0, needsFrame = true, callerFlags = CallerFlags.NEEDS_PFRAME)
859854
@ArgumentClinic(name = "depth", defaultValue = "0", conversion = ClinicConversion.Int)
860855
@GenerateNodeFactory
861-
public abstract static class GetFrameNode extends PythonClinicBuiltinNode {
856+
public abstract static class GetFrameNode extends PythonUnaryClinicBuiltinNode {
862857
@Override
863858
protected ArgumentClinicProvider getArgumentClinic() {
864859
return GetFrameNodeClinicProviderGen.INSTANCE;
865860
}
866861

867862
@Specialization
868-
static PFrame counted(VirtualFrame frame, int num,
863+
static PFrame counted(VirtualFrame frame, int depth,
869864
@Bind Node inliningTarget,
870-
@Cached ReadCallerFrameNode readCallerNode,
871-
@Cached InlinedConditionProfile callStackDepthProfile,
865+
@Cached ReadFrameNode readFrameNode,
872866
@Cached PRaiseNode raiseNode) {
873-
PFrame requested = escapeFrame(frame, num, readCallerNode);
874-
if (callStackDepthProfile.profile(inliningTarget, requested == null)) {
867+
PFrame requested = readFrameNode.getFrameForReference(frame, PArguments.getCurrentFrameInfo(frame), ReadFrameNode.AllPythonFramesSelector.INSTANCE, depth, 0);
868+
if (requested == null) {
875869
throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.CALL_STACK_NOT_DEEP_ENOUGH);
876870
}
871+
requested.getRef().markAsEscaped();
877872
return requested;
878873
}
879-
880-
private static PFrame escapeFrame(VirtualFrame frame, int num, ReadCallerFrameNode readCallerNode) {
881-
Reference currentFrameInfo = PArguments.getCurrentFrameInfo(frame);
882-
currentFrameInfo.markAsEscaped();
883-
return readCallerNode.executeWith(currentFrameInfo, num);
884-
}
885-
886874
}
887875

888876
@Builtin(name = "_current_frames")
@@ -893,14 +881,14 @@ Object currentFrames(VirtualFrame frame,
893881
@Bind Node inliningTarget,
894882
@Cached AuditNode auditNode,
895883
@Cached WarningsModuleBuiltins.WarnNode warnNode,
896-
@Cached ReadCallerFrameNode readCallerFrameNode,
884+
@Cached ReadFrameNode readFrameNode,
897885
@Cached HashingStorageSetItem setHashingStorageItem,
898886
@Bind PythonLanguage language) {
899887
auditNode.audit(inliningTarget, "sys._current_frames");
900888
if (!getLanguage().singleThreadedAssumption.isValid()) {
901889
warnNode.warn(frame, RuntimeWarning, ErrorMessages.WARN_CURRENT_FRAMES_MULTITHREADED);
902890
}
903-
PFrame currentFrame = readCallerFrameNode.executeWith(frame, 0);
891+
PFrame currentFrame = readFrameNode.getCurrentPythonFrame(frame);
904892
PDict result = PFactory.createDict(language);
905893
result.setDictStorage(setHashingStorageItem.execute(frame, inliningTarget, result.getDictStorage(), PThread.getThreadId(Thread.currentThread()), currentFrame));
906894
return result;

0 commit comments

Comments
 (0)