Skip to content

Commit 5b60585

Browse files
Properly handle static fields and compiled methods from the base layer.
Fix crash in CStructTests. Make sure params are not optimized out in PrettyPrinterTest. Only emit register locations for leaf ranges.
1 parent bc0b09f commit 5b60585

File tree

8 files changed

+89
-35
lines changed

8 files changed

+89
-35
lines changed

substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MethodEntry.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,20 @@ public record Local(LocalEntry localEntry, int line) {
4848
private boolean isInlined;
4949
private final boolean isOverride;
5050
private final boolean isConstructor;
51+
private final boolean isCompiledInPriorLayer;
5152
private final int vtableOffset;
5253
private final String symbolName;
5354

5455
public MethodEntry(FileEntry fileEntry, int line, String methodName, StructureTypeEntry ownerType,
5556
TypeEntry valueType, int modifiers, List<LocalEntry> params, String symbolName, boolean isDeopt, boolean isOverride, boolean isConstructor,
56-
int vtableOffset, int lastParamSlot) {
57+
boolean isCompiledInPriorLayer, int vtableOffset, int lastParamSlot) {
5758
super(fileEntry, line, methodName, ownerType, valueType, modifiers);
5859
this.params = params;
5960
this.symbolName = symbolName;
6061
this.isDeopt = isDeopt;
6162
this.isOverride = isOverride;
6263
this.isConstructor = isConstructor;
64+
this.isCompiledInPriorLayer = isCompiledInPriorLayer;
6365
this.vtableOffset = vtableOffset;
6466
this.lastParamSlot = lastParamSlot;
6567
this.locals = new ArrayList<>();
@@ -208,6 +210,10 @@ public boolean isConstructor() {
208210
return isConstructor;
209211
}
210212

213+
public boolean isCompiledInPriorLayer() {
214+
return isCompiledInPriorLayer;
215+
}
216+
211217
public boolean isVirtual() {
212218
return vtableOffset >= 0;
213219
}

substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ private int writeInstanceClasses(DebugContext context, byte[] buffer, int p) {
605605
* declaration in the owner type CU. Other information is already written to the
606606
* corresponding type units.
607607
*/
608-
if (classEntry.getMethods().stream().anyMatch(m -> m.isInRange() || m.isInlined()) ||
608+
if (classEntry.getMethods().stream().anyMatch(m -> m.isInRange() || m.isInlined() || m.isCompiledInPriorLayer()) ||
609609
classEntry.getFields().stream().anyMatch(DwarfInfoSectionImpl::isManifestedStaticField)) {
610610
setCUIndex(classEntry, pos);
611611
pos = writeInstanceClassInfo(context, classEntry, buffer, pos);
@@ -1279,7 +1279,7 @@ private int writeField(DebugContext context, StructureTypeEntry entry, FieldEntr
12791279
private int writeSkeletonMethodDeclarations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) {
12801280
int pos = p;
12811281
for (MethodEntry method : classEntry.getMethods()) {
1282-
if (method.isInRange() || method.isInlined()) {
1282+
if (method.isInRange() || method.isInlined() || method.isCompiledInPriorLayer()) {
12831283
/*
12841284
* Declare all methods whether or not they have been compiled or inlined.
12851285
*/
@@ -1357,7 +1357,7 @@ private int writeSkeletonMethodParameterDeclaration(DebugContext context, LocalE
13571357
private int writeMethodDeclarations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) {
13581358
int pos = p;
13591359
for (MethodEntry method : classEntry.getMethods()) {
1360-
if (method.isInRange() || method.isInlined()) {
1360+
if (method.isInRange() || method.isInlined() || method.isCompiledInPriorLayer()) {
13611361
/*
13621362
* Declare all methods whether they have been compiled or inlined.
13631363
*/

substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,11 @@ private int writeCompiledMethodLineInfo(DebugContext context, ClassEntry classEn
508508
pos = writeAdvancePCOp(context, addressDelta, buffer, pos);
509509
}
510510
}
511+
/*
512+
* Add a row to the line number table and reset some flags. This makes sure a
513+
* debugger can stop here and properly process line and address. Special opcodes
514+
* have a similar effect as the copy operation, hence it is only used here.
515+
*/
511516
pos = writeCopyOp(context, buffer, pos);
512517
}
513518
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/debug/SharedDebugInfoProvider.java

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -733,10 +733,11 @@ private MethodEntry createMethodEntry(SharedMethod method) {
733733
boolean isOverride = isOverride(method);
734734
boolean isDeopt = method.isDeoptTarget();
735735
boolean isConstructor = method.isConstructor();
736+
boolean isCompiledInPriorLayer = isCompiledInPriorLayer(method);
736737

737738
return new MethodEntry(fileEntry, line, methodName, ownerType,
738739
valueType, modifiers, params, symbolName, isDeopt, isOverride, isConstructor,
739-
vTableOffset, lastParamSlot);
740+
isCompiledInPriorLayer, vTableOffset, lastParamSlot);
740741
}
741742

742743
/**
@@ -1010,6 +1011,10 @@ public boolean isOverride(@SuppressWarnings("unused") SharedMethod method) {
10101011
return false;
10111012
}
10121013

1014+
public boolean isCompiledInPriorLayer(@SuppressWarnings("unused") SharedMethod method) {
1015+
return false;
1016+
}
1017+
10131018
public boolean isVirtual(@SuppressWarnings("unused") SharedMethod method) {
10141019
return false;
10151020
}
@@ -1217,7 +1222,7 @@ protected LocalEntry lookupLocalEntry(String name, TypeEntry typeEntry, int slot
12171222
/**
12181223
* Lookup a {@code LocalValueEntry}. This can either be a register, stack, constant value. This
12191224
* allows to reuse the same entries for multiple ranges.
1220-
*
1225+
*
12211226
* @param localValueEntry the {@code LocalValueEntry} to lookup
12221227
* @return the {@code LocalValueEntry} from the lookup map
12231228
*/
@@ -1403,7 +1408,7 @@ private Map<LocalEntry, LocalValueEntry> initSyntheticInfoList(ParamLocationProd
14031408
debug.log(DebugContext.DETAILED_LEVEL, "local[%d] %s type %s slot %d", paramIdx + 1, param.name(), param.type().getTypeName(), param.slot());
14041409
debug.log(DebugContext.DETAILED_LEVEL, " => %s", value);
14051410
}
1406-
LocalValueEntry localValueEntry = createLocalValueEntry(value, PRE_EXTEND_FRAME_SIZE);
1411+
LocalValueEntry localValueEntry = createLocalValueEntry(value, PRE_EXTEND_FRAME_SIZE, true);
14071412
if (localValueEntry != null) {
14081413
localValueInfos.put(param, localValueEntry);
14091414
}
@@ -1565,7 +1570,13 @@ public Range process(CompilationResultFrameTree.FrameNode node, CallRange caller
15651570
LineNumberTable lineNumberTable = method.getLineNumberTable();
15661571
int line = lineNumberTable == null ? -1 : lineNumberTable.getLineNumber(pos.getBCI());
15671572

1568-
Map<LocalEntry, LocalValueEntry> localValueInfos = initLocalInfoList(pos, methodEntry, frameSize);
1573+
/*
1574+
* Locals are stored in both leaf ranges and call ranges. However, for call ranges we do
1575+
* not want to store register values as registers may be overwritten in callee ranges.
1576+
* Thus, a debugger is still able to process stack values and constants for stack
1577+
* traces.
1578+
*/
1579+
Map<LocalEntry, LocalValueEntry> localValueInfos = initLocalInfoList(pos, methodEntry, frameSize, isLeaf);
15691580
Range locationInfo = Range.createSubrange(primary, methodEntry, localValueInfos, node.getStartPos(), node.getEndPos() + 1, line, callerInfo, isLeaf);
15701581

15711582
if (debug.isLogEnabled()) {
@@ -1585,9 +1596,10 @@ public Range process(CompilationResultFrameTree.FrameNode node, CallRange caller
15851596
* @param pos the bytecode position of the location info
15861597
* @param methodEntry the {@code MethodEntry} corresponding to the bytecode position
15871598
* @param frameSize the current frame size
1599+
* @param isLeaf whether the range to create this value for is a leaf range
15881600
* @return a mapping from {@code LocalEntry} to {@code LocalValueEntry}
15891601
*/
1590-
protected Map<LocalEntry, LocalValueEntry> initLocalInfoList(BytecodePosition pos, MethodEntry methodEntry, int frameSize) {
1602+
protected Map<LocalEntry, LocalValueEntry> initLocalInfoList(BytecodePosition pos, MethodEntry methodEntry, int frameSize, boolean isLeaf) {
15911603
Map<LocalEntry, LocalValueEntry> localInfos = new HashMap<>();
15921604

15931605
if (pos instanceof BytecodeFrame frame && frame.numLocals > 0) {
@@ -1688,7 +1700,7 @@ protected Map<LocalEntry, LocalValueEntry> initLocalInfoList(BytecodePosition po
16881700
* upfront from the local variable table, the LocalEntry already exists.
16891701
*/
16901702
LocalEntry localEntry = methodEntry.getOrAddLocalEntry(lookupLocalEntry(name, typeEntry, slot), line);
1691-
LocalValueEntry localValueEntry = createLocalValueEntry(value, frameSize);
1703+
LocalValueEntry localValueEntry = createLocalValueEntry(value, frameSize, isLeaf);
16921704
if (localEntry != null && localValueEntry != null) {
16931705
localInfos.put(localEntry, localValueEntry);
16941706
}
@@ -1703,16 +1715,24 @@ protected Map<LocalEntry, LocalValueEntry> initLocalInfoList(BytecodePosition po
17031715

17041716
/**
17051717
* Creates a {@code LocalValueEntry} for a given {@code JavaValue}. This processes register
1706-
* values, stack values, primitive constants and constant in the heap.
1718+
* values, stack values, primitive constants and constant in the heap. Register values are only
1719+
* added for leaf frames, as register may be overwritten within callee frames of a call range.
1720+
* But, stack values and constants also work for call ranges.
17071721
*
17081722
* @param value the given {@code JavaValue}
17091723
* @param frameSize the frame size for stack values
1724+
* @param isLeaf whether the range to create this value for is a leaf range
17101725
* @return the {@code LocalValueEntry} or {@code null} if the value can't be processed
17111726
*/
1712-
private LocalValueEntry createLocalValueEntry(JavaValue value, int frameSize) {
1727+
private LocalValueEntry createLocalValueEntry(JavaValue value, int frameSize, boolean isLeaf) {
17131728
switch (value) {
17141729
case RegisterValue registerValue -> {
1715-
return lookupLocalValueEntry(new RegisterValueEntry(registerValue.getRegister().number));
1730+
/*
1731+
* We only want to create register entries for leaf nodes. Thus, they are only valid
1732+
* within a leaf range but not over a whole call range where the register value is
1733+
* potentially overwritten.
1734+
*/
1735+
return isLeaf ? lookupLocalValueEntry(new RegisterValueEntry(registerValue.getRegister().number)) : null;
17161736
}
17171737
case StackSlot stackValue -> {
17181738
int stackSlot = frameSize == 0 ? stackValue.getRawOffset() : stackValue.getOffset(frameSize);
@@ -1827,7 +1847,7 @@ private Range createEmbeddedParentLocationInfo(PrimaryRange primary, Compilation
18271847
LineNumberTable lineNumberTable = method.getLineNumberTable();
18281848
int line = lineNumberTable == null ? -1 : lineNumberTable.getLineNumber(pos.getBCI());
18291849

1830-
Map<LocalEntry, LocalValueEntry> localValueInfos = initLocalInfoList(pos, methodEntry, frameSize);
1850+
Map<LocalEntry, LocalValueEntry> localValueInfos = initLocalInfoList(pos, methodEntry, frameSize, true);
18311851
Range locationInfo = Range.createSubrange(primary, methodEntry, localValueInfos, startPos, endPos, line, callerLocation, true);
18321852

18331853
if (debug.isLogEnabled()) {
@@ -1881,7 +1901,7 @@ private static boolean skipPos(BytecodePosition pos) {
18811901
* at native image build-time while still having comparable performance (for most of the index
18821902
* maps). The most performance critical maps that see more traffic will use the less memory
18831903
* efficient ConcurrentHashMaps instead.
1884-
*
1904+
*
18851905
* @param map the {@code EconomicMap} to perform {@code computeIfAbsent} on
18861906
* @param key the key to look for
18871907
* @param mappingFunction the function producing the value for a given key

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
import com.oracle.svm.core.debug.SubstrateDebugTypeEntrySupport;
7272
import com.oracle.svm.core.graal.meta.RuntimeConfiguration;
7373
import com.oracle.svm.core.image.ImageHeapPartition;
74+
import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo;
75+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
7476
import com.oracle.svm.core.meta.SharedMethod;
7577
import com.oracle.svm.core.meta.SharedType;
7678
import com.oracle.svm.core.util.VMError;
@@ -496,6 +498,11 @@ public boolean isOverride(SharedMethod method) {
496498
return method instanceof HostedMethod && allOverrides.contains(method);
497499
}
498500

501+
@Override
502+
public boolean isCompiledInPriorLayer(SharedMethod method) {
503+
return method instanceof HostedMethod hostedMethod && hostedMethod.isCompiledInPriorLayer();
504+
}
505+
499506
@Override
500507
public boolean isVirtual(SharedMethod method) {
501508
return method instanceof HostedMethod hostedMethod && hostedMethod.hasVTableIndex();
@@ -583,7 +590,14 @@ private void processFieldEntries(HostedType type, StructureTypeEntry structureTy
583590

584591
for (ResolvedJavaField field : type.getStaticFields()) {
585592
assert field instanceof HostedField;
586-
structureTypeEntry.addField(createFieldEntry((HostedField) field, structureTypeEntry));
593+
/*
594+
* If we are in a layered build only add debug info for a static field if it is
595+
* installed in the current layer.
596+
*/
597+
if (!ImageLayerBuildingSupport.buildingImageLayer() ||
598+
(((HostedField) field).hasInstalledLayerNum() && DynamicImageLayerInfo.getCurrentLayerNumber() == StaticFieldsSupport.getInstalledLayerNum(field))) {
599+
structureTypeEntry.addField(createFieldEntry((HostedField) field, structureTypeEntry));
600+
}
587601
}
588602
}
589603

substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/debug/CStructTests.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,10 @@
3636
import org.graalvm.nativeimage.c.type.CTypeConversion.CCharPointerHolder;
3737
import org.graalvm.word.PointerBase;
3838
import org.graalvm.word.SignedWord;
39+
import org.graalvm.word.WordBase;
3940

4041
import com.oracle.svm.core.NeverInline;
4142

42-
import jdk.graal.compiler.api.directives.GraalDirectives;
43-
4443
@CContext(CInterfaceDebugTestDirectives.class)
4544
public class CStructTests {
4645
@CPointerTo(nameOfCType = "int")
@@ -238,10 +237,20 @@ private static void testMixedArguments(String m1, short s, SimpleStruct ss1, lon
238237
System.out.println("You find " + m1);
239238
System.out.println("You find " + m2);
240239
System.out.println("You find " + m3);
241-
GraalDirectives.blackhole(s);
242-
GraalDirectives.blackhole(ss1);
243-
GraalDirectives.blackhole(l);
244-
GraalDirectives.blackhole(ss2);
240+
blackhole(s);
241+
blackhole(ss1);
242+
blackhole(l);
243+
blackhole(ss2);
244+
}
245+
246+
@NeverInline("For testing.")
247+
@SuppressWarnings("unused")
248+
static void blackhole(Object value) {
249+
}
250+
251+
@NeverInline("For testing.")
252+
@SuppressWarnings("unused")
253+
static void blackhole(WordBase value) {
245254
}
246255

247256
public static void main(String[] args) {

substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/debug/helper/PrettyPrinterTest.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,51 +115,54 @@ public static class Holder {
115115
@NeverInline("For testing purposes")
116116
static void testPrimitive(byte b, Byte bObj, short s, Short sObj, char c, Character cObj, int i, Integer iObj, long l, Long lObj,
117117
float f, Float fObj, double d, Double dObj, boolean x, Boolean xObj) {
118-
System.out.print("");
118+
blackhole(b, bObj, s, sObj, c, cObj, i, iObj, l, lObj, f, fObj, d, dObj, x, xObj);
119119
}
120120

121121
@SuppressWarnings("unused")
122122
@NeverInline("For testing purposes")
123123
static void testString(String nullStr, String emptyStr, String str, String uStr1, String uStr2, String uStr3, String uStr4, String uStr5, String str0) {
124-
System.out.print("");
124+
blackhole(nullStr, emptyStr, str, uStr1, uStr2, uStr3, uStr4, uStr5, str0);
125125
}
126126

127127
@SuppressWarnings("unused")
128128
@NeverInline("For testing purposes")
129129
static void testArray(int[] ia, Object[] oa, String[] sa) {
130-
System.out.print("");
130+
blackhole(ia, oa, sa);
131131
}
132132

133133
@SuppressWarnings("unused")
134134
@NeverInline("For testing purposes")
135135
static void testObject(ExampleClass object, ExampleClass recObject) {
136-
System.out.print("");
136+
blackhole(object, recObject);
137137
}
138138

139139
@SuppressWarnings("unused")
140140
@NeverInline("For testing purposes")
141141
static void testArrayList(ArrayList<String> strList, List<Object> mixedList, ArrayList<Object> nullList) {
142-
System.out.print("");
142+
blackhole(strList, mixedList, nullList);
143143
}
144144

145145
@SuppressWarnings("unused")
146146
@NeverInline("For testing purposes")
147147
static void testHashMap(HashMap<String, String> strMap, Map<Object, Object> mixedMap) {
148-
System.out.print("");
148+
blackhole(strMap, mixedMap);
149149
}
150150

151151
@SuppressWarnings("unused")
152152
@NeverInline("For testing purposes")
153153
static void testLambda(Function<String, String> lambda) {
154-
System.out.print("");
154+
blackhole(lambda);
155155
}
156156

157157
@SuppressWarnings("unused")
158158
@NeverInline("For testing purposes")
159159
static void testClassType(Class<?> clazz, Holder dyn) {
160-
System.out.print("");
161-
System.out.print(staticHolder.c);
162-
System.out.print(staticHolder.o);
160+
blackhole(clazz, dyn, staticHolder.c, staticHolder.o);
161+
}
162+
163+
@NeverInline("For testing.")
164+
@SuppressWarnings("unused")
165+
static void blackhole(Object... value) {
163166
}
164167

165168
static ExampleClass setupExampleObject(boolean recursive) {

substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/debug/helper/RuntimeCompileDebugInfoTest.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,6 @@ public static class RegisterMethodsFeature implements Feature {
219219
ModuleSupport.accessPackagesToClass(ModuleSupport.Access.EXPORT, RegisterMethodsFeature.class, false,
220220
"jdk.internal.vm.ci",
221221
"jdk.vm.ci.code");
222-
ModuleSupport.accessPackagesToClass(ModuleSupport.Access.EXPORT, RegisterMethodsFeature.class, false,
223-
"jdk.graal.compiler",
224-
"jdk.graal.compiler.api.directives", "jdk.graal.compiler.word");
225222
}
226223

227224
@Override

0 commit comments

Comments
 (0)