Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6fcf983
Augment Range with info for nested inlining
zakkak Sep 30, 2020
641c36f
Chain debugLineInfo instances to get call-chain for nested inlining
zakkak Sep 29, 2020
bf15d31
Extend DWARF abbrevs
zakkak Sep 29, 2020
d362461
Create subranges for nested inlined callers
zakkak Sep 30, 2020
f0c5eca
Add dwarf info for nested inlined subroutines
zakkak Sep 30, 2020
46ec35c
DebugInfo fix file association for corner case
zakkak Oct 7, 2020
ddd6d13
Update debuginfotest to work with new debug info
zakkak Mar 16, 2021
abe98ea
Optimize debug info generation with -H:+OmitInlinedMethodDebugLineInfo
zakkak Jun 29, 2021
cdeb901
Refactor: Improve readability of DwarfInfoSectionImpl#writeMethodLoca…
zakkak Jun 29, 2021
219a2e3
Refactor: Use types to decide if a method is inlined, used, etc.
adinn Jul 20, 2021
1334190
Generate abstract inline DIEs in classes' CUs
adinn Jul 20, 2021
99d3c5c
Filter out potentially invalid line and caller records
adinn Aug 17, 2021
8434b31
Refactor: Move isInline and isInRange logic in MethodEntry.updateRang…
zakkak Aug 17, 2021
49b9462
Refactor: Renaming variables
adinn Aug 17, 2021
57cd7c4
Introduce dwarf abbreviation for non-primary classes + cleanUp + docs
adinn Aug 17, 2021
7a627e5
Refactor: Improve logging and assert messages
adinn Aug 17, 2021
9f36419
Refactor: DwarfInfoSectionImpl#writeMethodLocation
adinn Aug 17, 2021
268c332
DebugInfo: Model subranges as trees to retain call-tree information
adinn Aug 17, 2021
6ae5665
Add missing documentation and rename some variables for readability
zakkak Aug 20, 2021
3a7f427
Refactor: Avoid toJavaName invocations when getting ranges' class
zakkak Aug 24, 2021
22014e6
Refactor: Perform binary search on sorted methods
zakkak Aug 24, 2021
a294e6d
Refactor: Use ResolvedJavaMethod to sort methods in ClassEntry
zakkak Aug 25, 2021
6ffc908
DebugInfo test extensions for nested inlined methods
zakkak Aug 23, 2021
7f0e606
Ensure call node source positions are not lost at substitution
adinn Sep 1, 2021
276a6d3
Correct regression introduced into debuginfo test script
adinn Sep 6, 2021
be1f5e0
Track methods with a hash index instead of a sorted list.
adinn Sep 6, 2021
65d5466
Remove redundant methods and fields
adinn Sep 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ public InvokeNode replaceWithInvoke() {
AbstractBeginNode oldException = this.exceptionEdge;
graph().replaceSplitWithFixed(this, newInvoke, this.next());
GraphUtil.killCFG(oldException);
// copy across any original node source position
newInvoke.setNodeSourcePosition(getNodeSourcePosition());
return newInvoke;
}

Expand Down
289 changes: 240 additions & 49 deletions substratevm/mx.substratevm/testhello.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.graalvm.compiler.debug.DebugContext;
Expand Down Expand Up @@ -63,6 +62,10 @@ public class ClassEntry extends StructureTypeEntry {
* Details of methods located in this instance.
*/
protected List<MethodEntry> methods;
/**
* An index of all currently known methods keyed by the unique local symbol name of the method.
*/
private Map<String, MethodEntry> methodsIndex;
/**
* A list recording details of all primary ranges included in this class sorted by ascending
* address range.
Expand Down Expand Up @@ -98,6 +101,7 @@ public ClassEntry(String className, FileEntry fileEntry, int size) {
this.interfaces = new ArrayList<>();
this.fileEntry = fileEntry;
this.methods = new ArrayList<>();
this.methodsIndex = new HashMap<>();
this.primaryEntries = new ArrayList<>();
this.primaryIndex = new HashMap<>();
this.localFiles = new ArrayList<>();
Expand Down Expand Up @@ -137,9 +141,7 @@ public void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInf
/* Add details of fields and field types */
debugInstanceTypeInfo.fieldInfoProvider().forEach(debugFieldInfo -> this.processField(debugFieldInfo, debugInfoBase, debugContext));
/* Add details of methods and method types */
debugInstanceTypeInfo.methodInfoProvider().forEach(methodFieldInfo -> this.methods.add(this.processMethod(methodFieldInfo, debugInfoBase, debugContext, false)));
/* Sort methods to improve lookup speed */
this.methods.sort(MethodEntry::compareTo);
debugInstanceTypeInfo.methodInfoProvider().forEach(debugMethodInfo -> this.processMethod(debugMethodInfo, debugInfoBase, debugContext));
}

