Skip to content

Commit 776dd1f

Browse files
committed
[GR-64644] Use eager probes for instrumenting statement nodes.
PullRequest: graal/20808
2 parents a4d886d + ab99e24 commit 776dd1f

File tree

7 files changed

+115
-190
lines changed

7 files changed

+115
-190
lines changed

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/AbstractInstrumentableBytecodeNode.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
2424

2525
import java.util.ArrayList;
2626
import java.util.HashMap;
27+
import java.util.Set;
2728

2829
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
2930
import com.oracle.truffle.api.frame.Frame;
@@ -160,4 +161,6 @@ private static boolean checkLocals(Local[] liveLocals, Method method) {
160161
public boolean hasTag(Class<? extends Tag> tag) {
161162
return tag == StandardTags.RootBodyTag.class;
162163
}
164+
165+
public abstract void prepareForInstrumentation(Set<Class<?>> tags);
163166
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java

Lines changed: 24 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,8 @@
290290
import com.oracle.truffle.api.frame.FrameDescriptor;
291291
import com.oracle.truffle.api.frame.VirtualFrame;
292292
import com.oracle.truffle.api.instrumentation.GenerateWrapper.YieldException;
293-
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
294293
import com.oracle.truffle.api.instrumentation.ProbeNode;
295294
import com.oracle.truffle.api.instrumentation.StandardTags.StatementTag;
296-
import com.oracle.truffle.api.instrumentation.Tag;
297295
import com.oracle.truffle.api.interop.InteropLibrary;
298296
import com.oracle.truffle.api.nodes.BytecodeOSRNode;
299297
import com.oracle.truffle.api.nodes.ControlFlowException;
@@ -1816,17 +1814,17 @@ public int getBci(Frame frame) {
18161814
}
18171815

18181816
@Override
1819-
public InstrumentableNode materializeInstrumentableNodes(Set<Class<? extends Tag>> materializedTags) {
1817+
public void prepareForInstrumentation(Set<Class<?>> tags) {
18201818
InstrumentationSupport info = this.instrumentation;
1821-
if (info == null && materializedTags.contains(StatementTag.class)) {
1819+
if (info == null && tags.contains(StatementTag.class)) {
18221820
Lock lock = getLock();
18231821
lock.lock();
18241822
try {
18251823
info = this.instrumentation;
18261824
// double checked locking
18271825
if (info == null) {
18281826
generifyBytecodeLevelInlining();
1829-
this.instrumentation = info = insert(new InstrumentationSupport(getMethodVersion(), frameDescriptor));
1827+
this.instrumentation = info = insert(new InstrumentationSupport(getMethodVersion()));
18301828
// the debug info contains instrumentable nodes so we need to notify for
18311829
// instrumentation updates.
18321830
notifyInserted(info);
@@ -1835,7 +1833,6 @@ public InstrumentableNode materializeInstrumentableNodes(Set<Class<? extends Tag
18351833
lock.unlock();
18361834
}
18371835
}
1838-
return this;
18391836
}
18401837

18411838
private static boolean takeBranchRef1(StaticObject operand, int opcode) {
@@ -2018,15 +2015,11 @@ private int beforeJumpChecks(VirtualFrame frame, int curBCI, int targetBCI, int
20182015
if (CompilerDirectives.inInterpreter() && BytecodeOSRNode.pollOSRBackEdge(this, REPORT_LOOP_STRIDE)) {
20192016
livenessAnalysis.catchUpOSR(frame, targetBCI, skipLivenessActions);
20202017
Object osrResult;
2021-
StoredWrapperNode storedWrapperNode = null;
20222018
try {
2023-
storedWrapperNode = storeWrapperNodeIfSet(frame, instrument);
20242019
osrResult = BytecodeOSRNode.tryOSR(this, targetBCI, new EspressoOSRInterpreterState(top, nextStatementIndex), null, frame);
20252020
} catch (Throwable any) {
20262021
// Has already been guest-handled in OSR. Shortcut out of the method.
20272022
throw new EspressoOSRReturnException(any);
2028-
} finally {
2029-
restoreWrapperNode(frame, storedWrapperNode, instrument);
20302023
}
20312024
if (osrResult != null) {
20322025
throw new EspressoOSRReturnException(osrResult);
@@ -2039,32 +2032,6 @@ private int beforeJumpChecks(VirtualFrame frame, int curBCI, int targetBCI, int
20392032
return nextStatementIndex;
20402033
}
20412034

2042-
private static void restoreWrapperNode(VirtualFrame frame, StoredWrapperNode storedWrapperNode, InstrumentationSupport instrument) {
2043-
// restore wrapper nodes after OSR
2044-
if (storedWrapperNode != null) {
2045-
frame.setAuxiliarySlot(instrument.wrapperSlotIndex, storedWrapperNode.storedWrapperNode());
2046-
if (InstrumentationSupport.assertionsEnabled()) {
2047-
frame.setAuxiliarySlot(instrument.indexSlotIndex, storedWrapperNode.storedIndex());
2048-
}
2049-
}
2050-
}
2051-
2052-
private static StoredWrapperNode storeWrapperNodeIfSet(VirtualFrame frame, InstrumentationSupport instrument) {
2053-
// check if we have stores wrapper nodes and index in the frame and store if so
2054-
if (instrument != null) {
2055-
Object storedWrapperNode = frame.getAuxiliarySlot(instrument.wrapperSlotIndex);
2056-
int storedIndex = 0;
2057-
if (InstrumentationSupport.assertionsEnabled()) {
2058-
storedIndex = (int) frame.getAuxiliarySlot(instrument.indexSlotIndex);
2059-
}
2060-
return new StoredWrapperNode(storedWrapperNode, storedIndex);
2061-
}
2062-
return null;
2063-
}
2064-
2065-
private record StoredWrapperNode(Object storedWrapperNode, int storedIndex) {
2066-
}
2067-
20682035
@ExplodeLoop
20692036
@SuppressWarnings("unused")
20702037
private ExceptionHandler resolveExceptionHandlers(int bci, StaticObject ex) {
@@ -2938,8 +2905,6 @@ private boolean lockIsHeld() {
29382905

29392906
static final class InstrumentationSupport extends EspressoNode {
29402907
static final int NO_STATEMENT = -1;
2941-
private static final Object WRAPPER_SLOT_KEY = new Object();
2942-
private static final Object WRAPPER_INDEX_SLOT_KEY = new Object();
29432908

29442909
@SuppressWarnings("all")
29452910
private static boolean assertionsEnabled() {
@@ -2948,22 +2913,16 @@ private static boolean assertionsEnabled() {
29482913
return areAssertionsEnabled;
29492914
}
29502915

2951-
@Children private final EspressoBaseStatementNode[] statementNodes;
2916+
@Children private final EspressoStatementNode[] statementNodes;
29522917
@Child private MapperBCI hookBCIToNodeIndex;
29532918

29542919
private final EspressoContext context;
29552920
private final MethodVersion method;
29562921

2957-
private final int wrapperSlotIndex;
2958-
private final int indexSlotIndex;
2959-
2960-
InstrumentationSupport(MethodVersion method, FrameDescriptor frameDescriptor) {
2922+
InstrumentationSupport(MethodVersion method) {
29612923
this.method = method;
29622924
this.context = method.getMethod().getContext();
29632925

2964-
this.wrapperSlotIndex = frameDescriptor.findOrAddAuxiliarySlot(WRAPPER_SLOT_KEY);
2965-
this.indexSlotIndex = frameDescriptor.findOrAddAuxiliarySlot(WRAPPER_INDEX_SLOT_KEY);
2966-
29672926
LineNumberTableAttribute table = method.getLineNumberTableAttribute();
29682927

29692928
if (table != LineNumberTableAttribute.EMPTY) {
@@ -2974,9 +2933,8 @@ private static boolean assertionsEnabled() {
29742933
Arrays.fill(seenLines, -1);
29752934
int maxSeenLine = -1;
29762935

2977-
this.statementNodes = new EspressoBaseStatementNode[entries.size()];
2978-
this.hookBCIToNodeIndex = new MapperBCI(table);
2979-
2936+
EspressoStatementNode[] statements = new EspressoStatementNode[entries.size()];
2937+
MapperBCI mapper = new MapperBCI(table);
29802938
for (int i = 0; i < entries.size(); i++) {
29812939
LineNumberTableAttribute.Entry entry = entries.get(i);
29822940
int lineNumber = entry.getLineNumber();
@@ -2991,11 +2949,13 @@ private static boolean assertionsEnabled() {
29912949
}
29922950
}
29932951
if (!seen) {
2994-
statementNodes[hookBCIToNodeIndex.initIndex(i, entry.getBCI())] = new EspressoStatementNode(entry.getBCI(), lineNumber);
2952+
statements[mapper.initIndex(i, entry.getBCI())] = new EspressoStatementNode(entry.getBCI(), method.getMethod().getSource().createSection(lineNumber));
29952953
seenLines[i] = lineNumber;
29962954
maxSeenLine = Math.max(maxSeenLine, lineNumber);
29972955
}
29982956
}
2957+
this.hookBCIToNodeIndex = mapper;
2958+
this.statementNodes = statements;
29992959
} else {
30002960
this.statementNodes = null;
30012961
this.hookBCIToNodeIndex = null;
@@ -3040,22 +3000,18 @@ public void notifyResume(VirtualFrame frame, AbstractInstrumentableBytecodeNode
30403000
}
30413001

30423002
void notifyExceptionAt(VirtualFrame frame, Throwable t, int statementIndex) {
3043-
assert (int) frame.getAuxiliarySlot(indexSlotIndex) == statementIndex;
3044-
WrapperNode wrapperNode = (WrapperNode) frame.getAuxiliarySlot(wrapperSlotIndex);
3045-
if (wrapperNode == null) {
3003+
ProbeNode probeNode = getProbeAt(statementIndex);
3004+
if (probeNode == null) {
30463005
return;
30473006
}
3048-
ProbeNode probeNode = wrapperNode.getProbeNode();
30493007
probeNode.onReturnExceptionalOrUnwind(frame, t, false);
30503008
}
30513009

30523010
void notifyYieldAt(VirtualFrame frame, Object o, int statementIndex) {
3053-
assert (int) frame.getAuxiliarySlot(indexSlotIndex) == statementIndex;
3054-
WrapperNode wrapperNode = (WrapperNode) frame.getAuxiliarySlot(wrapperSlotIndex);
3055-
if (wrapperNode == null) {
3011+
ProbeNode probeNode = getProbeAt(statementIndex);
3012+
if (probeNode == null) {
30563013
return;
30573014
}
3058-
ProbeNode probeNode = wrapperNode.getProbeNode();
30593015
probeNode.onYield(frame, o);
30603016
}
30613017

@@ -3076,21 +3032,10 @@ public void notifyFieldAccess(VirtualFrame frame, int index, Field field, Static
30763032
}
30773033

30783034
private void enterAt(VirtualFrame frame, int index) {
3079-
WrapperNode wrapperNode = getWrapperAt(index);
3080-
/*
3081-
* We need to store this wrapper node in the frame to make sure we exit on the same
3082-
* wrapper. Wrapper nodes can be replaced at arbitrary time for example when the
3083-
* debugger is disposed and the session is ended.
3084-
*/
3085-
frame.setAuxiliarySlot(wrapperSlotIndex, wrapperNode);
3086-
// only add wrapper index in frame when assertions enabled
3087-
if (assertionsEnabled()) {
3088-
frame.setAuxiliarySlot(indexSlotIndex, index);
3089-
}
3090-
if (wrapperNode == null) {
3035+
ProbeNode probeNode = getProbeAt(index);
3036+
if (probeNode == null) {
30913037
return;
30923038
}
3093-
ProbeNode probeNode = wrapperNode.getProbeNode();
30943039
try {
30953040
probeNode.onEnter(frame);
30963041
} catch (Throwable t) {
@@ -3109,21 +3054,10 @@ private void enterAt(VirtualFrame frame, int index) {
31093054
}
31103055

31113056
private void resumeAt(VirtualFrame frame, int index) {
3112-
WrapperNode wrapperNode = getWrapperAt(index);
3113-
/*
3114-
* We need to store this wrapper node in the frame to make sure we exit on the same
3115-
* wrapper. Wrapper nodes can be replaced at arbitrary time for example when the
3116-
* debugger is disposed and the session is ended.
3117-
*/
3118-
frame.setAuxiliarySlot(wrapperSlotIndex, wrapperNode);
3119-
// only add wrapper index in frame when assertions enabled
3120-
if (assertionsEnabled()) {
3121-
frame.setAuxiliarySlot(indexSlotIndex, index);
3122-
}
3123-
if (wrapperNode == null) {
3057+
ProbeNode probeNode = getProbeAt(index);
3058+
if (probeNode == null) {
31243059
return;
31253060
}
3126-
ProbeNode probeNode = wrapperNode.getProbeNode();
31273061
try {
31283062
probeNode.onResume(frame);
31293063
} catch (Throwable t) {
@@ -3142,12 +3076,10 @@ private void resumeAt(VirtualFrame frame, int index) {
31423076
}
31433077

31443078
private void exitAt(VirtualFrame frame, int index, Object returnValue) {
3145-
assert (int) frame.getAuxiliarySlot(indexSlotIndex) == index;
3146-
WrapperNode wrapperNode = (WrapperNode) frame.getAuxiliarySlot(wrapperSlotIndex);
3147-
if (wrapperNode == null) {
3079+
ProbeNode probeNode = getProbeAt(index);
3080+
if (probeNode == null) {
31483081
return;
31493082
}
3150-
ProbeNode probeNode = wrapperNode.getProbeNode();
31513083
try {
31523084
probeNode.onReturnValue(frame, returnValue);
31533085
} catch (Throwable t) {
@@ -3190,21 +3122,16 @@ int getStartStatementIndex(int startBci) {
31903122
return hookBCIToNodeIndex.lookupBucket(startBci);
31913123
}
31923124

3193-
/*
3194-
* This method must only be called when entering a node. The returned node should be stored
3195-
* in the frame in the WRAPPER_SLOT along with the index. This is needed to make sure that
3196-
* we always exit on the same wrapper.
3197-
*/
3198-
private WrapperNode getWrapperAt(int index) {
3125+
private ProbeNode getProbeAt(int index) {
31993126
if (statementNodes == null || index < 0) {
32003127
return null;
32013128
}
3202-
EspressoBaseStatementNode node = statementNodes[index];
3203-
if (!(node instanceof WrapperNode)) {
3129+
EspressoStatementNode node = statementNodes[index];
3130+
if (node == null) {
32043131
return null;
32053132
}
32063133
CompilerAsserts.partialEvaluationConstant(node);
3207-
return ((WrapperNode) node);
3134+
return node.findProbe();
32083135
}
32093136
}
32103137

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoBaseStatementNode.java

Lines changed: 0 additions & 78 deletions
This file was deleted.

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoInstrumentableRootNode.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,8 @@
2929
import com.oracle.truffle.espresso.impl.Method;
3030
import com.oracle.truffle.espresso.vm.continuation.UnwindContinuationException;
3131

32+
import java.util.Set;
33+
3234
/**
3335
* All methods in this class that can be overridden in subclasses must be abstract. If a generic
3436
* implementation should be provided it should be in {@link EspressoInstrumentableRootNodeImpl}.
@@ -61,4 +63,8 @@ public WrapperNode createWrapper(ProbeNode probeNode) {
6163

6264
@Override
6365
public abstract String toString();
66+
67+
public void prepareForInstrumentation(@SuppressWarnings("unused") Set<Class<?>> tags) {
68+
// do nothing by default, only method nodes with bytecode needs to take action
69+
}
6470
}

0 commit comments

Comments
 (0)