From ab99e241737ac9c8ec739aa6e0382694f0152cec Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Tue, 13 May 2025 07:10:34 +0200 Subject: [PATCH] use eager probes for instrumenting statement nodes --- .../AbstractInstrumentableBytecodeNode.java | 5 +- .../truffle/espresso/nodes/BytecodeNode.java | 121 ++++-------------- .../nodes/EspressoBaseStatementNode.java | 78 ----------- .../nodes/EspressoInstrumentableRootNode.java | 8 +- .../espresso/nodes/EspressoRootNode.java | 10 +- .../espresso/nodes/EspressoStatementNode.java | 74 +++++++++-- .../nodes/MethodWithBytecodeNode.java | 9 +- 7 files changed, 115 insertions(+), 190 deletions(-) delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoBaseStatementNode.java diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/AbstractInstrumentableBytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/AbstractInstrumentableBytecodeNode.java index e99cf99c7b91..969dc076ebb2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/AbstractInstrumentableBytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/AbstractInstrumentableBytecodeNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.Set; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.Frame; @@ -160,4 +161,6 @@ private static boolean checkLocals(Local[] liveLocals, Method method) { public boolean hasTag(Class tag) { return tag == StandardTags.RootBodyTag.class; } + + public abstract void prepareForInstrumentation(Set> tags); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java index 75b8af92efd3..4370ef902c3b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java @@ -290,10 +290,8 @@ import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.GenerateWrapper.YieldException; -import com.oracle.truffle.api.instrumentation.InstrumentableNode; import com.oracle.truffle.api.instrumentation.ProbeNode; import com.oracle.truffle.api.instrumentation.StandardTags.StatementTag; -import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.nodes.BytecodeOSRNode; import com.oracle.truffle.api.nodes.ControlFlowException; @@ -1816,9 +1814,9 @@ public int getBci(Frame frame) { } @Override - public InstrumentableNode materializeInstrumentableNodes(Set> materializedTags) { + public void prepareForInstrumentation(Set> tags) { InstrumentationSupport info = this.instrumentation; - if (info == null && materializedTags.contains(StatementTag.class)) { + if (info == null && tags.contains(StatementTag.class)) { Lock lock = getLock(); lock.lock(); try { @@ -1826,7 +1824,7 @@ public InstrumentableNode materializeInstrumentableNodes(Set tag) { - return tag == StandardTags.StatementTag.class; - } - - @Override - public WrapperNode createWrapper(ProbeNode probe) { - return new EspressoBaseStatementNodeWrapper(this, probe); - } - - public final BytecodeNode getBytecodeNode() { - Node parent = getParent(); - while (!(parent instanceof BytecodeNode) && parent != null) { - parent = parent.getParent(); - } - return (BytecodeNode) parent; - } - - @ExportMessage - @SuppressWarnings("static-method") - public final boolean hasScope(@SuppressWarnings("unused") Frame frame) { - return true; - } - - @ExportMessage - public final Object getScope(Frame frame, boolean nodeEnter) { - return getScopeSlowPath(frame != null ? frame.materialize() : null, nodeEnter); - } - - @TruffleBoundary - private Object getScopeSlowPath(MaterializedFrame frame, boolean nodeEnter) { - return getBytecodeNode().getScope(frame, nodeEnter); - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoInstrumentableRootNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoInstrumentableRootNode.java index 92744081fb5b..6d842b5b13bc 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoInstrumentableRootNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoInstrumentableRootNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.vm.continuation.UnwindContinuationException; +import java.util.Set; + /** * All methods in this class that can be overridden in subclasses must be abstract. If a generic * implementation should be provided it should be in {@link EspressoInstrumentableRootNodeImpl}. @@ -61,4 +63,8 @@ public WrapperNode createWrapper(ProbeNode probeNode) { @Override public abstract String toString(); + + public void prepareForInstrumentation(@SuppressWarnings("unused") Set> tags) { + // do nothing by default, only method nodes with bytecode needs to take action + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoRootNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoRootNode.java index 3be3870f9a56..68470a223353 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoRootNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoRootNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package com.oracle.truffle.espresso.nodes; import java.util.Arrays; +import java.util.Set; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; @@ -59,7 +60,6 @@ */ public abstract class EspressoRootNode extends RootNode implements ContextAccess { - // must not be of type EspressoMethodNode as it might be wrapped by instrumentation @Child protected EspressoInstrumentableRootNode methodNode; private static final int SLOT_UNUSED = -2; @@ -253,6 +253,12 @@ public static EspressoRootNode createContinuable(Method.MethodVersion methodVers return create(bytecodeNode.getFrameDescriptor(), new ContinuableMethodWithBytecode(bytecodeNode, bci, fd)); } + @Override + protected void prepareForInstrumentation(Set> tags) { + // delegate to the instrumentable method node + methodNode.prepareForInstrumentation(tags); + } + public final int readBCI(Frame frame) { return methodNode.getBci(frame); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoStatementNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoStatementNode.java index 67312da5735f..02481e41f13c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoStatementNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoStatementNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,33 +22,87 @@ */ package com.oracle.truffle.espresso.nodes; +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.Frame; -import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.instrumentation.ProbeNode; +import com.oracle.truffle.api.instrumentation.StandardTags; +import com.oracle.truffle.api.instrumentation.Tag; +import com.oracle.truffle.api.interop.NodeLibrary; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.SourceSection; /** * Node that simulates espresso statements for debugging support. */ -public final class EspressoStatementNode extends EspressoBaseStatementNode implements BciProvider { +@ExportLibrary(NodeLibrary.class) +public final class EspressoStatementNode extends EspressoInstrumentableNode implements BciProvider { private final int startBci; - private final int lineNumber; + @Child private volatile ProbeNode eagerProbe; + private final SourceSection sourceSection; - EspressoStatementNode(int startBci, int lineNumber) { - this.lineNumber = lineNumber; + EspressoStatementNode(int startBci, SourceSection section) { this.startBci = startBci; + this.sourceSection = section; } @Override public SourceSection getSourceSection() { - Source s = getBytecodeNode().getSource(); - // when there is a line number table we also have a source - assert s != null; - return s.createSection(lineNumber); + return sourceSection; } @Override public int getBci(@SuppressWarnings("unused") Frame frame) { return startBci; } + + @Override + public ProbeNode findProbe() { + ProbeNode p = this.eagerProbe; + if (p == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + this.eagerProbe = p = insert(createProbe(getSourceSection())); + } + CompilerAsserts.partialEvaluationConstant(p); + return p; + } + + @Override + public boolean hasTag(Class tag) { + return tag == StandardTags.StatementTag.class; + } + + @Override + public WrapperNode createWrapper(ProbeNode probe) { + throw new UnsupportedOperationException(); + } + + private BytecodeNode getBytecodeNode() { + Node parent = getParent(); + while (!(parent instanceof BytecodeNode) && parent != null) { + parent = parent.getParent(); + } + return (BytecodeNode) parent; + } + + @ExportMessage + @SuppressWarnings("static-method") + public boolean hasScope(@SuppressWarnings("unused") Frame frame) { + return true; + } + + @ExportMessage + public Object getScope(Frame frame, boolean nodeEnter) { + return getScopeSlowPath(frame != null ? frame.materialize() : null, nodeEnter); + } + + @TruffleBoundary + private Object getScopeSlowPath(MaterializedFrame frame, boolean nodeEnter) { + return getBytecodeNode().getScope(frame, nodeEnter); + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/MethodWithBytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/MethodWithBytecodeNode.java index 4eb28ed1b158..ba54a74f2e10 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/MethodWithBytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/MethodWithBytecodeNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,8 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.espresso.impl.SuppressFBWarnings; +import java.util.Set; + /** * {@link RootTag} node that separates the Java method prolog e.g. copying arguments to the frame, * initializes {@code bci=0}, from the execution of the {@link BytecodeNode bytecodes/body}. @@ -93,4 +95,9 @@ public Object getScope(Frame frame, boolean nodeEnter) { private Object getScopeSlowPath(MaterializedFrame frame, boolean nodeEnter) { return bytecodeNode.getScope(frame, nodeEnter); } + + @Override + public void prepareForInstrumentation(Set> tags) { + bytecodeNode.prepareForInstrumentation(tags); + } }