public void indexPrimary(Range primary, List<DebugFrameSizeChange> frameSizeInfos, int frameSize) {
Expand Down Expand Up @@ -168,13 +170,19 @@ public void indexSubRange(Range subrange) {
/* We should already have seen the primary range. */
assert primaryEntry != null;
assert primaryEntry.getClassEntry() == this;
primaryEntry.addSubRange(subrange);
FileEntry subFileEntry = subrange.getFileEntry();
if (subFileEntry != null) {
indexLocalFileEntry(subFileEntry);
}
}

private void indexMethodEntry(MethodEntry methodEntry) {
String methodName = methodEntry.getSymbolName();
assert methodsIndex.get(methodName) == null : methodName;
methods.add(methodEntry);
methodsIndex.put(methodName, methodEntry);
}

private void indexLocalFileEntry(FileEntry localFileEntry) {
if (localFilesIndex.get(localFileEntry) == null) {
localFiles.add(localFileEntry);
Expand Down Expand Up @@ -273,8 +281,8 @@ private void processInterface(String interfaceName, DebugInfoBase debugInfoBase,
interfaceClassEntry.addImplementor(this, debugContext);
}

protected MethodEntry processMethod(DebugMethodInfo debugMethodInfo, DebugInfoBase debugInfoBase, DebugContext debugContext, boolean fromRangeInfo) {
String methodName = debugInfoBase.uniqueDebugString(debugMethodInfo.name());
protected MethodEntry processMethod(DebugMethodInfo debugMethodInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) {
String methodName = debugMethodInfo.name();
String resultTypeName = TypeEntry.canonicalize(debugMethodInfo.valueType());
int modifiers = debugMethodInfo.modifiers();
List<String> paramTypes = debugMethodInfo.paramTypes();
Expand All @@ -297,8 +305,11 @@ protected MethodEntry processMethod(DebugMethodInfo debugMethodInfo, DebugInfoBa
* substitution
*/
FileEntry methodFileEntry = debugInfoBase.ensureFileEntry(debugMethodInfo);
return new MethodEntry(methodFileEntry, debugMethodInfo.symbolNameForMethod(), methodName, this, resultType,
paramTypeArray, paramNameArray, modifiers, debugMethodInfo.isDeoptTarget(), fromRangeInfo);
MethodEntry methodEntry = new MethodEntry(debugInfoBase, debugMethodInfo, methodFileEntry, methodName,
this, resultType, paramTypeArray, paramNameArray);
indexMethodEntry(methodEntry);

return methodEntry;
}

@Override
Expand Down Expand Up @@ -340,35 +351,19 @@ public ClassEntry getSuperClass() {
}

public MethodEntry ensureMethodEntryForDebugRangeInfo(DebugRangeInfo debugRangeInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) {
assert listIsSorted(methods);
ListIterator<MethodEntry> methodIterator = methods.listIterator();
String methodName = debugInfoBase.uniqueDebugString(debugRangeInfo.name());
String paramSignature = debugRangeInfo.paramSignature();
String returnTypeName = debugRangeInfo.valueType();
while (methodIterator.hasNext()) {
MethodEntry methodEntry = methodIterator.next();
int comparisonResult = methodEntry.compareTo(methodName, paramSignature, returnTypeName);
if (comparisonResult == 0) {
methodEntry.setInRangeAndUpdateFileEntry(debugInfoBase, debugRangeInfo);
if (methodEntry.fileEntry != null) {
/* Ensure that the methodEntry's fileEntry is present in the localsFileIndex */
indexLocalFileEntry(methodEntry.fileEntry);
}
return methodEntry;
} else if (comparisonResult > 0) {
methodIterator.previous();
break;

MethodEntry methodEntry = methodsIndex.get(debugRangeInfo.symbolNameForMethod());
if (methodEntry == null) {
methodEntry = processMethod(debugRangeInfo, debugInfoBase, debugContext);
} else {
methodEntry.updateRangeInfo(debugInfoBase, debugRangeInfo);
/* Ensure that the methodEntry's fileEntry is present in the localsFileIndex */
FileEntry methodFileEntry = methodEntry.fileEntry;
if (methodFileEntry != null) {
indexLocalFileEntry(methodFileEntry);
}
}
MethodEntry newMethodEntry = processMethod(debugRangeInfo, debugInfoBase, debugContext, true);
methodIterator.add(newMethodEntry);
return newMethodEntry;
}

private static boolean listIsSorted(List<MethodEntry> list) {
List<MethodEntry> copy = new ArrayList<>(list);
copy.sort(MethodEntry::compareTo);
return list.equals(copy);
return methodEntry;
}

public List<MethodEntry> getMethods() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.util.Map;

import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFileInfo;
import jdk.vm.ci.meta.ResolvedJavaType;
import org.graalvm.compiler.debug.DebugContext;

import com.oracle.objectfile.debuginfo.DebugInfoProvider;
Expand Down Expand Up @@ -103,7 +104,7 @@ public abstract class DebugInfoBase {
/**
* index of already seen classes.
*/
private Map<String, ClassEntry> primaryClassesIndex = new HashMap<>();
private Map<ResolvedJavaType, ClassEntry> primaryClassesIndex = new HashMap<>();
/**
* Index of files which contain primary or secondary ranges.
*/
Expand Down Expand Up @@ -238,38 +239,24 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) {
*/
String fileName = debugCodeInfo.fileName();
Path filePath = debugCodeInfo.filePath();
String className = TypeEntry.canonicalize(debugCodeInfo.ownerType());
ResolvedJavaType ownerType = debugCodeInfo.ownerType();
String methodName = debugCodeInfo.name();
int lo = debugCodeInfo.addressLo();
int hi = debugCodeInfo.addressHi();
int primaryLine = debugCodeInfo.line();

/* Search for a method defining this primary range. */
ClassEntry classEntry = ensureClassEntry(className);
ClassEntry classEntry = ensureClassEntry(ownerType);
MethodEntry methodEntry = classEntry.ensureMethodEntryForDebugRangeInfo(debugCodeInfo, this, debugContext);
Range primaryRange = new Range(stringTable, methodEntry, lo, hi, primaryLine);
debugContext.log(DebugContext.INFO_LEVEL, "PrimaryRange %s.%s %s %s:%d [0x%x, 0x%x]", className, methodName, filePath, fileName, primaryLine, lo, hi);
debugContext.log(DebugContext.INFO_LEVEL, "PrimaryRange %s.%s %s %s:%d [0x%x, 0x%x]", ownerType.toJavaName(), methodName, filePath, fileName, primaryLine, lo, hi);
classEntry.indexPrimary(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize());
debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> {
String fileNameAtLine = debugLineInfo.fileName();
Path filePathAtLine = debugLineInfo.filePath();
String classNameAtLine = TypeEntry.canonicalize(debugLineInfo.ownerType());
String methodNameAtLine = debugLineInfo.name();
int loAtLine = lo + debugLineInfo.addressLo();
int hiAtLine = lo + debugLineInfo.addressHi();
int line = debugLineInfo.line();
/*
* Record all subranges even if they have no line or file so we at least get a
* symbol for them and don't see a break in the address range.
*/
ClassEntry subClassEntry = ensureClassEntry(classNameAtLine);
MethodEntry subMethodEntry = subClassEntry.ensureMethodEntryForDebugRangeInfo(debugLineInfo, this, debugContext);
Range subRange = new Range(stringTable, subMethodEntry, loAtLine, hiAtLine, line, primaryRange);
classEntry.indexSubRange(subRange);
try (DebugContext.Scope s = debugContext.scope("Subranges")) {
debugContext.log(DebugContext.VERBOSE_LEVEL, "SubRange %s.%s %s %s:%d 0x%x, 0x%x]", classNameAtLine, methodNameAtLine, filePathAtLine, fileNameAtLine, line, loAtLine, hiAtLine);
}
});
/*
* Record all subranges even if they have no line or file so we at least get a symbol
* for them and don't see a break in the address range.
*/
debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> recursivelyAddSubRanges(debugLineInfo, primaryRange, classEntry, debugContext));
primaryRange.mergeSubranges(debugContext);
}));

debugInfoProvider.dataInfoProvider().forEach(debugDataInfo -> debugDataInfo.debugContext((debugContext) -> {
Expand Down Expand Up @@ -350,17 +337,60 @@ ClassEntry lookupClassEntry(String typeName) {
return (ClassEntry) typeEntry;
}

private ClassEntry ensureClassEntry(String className) {
/**
* Recursively creates subranges based on DebugLineInfo including, and appropriately linking,
* nested inline subranges.
*
* @param lineInfo
* @param primaryRange
* @param classEntry
* @param debugContext
* @return the subrange for {@code lineInfo} linked with all its caller subranges up to the
* primaryRange
*/
@SuppressWarnings("try")
private Range recursivelyAddSubRanges(DebugInfoProvider.DebugLineInfo lineInfo, Range primaryRange, ClassEntry classEntry, DebugContext debugContext) {
if (lineInfo == null) {
return primaryRange;
}
/*
* We still insert subranges for the primary method but they don't actually count as inline.
* we only need a range so that subranges for inline code can refer to the top level line
* number
*/
boolean isInline = lineInfo.getCaller() != null;
assert (isInline || (lineInfo.name().equals(primaryRange.getMethodName()) && TypeEntry.canonicalize(lineInfo.ownerType().toJavaName()).equals(primaryRange.getClassName())));

Range caller = recursivelyAddSubRanges(lineInfo.getCaller(), primaryRange, classEntry, debugContext);
final String fileName = lineInfo.fileName();
final Path filePath = lineInfo.filePath();
final ResolvedJavaType ownerType = lineInfo.ownerType();
final String methodName = lineInfo.name();
final int lo = primaryRange.getLo() + lineInfo.addressLo();
final int hi = primaryRange.getLo() + lineInfo.addressHi();
final int line = lineInfo.line();
ClassEntry subRangeClassEntry = ensureClassEntry(ownerType);
MethodEntry subRangeMethodEntry = subRangeClassEntry.ensureMethodEntryForDebugRangeInfo(lineInfo, this, debugContext);
Range subRange = new Range(stringTable, subRangeMethodEntry, lo, hi, line, primaryRange, isInline, caller);
classEntry.indexSubRange(subRange);
try (DebugContext.Scope s = debugContext.scope("Subranges")) {
debugContext.log(DebugContext.VERBOSE_LEVEL, "SubRange %s.%s %s %s:%d 0x%x, 0x%x]",
ownerType.toJavaName(), methodName, filePath, fileName, line, lo, hi);
}
return subRange;
}

private ClassEntry ensureClassEntry(ResolvedJavaType type) {
/* See if we already have an entry. */
ClassEntry classEntry = primaryClassesIndex.get(className);
ClassEntry classEntry = primaryClassesIndex.get(type);
if (classEntry == null) {
TypeEntry typeEntry = typesIndex.get(className);
TypeEntry typeEntry = typesIndex.get(TypeEntry.canonicalize(type.toJavaName()));
assert (typeEntry != null && typeEntry.isClass());
classEntry = (ClassEntry) typeEntry;
primaryClasses.add(classEntry);
primaryClassesIndex.put(className, classEntry);
primaryClassesIndex.put(type, classEntry);
}
assert (classEntry.getTypeName().equals(className));
assert (classEntry.getTypeName().equals(TypeEntry.canonicalize(type.toJavaName())));
return classEntry;
}

Expand Down
Loading