diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java index d827a87f2c..4bf3baf235 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java @@ -1476,10 +1476,12 @@ private BytecodeDSLCodeUnit readBytecodeDSLCodeUnit() { int endColumn = readInt(); int classcellIndex = readInt(); int selfIndex = readInt(); + int yieldFromGeneratorIndex = readInt(); + int instrumentationDataIndex = readInt(); BytecodeSupplier provider = new BytecodeSupplier(serialized, bytecodeFile, bytecodeOffset, bytecodeSize, cacheKey); return new BytecodeDSLCodeUnit(name, qualname, argCount, kwOnlyArgCount, positionalOnlyArgCount, flags, names, varnames, cellvars, freevars, cell2arg, constants, - startLine, startColumn, endLine, endColumn, classcellIndex, selfIndex, provider); + startLine, startColumn, endLine, endColumn, classcellIndex, selfIndex, yieldFromGeneratorIndex, instrumentationDataIndex, provider); } private void writeCodeUnit(CodeUnit code) throws IOException { @@ -1553,6 +1555,8 @@ private void writeBytecodeDSLCodeUnit(BytecodeDSLCodeUnit code) throws IOExcepti writeInt(code.endColumn); writeInt(code.classcellIndex); writeInt(code.selfIndex); + writeInt(code.yieldFromGeneratorIndex); + writeInt(code.instrumentationDataIndex); } private PCode readCode() { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index 23f869bcb6..fab70a3b20 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -1113,9 +1113,9 @@ static Object settrace(Object function, PythonLanguage language = context.getLanguage(inliningTarget); PythonContext.PythonThreadState state = context.getThreadState(language); if (function == PNone.NONE) { - state.setTraceFun(null, language); + state.setTraceFun(inliningTarget, null, language); } else { - state.setTraceFun(function, language); + state.setTraceFun(inliningTarget, function, language); } return PNone.NONE; } @@ -1132,9 +1132,9 @@ static Object settrace(Object function, PythonLanguage language = context.getLanguage(inliningTarget); PythonContext.PythonThreadState state = context.getThreadState(language); if (function == PNone.NONE) { - state.setProfileFun(null, language); + state.setProfileFun(inliningTarget, null, language); } else { - state.setProfileFun(function, language); + state.setProfileFun(inliningTarget, function, language); } return PNone.NONE; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java index f64832826f..b83c1d6190 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/PGenerator.java @@ -345,10 +345,10 @@ public Object getYieldFrom() { if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) { PBytecodeDSLRootNode rootNode = getBytecodeDSLState().rootNode; - if (rootNode.yieldFromGeneratorIndex == -1 || !getBytecodeDSLState().isStarted) { + if (!rootNode.hasYieldFromGenerator() || !getBytecodeDSLState().isStarted) { return null; } - return getContinuationBytecodeNode().getLocalValue(0, getGeneratorFrame(), rootNode.yieldFromGeneratorIndex); + return rootNode.readYieldFromGenerator(getContinuationBytecodeNode(), getGeneratorFrame()); } else { return ((BytecodeFrameInfo) frameInfo).getYieldFrom(frame, getBci(), getBytecodeState().getCurrentRootNode().getResumeStackTop()); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java index 10ee77f971..bfcdeba7be 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java @@ -265,6 +265,8 @@ public final class RootNodeCompiler implements BaseBytecodeDSLVisitor futureFeatures) { this(ctx, parent, null, rootNode, rootNode, futureFeatures); } @@ -458,12 +460,10 @@ flags, orderedTruffleStringArray(names), sourceRange.endColumn, classcellIndex, selfIndex, + yieldFromGenerator != null ? yieldFromGenerator.getLocalIndex() : -1, + instrumentationDataLocal.getLocalIndex(), new BytecodeSupplier(nodes)); rootNode.setMetadata(codeUnit, ctx.errorCallback); - if (codeUnit.isCoroutine() || codeUnit.isAsyncGenerator() || scope.isGeneratorWithYieldFrom()) { - rootNode.yieldFromGeneratorIndex = yieldFromGenerator.getLocalIndex(); - } - return new BytecodeDSLCompilerResult(rootNode, codeUnit); } @@ -1413,10 +1413,18 @@ private void emitYield(Consumer yieldValueProducer, Statement savedExLocal = currentSaveExceptionLocal; } - statementCompiler.b.beginResumeYield(generatorExceptionStateLocal, savedExLocal); + statementCompiler.b.beginResumeYield(); + statementCompiler.b.beginResumeInstrumentedYield(); + statementCompiler.b.beginPreResumeYield(generatorExceptionStateLocal, savedExLocal); + statementCompiler.b.beginYieldValue(); + statementCompiler.b.beginTraceYieldValue(); yieldValueProducer.accept(statementCompiler); + statementCompiler.b.endTraceYieldValue(); statementCompiler.b.endYieldValue(); + + statementCompiler.b.endPreResumeYield(); + statementCompiler.b.endResumeInstrumentedYield(); statementCompiler.b.endResumeYield(); } @@ -1696,6 +1704,11 @@ public void setUpFrame(ArgumentsTy args, Builder b) { if (scope.isGeneratorWithYieldFrom() || scope.isCoroutine()) { yieldFromGenerator = b.createLocal(); } + + // We always create this local, but it is used only by TRACE_AND_PROFILE_CONFIG + // configuration + instrumentationDataLocal = b.createLocal(); + b.emitEnterInstrumentedRoot(); } private void copyArguments(ArgumentsTy args, Builder b) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeRootNode.java index 72bb7f5225..e86ab84f0c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeRootNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeRootNode.java @@ -3309,7 +3309,7 @@ private void invokeTraceFunction(VirtualFrame virtualFrame, Object arg, PythonCo pyFrame.setLocalTraceFun(null); } } catch (Throwable e) { - threadState.setTraceFun(null, getLanguage()); + threadState.setTraceFun(null, null, getLanguage()); throw e; } finally { if (line != -1) { @@ -3377,7 +3377,7 @@ private void invokeProfileFunction(VirtualFrame virtualFrame, Object arg, Python Object realResult = result == PNone.NONE ? null : result; pyFrame.setLocalTraceFun(realResult); } catch (Throwable e) { - threadState.setProfileFun(null, getLanguage()); + threadState.setProfileFun(null, null, getLanguage()); throw e; } finally { threadState.profilingStop(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/BytecodeDSLCodeUnit.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/BytecodeDSLCodeUnit.java index 0afe50e3dc..bcf48e3557 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/BytecodeDSLCodeUnit.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/BytecodeDSLCodeUnit.java @@ -51,15 +51,19 @@ public final class BytecodeDSLCodeUnit extends CodeUnit { public final int classcellIndex; public final int selfIndex; + public final int yieldFromGeneratorIndex; + public final int instrumentationDataIndex; private final BytecodeSupplier supplier; public BytecodeDSLCodeUnit(TruffleString name, TruffleString qualname, int argCount, int kwOnlyArgCount, int positionalOnlyArgCount, int flags, TruffleString[] names, TruffleString[] varnames, TruffleString[] cellvars, TruffleString[] freevars, int[] cell2arg, Object[] constants, int startLine, int startColumn, int endLine, int endColumn, - int classcellIndex, int selfIndex, BytecodeSupplier supplier) { + int classcellIndex, int selfIndex, int yieldFromGeneratorIndex, int instrumentationDataIndex, BytecodeSupplier supplier) { super(name, qualname, argCount, kwOnlyArgCount, positionalOnlyArgCount, flags, names, varnames, cellvars, freevars, cell2arg, constants, startLine, startColumn, endLine, endColumn); this.classcellIndex = classcellIndex; this.selfIndex = selfIndex; this.supplier = supplier; + this.yieldFromGeneratorIndex = yieldFromGeneratorIndex; + this.instrumentationDataIndex = instrumentationDataIndex; } public abstract static class BytecodeSupplier { @@ -71,7 +75,7 @@ public abstract static class BytecodeSupplier { public BytecodeDSLCodeUnit withFlags(int flags) { return new BytecodeDSLCodeUnit(name, qualname, argCount, kwOnlyArgCount, positionalOnlyArgCount, flags, names, varnames, cellvars, freevars, cell2arg, constants, - startLine, startColumn, endLine, endColumn, classcellIndex, selfIndex, supplier); + startLine, startColumn, endLine, endColumn, classcellIndex, selfIndex, yieldFromGeneratorIndex, instrumentationDataIndex, supplier); } @TruffleBoundary diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java index c90dc74d86..7e21dc1dee 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java @@ -370,6 +370,10 @@ public abstract class PBytecodeDSLRootNode extends PRootNode implements Bytecode addInstrumentation(TraceOrProfileReturn.class).// addInstrumentation(TraceException.class).// addInstrumentation(TraceLineWithArgument.class).// + addInstrumentation(EnterInstrumentedRoot.class).// + addInstrumentation(ResumeYieldGenerator.class).// + addInstrumentation(TraceYieldValue.class).// + addInstrumentation(ResumeInstrumentedYield.class).// build(); @Child private transient CalleeContext calleeContext = CalleeContext.create(); @@ -390,7 +394,8 @@ private static final class TracingNodes extends Node { @CompilationFinal protected transient Signature signature; @CompilationFinal protected transient int selfIndex; @CompilationFinal protected transient int classcellIndex; - @CompilationFinal public int yieldFromGeneratorIndex = -1; + @CompilationFinal protected transient int instrumentationDataIndex; + @CompilationFinal protected transient int yieldFromGeneratorIndex = -1; @CompilationFinal(dimensions = 1) protected transient Assumption[] cellEffectivelyFinalAssumptions; private transient boolean pythonInternal; @@ -409,6 +414,11 @@ public static PBytecodeDSLRootNode cast(RootNode root) { return PBytecodeDSLRootNodeGen.BYTECODE.cast(root); } + @TruffleBoundary + public static void updateAllToTracingConfig(PythonLanguage language) { + PBytecodeDSLRootNodeGen.BYTECODE.update(language, TRACE_AND_PROFILE_CONFIG); + } + public final PythonLanguage getLanguage() { return getLanguage(PythonLanguage.class); } @@ -427,6 +437,8 @@ public void setMetadata(BytecodeDSLCodeUnit co, ParserCallbacksImpl parserErrorC cellEffectivelyFinalAssumptions[i] = Truffle.getRuntime().createAssumption("cell is effectively final"); } } + instrumentationDataIndex = co.instrumentationDataIndex; + yieldFromGeneratorIndex = co.yieldFromGeneratorIndex; } @Override @@ -460,11 +472,37 @@ public static final class EnterCalleeContext { public static void doEnter(VirtualFrame frame, @Bind PBytecodeDSLRootNode root) { root.calleeContext.enter(frame, root); + } + } - if (root.needsTraceAndProfileInstrumentation()) { - root.ensureTraceAndProfileEnabled(); - root.getThreadState().pushInstrumentationData(root); - } + private InstrumentationData getInstrumentationData(VirtualFrame frame, BytecodeNode bytecode) { + InstrumentationData current = (InstrumentationData) bytecode.getLocalValue(0, frame, instrumentationDataIndex); + if (current == null) { + // This should only happen when this root was on stack when the config was updated. It + // should have been deoptimized anyway when the stack was unwound back to it. + CompilerDirectives.transferToInterpreterAndInvalidate(); + current = new InstrumentationData(); + bytecode.setLocalValue(0, frame, instrumentationDataIndex, current); + } + return current; + } + + private void resetInstrumenationData(VirtualFrame frame, BytecodeNode bytecode) { + InstrumentationData current = (InstrumentationData) bytecode.getLocalValue(0, frame, instrumentationDataIndex); + if (current == null) { + current = new InstrumentationData(); + bytecode.setLocalValue(0, frame, instrumentationDataIndex, current); + } + current.reset(); + } + + @Instrumentation(storeBytecodeIndex = false) + public static final class EnterInstrumentedRoot { + @Specialization + public static void doEnter(VirtualFrame frame, + @Bind PBytecodeDSLRootNode root, + @Bind BytecodeNode bytecode) { + bytecode.setLocalValue(0, frame, root.instrumentationDataIndex, new InstrumentationData()); } } @@ -474,10 +512,6 @@ public static final class EpilogForReturn { public static Object doExit(VirtualFrame frame, Object returnValue, @Bind PBytecodeDSLRootNode root, @Bind BytecodeNode location) { - if (root.needsTraceAndProfileInstrumentation()) { - root.getThreadState().popInstrumentationData(root); - } - root.calleeContext.exit(frame, root, location); return returnValue; } @@ -492,15 +526,10 @@ public static void doExit(VirtualFrame frame, AbstractTruffleException ate, if (ate instanceof PException pe) { pe.notifyAddedTracebackFrame(!root.isInternal()); } - + // We cannot use instrumentation for exceptional exit if (root.needsTraceAndProfileInstrumentation()) { - try { - root.traceOrProfileReturn(frame, location, null); - } finally { - root.getThreadState().popInstrumentationData(root); - } + root.traceOrProfileReturn(frame, location, null); } - root.calleeContext.exit(frame, root, location); } } @@ -509,26 +538,13 @@ public static void doExit(VirtualFrame frame, AbstractTruffleException ate, * Data for tracing, profiling and instrumentation */ public static final class InstrumentationData { - private final InstrumentationData previous; - private final PBytecodeDSLRootNode rootNode; private int pastLine; // Sometimes, we need to use pastLine value after it has been cleared. Implicit returns in // combination with loops are one such scenario. private int nonClearingPastLine; - public InstrumentationData(PBytecodeDSLRootNode rootNode, InstrumentationData previous) { - this.previous = previous; - this.rootNode = rootNode; - this.pastLine = -1; - this.nonClearingPastLine = -1; - } - - public InstrumentationData getPrevious() { - return previous; - } - - public PBytecodeDSLRootNode getRootNode() { - return rootNode; + public InstrumentationData() { + reset(); } int getPastLine() { @@ -550,6 +566,11 @@ int getNonClearingPastLine() { void setNonClearingPastLine(int value) { nonClearingPastLine = value; } + + public void reset() { + this.pastLine = -1; + this.nonClearingPastLine = -1; + } } @NonIdempotent @@ -563,18 +584,6 @@ public final PythonThreadState getThreadState() { return PythonContext.get(this).getThreadState(getLanguage()); } - /** - * Reparses with instrumentations for settrace and setprofile enabled. - */ - public final void ensureTraceAndProfileEnabled() { - try { - getRootNodes().update(TRACE_AND_PROFILE_CONFIG); - } catch (MarshalModuleBuiltins.ReparseError e) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw PRaiseNode.raiseStatic(getBytecodeNode(), SystemError, ErrorMessages.FAILED_TO_REPARSE_BYTECODE_FILE); - } - } - private TracingNodes getTracingNodes(BytecodeNode location) { /* * The TracingNodes node must be child of the BytecodeNode and not the PBytecodeRootNode, so @@ -612,7 +621,7 @@ private void invokeProfileFunction(VirtualFrame virtualFrame, BytecodeNode locat Object realResult = result == PNone.NONE ? null : result; pyFrame.setLocalTraceFun(realResult); } catch (Throwable e) { - threadState.setProfileFun(null, getLanguage()); + threadState.setProfileFun(null, null, getLanguage()); throw e; } finally { threadState.profilingStop(); @@ -663,7 +672,7 @@ private void invokeTraceFunction(VirtualFrame virtualFrame, BytecodeNode locatio pyFrame.setLocalTraceFun(null); } } catch (Throwable e) { - threadState.setTraceFun(null, getLanguage()); + threadState.setTraceFun(null, null, getLanguage()); throw e; } finally { if (line != -1) { @@ -689,7 +698,7 @@ private void traceOrProfileCall(VirtualFrame frame, BytecodeNode bytecode, int b @InliningCutoff private void traceLine(VirtualFrame frame, BytecodeNode location, int line) { PythonThreadState threadState = getThreadState(); - InstrumentationData instrumentationData = threadState.getInstrumentationData(this); + InstrumentationData instrumentationData = getInstrumentationData(frame, location); // TODO: this should never happen by nature of how we emit TraceLine, but sometimes does. // needs investigation. @@ -711,7 +720,7 @@ private void traceLine(VirtualFrame frame, BytecodeNode location, int line) { @InliningCutoff private void traceLineAtLoopHeader(VirtualFrame frame, BytecodeNode location, int line) { PythonThreadState threadState = getThreadState(); - InstrumentationData instrumentationData = threadState.getInstrumentationData(this); + InstrumentationData instrumentationData = getInstrumentationData(frame, location); int pastLine = instrumentationData.getPastLine(); instrumentationData.setPastLine(line); @@ -744,7 +753,8 @@ private void traceOrProfileReturn(VirtualFrame frame, BytecodeNode location, Obj PythonThreadState threadState = getThreadState(); Object traceFun = threadState.getTraceFun(); if (traceFun != null) { - int pastLine = threadState.getInstrumentationData(this).getNonClearingPastLine(); + InstrumentationData instrumentationData = getInstrumentationData(frame, location); + int pastLine = instrumentationData.getNonClearingPastLine(); invokeTraceFunction(frame, location, traceFun, threadState, TraceEvent.RETURN, value, pastLine); } Object profileFun = threadState.getProfileFun(); @@ -1075,6 +1085,14 @@ public Object readSelf(BytecodeFrame frame) { } } + public Object readYieldFromGenerator(BytecodeNode bytecodeNode, MaterializedFrame frame) { + return bytecodeNode.getLocalValue(0, frame, yieldFromGeneratorIndex); + } + + public boolean hasYieldFromGenerator() { + return yieldFromGeneratorIndex != -1; + } + @Operation @ConstantOperand(type = int.class) public static final class ArrayIndex { @@ -1122,13 +1140,7 @@ public static Object doYield( @Bind ContinuationRootNode continuationRootNode, @Bind PBytecodeDSLRootNode innerRoot, @Bind BytecodeNode bytecodeNode) { - try { - return createGenerator(continuationFrame, inliningTarget, continuationRootNode, innerRoot); - } finally { - if (innerRoot.needsTraceAndProfileInstrumentation()) { - innerRoot.getThreadState().popInstrumentationData(innerRoot); - } - } + return createGenerator(continuationFrame, inliningTarget, continuationRootNode, innerRoot); } private static PythonAbstractObject createGenerator(MaterializedFrame continuationFrame, Node inliningTarget, @@ -1153,21 +1165,28 @@ private static PythonAbstractObject createGenerator(MaterializedFrame continuati * Resumes execution after the artificial yield of the generator object * ({@link YieldGenerator}). */ - @Operation(storeBytecodeIndex = true) + @Instrumentation(storeBytecodeIndex = true) public static final class ResumeYieldGenerator { @Specialization - public static void doObject(VirtualFrame frame, Object generator, - @Bind Node location, + public static Object doObject(VirtualFrame frame, Object generator, @Bind PBytecodeDSLRootNode root, @Bind BytecodeNode bytecode, - @Bind("$bytecodeIndex") int bci, - @Cached GetSendValueNode getSendValue) { - if (root.needsTraceAndProfileInstrumentation()) { - // We may not have reparsed the root with instrumentation yet. - root.ensureTraceAndProfileEnabled(); - root.getThreadState().pushInstrumentationData(root); - root.traceOrProfileCall(frame, bytecode, bci); - } + @Bind("$bytecodeIndex") int bci) { + root.resetInstrumenationData(frame, bytecode); + root.traceOrProfileCall(frame, bytecode, bci); + return generator; + } + } + + @Instrumentation(storeBytecodeIndex = true) + public static final class TraceYieldValue { + @Specialization + public static Object doObject(Object value, + @Bind MaterializedFrame frame, + @Bind PBytecodeDSLRootNode root, + @Bind BytecodeNode bytecode) { + root.traceOrProfileReturn(frame, bytecode, value); + return value; } } @@ -1183,14 +1202,6 @@ public static Object doObject(Object value, @Bind MaterializedFrame frame, @Bind PBytecodeDSLRootNode root, @Bind BytecodeNode bytecode) { - if (root.needsTraceAndProfileInstrumentation()) { - try { - root.traceOrProfileReturn(frame, bytecode, value); - } finally { - root.getThreadState().popInstrumentationData(root); - } - } - // Suspended generators have no backref PArguments.getCurrentFrameInfo(frame.getArguments()).setCallerInfo(PFrame.Reference.EMPTY); // we may need to synchronize the generator's frame locals to the PFrame if it escaped @@ -3404,19 +3415,18 @@ public static Object doOther(VirtualFrame frame, Object receiver, Object key, } /** - * Resumes execution after yield. + * Prepares for resuming execution after yield: sets up exception context. This needs to be done + * before yield instrumentation, which needs to be done before receiving the sent value, which + * may potentially raise an exception passed in + * {@link com.oracle.graal.python.builtins.objects.generator.ThrowData}. */ - @Operation(storeBytecodeIndex = true) + @Operation(storeBytecodeIndex = false) @ConstantOperand(type = LocalAccessor.class) @ConstantOperand(type = LocalAccessor.class) - public static final class ResumeYield { + public static final class PreResumeYield { @Specialization public static Object doObject(VirtualFrame frame, LocalAccessor currentGeneratorException, LocalAccessor savedException, Object sendValue, - @Bind Node location, - @Bind PBytecodeDSLRootNode root, - @Bind BytecodeNode bytecode, - @Bind("$bytecodeIndex") int bci, - @Cached GetSendValueNode getSendValue) { + @Bind BytecodeNode bytecode) { if (savedException != currentGeneratorException) { // We cannot pass `null` as savedException, so savedException == // currentGeneratorException means "no saveException" @@ -3440,13 +3450,34 @@ public static Object doObject(VirtualFrame frame, LocalAccessor currentGenerator } } - if (root.needsTraceAndProfileInstrumentation()) { - // We may not have reparsed the root with instrumentation yet. - root.ensureTraceAndProfileEnabled(); - root.getThreadState().pushInstrumentationData(root); - root.traceOrProfileCall(frame, bytecode, bci); - } + return sendValue; + } + } + + /** + * Wraps {@link ResumeYield} to trace the resume event. + */ + @Instrumentation(storeBytecodeIndex = true) + public static final class ResumeInstrumentedYield { + @Specialization + public static Object doObject(VirtualFrame frame, Object sendValue, + @Bind PBytecodeDSLRootNode root, + @Bind BytecodeNode bytecode, + @Bind("$bytecodeIndex") int bci) { + root.resetInstrumenationData(frame, bytecode); + root.traceOrProfileCall(frame, bytecode, bci); + return sendValue; + } + } + /** + * Resumes execution after yield. + */ + @Operation(storeBytecodeIndex = true) + public static final class ResumeYield { + @Specialization + public static Object doObject(Object sendValue, + @Cached GetSendValueNode getSendValue) { return getSendValue.execute(sendValue); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java index 4eace446a8..1b91e7d4d7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java @@ -29,6 +29,7 @@ import static com.oracle.graal.python.PythonLanguage.throwIfUnsupported; import static com.oracle.graal.python.annotations.PythonOS.PLATFORM_DARWIN; import static com.oracle.graal.python.annotations.PythonOS.PLATFORM_WIN32; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError; import static com.oracle.graal.python.builtins.modules.SysModuleBuiltins.T_CACHE_TAG; import static com.oracle.graal.python.builtins.modules.SysModuleBuiltins.T__MULTIARCH; import static com.oracle.graal.python.builtins.modules.io.IONodes.T_CLOSED; @@ -104,6 +105,7 @@ import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; +import com.oracle.graal.python.builtins.modules.MarshalModuleBuiltins; import com.oracle.graal.python.builtins.modules.MathGuards; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass; @@ -128,7 +130,6 @@ import com.oracle.graal.python.builtins.objects.frame.PFrame.Reference; import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.function.PKeyword; -import com.oracle.graal.python.builtins.objects.generator.PGenerator; import com.oracle.graal.python.builtins.objects.list.PList; import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.str.PString; @@ -178,7 +179,6 @@ import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.ThreadLocalAction; -import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleContext; import com.oracle.truffle.api.TruffleContext.Builder; import com.oracle.truffle.api.TruffleFile; @@ -198,7 +198,6 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.utilities.CyclicAssumption; @@ -505,51 +504,13 @@ public void dispose(PythonContext context, boolean canRunGuestCode) { } } - private static void invalidateNoTracingOrProfilingAssumption(PythonLanguage language) { - if (language.noTracingOrProfilingAssumption.isValid()) { - language.noTracingOrProfilingAssumption.invalidate(); - - if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) { - enableTracingOrProfilingForActiveRootNodes(); - } - } - } - - @TruffleBoundary - private static void enableTracingOrProfilingForActiveRootNodes() { - final List rootNodes = new ArrayList<>(); - - // Ensure tracing + profiling are enabled for each method on the stack. - Truffle.getRuntime().iterateFrames((frameInstance) -> { - if (frameInstance.getCallTarget() instanceof RootCallTarget c) { - RootNode root = PGenerator.unwrapContinuationRoot(c.getRootNode()); - if (root instanceof PBytecodeDSLRootNode r) { - if (r.needsTraceAndProfileInstrumentation()) { - r.ensureTraceAndProfileEnabled(); - } - rootNodes.add(r); - } - } - return null; - }); - - /** - * Normally, a root node will push + pop the instrumentation data in its prolog/epilog. - * Since these nodes are on stack, we need to push them manually, starting from the - * deepest stack frame. - */ - for (PBytecodeDSLRootNode rootNode : rootNodes.reversed()) { - rootNode.getThreadState().pushInstrumentationData(rootNode); - } - } - public Object getTraceFun() { return traceFun; } - public void setTraceFun(Object traceFun, PythonLanguage language) { + public void setTraceFun(Node location, Object traceFun, PythonLanguage language) { if (this.traceFun != traceFun) { - invalidateNoTracingOrProfilingAssumption(language); + enableTracingOrProfiling(location, language); this.traceFun = traceFun; } } @@ -576,13 +537,25 @@ public void setTracingWhat(TraceEvent tracingWhat) { this.tracingWhat = tracingWhat; } - public void setProfileFun(Object profileFun, PythonLanguage language) { + public void setProfileFun(Node location, Object profileFun, PythonLanguage language) { if (this.profileFun != profileFun) { - invalidateNoTracingOrProfilingAssumption(language); + enableTracingOrProfiling(location, language); this.profileFun = profileFun; } } + private void enableTracingOrProfiling(Node location, PythonLanguage language) { + if (language.noTracingOrProfilingAssumption.isValid()) { + language.noTracingOrProfilingAssumption.invalidate(); + } + try { + PBytecodeDSLRootNode.updateAllToTracingConfig(language); + } catch (MarshalModuleBuiltins.ReparseError e) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw PRaiseNode.raiseStatic(location, SystemError, ErrorMessages.FAILED_TO_REPARSE_BYTECODE_FILE); + } + } + public Object getProfileFun() { return profileFun; } @@ -600,25 +573,6 @@ public void profilingStop() { this.profiling = false; } - public PBytecodeDSLRootNode.InstrumentationData getInstrumentationData(PBytecodeDSLRootNode rootNode) { - assert PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER; - assert instrumentationData != null && instrumentationData.getRootNode() == rootNode; - return instrumentationData; - } - - public void pushInstrumentationData(PBytecodeDSLRootNode rootNode) { - assert PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER; - instrumentationData = new PBytecodeDSLRootNode.InstrumentationData(rootNode, instrumentationData); - } - - public void popInstrumentationData(PBytecodeDSLRootNode rootNode) { - assert PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER; - if (instrumentationData != null) { - assert instrumentationData.getRootNode() == rootNode : String.format("%s != %s", instrumentationData.getRootNode(), rootNode); - instrumentationData = instrumentationData.getPrevious(); - } - } - public Object getAsyncgenFirstIter() { return asyncgenFirstIter; }