From 8ad61e7f1ee78bf80654d3fc1786003ae76d9ecb Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 12 Apr 2023 12:11:16 +0100 Subject: [PATCH 1/9] Working version with one compile unti for all code. --- .../objectfile/debugentry/ClassEntry.java | 183 +- .../objectfile/debugentry/DebugInfoBase.java | 72 +- .../objectfile/debugentry/DirEntry.java | 14 +- .../objectfile/debugentry/FileEntry.java | 13 +- .../objectfile/debugentry/MemberEntry.java | 4 + .../debugentry/range/PrimaryRange.java | 6 - .../objectfile/debugentry/range/Range.java | 4 +- .../objectfile/debugentry/range/SubRange.java | 7 - .../debuginfo/DebugInfoProvider.java | 2 + .../elf/dwarf/DwarfARangesSectionImpl.java | 112 +- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 1663 ++++++++--------- .../objectfile/elf/dwarf/DwarfDebugInfo.java | 186 +- .../elf/dwarf/DwarfFrameSectionImpl.java | 13 +- .../elf/dwarf/DwarfInfoSectionImpl.java | 675 +++---- .../elf/dwarf/DwarfLineSectionImpl.java | 248 ++- .../elf/dwarf/DwarfLocSectionImpl.java | 36 +- .../elf/dwarf/DwarfSectionImpl.java | 89 +- .../image/NativeImageDebugInfoProvider.java | 5 + 18 files changed, 1375 insertions(+), 1957 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java index 965ac3155fcc..0c85e8b9d252 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java @@ -80,50 +80,16 @@ public class ClassEntry extends StructureTypeEntry { * A list recording details of all normal compiled methods included in this class sorted by * ascending address range. Note that the associated address ranges are disjoint and contiguous. */ - private final List normalCompiledEntries = new ArrayList<>(); + private final List compiledEntries = new ArrayList<>(); /** - * A list recording details of all deopt fallback compiled methods included in this class sorted - * by ascending address range. Note that the associated address ranges are disjoint, contiguous - * and above all ranges for normal compiled methods. - */ - private List deoptCompiledEntries; - /** - * An index identifying ranges for compiled method which have already been encountered, whether - * normal or deopt fallback methods. + * An index identifying ranges for compiled method which have already been encountered. */ private final EconomicMap compiledMethodIndex = EconomicMap.create(); - /** - * An index of all primary and secondary files referenced from this class's compilation unit. - */ - private final EconomicMap localFilesIndex = EconomicMap.create(); - /** - * A list of the same files. - */ - private final List localFiles = new ArrayList<>(); - /** - * An index of all primary and secondary dirs referenced from this class's compilation unit. - */ - private final EconomicMap localDirsIndex = EconomicMap.create(); - /** - * A list of the same dirs. - */ - private final List localDirs = new ArrayList<>(); public ClassEntry(String className, FileEntry fileEntry, int size) { super(className, size); this.fileEntry = fileEntry; this.loader = null; - // deopt methods list is created on demand - this.deoptCompiledEntries = null; - if (fileEntry != null) { - localFiles.add(fileEntry); - localFilesIndex.put(fileEntry, localFiles.size()); - DirEntry dirEntry = fileEntry.getDirEntry(); - if (dirEntry != null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); - } - } } @Override @@ -159,25 +125,12 @@ public void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInf debugInstanceTypeInfo.methodInfoProvider().forEach(debugMethodInfo -> this.processMethod(debugMethodInfo, debugInfoBase, debugContext)); } - public void indexPrimary(PrimaryRange primary, List frameSizeInfos, int frameSize) { - if (compiledMethodIndex.get(primary) == null) { - CompiledMethodEntry compiledEntry = new CompiledMethodEntry(primary, frameSizeInfos, frameSize, this); - compiledMethodIndex.put(primary, compiledEntry); - if (primary.isDeoptTarget()) { - if (deoptCompiledEntries == null) { - deoptCompiledEntries = new ArrayList<>(); - } - deoptCompiledEntries.add(compiledEntry); - } else { - normalCompiledEntries.add(compiledEntry); - /* deopt targets should all come after normal methods */ - assert deoptCompiledEntries == null; - } - FileEntry primaryFileEntry = primary.getFileEntry(); - if (primaryFileEntry != null) { - indexLocalFileEntry(primaryFileEntry); - } - } + public CompiledMethodEntry indexPrimary(PrimaryRange primary, List frameSizeInfos, int frameSize) { + assert compiledMethodIndex.get(primary) == null : "repeat of primary range [0x%x, 0x%x]!".formatted(primary.getLo(), primary.getHi()); + CompiledMethodEntry compiledEntry = new CompiledMethodEntry(primary, frameSizeInfos, frameSize, this); + compiledMethodIndex.put(primary, compiledEntry); + compiledEntries.add(compiledEntry); + return compiledEntry; } public void indexSubRange(SubRange subrange) { @@ -188,10 +141,6 @@ public void indexSubRange(SubRange subrange) { /* We should already have seen the primary range. */ assert compiledEntry != null; assert compiledEntry.getClassEntry() == this; - FileEntry subFileEntry = subrange.getFileEntry(); - if (subFileEntry != null) { - indexLocalFileEntry(subFileEntry); - } } private void indexMethodEntry(MethodEntry methodEntry, ResolvedJavaMethod idMethod) { @@ -200,34 +149,6 @@ private void indexMethodEntry(MethodEntry methodEntry, ResolvedJavaMethod idMeth methodsIndex.put(idMethod, methodEntry); } - private void indexLocalFileEntry(FileEntry localFileEntry) { - if (localFilesIndex.get(localFileEntry) == null) { - localFiles.add(localFileEntry); - localFilesIndex.put(localFileEntry, localFiles.size()); - DirEntry dirEntry = localFileEntry.getDirEntry(); - if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); - } - } - } - - public int localDirsIdx(DirEntry dirEntry) { - if (dirEntry != null) { - return localDirsIndex.get(dirEntry); - } else { - return 0; - } - } - - public int localFilesIdx() { - return localFilesIndex.get(fileEntry); - } - - public int localFilesIdx(@SuppressWarnings("hiding") FileEntry fileEntry) { - return localFilesIndex.get(fileEntry); - } - public String getFileName() { if (fileEntry != null) { return fileEntry.getFileName(); @@ -236,7 +157,6 @@ public String getFileName() { } } - @SuppressWarnings("unused") public String getFullFileName() { if (fileEntry != null) { return fileEntry.getFullName(); @@ -258,6 +178,10 @@ public FileEntry getFileEntry() { return fileEntry; } + public int getFileIdx() { + return fileEntry.getIdx(); + } + public String getLoaderId() { return (loader != null ? loader.getLoaderId() : ""); } @@ -269,11 +193,7 @@ public String getLoaderId() { * @return a stream of all compiled method entries for this class. */ public Stream compiledEntries() { - Stream stream = normalCompiledEntries.stream(); - if (deoptCompiledEntries != null) { - stream = Stream.concat(stream, deoptCompiledEntries.stream()); - } - return stream; + return compiledEntries.stream(); } /** @@ -283,32 +203,7 @@ public Stream compiledEntries() { * @return a stream of all normal compiled method entries for this class. */ public Stream normalCompiledEntries() { - return normalCompiledEntries.stream(); - } - - /** - * Retrieve a stream of all deopt fallback compiled method entries for this class. - * - * @return a stream of all deopt fallback compiled method entries for this class. - */ - public Stream deoptCompiledEntries() { - if (hasDeoptCompiledEntries()) { - return deoptCompiledEntries.stream(); - } else { - return Stream.empty(); - } - } - - public List getLocalDirs() { - return localDirs; - } - - public List getLocalFiles() { - return localFiles; - } - - public boolean hasDeoptCompiledEntries() { - return deoptCompiledEntries != null; + return compiledEntries(); } private void processInterface(ResolvedJavaType interfaceType, DebugInfoBase debugInfoBase, DebugContext debugContext) { @@ -352,10 +247,6 @@ protected MethodEntry processMethod(DebugMethodInfo debugMethodInfo, DebugInfoBa @Override protected FieldEntry addField(DebugFieldInfo debugFieldInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) { FieldEntry fieldEntry = super.addField(debugFieldInfo, debugInfoBase, debugContext); - FileEntry fieldFileEntry = fieldEntry.getFileEntry(); - if (fieldFileEntry != null) { - indexLocalFileEntry(fieldFileEntry); - } return fieldEntry; } @@ -377,7 +268,7 @@ private static String formatParams(DebugLocalInfo[] paramInfo) { } public boolean hasCompiledEntries() { - return normalCompiledEntries.size() != 0; + return compiledEntries.size() != 0; } public ClassEntry getSuperClass() { @@ -391,11 +282,6 @@ public MethodEntry ensureMethodEntryForDebugRangeInfo(DebugRangeInfo debugRangeI 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); - } } return methodEntry; } @@ -417,47 +303,18 @@ public List getMethods() { */ public int lowpc() { assert hasCompiledEntries(); - return normalCompiledEntries.get(0).getPrimary().getLo(); + return compiledEntries.get(0).getPrimary().getLo(); } /** - * Retrieve the lowest code section offset for compiled method code belonging to this class that - * belongs to a deoptimization fallback compiled method. It is an error to call this for a class - * entry which has no deoptimization fallback compiled methods. - * - * @return the lowest code section offset for a deoptimization fallback compiled method - * belonging to this class. - */ - public int lowpcDeopt() { - assert hasCompiledEntries(); - assert hasDeoptCompiledEntries(); - return deoptCompiledEntries.get(0).getPrimary().getLo(); - } - - /** - * Retrieve the highest code section offset for compiled method code belonging to this class - * that does not belong to a deoptimization fallback compiled method. The returned value is the - * offset of the first byte that succeeds the code for that method. It is an error to call this - * for a class entry which has no compiled methods. + * Retrieve the highest code section offset for compiled method code belonging to this class. + * The returned value is the offset of the first byte that succeeds the code for that method. + * It is an error to call this for a class entry which has no compiled methods. * * @return the highest code section offset for compiled method code belonging to this class */ public int hipc() { assert hasCompiledEntries(); - return normalCompiledEntries.get(normalCompiledEntries.size() - 1).getPrimary().getHi(); - } - - /** - * Retrieve the highest code section offset for compiled method code belonging to this class - * that belongs to a deoptimization fallback compiled method. It is an error to call this for a - * class entry which has no deoptimization fallback compiled methods. - * - * @return the highest code section offset for a deoptimization fallback compiled method - * belonging to this class. - */ - public int hipcDeopt() { - assert hasCompiledEntries(); - assert hasDeoptCompiledEntries(); - return deoptCompiledEntries.get(deoptCompiledEntries.size() - 1).getPrimary().getHi(); + return compiledEntries.get(compiledEntries.size() - 1).getPrimary().getHi(); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java index 217ed977107c..6000297b161a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java @@ -43,6 +43,7 @@ import org.graalvm.compiler.debug.DebugContext; import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLocationInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLocalValueInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; @@ -108,6 +109,10 @@ public abstract class DebugInfoBase { * debug_str section. */ private final StringTable stringTable = new StringTable(); + /** + * List of dirs in which files are found to reside. + */ + private final List dirs = new ArrayList<>(); /** * Index of all dirs in which files are found to reside either as part of substrate/compiler or * user code. @@ -141,6 +146,11 @@ public abstract class DebugInfoBase { * Handle on class entry for java.lang.Object. */ private ClassEntry objectClass; + /** + * List of all top level compiled methods found in debug info. These ought to arrive + * via the debug info API in ascending address range order. + */ + private final List compiledMethods = new ArrayList<>(); /** * List of of files which contain primary or secondary ranges. */ @@ -190,11 +200,15 @@ public abstract class DebugInfoBase { */ private int oopAlignShift; /** - * * The compilation directory in which to look for source files as a {@link String}. */ private String cachePath; + /** + * The offset of the first byte beyond the end of the Java compiled code address range. + */ + private int compiledCodeMax; + /** * The type entry for java.lang.Class. */ @@ -210,6 +224,13 @@ public DebugInfoBase(ByteOrder byteOrder) { this.oopAlignment = 0; this.oopAlignShift = 0; this.hubClassEntry = null; + this.compiledCodeMax = 0; + // create and index an empty dir with index 0. + ensureDirEntry(EMPTY_PATH); + } + + public int compiledCodeMax() { + return compiledCodeMax; } /** @@ -264,6 +285,9 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { /* Reference alignment must be 8 bytes. */ assert oopAlignment == 8; + /* retrieve limit for Java code address range */ + compiledCodeMax = debugInfoProvider.compiledCodeMax(); + /* Ensure we have a null string and cachePath in the string section. */ String uniqueNullString = stringTable.uniqueDebugString(""); if (debugInfoProvider.getCachePath() != null) { @@ -314,7 +338,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { MethodEntry methodEntry = classEntry.ensureMethodEntryForDebugRangeInfo(debugCodeInfo, this, debugContext); PrimaryRange primaryRange = Range.createPrimary(methodEntry, lo, hi, primaryLine); 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()); + addPrimaryRange(primaryRange, debugCodeInfo, classEntry); /* * 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. @@ -433,6 +457,10 @@ public ClassEntry lookupObjectClass() { return objectClass; } + private void addPrimaryRange(PrimaryRange primaryRange, DebugCodeInfo debugCodeInfo, ClassEntry classEntry) { + CompiledMethodEntry compiledMethod = classEntry.indexPrimary(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); + indexCompiledMethod(compiledMethod); + } /** * Recursively creates subranges based on DebugLocationInfo including, and appropriately * linking, nested inline subranges. @@ -492,6 +520,26 @@ private void indexInstanceClass(ResolvedJavaType idType, ClassEntry classEntry) instanceClassesIndex.put(idType, classEntry); } + private void indexCompiledMethod(CompiledMethodEntry compiledMethod) { + assert verifyMethodOrder(compiledMethod); + compiledMethods.add(compiledMethod); + } + + private boolean verifyMethodOrder(CompiledMethodEntry next) { + int size = compiledMethods.size(); + if (size > 0) { + CompiledMethodEntry last = compiledMethods.get(size - 1); + PrimaryRange lastRange = last.getPrimary(); + PrimaryRange nextRange = next.getPrimary(); + if (lastRange.getHi() > nextRange.getLo()) { + assert false : "methods %s [0x%x, 0x%x] and %s [0x%x, 0x%x] presented out of order".formatted(lastRange.getFullMethodName(), lastRange.getLo(), lastRange.getHi(), nextRange.getFullMethodName(), nextRange.getLo(), nextRange.getHi()); + return false; + } + } + return true; + } + + final static Path EMPTY_PATH = Paths.get(""); private FileEntry addFileEntry(String fileName, Path filePath) { assert fileName != null; Path fileAsPath; @@ -499,6 +547,7 @@ private FileEntry addFileEntry(String fileName, Path filePath) { fileAsPath = filePath.resolve(fileName); } else { fileAsPath = Paths.get(fileName); + filePath = EMPTY_PATH; } FileEntry fileEntry = filesIndex.get(fileAsPath); if (fileEntry == null) { @@ -506,13 +555,12 @@ private FileEntry addFileEntry(String fileName, Path filePath) { /* Ensure file and cachepath are added to the debug_str section. */ uniqueDebugString(fileName); uniqueDebugString(cachePath); - fileEntry = new FileEntry(fileName, dirEntry); + fileEntry = new FileEntry(fileName, dirEntry, files.size() + 1); files.add(fileEntry); /* Index the file entry by file path. */ filesIndex.put(fileAsPath, fileEntry); } else { - assert (filePath == null || - fileEntry.getDirEntry().getPath().equals(filePath)); + assert fileEntry.getDirEntry().getPath().equals(filePath); } return fileEntry; } @@ -545,8 +593,9 @@ private DirEntry ensureDirEntry(Path filePath) { if (dirEntry == null) { /* Ensure dir path is entered into the debug_str section. */ uniqueDebugString(filePath.toString()); - dirEntry = new DirEntry(filePath); + dirEntry = new DirEntry(filePath, dirs.size()); dirsIndex.put(filePath, dirEntry); + dirs.add(dirEntry); } return dirEntry; } @@ -573,11 +622,18 @@ public List getInstanceClasses() { return instanceClasses; } - @SuppressWarnings("unused") + public List getCompiledMethods() { + return compiledMethods; + } + public List getFiles() { return files; } + public List getDirs() { + return dirs; + } + @SuppressWarnings("unused") public FileEntry findFile(Path fullFileName) { return filesIndex.get(fullFileName); @@ -657,7 +713,7 @@ public boolean isHubClassEntry(ClassEntry classEntry) { } public int classLayoutAbbrevCode(ClassEntry classEntry) { - if (useHeapBase & isHubClassEntry(classEntry)) { + if (!useHeapBase & isHubClassEntry(classEntry)) { /* * This layout adds special logic to remove tag bits from indirect pointers to this * type. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java index 4b31fb754d62..6edee7d4a1bb 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java @@ -37,9 +37,11 @@ */ public class DirEntry { private Path path; + private int idx; - public DirEntry(Path path) { + public DirEntry(Path path, int idx) { this.path = path; + this.idx = idx; } public Path getPath() { @@ -49,4 +51,14 @@ public Path getPath() { public String getPathString() { return path.toString(); } + + /** + * Retrieve the index of the dir entry in the list of all known dirs + * + * @return the index of the file entry. + */ + public int getIdx() { + return idx; + } + } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java index eed143c7aa08..9eb99d3a72c2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java @@ -32,10 +32,12 @@ public class FileEntry { private String fileName; private DirEntry dirEntry; + private int idx; - public FileEntry(String fileName, DirEntry dirEntry) { + public FileEntry(String fileName, DirEntry dirEntry, int idx) { this.fileName = fileName; this.dirEntry = dirEntry; + this.idx = idx; } /** @@ -45,6 +47,15 @@ public String getFileName() { return fileName; } + /** + * Retrieve the index of the file entry in the list of all known files. + * + * @return the index of the file entry. + */ + public int getIdx() { + return idx; + } + public String getPathName() { @SuppressWarnings("hiding") DirEntry dirEntry = getDirEntry(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MemberEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MemberEntry.java index 1522a5a951a1..f907ad72d936 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MemberEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MemberEntry.java @@ -81,6 +81,10 @@ public FileEntry getFileEntry() { return fileEntry; } + public int getFileIdx() { + return fileEntry.getIdx(); + } + public int getLine() { return line; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/PrimaryRange.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/PrimaryRange.java index 5a75dd4837d0..405967743f0a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/PrimaryRange.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/PrimaryRange.java @@ -46,12 +46,6 @@ protected PrimaryRange(MethodEntry methodEntry, int lo, int hi, int line) { this.lastCallee = null; } - @Override - public int getFileIndex() { - ClassEntry owner = methodEntry.ownerType(); - return owner.localFilesIdx(getFileEntry()); - } - @Override public boolean isPrimary() { return true; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/Range.java index 653b459d375c..f669eabdc684 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/Range.java @@ -211,7 +211,9 @@ public FileEntry getFileEntry() { return methodEntry.getFileEntry(); } - public abstract int getFileIndex(); + public int getFileIndex() { + return getFileEntry().getIdx(); + }; public int getModifiers() { return methodEntry.getModifiers(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/SubRange.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/SubRange.java index 6e0fecbd6a39..8b91202f7d38 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/SubRange.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/SubRange.java @@ -74,13 +74,6 @@ public Range getPrimary() { return primary; } - @Override - public int getFileIndex() { - // the primary range's class entry indexes all files defined by the compilation unit - ClassEntry owner = primary.methodEntry.ownerType(); - return owner.localFilesIdx(getFileEntry()); - } - @Override public boolean isPrimary() { return false; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java index e6b5ea1fb424..85ec41c0402c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java @@ -69,6 +69,8 @@ public interface DebugInfoProvider { */ int oopAlignment(); + int compiledCodeMax(); + /** * An interface implemented by items that can be located in a file. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index 9231d4fa58d8..f118ad407886 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -60,7 +60,7 @@ public String getSectionName() { @Override public void createContent() { /* - * We need an entry for each compilation unit. + * We need a single entry for the Java compilation unit * *
    * @@ -68,7 +68,7 @@ public void createContent() { * *
  • uint16 dwarf_version ..... always 2 * - *
  • uint32 info_offset ....... offset of compilation unit on debug_info + *
  • uint32 info_offset ....... offset of compilation unit in debug_info -- always 0 * *
  • uint8 address_size ....... always 8 * @@ -92,44 +92,25 @@ public void createContent() { * *
* - * Where N is the number of ranges belonging to the compilation unit and the last range - * contains two zeroes. + * Where N is the number of compiled methods. */ assert !contentByteArrayCreated(); - Cursor cursor = new Cursor(); - // size arange entries for normal compiled methods - instanceClassStream().filter(ClassEntry::hasCompiledEntries).forEach(classEntry -> { - cursor.add(normalEntrySize(classEntry)); - }); - // size arange entries for deopt compiled methods - instanceClassStream().filter(ClassEntry::hasDeoptCompiledEntries).forEach(classEntry -> { - cursor.add(deoptEntrySize(classEntry)); - }); - byte[] buffer = new byte[cursor.get()]; + int methodCount = compiledMethodsCount(); + byte[] buffer = new byte[entrySize(methodCount)]; super.setContent(buffer); } - private static int normalEntrySize(ClassEntry classEntry) { - assert classEntry.hasCompiledEntries(); - return entrySize(classEntry.normalCompiledEntries()); - } - - private static int deoptEntrySize(ClassEntry classEntry) { - assert classEntry.hasDeoptCompiledEntries(); - return entrySize(classEntry.deoptCompiledEntries()); - } - - private static int entrySize(Stream compiledEntries) { - long size = 0; + private static int entrySize(int methodCount) { + int size = 0; // allow for header data size += DW_AR_HEADER_SIZE; // align to 2 * address size. size += DW_AR_HEADER_PAD_SIZE; // count 16 bytes for each deopt compiled method - size += compiledEntries.count() * (2 * 8); + size += methodCount * (2 * 8); // allow for two trailing zeroes to terminate size += 2 * 8; - return Math.toIntExact(size); + return size; } @Override @@ -154,44 +135,21 @@ public void writeContent(DebugContext context) { assert contentByteArrayCreated(); byte[] buffer = getContent(); int size = buffer.length; - int pos = 0; - - enableLog(context, pos); + Cursor cursor = new Cursor(); - // write normal entry aranges - List classEntries = instanceClassStream().filter(ClassEntry::hasCompiledEntries).collect(Collectors.toList()); - classEntries.sort(this::sortByLowPC); + enableLog(context, cursor.get()); - log(context, " [0x%08x] DEBUG_ARANGES", pos); - for (ClassEntry classEntry : classEntries) { - int lengthPos = pos; - int cuIndex = getCUIndex(classEntry); - log(context, " [0x%08x] %s CU %d ", pos, classEntry.getFileName(), cuIndex); - pos = writeHeader(cuIndex, buffer, pos); - pos = writeARanges(context, classEntry.normalCompiledEntries(), buffer, pos); - // write two terminating zeroes - pos = writeLong(0, buffer, pos); - pos = writeLong(0, buffer, pos); - // backpatch the length field - patchLength(lengthPos, buffer, pos); - } - // now write the deopt entry aranges - classEntries = instanceClassStream().filter(ClassEntry::hasDeoptCompiledEntries).collect(Collectors.toList()); - classEntries.sort(this::sortByLowPCDeopt); - - for (ClassEntry classEntry : classEntries) { - int lengthPos = pos; - int cuIndex = getDeoptCUIndex(classEntry); - log(context, " [0x%08x] %s CU (deopt) %d ", pos, classEntry.getFileName(), cuIndex); - pos = writeHeader(cuIndex, buffer, pos); - pos = writeARanges(context, classEntry.deoptCompiledEntries(), buffer, pos); - // write two terminating zeroes - pos = writeLong(0, buffer, pos); - pos = writeLong(0, buffer, pos); - // backpatch the length field - patchLength(lengthPos, buffer, pos); - } - assert pos == size; + log(context, " [0x%08x] DEBUG_ARANGES", cursor.get()); + int lengthPos = cursor.get(); + cursor.set(writeHeader(0, buffer, cursor.get())); + compiledMethodsStream().forEach( compiledMethodEntry -> { + cursor.set(writeARange(context, compiledMethodEntry, buffer, cursor.get())); + }); + // write two terminating zeroes + cursor.set(writeLong(0, buffer, cursor.get())); + cursor.set(writeLong(0, buffer, cursor.get())); + patchLength(lengthPos, buffer, cursor.get()); + assert cursor.get() == buffer.length; } private int writeHeader(int cuIndex, byte[] buffer, int p) { @@ -215,25 +173,13 @@ private int writeHeader(int cuIndex, byte[] buffer, int p) { return pos; } - int writeARanges(DebugContext context, Stream compiledEntries, byte[] buffer, int p) { - return compiledEntries.reduce(p, - (p1, compiledEntry) -> { - int pos = p1; - Range primary = compiledEntry.getPrimary(); - log(context, " [0x%08x] %016x %016x %s", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodNameWithParams()); - pos = writeRelocatableCodeOffset(primary.getLo(), buffer, pos); - pos = writeLong(primary.getHi() - primary.getLo(), buffer, pos); - return pos; - }, - (oldpos, newpos) -> newpos); - } - - private int sortByLowPC(ClassEntry classEntry1, ClassEntry classEntry2) { - return classEntry1.lowpc() - classEntry2.lowpc(); - } - - private int sortByLowPCDeopt(ClassEntry classEntry1, ClassEntry classEntry2) { - return classEntry1.lowpcDeopt() - classEntry2.lowpcDeopt(); + int writeARange(DebugContext context, CompiledMethodEntry compiledMethod, byte[] buffer, int p) { + int pos = p; + Range primary = compiledMethod.getPrimary(); + log(context, " [0x%08x] %016x %016x %s", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodNameWithParams()); + pos = writeRelocatableCodeOffset(primary.getLo(), buffer, pos); + pos = writeLong(primary.getHi() - primary.getLo(), buffer, pos); + return pos; } /* diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java index 22079a3640a0..990c991a69ce 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java @@ -30,806 +30,795 @@ import org.graalvm.compiler.debug.DebugContext; /** - * Section generator for debug_abbrev section. - */ -public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { - - public DwarfAbbrevSectionImpl(DwarfDebugInfo dwarfSections) { - super(dwarfSections); - } - - @Override - public String getSectionName() { - return DwarfDebugInfo.DW_ABBREV_SECTION_NAME; - } - - @Override - public void createContent() { - assert !contentByteArrayCreated(); - /* - * An abbrev table contains abbrev entries for one or more CUs. the table includes a - * sequence of abbrev entries each of which defines a specific DIE layout employed to - * describe some DIE in a CU. a table is terminated by a null entry. - * - * A null entry consists of just a 0 abbrev code. - * - *
    - * - *
  • LEB128 abbrev_code; ...... == 0 - * - *
- * - * Non-null entries have the following format. - * - *
    - * - *
  • LEB128 abbrev_code; ......unique noncode for this layout != 0 - * - *
  • LEB128 tag; .............. defines the type of the DIE (class, subprogram, var - * etc) - * - *
  • uint8 has_chldren; ....... is the DIE followed by child DIEs or a sibling - * DIE - * - *
  • attribute_spec* .......... zero or more attributes - * - *
  • null_attribute_spec ...... terminator - * - *
- * - * An attribute_spec consists of an attribute name and form - * - *
    - * - *
  • LEB128 attr_name; ........ 0 for the null attribute name - * - *
  • LEB128 attr_form; ........ 0 for the null attribute form - * - *
- * - * For the moment we only use one abbrev table for all CUs. It contains the following DIES: - * - *
    - * - *
  • Level 0 DIEs - * - *
  • code = null, TAG = null - empty terminator - * - *
  • code = builtin_unit, TAG = compile_unit - Java primitive and header type - * compile unit - * - *
  • code = class_unit1/2, tag = compile_unit - Java instance type compile - * unit - * - *
  • code = array_unit, tag = compile_unit - Java array type compile unit - * - *
- * - *
    - * - *
  • Level 1 DIES - * - *
  • code = primitive_type, tag = base_type - Java primitive type (non-void) - * - *
  • code = void_type, tag = unspecified_type - Java void type - * - *
  • code = object_header, tag = structure_type - Java object header - * - *
  • code = class_layout, tag = class_type, parent = class_unit - Java - * instance type structure definition - * - *
  • code = class_pointer, tag = pointer_type, parent = class_unit - Java - * instance ref type - * - *
  • code = method_location, tag = subprogram , parent = class_unit - Java - * method code definition (i.e. location of code) - * - *
  • code = abstract_inline_method, tag = subprogram , parent = class_unit - - * Java abstract inline method (i.e. proxy for method definition referenced by concrete - * inline instance) - * - *
  • code = static_field_location, tag = variable, parent = class_unit - Java - * static field definition (i.e. location of data) - * - *
  • code = array_layout, tag = structure_type, parent = array_unit - Java - * array type structure definition - * - *
  • code = array_pointer, tag = pointer_type, parent = array_unit - Java - * array ref type - * - *
  • code = interface_layout, tag = union_type, parent = class_unit - Java - * array type structure definition - * - *
  • code = interface_pointer, tag = pointer_type, parent = class_unit - Java - * interface ref type - * - *
  • code = indirect_layout, tag = class_type, parent = class_unit, array_unit, - * interface_unit - wrapper layout attaches address rewriting logic to the layout - * types that it wraps using a data_location attribute - * - *
  • code = indirect_pointer, tag = pointer_type, parent = class_unit, array_unit, - * interface_unit - indirect ref type used to type indirect oops that encode the - * address of an object, whether by adding tag bits or representing the address as an offset - * from some base address. these are used to type object references stored in static and - * instance fields. They are not needed when typing local vars and parameters held in - * registers or on the stack as they appear as raw addresses. - * - *
  • code = namespace, tag = namespace, parent = class_unit, array_unit, - * interface_unit - a wrap-around DIE that is used to embed all the normal level 1 - * DIEs of a class_unit or array_unit in a namespace. This is - * needed when the corresponding class/interface or array base element type have been loaded - * by a loader with a non-empty loader in order to ensure that mangled names for the class - * and its members can legitimately employ the loader id as a namespace prefix. Note that - * use of a namespace wrapper DIE causes all the embedded level 1+ DIEs documented above and - * all their children to be generated at a level one greater than documented here. - * - *
- * - *
    - * - *
  • Level 2 DIEs - * - *
  • code = header_field, tag = member, parent = object_header - object/array - * header field - * - *
  • code == method_declaration1/2, tag == subprogram, parent = class_layout - * - *
  • code = field_declaration1/2/3/4, tag = member, parent = - * object_header/class_layout - object header or instance field declaration (i.e. - * specification of properties) - * - *
  • code == super_reference, tag == inheritance, parent = class_layout, - * array_layout - reference to super class layout or to appropriate header struct for - * {code java.lang.Object} or arrays. - * - *
  • code == interface_implementor, tag == member, parent = interface_layout - * - union member typed using class layout of a given implementing class - * - *
  • code = inlined_subroutine/inlined_subroutine_with_children, tag = subprogram, - * parent = method_location/inlined_subroutine_with_children - provides range and - * abstract origin for a concrete inline method - * - *
- * - *
  • Level 2/3 DIEs - * - *
  • code == method_parameter_declaration1/2/3, tag == formal_parameter, parent = - * method_declaration1/2, abstract_inline_method - details of method parameters - * - *
  • code == method_local_declaration1/2, tag == variable, parent = - * method_declaration1/2, abstract_inline_method - details of method parameters - * - *
  • Level 3 DIEs - * - *
  • code == method_local_location, tag == formal_parameter, parent = - * method_location, concrete_inline_method - details of method parameter or local - * locations - * - * Details of each specific DIE contents are as follows: - * - * A single instance of the level 0 builtin_unit compile unit provides details - * of all Java primitive types and of the struct type which describes the layout of object - * headers, including array headers. - * - *
  • abbrev_code == builtin_unit, tag == DW_TAG_compilation_unit, - * has_children - * - *
  • DW_AT_language : ... DW_FORM_data1 - * - * - * - * Primitive Types: For each non-void Java primitive type there is a level 1 DIE defining a - * base type - * - *
      - * - *
    • abbrev_code == primitive_type, tag == DW_TAG_base_type, no_children - * - *
    • DW_AT_byte_size : ... DW_FORM_data1 (or data2 ???) - * - *
    • DW_AT_bit_size : ... DW_FORM_data1 (or data2 ???) - * - *
    • DW_AT_encoding : .... DW_FORM_data1 - * - *
    • DW_AT_name : ........ DW_FORM_strp - * - *
    - * - *
      - * - * The void type is defined as an unspecified type - * - *
    • abbrev_code == void_type, tag == DW_TAG_unspecified_type, no_children - * - *
    • DW_AT_name : ........ DW_FORM_strp - * - *
    - * - * Header: There is a level 1 DIE defining structure types used to define the various types - * of header structure embedded at the start of every instance or array. All instances embed - * the same object header. Array headers embed the object header as a parent type, allowing - * an array to be viewed as a type of object. Multiple array headers structures are defined - * to allow for the possibility of different amounts of padding required between the array - * header fields and the array elements that are allocate at the end of the header. Child - * DIEs are employed to define the name, type and layout of fields in each header. - * - *
      - * - *
    • abbrev_code == object_header, tag == DW_TAG_structure_type, has_children - * - *
    • DW_AT_name : ......... DW_FORM_strp "oop" - * - *
    • DW_AT_byte_size : ... DW_FORM_data1 "oop" - * - *
    - * - * Header Data: A level 2 DIE of type member is used to describe the fields of both object - * and array headers. This includes the type tag and other tag bits in all objects, the - * length field in all arrays and any padding bytes needed to complete the layout. - * - *
      - * - *
    • abbrev_code = header_field, tag == DW_TAG_member, no_children - * - *
    • Dw_AT_name : ................... DW_FORM_strp - * - *
    • Dw_AT_type : ................... DW_FORM_ref_addr - * - *
    • Dw_AT_data_member_location : ... DW_FORM_data1 - * - *
    • Dw_AT_accessibility : .......... DW_FORM_data1 - * - *
    - * - * Instance Classes: For each class there is a level 0 DIE defining the class compilation - * unit. low_pc and hi_pc are only included if the class has compiled methods i.e. for - * variants 1 and 2. stmt_list is included for all classes, even when they have no compiled - * methods, to ensure that a basic line entry record exists for the class. This is needed to - * ensure some tools report a file name for methods that may only exist inlined. - * - *
      - * - *
    • abbrev_code == class_unit1/2, tag == DW_TAG_compilation_unit, - * has_children - * - *
    • DW_AT_language : ... DW_FORM_data1 - * - *
    • DW_AT_name : ....... DW_FORM_strp - * - *
    • DW_AT_comp_dir : ... DW_FORM_strp - * - *
    • DW_AT_low_pc : ..... DW_FORM_address n.b only for abbrev-code == - * class_unit1 - * - *
    • DW_AT_hi_pc : ...... DW_FORM_address n.b only for abbrev-code == - * class_unit1 - * - *
    • DW_AT_use_UTF8 : ... DW_FORM_flag - * - *
    • DW_AT_stmt_list : .. DW_FORM_sec_offset - * - *
    - * - * Namespace embedding: - * - * When the class loader associated with a class defined in a class_unit - * compile unit has a non-empty loader id string then a namespace DIE is used to wrap all - * its child DIEs. Otherwise the children are embedded directly. The namespace DIE has a - * single attribute defining the namespace's name as the loader id string. - * - *
  • abbrev_code == namespace, tag == DW_TAG_namespace, has_children - * - *
  • DW_AT_name : ....... DW_FORM_strp - * - * - * - * - * Instance Class Structure: Each class_unit DIE contains a series of level 1 DIEs. The - * first one describes the class layout. The normal layout does not include a data_location - * attribute. However, an alternative layout, including that extra attribute, is provided to - * ensure that tag bits can be removed from pointers to instances of java.lang.Class. This - * alternative layout is only needed when a heapbase register is not in use and fields hold - * raw oops. If a heapbase register is in use and fields hold indirect oops then the masking - * logic for* class pointer tags is included in the data_location attribute attached to the - * indirect layout record (see below) - * - *
      - * - *
    • abbrev_code == class_layout1/class_layout2, tag == DW_TAG_class_type, - * has_children - * - *
    • Dw_AT_name : ........ DW_FORM_strp - * - *
    • Dw_AT_byte_size : ... DW_FORM_data1/2 - * - *
    • Dw_AT_decl_file : ... DW_FORM_data1/2 - * - *
    • Dw_AT_decl_line : ... DW_FORM_data1/2 - * - *
    • Dw_AT_data_location : ... DW_FORM_expr_loc n.b. only for class_layout2 - * - *
    - * - * Instance Class members: A level 1 class_layout DIE includes a level 2 child for each of - * the class's methods and fields. The first type declares a method but omits details of the - * location of the code that implements the method. The second type declares an instance or - * static field. A class_layout DIE also contains an level 2 DIE specifying the type from - * which it inherits superclass structure. In the case of class Object structure is - * inherited from the object header structure type. - * - * n.b. Code implementation details for each method are provided in an auxiliary level 1 - * method_location DIE that follows the class_unit DIE. Instance field declarations need no - * auxiliary level 1 DIE as all relevant details, including size and offset in the instance, - * are specified in the level 2 field declaration DIE. Static field locations are provided - * in an auxiliary level 1 DIE (with tag variable) that follows the class_unit DIE. - * - *
      - * - *
    • abbrev_code == method_declaration1/2, tag == DW_TAG_subprogram, - * has_children - * - *
    • DW_AT_external : .......... DW_FORM_flag - * - *
    • Dw_AT_name : .............. DW_FORM_strp - * - *
    • DW_AT_decl_file : ......... DW_FORM_data1/2 - * - *
    • DW_AT_decl_line : ......... DW_FORM_data1/2 - * - *
    • Dw_AT_linkage_name : ...... DW_FORM_strp - * - *
    • Dw_AT_type : .............. DW_FORM_ref_addr (optional!!) - * - *
    • DW_AT_artificial : ........ DW_FORM_flag - * - *
    • DW_AT_accessibility : ..... DW_FORM_data1 - * - *
    • DW_AT_declaration : ....... DW_FORM_flag - * - *
    • Dw_AT_object_pointer : .... DW_FORM_ref_addr n.b. only for - * method_declaration1, points to param 0 DIE - * - *
    • DW_AT_virtuality : ........ DW_FORM_data1 (for override methods) - * - *
    • DW_AT_containing_type : ... DW_FORM_ref_addr (for override methods) - * - *
    - * - *
      - * - *
    • abbrev_code == field_declaration1/2/3/4, tag == DW_TAG_member, - * no_children - * - *
    • Dw_AT_name : ................... DW_FORM_strp - * - *
    • DW_AT_decl_file : .............. DW_FORM_data1/2 n.b. only for - * field_declaration2/4 - * - *
    • DW_AT_decl_line : .............. DW_FORM_data1/2 n.b. only for - * field_declaration2/4 - * - *
    • Dw_AT_type : ................... DW_FORM_ref_addr - * - *
    • Dw_AT_data_member_location : ... DW_FORM_data1/2 (n.b. nly for - * field_declaration1/2 instance - * - *
    • Dw_AT_artificial : ............. DW_FORM_flag - * - *
    • Dw_AT_accessibility : .......... DW_FORM_data1 - * - *
    • Dw_AT_external : ............... DW_FORM_flag (n.b. only for - * field_declaration3/4 static - * - *
    • Dw_AT_declaration : ............ DW_FORM_flag n.b. only for - * field_declaration3/4 static - * - *
    - * - *
      - * - *
    • abbrev_code == super_reference, tag == DW_TAG_inheritance, no_children - * - *
    • Dw_AT_type : ................... DW_FORM_ref_addr - * - *
    • Dw_AT_data_member_location : ... DW_FORM_data1/2 - * - *
    • Dw_AT_accessibility :........... DW_FORM_data1 - * - *
    - * - * Method Parameters: Level 2 method_declaration DIEs may include level 3 DIEs that describe - * their parameters - * - *
      - * - *
    • abbrev_code == method_parameter_declaration1/2/3, tag == - * DW_TAG_formal_parameter, no_children - * - *
    • Dw_AT_name : ... DW_FORM_strp (may be empty string) - * - *
    • Dw_AT_file : ... DW_FORM_data1/2 n.b. only for - * method_parameter_declaration2 - * - *
    • Dw_AT_line : ... DW_FORM_data1/2 n.b. only for - * method_parameter_declaration2 - * - *
    • Dw_AT_type : ... DW_FORM_ref_addr - * - *
    • Dw_AT_artificial : ... DW_FORM_flag n.b. only for - * method_parameter_declaration1 used for this and access vars - * - *
    • Dw_AT_declaration : ... DW_FORM_flag - * - *
    - * - *
  • abbrev_code == method_local_declaration1/2, tag == DW_TAG_variable, - * no_children - * - *
  • Dw_AT_name : ... DW_FORM_strp (may be empty string) - * - *
  • Dw_AT_file : ... DW_FORM_data1/2 n.b. only for - * method_parameter_declaration1 - * - *
  • Dw_AT_line : ... DW_FORM_data1/2 n.b. only for - * method_parameter_declaration1 - * - *
  • Dw_AT_type : ... DW_FORM_ref_addr - * - *
  • Dw_AT_declaration : ... DW_FORM_flag - * - * - * - * Indirect Instance Class Structure: The level 1 class layout DIE may be followed by a - * level 1 indirect_layout DIE that wraps the class layout as a super class. The wrapper - * type supplies a data_location attribute, allowing indirect pointers to the class (see - * next item) to be translated to raw addresses. The name of the indirect type is - * constructed by prefixing the class name with DwarfDebufInfo.INDIRECT_PREFIX. This DIE has - * only one child DIE with type super_reference (see above). The latter references the class - * layout DIE as a super, effectively embedding the standard layout type in the indirect - * layout. The size of the indirect layout is the same as the size of the class layout. - * - *
      - * - *
    • abbrev_code == indirect_layout, tag == DW_TAG_class_type, has_children - * - *
    • Dw_AT_name : ........ DW_FORM_strp - * - *
    • Dw_AT_byte_size : ... DW_FORM_data1/2 - * - *
    • Dw_AT_data_location : ... DW_FORM_expr_loc - * - *
    - * - * Instance Class Reference Types: The level 1 class_layout and indirect_layout DIEs are - * followed by DIEs defining pointers to the respective class layouts. A class_pointer DIE - * defines a pointer type for the class_layout type and is used to type pointers which - * directly address an instance. It is used to type local and parameter var references - * whether located in a register or on the stack. It is followed by an indirect_pointer DIE - * which defines a pointer type for the class's indirect_layout type. This is used to type - * references to instances of the class located in a static or instance field. These - * references require address translation by masking off tag bits and rebasing from an - * offset to a raw address. The logic for this translation is encoded in a data_location - * attribute of the indirect_layout DIE. - * - *
      - * - *
    • abbrev_code == class_pointer, tag == DW_TAG_pointer_type, no_children - * - *
    • Dw_AT_byte_size : ... DW_FORM_data1 - * - *
    • Dw_AT_type : ........ DW_FORM_ref_addr - * - *
    - * - *
      - * - *
    • abbrev_code == indirect_pointer, tag == DW_TAG_pointer_type, no_children - * - *
    • Dw_AT_byte_size : ... DW_FORM_data1 - * - *
    • Dw_AT_type : ........ DW_FORM_ref_addr - * - *
    - * - * n.b. the name used in the class_layout DIE is the Java class name. This is deliberately - * inconsistent with the Java naming where the name refers to the pointer type. In - * consequence when gdb displays Java types and signatures oop reference appear as pointer - * types. So, for example the Java String class looks like - * - *
      - * - *
    • class java.lang.String : public java.lang.Object { - * - *
    • private: - * - *
    • byte[] value; - * - *
    • ... - * - *
    • public: - * - *
    • ... - * - *
    • java.lang.String *concat(java.lang.String *); - * - *
    • ... - * - *
    - * - * Method Code Locations: For each method within a class there will normally be a - * corresponding level 1 DIE providing details of the location of the compiled code for the - * method. This DIE should inherit attributes from the method_definition DIE referenced from - * its specification attribute without the need to repeat them, including attributes - * specified in child DIEs of the method_definition. It is actually necessary to provide the - * method_location DIE with method_parameter child DIES in order to ensure that gdb carries - * across parameter attributes across from the specification DIE. The local method_parameter - * DIEs refer to their originals using a specification attribute. - * - * Note that for methods which only occur as inlined code rather than as a top-level - * compiles method the method location DIE will be omitted - * - *
      - * - *
    • abbrev_code == DW_ABBREV_CODE_method_location, tag == DW_TAG_subprogram, - * has_children - * - *
    • DW_AT_low_pc : .......... DW_FORM_addr - * - *
    • DW_AT_hi_pc : ........... DW_FORM_addr - * - *
    • DW_AT_external : ........ DW_FORM_flag - * - *
    • DW_AT_specification : ... DW_FORM_ref_addr - * - *
    - * - * Method local locations: A method location is followed by zero or more - * method_local_location DIEs that refer back to the corresponding - * method_parameter_declaration or method_local_declaration that follows the method - * declaration. These DIEs also specify a location list which defines address ranges where - * the parameter or local is valid and provide details of where to find the value of the - * parameter or local in memory. Likewise, an inline concrete method DIE is followed by zero - * or more method_local_location DIEs providing details of where to find the specification - * of inlined parameters or locals and their value in memory. - * - *
      - * - *
    • abbrev_code == DW_ABBREV_CODE_method_local_location1/2, tag == - * DW_TAG_formal_parameter, no_children - * - *
    • DW_AT_specification : .......... DW_FORM_ref_addr - * - *
    • DW_AT_location: ................ DW_FORM_sec_offset n.b. only for - * method_local_location2 - * - *
    - * - * Abstract Inline Methods: For any method m' which has been inlined into a top level - * compiled method m there will be an abstract_inline_method DIE for m' at level 1 DIE in - * the CU to which m belongs. The declaration serves as an abstract_origin for any - * corresponding inlined method DIEs appearing as children of m. The abstract_inline_method - * DIE should inherit attributes from the method_definition DIE referenced as its - * specification attribute without the need to repeat them, including attributes specified - * in child DIEs of the method_definition. However, it is actually necessary to replicate - * the method_parameter/local_declaration DIEs of the specification as children of the - * abstract_inline_method DIE. This provides a CU-local target for references from the - * corresponding method_parameter/local_location DIEs that sit below the inlined_subroutine - * DIEs in the concrete inlined subroutine tree. This is needed because some tools require - * the location DIEs abstract_origin attribute that links the location to specification to - * be a CU-relative offset (FORM_Ref4) rather than an info section offset. - * - *
      - * - *
    • abbrev_code == DW_ABBREV_CODE_abstract_inline_method, tag == DW_TAG_subprogram, - * has_children - * - *
    • DW_AT_inline : .......... DW_FORM_data1 - * - *
    • DW_AT_external : ........ DW_FORM_flag - * - *
    • DW_AT_specification : ... DW_FORM_ref_addr - * - *
    - * - * Concrete Inlined Methods: Concrete inlined method DIEs are nested as a tree of children - * under the method_location DIE for the method into which they have been inlined. Each - * inlined method DIE defines an address range that is a subrange of its parent DIE. A - * method_location DIE occurs at depth 1 in a compile unit (class_unit). So, this means that - * for any method which has been inlined into a compiled method at depth K in the inline - * frame stack there will be a corresponding level 2+K DIE that identifies the method that - * was inlined (by referencing the corresponding abstract inline method DIE) and locates the - * call point by citing the file index and line number of its caller. So, if compiled method - * M inlines a call to m1 at source position f0:l0, m1 inlines a call to method m2 at source - * position f1:l1 and m2 inlines a call to m3 at source position f2:l2 then there will be a - * level 2 DIE for the inline code range derived from m1 referencing the abstract entry for - * m1 with f0 and l0 as file and line, a level 3 DIE for the inline code range derived from - * m2 referencing the abstract entry for m2 with f1 and l1 as file and line and a level 3 - * DIE for the inline code range derived from m3 referencing the abstract entry for m3 with - * f2 and l2 as file and line. - * - *
      - * - *
    • abbrev_code == DW_ABBREV_CODE_inlined_subroutine, tag == DW_TAG_subprogram, - * no_children - * - *
    • abbrev_code == DW_ABBREV_CODE_inlined_subroutine_with_children, tag == - * DW_TAG_subprogram, has_children - * - *
    • DW_AT_abstract_origin : ... DW_FORM_ref_addr - * - *
    • DW_AT_low_pc : ............ DW_FORM_addr - * - *
    • DW_AT_hi_pc : ............. DW_FORM_addr - * - *
    • DW_AT_call_file : ......... DW_FORM_data4 - * - *
    • DW_AT_call_line : ......... DW_FORM_data4 - * - *
    - * - * Static Field Locations: For each static field within the class there is a level 1 DIE - * providing details of the static field location - * - *
      - * - *
    • abbrev_code == static_field_location, tag == DW_TAG_variable, - * no_children - * - *
    • DW_AT_specification : ... DW_FORM_ref_addr - * - *
    • DW_AT_linkage_name : .... DW_FORM_strp - * - *
    • DW_AT_location : ........ DW_FORM_expr_loc - * - *
    - * - * Arrays: For each array type there is a level 0 DIE defining the array compilation unit - * - *
      - * - *
    • abbrev_code == array_unit, tag == DW_TAG_compilation_unit, has_children - * - *
    • DW_AT_language : ... DW_FORM_data1 - * - *
    • DW_AT_name : ....... DW_FORM_strp - * - *
    - * - * Array Structure: Each array_unit DIE contains four level 1 DIEs. The first one describes - * the array layout. It has only one child, a super_reference DIE (see above) that - * references the appropriate array header type for an object array or primitive array of - * the relevant primitive type). The size of the array layout is the same as the size of the - * array header. - * - * Note that when the base element type of the array is a class whose loader has an - * associated loader id the array's children are embedded in a namespace DIE. This is needed - * because the encoded type name for the array will include a namespace prefix in order to - * guarantee that it remains unique. - * - *
      - * - *
    • abbrev_code == array_layout, tag == DW_TAG_class_type, has_children - * - *
    • Dw_AT_name : ........ DW_FORM_strp - * - *
    • Dw_AT_byte_size : ... DW_FORM_data1/2 - * - *
    - * - * The immediately following DIE is an indirect_layout (see above) that wraps the array - * layout as its super type (just as with class layouts). The wrapper type supplies a - * data_location attribute, allowing indirect pointers to the array to be translated to raw - * addresses. The name of the indirect array type is constructed by prefixing the array name - * with INDIRECT_PREFIX. This DIE has only one child DIE with type super_reference (see - * above). The latter references the array layout DIE, effectively embedding the standard - * array layout type in the indirect layout. The size of the indirect layout is the same as - * the size of the array layout. - * - * The third and fourth DIEs define array reference types as a pointers to the underlying - * structure layout types. As with classes, there is an array_pointer type for raw address - * references used to type local and param vars and an indirect_pointer type (see above) for - * array references stored in static and instance fields. - * - *
      - * - *
    • abbrev_code == array_pointer, tag == DW_TAG_pointer_type, no_children - * - *
    • Dw_AT_byte_size : ... DW_FORM_data1 - * - *
    • Dw_AT_type : ........ DW_FORM_ref_addr - * - *
    - * - * n.b. the name used in the array_layout DIE is the Java array name. This is deliberately - * inconsistent with the Java naming where the name refers to the pointer type. As with - * normal objects an array reference in a Java signature appears as a pointer to an array - * layout when printed by gdb. - * - * Array members: The level 1 array_layout DIE includes level 2 child DIEs with tag member - * that describe the layout of the array. header_field DIEs are used to declare members of - * the array header, including the zero length array data member that follows other header - * fields. An auxiliary array_data_type DIE with tag array_type also occurs as a child DIE - * defining the type for the array data member. - * - *
      - * - *
    • abbrev_code == array_data_type, tag == DW_TAG_array_type, no_children - * - *
    • Dw_AT_byte_size : ... DW_FORM_data1 - * - *
    • Dw_AT_type : ........ DW_FORM_ref_addr - * - *
    - * - * Interfaces: For each interface there is a level 0 class_unit DIE defining the interface - * compilation unit. - * - * Interface Layout and Reference Types: The level 0 class_unit DIE for an interface is - * followed by a level 1 DIE defining the interface layout as a union of all the layouts for - * the classes which implement the interface. The size of the interface layout is the - * maximum of the sizes for the implementing classes. - * - *
      - * - *
    • abbrev_code == interface_layout, tag == union_type, has_children - * - *
    • Dw_AT_name : ....... DW_FORM_strp - * - *
    - * - * A second level 1 DIE provides an indirect_layout that wraps the interface layout as its - * super type (just as with class layouts). The wrapper type supplies a data_location - * attribute, allowing indirect pointers to the interface to be translated to raw addresses. - * The name of the indirect interface type is constructed by prefixing the interface name - * with INDIRECT_PREFIX. This DIE has only one child DIE with type super_reference (see - * above). The latter references the interface layout DIE, effectively embedding the - * standard interface layout type in the indirect layout. The size of the indirect layout is - * the same as the size of the interface layout. - * - * The third and fourth DIEs define interface reference types as a pointers to the - * underlying structure layout types. As with classes, there is an interface_pointer type - * for raw address references used to type local and param vars and an indirect_pointer type - * (see above) for interface references stored in static and instance fields. - * - * A second level 1 defines a pointer to this layout type. - * - * n.b. the name used in the interface_layout DIE is the Java array name. This is - * deliberately inconsistent with the Java naming where the name refers to the pointer type. - * As with normal objects an interface reference in a Java signature appears as a pointer to - * an interface layout when printed by gdb. - * - *
      - * - *
    • abbrev_code == interface_pointer, tag == pointer_type, has_children - * - *
    • Dw_AT_byte_size : ... DW_FORM_data1 - * - *
    • DW_AT_TYPE : ....... DW_FORM_ref_addr - * - *
    - * - * The union type embeds level 2 DIEs with tag member. There is a member for each - * implementing class, typed using the layout. - * - *
      - * - *
    • abbrev_code == interface_implementor, tag == member, no_children - * - *
    • Dw_AT_name : ................... DW_FORM_strp - * - *
    • Dw_AT_type : ................... DW_FORM_ref_addr - * - *
    • Dw_AT_accessibility : .......... DW_FORM_data1 - * - *
    - * - * The member name is constructed by appending an '_' to the Java* name of the implementing - * class. So, this means that, for example, the Java interface java.lang.CharSequence will - * include members for String, StringBuffer etc as follows - * - * union java.lang.CharSequence { java.lang.String _java.lang.String; - * java.lang.StringBuffer _java.lang.StringBuffer; ... }; - * + * Section generator for debug_abbrev section. That section defines the + * layout of the DWARF Information Entries (DIEs) used to model Java debug info. Top + * level DIEs define Java Compile Units (CUs). Embedded DIEs describe the content of + * the CU: types, code, variable, etc. These definitions are used to interpret the DIE + * content inserted into the debug_info section.

    + * + * An abbrev table contains abbrev entries for one or more DIEs, the last one being + * a null entry.

    + * + * A null entry consists of just a 0 abbrev code. + * + *

      + * + *
    • LEB128 abbrev_code; ...... == 0 + * + *
    + * + * Non-null entries have the following format: + * + *
      + * + *
    • LEB128 abbrev_code; ......unique code for this layout != 0 + * + *
    • LEB128 tag; .............. defines the type of the DIE (class, subprogram, var + * etc) + * + *
    • uint8 has_chldren; ....... is the DIE followed by child DIEs or a sibling + * DIE + * + *
    • attribute_spec* .......... zero or more attributes + * + *
    • null_attribute_spec ...... terminator + * + *
    + * + * An attribute_spec consists of an attribute name and form: + * + *
      + * + *
    • LEB128 attr_name; ........ 0 for the null attribute name + * + *
    • LEB128 attr_form; ........ 0 for the null attribute form + * + *
    + * + * For the moment we only use one abbrev table and one CU. It employs the following top + * level and nested DIES

    + * + * Level 0 DIEs + * + *

      + * + *
    • code = null, tag == null - empty terminator + * + *
    • code = class_unit, tag == compile_unit - CU that defines the Java object header + * struct, all Java primitive and object types and all Java compiled code. + * + *
    + * + * Level 1 DIES + * + *
      + * + *
    • code = primitive_type, tag == base_type, parent = class_unit - Java primitive type (non-void) + * + *
    • code = void_type, tag == unspecified_type, parent = class_unit - Java void type + * + *
    • code = object_header, tag == structure_type, parent = class_unit - Java object header + * + *
    • code = class_layout, tag == class_type, parent = class_unit - Java + * instance type structure definition + * + *
    • code = class_pointer, tag == pointer_type, parent = class_unit - Java + * instance ref type + * + *
    • code = method_location, tag == subprogram , parent = class_unit - Java + * method code definition (i.e. location of code) + * + *
    • code = abstract_inline_method, tag == subprogram , parent = class_unit - + * Java abstract inline method (i.e. proxy for method definition referenced by concrete + * inline instance) + * + *
    • code = static_field_location, tag == variable, parent = class_unit - Java + * static field definition (i.e. location of data) + * + *
    • code = array_layout, tag == structure_type, parent = array_unit - Java + * array type structure definition + * + *
    • code = array_pointer, tag == pointer_type, parent = array_unit - Java + * array ref type + * + *
    • code = interface_layout, tag == union_type, parent = class_unit - Java + * array type structure definition + * + *
    • code = interface_pointer, tag == pointer_type, parent = class_unit - Java + * interface ref type + * + *
    • code = indirect_layout, tag == class_type, parent = class_unit, array_unit, + * interface_unit - wrapper layout attaches address rewriting logic to the layout + * types that it wraps using a data_location attribute + * + *
    • code = indirect_pointer, tag == pointer_type, parent = class_unit, array_unit, + * interface_unit - indirect ref type used to type indirect oops that encode the + * address of an object, whether by adding tag bits or representing the address as an offset + * from some base address. these are used to type object references stored in static and + * instance fields. They are not needed when typing local vars and parameters held in + * registers or on the stack as they appear as raw addresses. + * + *
    • code = namespace, tag == namespace, parent = class_unit, array_unit, + * interface_unit - a wrap-around DIE that is used to embed all the normal level 1 + * DIEs of a class_unit or array_unit in a namespace. This is + * needed when the corresponding class/interface or array base element type have been loaded + * by a loader with a non-empty loader in order to ensure that mangled names for the class + * and its members can legitimately employ the loader id as a namespace prefix. Note that + * use of a namespace wrapper DIE causes all the embedded level 1+ DIEs documented above and + * all their children to be generated at a level one greater than documented here. + * + *
    + * + * Level 2 DIEs + * + *
      + * + *
    • code = header_field, tag == member, parent = object_header - object/array + * header field + * + *
    • code == method_declaration1/2, tag == subprogram, parent = class_layout + * + *
    • code = field_declaration1/2/3/4, tag == member, parent = class_layout - instance + * field declaration (i.e. specification of properties) + * + *
    • code == super_reference, tag == inheritance, parent = class_layout, + * array_layout - reference to super class layout or to appropriate header struct for + * {code java.lang.Object} or arrays. + * + *
    • code == interface_implementor, tag == member, parent = interface_layout + * - union member typed using class layout of a given implementing class + * + *
    • code = inlined_subroutine/inlined_subroutine_with_children, tag == subprogram, + * parent = method_location/inlined_subroutine_with_children - provides range and + * abstract origin for a concrete inline method + * + *
    • code == method_parameter_declaration1/2/3, tag == formal_parameter, parent = + * method_declaration1/2, abstract_inline_method - details of method parameters + * + *
    • code == method_local_declaration1/2, tag == variable, parent = + * method_declaration1/2, abstract_inline_method - details of method local vars + * + *
    + * + * Level 3 DIEs + * + *
      + * + *
    • code == method_local_location, tag == formal_parameter, parent = + * method_location, concrete_inline_method - details of method parameter or local + * locations + * + *
    + * + * Detailed layouts of the DIEs listed above are as follows:

    + * + * A single instance of the level 0 class_unit compile unit provides details + * of the object header struct, all Java primitive and object types and all Java compiled + * code. + * + *

      + * + *
    • abbrev_code == class_unit, tag == DW_TAG_compilation_unit, + * has_children + * + *
    • DW_AT_language : ... DW_FORM_data1 + * + *
    • DW_AT_name : ....... DW_FORM_strp + * + *
    • DW_AT_comp_dir : ... DW_FORM_strp + * + *
    • DW_AT_low_pc : ..... DW_FORM_address + * + *
    • DW_AT_hi_pc : ...... DW_FORM_address + * + *
    • DW_AT_use_UTF8 : ... DW_FORM_flag + * + *
    • DW_AT_stmt_list : .. DW_FORM_sec_offset + * + *
    + * + * All other Java derived DIEs are embedded within this top level CU.

    + * + * Primitive Types: For each non-void Java primitive type there is a level 1 DIE defining a + * base type + * + *

      + * + *
    • abbrev_code == primitive_type, tag == DW_TAG_base_type, no_children + * + *
    • DW_AT_byte_size : ... DW_FORM_data1 (or data2 ???) + * + *
    • DW_AT_bit_size : ... DW_FORM_data1 (or data2 ???) + * + *
    • DW_AT_encoding : .... DW_FORM_data1 + * + *
    • DW_AT_name : ........ DW_FORM_strp + * + *
    + * + *
      + * + * The void type is defined as an unspecified type + * + *
    • abbrev_code == void_type, tag == DW_TAG_unspecified_type, no_children + * + *
    • DW_AT_name : ........ DW_FORM_strp + * + *
    + * + * Header Struct: There is a level 1 DIE defining a structure type which models the + * header information embedded at the start of every instance or array (all instances embed + * the same object header). Child DIEs are employed to define the name, type and layout of + * fields in the header. + * + *
      + * + *
    • abbrev_code == object_header, tag == DW_TAG_structure_type, has_children + * + *
    • DW_AT_name : ......... DW_FORM_strp "oop" + * + *
    • DW_AT_byte_size : ... DW_FORM_data1 "oop" + * + *
    + * + * Header Data: A level 2 DIE of type member is used to describe the fields of both object + * and array headers. This includes the type tag and other tag bits in all objects and the + * length field in all arrays. + * + *
      + * + *
    • abbrev_code = header_field, tag == DW_TAG_member, no_children + * + *
    • Dw_AT_name : ................... DW_FORM_strp + * + *
    • Dw_AT_type : ................... DW_FORM_ref_addr + * + *
    • Dw_AT_data_member_location : ... DW_FORM_data1 + * + *
    • Dw_AT_accessibility : .......... DW_FORM_data1 + * + *
    + * + * Namespace embedding for Java class DIEs:

    + * + * When the class loader associated with a class defined in the Java class + * compile unit has a non-empty loader id string then a namespace DIE is used to wrap + * the level 1 DIEs that define the class layout, methods etc. Otherwise, these children + * are embedded directly in the Java class compile unit. The namespace DIE has a + * single attribute defining the namespace's name as the loader id string. + * + *

  • abbrev_code == namespace, tag == DW_TAG_namespace, parent = class_unit, has_children + * + *
  • DW_AT_name : ....... DW_FORM_strp + * + * + * + * Instance Classes: For each instance class type there is a sequence of up to four level 1 DIEs + * defining the class.

    + * + * Instance Class Structure: Each java class is described by a series of level 1 DIEs. The first + * one describes the class layout. The normal layout does not include a data_location + * attribute. However, an alternative layout, including that extra attribute, is provided to deal + * with a single special case, java.lang.Class. Oop references to instances of this + * class are encoded using tag bits. The data_location attribute defines masking logic + * which a debugger can use to decode the oop pointer to a raw address. n.b. this only applies in + * the case where normal oop references are raw addresses (no compressed oops, no isolates). If a + * heapbase register is being used then decoding logic is encoded for both normal classes and for + * code>java.lang.Class using an indirect layout (see below). + * + *

      + * + *
    • abbrev_code == class_layout1/class_layout2, tag == DW_TAG_class_type, + * has_children + * + *
    • Dw_AT_name : ........ DW_FORM_strp + * + *
    • Dw_AT_byte_size : ... DW_FORM_data1/2 + * + *
    • Dw_AT_decl_file : ... DW_FORM_data1/2 + * + *
    • Dw_AT_decl_line : ... DW_FORM_data1/2 + * + *
    • Dw_AT_data_location : ... DW_FORM_expr_loc n.b. only for class_layout2 + * + *
    + * + * Instance Class members: A level 1 class_layout DIE includes a level 2 child for each of + * the class's methods and fields. The first type declares a method but omits details of the + * location of the code that implements the method. The second type declares an instance or + * static field. A class_layout DIE also contains a level 2 DIE specifying the type from + * which it inherits superclass structure. In the case of class Object structure is + * inherited from the object header structure type. + * + * n.b. Code implementation details for each method (i.e. the method definition) are + * provided in an auxiliary level 1 method_location DIE that follows the + * class_layout DIE. Instance field declarations need no auxiliary level 1 DIE as all + * relevant details, including size and offset in the instance, are specified in the field declaration + * DIE. Static field locations (i.e. the field definition) are provided in an auxiliary level 1 + * static_field_locationDIE that follows the class_layout DIE. + * + *
      + * + *
    • abbrev_code == method_declaration1/2, tag == DW_TAG_subprogram, + * has_children + * + *
    • DW_AT_external : .......... DW_FORM_flag + * + *
    • Dw_AT_name : .............. DW_FORM_strp + * + *
    • DW_AT_decl_file : ......... DW_FORM_data1/2 + * + *
    • DW_AT_decl_line : ......... DW_FORM_data1/2 + * + *
    • Dw_AT_linkage_name : ...... DW_FORM_strp + * + *
    • Dw_AT_type : .............. DW_FORM_ref_addr (optional!!) + * + *
    • DW_AT_artificial : ........ DW_FORM_flag + * + *
    • DW_AT_accessibility : ..... DW_FORM_data1 + * + *
    • DW_AT_declaration : ....... DW_FORM_flag + * + *
    • Dw_AT_object_pointer : .... DW_FORM_ref_addr n.b. only for + * method_declaration1, points to param 0 DIE + * + *
    • DW_AT_virtuality : ........ DW_FORM_data1 (for override methods) + * + *
    • DW_AT_containing_type : ... DW_FORM_ref_addr (for override methods) + * + *
    + * + *
      + * + *
    • abbrev_code == field_declaration1/2/3/4, tag == DW_TAG_member, no_children + * + *
    • Dw_AT_name : ................... DW_FORM_strp + * + *
    • DW_AT_decl_file : .............. DW_FORM_data1/2 n.b. only for + * field_declaration2/4 + * + *
    • DW_AT_decl_line : .............. DW_FORM_data1/2 n.b. only for + * field_declaration2/4 + * + *
    • Dw_AT_type : ................... DW_FORM_ref_addr + * + *
    • Dw_AT_data_member_location : ... DW_FORM_data1/2 (n.b. nly for + * field_declaration1/2 instance + * + *
    • Dw_AT_artificial : ............. DW_FORM_flag + * + *
    • Dw_AT_accessibility : .......... DW_FORM_data1 + * + *
    • Dw_AT_external : ............... DW_FORM_flag (n.b. only for + * field_declaration3/4 static + * + *
    • Dw_AT_declaration : ............ DW_FORM_flag n.b. only for + * field_declaration3/4 static + * + *
    + * + *
      + * + *
    • abbrev_code == super_reference, tag == DW_TAG_inheritance, no_children + * + *
    • Dw_AT_type : ................... DW_FORM_ref_addr + * + *
    • Dw_AT_data_member_location : ... DW_FORM_data1/2 + * + *
    • Dw_AT_accessibility :........... DW_FORM_data1 + * + *
    + * + * Method Parameters: Level 2 method_declaration DIEs may include level 3 DIEs that describe + * their parameters and/or their local variables. n.b. these two DIEs only differ in the value + * of their tag. + * + *
      + * + *
    • abbrev_code == method_parameter_declaration1/2/3, tag == + * DW_TAG_formal_parameter, no_children + * + *
    • Dw_AT_name : ... DW_FORM_strp (may be empty string) + * + *
    • Dw_AT_file : ... DW_FORM_data1/2 n.b. only for + * method_parameter_declaration2 + * + *
    • Dw_AT_line : ... DW_FORM_data1/2 n.b. only for + * method_parameter_declaration2 + * + *
    • Dw_AT_type : ... DW_FORM_ref_addr + * + *
    • Dw_AT_artificial : ... DW_FORM_flag n.b. only for + * method_parameter_declaration1 used for this and access vars + * + *
    • Dw_AT_declaration : ... DW_FORM_flag + * + *
    + * + *
  • abbrev_code == method_local_declaration1/2, tag == DW_TAG_variable, + * no_children + * + *
  • Dw_AT_name : ... DW_FORM_strp (may be empty string) + * + *
  • Dw_AT_file : ... DW_FORM_data1/2 n.b. only for + * method_parameter_declaration1 + * + *
  • Dw_AT_line : ... DW_FORM_data1/2 n.b. only for + * method_parameter_declaration1 + * + *
  • Dw_AT_type : ... DW_FORM_ref_addr + * + *
  • Dw_AT_declaration : ... DW_FORM_flag + * + * + * + * Indirect Instance Class Structure: The level 1 class layout DIE may be followed by a + * level 1 indirect_layout DIE. The indirect layout is only needed when a + * heapbase register is in use (isolates or compressed oops are enabled). This means that + * oop fields will hold encoded oops. The indirect layout defines an empty wrapper class + * which declares the previous layout as its super class. This wrapper type also supplies a + * data_location attribute, ensuring that indirect pointers to the class (see next + * item) are translated to raw addresses. The name of the indirect type is constructed by + * prefixing the class name with DwarfDebugInfo.INDIRECT_PREFIX. This DIE has only + * one child DIE with type super_reference (see above). This effectively embeds the standard + * layout type in the indirect layout as a type compatible referent for the Java oop. The size + * of the indirect layout is the same as the size of the class layout. + * + *
      + * + *
    • abbrev_code == indirect_layout, tag == DW_TAG_class_type, has_children + * + *
    • Dw_AT_name : ........ DW_FORM_strp + * + *
    • Dw_AT_byte_size : ... DW_FORM_data1/2 + * + *
    • Dw_AT_data_location : ... DW_FORM_expr_loc + * + *
    + * + * Instance Class Reference Types: The level 1 class_layout and + * indirect_layout DIEs are followed by level 1 DIEs defining pointers to the + * respective class layouts. A class_pointer DIE defines a pointer type for the + * class_layout type and is used to type pointers which directly address an instance. + * It is used to type local and parameter var references whether located in a register or on the + * stack. It may be followed by an indirect_pointer DIE which defines a pointer type + * for the class's indirect_layout type. This is used to type references to instances + * of the class located in a static or instance field. These latter references require address + * translation by masking off tag bits and/or rebasing from an offset to a raw address. The logic + * for this translation is encoded in the data_location attribute of the corresponding + * indirect_layout DIE. + * + *
      + * + *
    • abbrev_code == class_pointer, tag == DW_TAG_pointer_type, no_children + * + *
    • Dw_AT_byte_size : ... DW_FORM_data1 + * + *
    • Dw_AT_type : ........ DW_FORM_ref_addr + * + *
    + * + *
      + * + *
    • abbrev_code == indirect_pointer, tag == DW_TAG_pointer_type, no_children + * + *
    • Dw_AT_byte_size : ... DW_FORM_data1 + * + *
    • Dw_AT_type : ........ DW_FORM_ref_addr + * + *
    + * + * n.b. the name used in the class_layout DIE is the Java class name. This is + * deliberately inconsistent with the Java naming where the name refers to the pointer + * type. In consequence when gdb displays Java types and signatures oop references appear as + * pointer types. So, for example the Java String class looks like

    + * + *

    + *   class java.lang.String : public java.lang.Object {
    + *    private:
    + *     byte[] value;
    + *     ...
    + *    public:
    + *     ...
    + *     java.lang.String *concat(java.lang.String *)
    + *     ...
    + * 
    + * + * Method Code Locations: For each level 2 method declaration which has been compiled + * as a top-level method (i.e. not just occurring inline) there will be a corresponding level + * 1 method definition DIE providing details of the location of the compiled code. The + * two DIEs are cross-referenced using a specification attribute. + * This cross-reference should imply that the location DIE inherits attributes from the + * method_definition DIE, including attributes specified int the latter's child DIEs, + * such as parameter and local variable declarations. + * + * TODO - check we no longer need to replicate the DIES + * + * However, it is actually necessary to replicate the parameter and local variable declarations + * as children of the method definition DIE in order to ensure that gdb is aware of the parameters + * and locals. + * + *
      + * + *
    • abbrev_code == DW_ABBREV_CODE_method_location, tag == DW_TAG_subprogram, + * has_children + * + *
    • DW_AT_low_pc : .......... DW_FORM_addr + * + *
    • DW_AT_hi_pc : ........... DW_FORM_addr + * + *
    • DW_AT_external : ........ DW_FORM_flag + * + *
    • DW_AT_specification : ... DW_FORM_ref_addr + * + *
    + * + * Method local locations: A method location may be followed by zero or more + * method_local_location DIEs which identify the in-memory location of + * parameter and/or local values during execution of the compiled code. A + * method_local_location DIE references the corresponding + * method_parameter_declaration or method_local_declaration. + * It also specifies a location list which defines address ranges where the parameter or + * local is valid and provides details of where to find the value of the parameter or local + * in memory. Likewise, an inline concrete method DIE is followed by zero or more + * method_local_location DIEs, providing details of where to find the specification + * of inlined parameters or locals and their value in memory. + * + *
      + * + *
    • abbrev_code == DW_ABBREV_CODE_method_local_location1/2, tag == + * DW_TAG_formal_parameter, no_children + * + *
    • DW_AT_specification : .......... DW_FORM_ref_addr + * + *
    • DW_AT_location: ................ DW_FORM_sec_offset n.b. only for + * method_local_location2 + * + *
    + * + * Abstract Inline Methods: For any method m' which has been inlined into a + * top level compiled method m there will be an abstract_inline_method + * DIE for m' at level 1 in the Java CU. The declaration serves as the + * abstract_origin for any corresponding inlined method DIEs appearing as children + * of m. + * + * TODO - ensure we only generate per inlined method rather than per class per method inlined by that class + * + * The abstract_inline_method DIE should inherit attributes from + * the method_definition DIE referenced as its abstract_origin attribute without the + * need to repeat them. However, it is actually necessary to replicate the method parameter and + * local declaration DIEs of the specification as children of the abstract_inline_method + * DIE. + * + *
      + * + *
    • abbrev_code == DW_ABBREV_CODE_abstract_inline_method, tag == DW_TAG_subprogram, + * has_children + * + *
    • DW_AT_inline : .......... DW_FORM_data1 + * + *
    • DW_AT_external : ........ DW_FORM_flag + * + *
    • DW_AT_specification : ... DW_FORM_ref_addr + * + *
    + * + * Concrete Inlined Methods: Concrete inlined method DIEs are nested as a tree of children + * under the method_location DIE for the method into which they have been inlined. Each + * inlined method DIE defines an address range that is a subrange of its parent DIE. A + * method_location DIE occurs at depth 1 in a compile unit (class_unit). So, this means that + * for any method which has been inlined into a compiled method at depth K in the inline + * frame stack there will be a corresponding level 2+K DIE that identifies the method that + * was inlined (by referencing the corresponding abstract inline method DIE) and locates the + * call point by citing the file index and line number of its caller. So, if compiled method + * M inlines a call to m1 at source position f0:l0, m1 inlines a call to method m2 at source + * position f1:l1 and m2 inlines a call to m3 at source position f2:l2 then there will be a + * level 2 DIE for the inline code range derived from m1 referencing the abstract entry for + * m1 with f0 and l0 as file and line, a level 3 DIE for the inline code range derived from + * m2 referencing the abstract entry for m2 with f1 and l1 as file and line and a level 3 + * DIE for the inline code range derived from m3 referencing the abstract entry for m3 with + * f2 and l2 as file and line. + * + *
      + * + *
    • abbrev_code == DW_ABBREV_CODE_inlined_subroutine, tag == DW_TAG_subprogram, + * no_children + * + *
    • abbrev_code == DW_ABBREV_CODE_inlined_subroutine_with_children, tag == + * DW_TAG_subprogram, has_children + * + *
    • DW_AT_abstract_origin : ... DW_FORM_ref_addr + * + *
    • DW_AT_low_pc : ............ DW_FORM_addr + * + *
    • DW_AT_hi_pc : ............. DW_FORM_addr + * + *
    • DW_AT_call_file : ......... DW_FORM_data4 + * + *
    • DW_AT_call_line : ......... DW_FORM_data4 + * + *
    + * + * Static Field Locations: For each static field within the class there is a level 1 + * field definitionDIE providing details of the static field location + * + *
      + * + *
    • abbrev_code == static_field_location, tag == DW_TAG_variable, + * no_children + * + *
    • DW_AT_specification : ... DW_FORM_ref_addr + * + *
    • DW_AT_linkage_name : .... DW_FORM_strp + * + *
    • DW_AT_location : ........ DW_FORM_expr_loc + * + *
    + * + * Arrays: For each array type there is a sequence of up to five level 1 DIEs defining the array.

    + * + * Array Layout: The first array DIE describes the array layout. It has three children. The + * first is a super_reference DIE (see above) to class java.lang.Object. + * The other two children are field declarations, a length field that overlays the Java array + * length field and an array data field which aligns with the element 0 of the Java + * array's data area. The data field type is typed (via a later level 1 DIE) as a DWARF + * array, i.e. it is a data block embedded directly in the layout, with a nominal element count + * of 0. The elements of this DWARF array are typed using the DWARF type corresponding to the + * Java array's element type. It is either a Java primitive type or a Java reference type (i.e. + * the pointer type ot the underlying layout type). A nominal array length of zero means that + * this second data field does not actually add any extra size to the array layout. So, all array + * types have the same length.

    + * + * Note that when the base element type of the array is a class whose loader has an + * associated loader id the array type and associated types are embedded in a namespace DIE. This + * is needed because the encoded type name for the array will include a namespace prefix in order to + * guarantee that it remains unique. + * + *

      + * + *
    • abbrev_code == array_layout, tag == DW_TAG_class_type, has_children + * + *
    • Dw_AT_name : ........ DW_FORM_strp + * + *
    • Dw_AT_byte_size : ... DW_FORM_data1/2 + * + *
    + * + * The immediately following DIE is an indirect_layout (see above) that wraps the array + * layout as its super type (just as with class layouts). The wrapper type supplies a + * data_location attribute, allowing indirect pointers to the array to be translated to raw + * addresses. The name of the indirect array type is constructed by prefixing the array name + * with DwarfDebugInfo.INDIRECT_PREFIX. This DIE has only one child DIE with type + * super_reference (see above). The latter references the array layout DIE, + * effectively embedding the standard array layout type in the indirect layout. The size of + * the indirect layout is the same as the size of the array layout.

    + * + * The third and fourth DIEs define array reference types as a pointers to the underlying + * structure layout types. As with classes, there is an array_pointer type for raw address + * references used to type local and param vars and an indirect_pointer type (see above) for + * array references stored in static and instance fields. + * + *

      + * + *
    • abbrev_code == array_pointer, tag == DW_TAG_pointer_type, no_children + * + *
    • Dw_AT_byte_size : ... DW_FORM_data1 + * + *
    • Dw_AT_type : ........ DW_FORM_ref_addr + * + *
    + * + * n.b. the name used in the array_layout DIE is the Java array name. This is deliberately + * inconsistent with the Java naming where the name refers to the pointer type. As with + * normal objects an array reference in a Java signature appears as a pointer to an array + * layout when printed by gdb. + * + * Array members: The level 1 array_layout DIE includes a member field DIE that defines + * the layout of the array data. The type of this embedded field is declared by a fifth + * level 1 DIE, a array_data_type DIE (with DWARF tag array_type). + * + *
      + * + *
    • abbrev_code == array_data_type, tag == DW_TAG_array_type, no_children + * + *
    • Dw_AT_byte_size : ... DW_FORM_data1 + * + *
    • Dw_AT_type : ........ DW_FORM_ref_addr + * + *
    + * + * Interfaces: For each interface there is a sequence of DIEs defining the interface.

    + * + * Interface Layout and Reference Types: An interface is primarily modeled by a level 1 + * DIE defining its layout as a union of all the layouts for the classes which implement + * the interface. The size of the interface layout is the maximum of the sizes for the + * implementing classes. A DWARF union type is used to ensure that the resulting layout is + * overlay type compatible with all its implementors. This also means that a reference + * to an instance of the interface can be cast to a reference to any of the implementors. + * + *

      + * + *
    • abbrev_code == interface_layout, tag == union_type, has_children + * + *
    • Dw_AT_name : ....... DW_FORM_strp + * + *
    + * + * A second level 1 DIE provides an indirect layout that wraps the interface layout as its + * super type (just as with class layouts). The wrapper type supplies a data_location + * attribute, allowing indirect pointers to the interface to be translated to raw addresses. + * The name of the indirect interface type is constructed by prefixing the interface name + * with DwarfDebugInfo.INDIRECT_PREFIX. This DIE has only one child DIE with type + * sup[er_reference (see above). The latter references the interface layout DIE, + * effectively embedding the standard interface layout type in the indirect layout. The size + * of the indirect layout is the same as the size of the interface layout. + * + * The third and fourth DIEs define interface reference types as a pointers to the + * underlying structure layout types. As with classes, there is an interface_pointer type + * for raw address references used to type local and param vars and an indirect_pointer type + * (see above) for interface references stored in static and instance fields. + * + * A second level 1 defines a pointer to this layout type. + * + * n.b. the name used in the interface_layout DIE is the Java array name. This is + * deliberately inconsistent with the Java naming where the name refers to the pointer type. + * As with normal objects an interface reference in a Java signature appears as a pointer to + * an interface layout when printed by gdb. + * + *
      + * + *
    • abbrev_code == interface_pointer, tag == pointer_type, has_children + * + *
    • Dw_AT_byte_size : ... DW_FORM_data1 + * + *
    • DW_AT_TYPE : ....... DW_FORM_ref_addr + * + *
    + * + * The union type embeds level 2 DIEs with tag member. There is a member for each + * implementing class, typed using the layout. + * + *
      + * + *
    • abbrev_code == interface_implementor, tag == member, no_children + * + *
    • Dw_AT_name : ................... DW_FORM_strp + * + *
    • Dw_AT_type : ................... DW_FORM_ref_addr + * + *
    • Dw_AT_accessibility : .......... DW_FORM_data1 + * + *
    + * + * The union member name is constructed by appending an '_' to the Java* name of the implementing + * class. So, this means that, for example, the Java interface java.lang.CharSequence will + * include members for String, StringBuffer etc as follows + * + *
    + *   union java.lang.CharSequence {
    + *     java.lang.String _java.lang.String;
    + *     java.lang.StringBuffer _java.lang.StringBuffer;
    + *     ...
    + *   };
    + * 
    + * + */ +public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { + + public DwarfAbbrevSectionImpl(DwarfDebugInfo dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DwarfDebugInfo.DW_ABBREV_SECTION_NAME; + } + + @Override + public void createContent() { + assert !contentByteArrayCreated(); + /* */ int pos = 0; @@ -856,9 +845,7 @@ public void writeContent(DebugContext context) { public int writeAbbrevs(DebugContext context, byte[] buffer, int p) { int pos = p; - pos = writeBuiltInUnitAbbrev(context, buffer, pos); - pos = writeClassUnitAbbrevs(context, buffer, pos); - pos = writeArrayUnitAbbrev(context, buffer, pos); + pos = writeClassUnitAbbrev(context, buffer, pos); pos = writePrimitiveTypeAbbrev(context, buffer, pos); pos = writeVoidTypeAbbrev(context, buffer, pos); @@ -871,8 +858,10 @@ public int writeAbbrevs(DebugContext context, byte[] buffer, int p) { pos = writeMethodDeclarationAbbrevs(context, buffer, pos); pos = writeFieldDeclarationAbbrevs(context, buffer, pos); pos = writeClassConstantAbbrev(context, buffer, pos); + pos = writeArrayLayoutAbbrev(context, buffer, pos); pos = writeArrayReferenceAbbrev(context, buffer, pos); + pos = writeInterfaceLayoutAbbrev(context, buffer, pos); pos = writeInterfaceReferenceAbbrev(context, buffer, pos); @@ -920,37 +909,9 @@ private int writeAttrForm(long code, byte[] buffer, int pos) { return writeSLEB(code, buffer, pos); } - private int writeBuiltInUnitAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { - int pos = p; - pos = writeAbbrevCode(DwarfDebugInfo.DW_ABBREV_CODE_builtin_unit, buffer, pos); - pos = writeTag(DwarfDebugInfo.DW_TAG_compile_unit, buffer, pos); - pos = writeFlag(DwarfDebugInfo.DW_CHILDREN_yes, buffer, pos); - pos = writeAttrType(DwarfDebugInfo.DW_AT_language, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_data1, buffer, pos); - pos = writeAttrType(DwarfDebugInfo.DW_AT_comp_dir, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_strp, buffer, pos); - pos = writeAttrType(DwarfDebugInfo.DW_AT_stmt_list, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_sec_offset, buffer, pos); - /* - * Now terminate. - */ - pos = writeAttrType(DwarfDebugInfo.DW_AT_null, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_null, buffer, pos); - return pos; - } - - private int writeClassUnitAbbrevs(DebugContext context, byte[] buffer, int p) { - int pos = p; - /* class compile unit with compiled methods and line info */ - pos = writeClassUnitAbbrev(context, DwarfDebugInfo.DW_ABBREV_CODE_class_unit1, buffer, pos); - /* class compile unit without compiled methods */ - pos = writeClassUnitAbbrev(context, DwarfDebugInfo.DW_ABBREV_CODE_class_unit2, buffer, pos); - return pos; - } - - private int writeClassUnitAbbrev(@SuppressWarnings("unused") DebugContext context, int abbrevCode, byte[] buffer, int p) { + private int writeClassUnitAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { int pos = p; - pos = writeAbbrevCode(abbrevCode, buffer, pos); + pos = writeAbbrevCode(DwarfDebugInfo.DW_ABBREV_CODE_class_unit, buffer, pos); pos = writeTag(DwarfDebugInfo.DW_TAG_compile_unit, buffer, pos); pos = writeFlag(DwarfDebugInfo.DW_CHILDREN_yes, buffer, pos); pos = writeAttrType(DwarfDebugInfo.DW_AT_language, buffer, pos); @@ -961,34 +922,10 @@ private int writeClassUnitAbbrev(@SuppressWarnings("unused") DebugContext contex pos = writeAttrForm(DwarfDebugInfo.DW_FORM_strp, buffer, pos); pos = writeAttrType(DwarfDebugInfo.DW_AT_comp_dir, buffer, pos); pos = writeAttrForm(DwarfDebugInfo.DW_FORM_strp, buffer, pos); - if (abbrevCode == DwarfDebugInfo.DW_ABBREV_CODE_class_unit1) { - pos = writeAttrType(DwarfDebugInfo.DW_AT_low_pc, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_addr, buffer, pos); - pos = writeAttrType(DwarfDebugInfo.DW_AT_hi_pc, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_addr, buffer, pos); - } - pos = writeAttrType(DwarfDebugInfo.DW_AT_stmt_list, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_sec_offset, buffer, pos); - /* - * Now terminate. - */ - pos = writeAttrType(DwarfDebugInfo.DW_AT_null, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_null, buffer, pos); - return pos; - } - - private int writeArrayUnitAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { - int pos = p; - - pos = writeAbbrevCode(DwarfDebugInfo.DW_ABBREV_CODE_array_unit, buffer, pos); - pos = writeTag(DwarfDebugInfo.DW_TAG_compile_unit, buffer, pos); - pos = writeFlag(DwarfDebugInfo.DW_CHILDREN_yes, buffer, pos); - pos = writeAttrType(DwarfDebugInfo.DW_AT_language, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_data1, buffer, pos); - pos = writeAttrType(DwarfDebugInfo.DW_AT_name, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_strp, buffer, pos); - pos = writeAttrType(DwarfDebugInfo.DW_AT_comp_dir, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_strp, buffer, pos); + pos = writeAttrType(DwarfDebugInfo.DW_AT_low_pc, buffer, pos); + pos = writeAttrForm(DwarfDebugInfo.DW_FORM_addr, buffer, pos); + pos = writeAttrType(DwarfDebugInfo.DW_AT_hi_pc, buffer, pos); + pos = writeAttrForm(DwarfDebugInfo.DW_FORM_addr, buffer, pos); pos = writeAttrType(DwarfDebugInfo.DW_AT_stmt_list, buffer, pos); pos = writeAttrForm(DwarfDebugInfo.DW_FORM_sec_offset, buffer, pos); /* @@ -1089,7 +1026,7 @@ private int writeClassLayoutAbbrev(@SuppressWarnings("unused") DebugContext cont pos = writeAttrType(DwarfDebugInfo.DW_AT_decl_file, buffer, pos); pos = writeAttrForm(DwarfDebugInfo.DW_FORM_data2, buffer, pos); /*- - * At present we definitely don't have line numbers. + * At present we definitely don't have a line number for the class itself. pos = writeAttrType(DwarfDebugInfo.DW_AT_decl_line, buffer, pos); pos = writeAttrForm(DwarfDebugInfo.DW_FORM_data2, buffer, pos); */ @@ -1109,7 +1046,7 @@ private int writeClassLayoutAbbrev(@SuppressWarnings("unused") DebugContext cont private int writeClassReferenceAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { int pos = p; - /* First the basic pointer type for a pointer to the class struct type. */ + /* A pointer to the class struct type. */ pos = writeAbbrevCode(DwarfDebugInfo.DW_ABBREV_CODE_class_pointer, buffer, pos); pos = writeTag(DwarfDebugInfo.DW_TAG_pointer_type, buffer, pos); pos = writeFlag(DwarfDebugInfo.DW_CHILDREN_no, buffer, pos); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java index 35cadbdaedb7..5f0d06fcee38 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java @@ -70,53 +70,50 @@ public class DwarfDebugInfo extends DebugInfoBase { */ @SuppressWarnings("unused") public static final int DW_ABBREV_CODE_null = 0; /* Level 0 DIEs. */ - public static final int DW_ABBREV_CODE_builtin_unit = 1; - public static final int DW_ABBREV_CODE_class_unit1 = 2; - public static final int DW_ABBREV_CODE_class_unit2 = 3; - public static final int DW_ABBREV_CODE_array_unit = 4; + public static final int DW_ABBREV_CODE_class_unit = 1; /* Level 1 DIEs. */ - public static final int DW_ABBREV_CODE_primitive_type = 5; - public static final int DW_ABBREV_CODE_void_type = 6; - public static final int DW_ABBREV_CODE_object_header = 7; - public static final int DW_ABBREV_CODE_namespace = 8; - public static final int DW_ABBREV_CODE_class_layout1 = 9; - public static final int DW_ABBREV_CODE_class_layout2 = 10; - public static final int DW_ABBREV_CODE_class_pointer = 11; - public static final int DW_ABBREV_CODE_method_location = 12; - public static final int DW_ABBREV_CODE_abstract_inline_method = 13; - public static final int DW_ABBREV_CODE_static_field_location = 14; - public static final int DW_ABBREV_CODE_array_layout = 15; - public static final int DW_ABBREV_CODE_array_pointer = 16; - public static final int DW_ABBREV_CODE_interface_layout = 17; - public static final int DW_ABBREV_CODE_interface_pointer = 18; - public static final int DW_ABBREV_CODE_indirect_layout = 19; - public static final int DW_ABBREV_CODE_indirect_pointer = 20; + public static final int DW_ABBREV_CODE_primitive_type = 2; + public static final int DW_ABBREV_CODE_void_type = 3; + public static final int DW_ABBREV_CODE_object_header = 4; + public static final int DW_ABBREV_CODE_namespace = 5; + public static final int DW_ABBREV_CODE_class_layout1 = 6; + public static final int DW_ABBREV_CODE_class_layout2 = 7; + public static final int DW_ABBREV_CODE_class_pointer = 8; + public static final int DW_ABBREV_CODE_method_location = 9; + public static final int DW_ABBREV_CODE_abstract_inline_method = 10; + public static final int DW_ABBREV_CODE_static_field_location = 11; + public static final int DW_ABBREV_CODE_array_layout = 12; + public static final int DW_ABBREV_CODE_array_pointer = 13; + public static final int DW_ABBREV_CODE_interface_layout = 14; + public static final int DW_ABBREV_CODE_interface_pointer = 15; + public static final int DW_ABBREV_CODE_indirect_layout = 16; + public static final int DW_ABBREV_CODE_indirect_pointer = 17; /* Level 2 DIEs. */ - public static final int DW_ABBREV_CODE_method_declaration = 21; - public static final int DW_ABBREV_CODE_method_declaration_static = 22; - public static final int DW_ABBREV_CODE_field_declaration1 = 23; - public static final int DW_ABBREV_CODE_field_declaration2 = 24; - public static final int DW_ABBREV_CODE_field_declaration3 = 25; - public static final int DW_ABBREV_CODE_field_declaration4 = 26; - public static final int DW_ABBREV_CODE_class_constant = 42; - public static final int DW_ABBREV_CODE_header_field = 27; - public static final int DW_ABBREV_CODE_array_data_type = 28; - public static final int DW_ABBREV_CODE_super_reference = 29; - public static final int DW_ABBREV_CODE_interface_implementor = 30; + public static final int DW_ABBREV_CODE_method_declaration = 18; + public static final int DW_ABBREV_CODE_method_declaration_static = 19; + public static final int DW_ABBREV_CODE_field_declaration1 = 20; + public static final int DW_ABBREV_CODE_field_declaration2 = 21; + public static final int DW_ABBREV_CODE_field_declaration3 = 22; + public static final int DW_ABBREV_CODE_field_declaration4 = 23; + public static final int DW_ABBREV_CODE_class_constant = 24; + public static final int DW_ABBREV_CODE_header_field = 25; + public static final int DW_ABBREV_CODE_array_data_type = 26; + public static final int DW_ABBREV_CODE_super_reference = 27; + public static final int DW_ABBREV_CODE_interface_implementor = 28; /* Level 2+K DIEs (where inline depth K >= 0) */ - public static final int DW_ABBREV_CODE_inlined_subroutine = 31; - public static final int DW_ABBREV_CODE_inlined_subroutine_with_children = 32; + public static final int DW_ABBREV_CODE_inlined_subroutine = 29; + public static final int DW_ABBREV_CODE_inlined_subroutine_with_children = 30; /* Level 2 DIEs. */ - public static final int DW_ABBREV_CODE_method_parameter_declaration1 = 33; - public static final int DW_ABBREV_CODE_method_parameter_declaration2 = 34; - public static final int DW_ABBREV_CODE_method_parameter_declaration3 = 35; - public static final int DW_ABBREV_CODE_method_local_declaration1 = 36; - public static final int DW_ABBREV_CODE_method_local_declaration2 = 37; + public static final int DW_ABBREV_CODE_method_parameter_declaration1 = 31; + public static final int DW_ABBREV_CODE_method_parameter_declaration2 = 32; + public static final int DW_ABBREV_CODE_method_parameter_declaration3 = 33; + public static final int DW_ABBREV_CODE_method_local_declaration1 = 34; + public static final int DW_ABBREV_CODE_method_local_declaration2 = 35; /* Level 3 DIEs. */ - public static final int DW_ABBREV_CODE_method_parameter_location1 = 38; - public static final int DW_ABBREV_CODE_method_parameter_location2 = 39; - public static final int DW_ABBREV_CODE_method_local_location1 = 40; - public static final int DW_ABBREV_CODE_method_local_location2 = 41; + public static final int DW_ABBREV_CODE_method_parameter_location1 = 36; + public static final int DW_ABBREV_CODE_method_parameter_location2 = 37; + public static final int DW_ABBREV_CODE_method_local_location1 = 38; + public static final int DW_ABBREV_CODE_method_local_location2 = 39; /* * Define all the Dwarf tags we need for our DIEs. @@ -472,14 +469,6 @@ public TypeEntry getTypeEntry() { */ static class DwarfClassProperties extends DwarfTypeProperties { - /** - * Index of debug_info section compilation unit for this class. - */ - private int cuIndex; - /** - * index of debug_info section compilation unit for deopt target methods. - */ - private int deoptCUIndex; /** * Index of the class entry's class_layout DIE in the debug_info section. */ @@ -488,18 +477,6 @@ static class DwarfClassProperties extends DwarfTypeProperties { * Index of the class entry's indirect layout DIE in the debug_info section. */ private int indirectLayoutIndex; - /** - * Index into debug_line section for associated compilation unit. - */ - private int lineIndex; - /** - * Size of line number info prologue region for associated compilation unit. - */ - private int linePrologueSize; - /** - * Total size of line number info region for associated compilation unit. - */ - private int lineSectionSize; /** * Map from field names to info section index for the field declaration. */ @@ -516,13 +493,8 @@ static class DwarfClassProperties extends DwarfTypeProperties { DwarfClassProperties(StructureTypeEntry entry) { super(entry); - this.cuIndex = -1; - this.deoptCUIndex = -1; this.layoutIndex = -1; this.indirectLayoutIndex = -1; - this.lineIndex = -1; - this.linePrologueSize = -1; - this.lineSectionSize = -1; fieldDeclarationIndex = null; abstractInlineMethodIndex = null; methodLocalPropertiesIndex = null; @@ -653,37 +625,6 @@ int getIndirectTypeIndex(DwarfTypeProperties typeProperties) { return typeProperties.getIndirectTypeInfoIndex(); } - void setCUIndex(ClassEntry classEntry, int idx) { - DwarfClassProperties classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert classProperties.cuIndex == -1 || classProperties.cuIndex == idx; - classProperties.cuIndex = idx; - } - - int getCUIndex(ClassEntry classEntry) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert classProperties.cuIndex >= 0; - return classProperties.cuIndex; - } - - void setDeoptCUIndex(ClassEntry classEntry, int idx) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert (classProperties.deoptCUIndex == -1 || classProperties.deoptCUIndex == idx); - classProperties.deoptCUIndex = idx; - } - - int getDeoptCUIndex(ClassEntry classEntry) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert classProperties.deoptCUIndex >= 0; - return classProperties.deoptCUIndex; - } - void setLayoutIndex(ClassEntry classEntry, int idx) { DwarfClassProperties classProperties = lookupClassProperties(classEntry); assert classProperties.getTypeEntry() == classEntry; @@ -714,55 +655,6 @@ int getIndirectLayoutIndex(ClassEntry classEntry) { return classProperties.indirectLayoutIndex; } - void setLineIndex(ClassEntry classEntry, int idx) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert (classProperties.lineIndex == -1 || classProperties.lineIndex == idx); - classProperties.lineIndex = idx; - } - - public int getLineIndex(ClassEntry classEntry) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - /* line index may be fetched without being set */ - assert classProperties.lineIndex >= -1; - return classProperties.lineIndex; - } - - public void setLinePrologueSize(ClassEntry classEntry, int prologueSize) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert (classProperties.linePrologueSize == -1 || classProperties.linePrologueSize == prologueSize); - classProperties.linePrologueSize = prologueSize; - } - - public int getLinePrologueSize(ClassEntry classEntry) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert classProperties.linePrologueSize >= 0; - return classProperties.linePrologueSize; - } - - public void setLineSectionSize(ClassEntry classEntry, int totalSize) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert (classProperties.lineSectionSize == -1 || classProperties.lineSectionSize == totalSize); - classProperties.lineSectionSize = totalSize; - } - - public int getLineSectionSize(ClassEntry classEntry) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert classProperties.lineSectionSize >= 0; - return classProperties.lineSectionSize; - } - public void setFieldDeclarationIndex(StructureTypeEntry entry, String fieldName, int pos) { DwarfClassProperties classProperties; classProperties = lookupClassProperties(entry); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index 81192c206839..562a3fd806b2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -152,17 +152,8 @@ private int writeMethodFrame(CompiledMethodEntry compiledEntry, byte[] buffer, i private int writeMethodFrames(byte[] buffer, int p) { Cursor cursor = new Cursor(p); - /* Write frames for normal methods. */ - instanceClassStream().filter(ClassEntry::hasCompiledEntries).forEach(classEntry -> { - classEntry.normalCompiledEntries().forEach(compiledEntry -> { - cursor.set(writeMethodFrame(compiledEntry, buffer, cursor.get())); - }); - }); - /* Now write frames for deopt targets. */ - instanceClassStream().filter(ClassEntry::hasDeoptCompiledEntries).forEach(classEntry -> { - classEntry.deoptCompiledEntries().forEach(compiledEntry -> { - cursor.set(writeMethodFrame(compiledEntry, buffer, cursor.get())); - }); + compiledMethodsStream().forEach(compiledMethod -> { + cursor.set(writeMethodFrame(compiledMethod, buffer, cursor.get())); }); return cursor.get(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java index e455d04ee6dc..3518a91ffb11 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java @@ -33,7 +33,6 @@ import java.util.Iterator; import java.util.List; import java.util.stream.Stream; -import java.util.function.Predicate; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -75,7 +74,6 @@ public class DwarfInfoSectionImpl extends DwarfSectionImpl { public DwarfInfoSectionImpl(DwarfDebugInfo dwarfSections) { super(dwarfSections); - cuStart = -1; } @Override @@ -138,90 +136,85 @@ byte computeEncoding(int flags, int bitCount) { public int generateContent(DebugContext context, byte[] buffer) { int pos = 0; - - /* Write entries for all the types known to the generator. */ - - pos = writeBuiltInUnit(context, buffer, pos); - + // Write the single Java compile unit header + int lengthPos = pos; + log(context, " [0x%08x] <0> Java Compile Unit", pos); + pos = writeCUHeader(buffer, pos); + assert pos == lengthPos + DW_DIE_HEADER_SIZE; + int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_class_unit; + log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + log(context, " [0x%08x] language %s", pos, "DW_LANG_Java"); + pos = writeAttrData1(DwarfDebugInfo.LANG_ENCODING, buffer, pos); + log(context, " [0x%08x] use_UTF8", pos); + pos = writeFlag((byte) 1, buffer, pos); + String name = uniqueDebugString("JAVA"); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); + pos = writeStrSectionOffset(name, buffer, pos); + String compilationDirectory = dwarfSections.getCachePath(); + log(context, " [0x%08x] comp_dir 0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory); + pos = writeStrSectionOffset(compilationDirectory, buffer, pos); /* - * Write class units for non-compiled instance classes i.e. ones which don't have any - * compiled methods. + * Code addresses start at offset 0 and range up to the limit defined by the code cache size. */ + int lo = 0; + int hi = dwarfSections.compiledCodeMax(); + // there is one line section starting at offset 0 + int lineIndex = 0; + log(context, " [0x%08x] lo_pc 0x%08x", pos, lo); + pos = writeAttrAddress(lo, buffer, pos); + log(context, " [0x%08x] hi_pc 0x%08x", pos, hi); + pos = writeAttrAddress(hi, buffer, pos); + log(context, " [0x%08x] stmt_list 0x%08x", pos, lineIndex); + pos = writeLineSectionOffset(lineIndex, buffer, pos); + + /* Write DIEs for primitive types and header struct */ - pos = writeNonCompiledClasses(context, buffer, pos); + pos = writeBuiltInTypes(context, buffer, pos); /* - * Write class units for compiled instance classes i.e. ones which have associated compiled - * methods. + * Write DIEs for all instance classes, which includes interfaces and enums */ - pos = writeCompiledClasses(context, buffer, pos); + pos = writeInstanceClasses(context, buffer, pos); - /* Write class units for array types. */ + /* Write DIEs for array types. */ pos = writeArrayTypes(context, buffer, pos); + /* Write all compiled code locations */ + + pos = writeMethodLocations(context, buffer, pos); + + /* Write all static field definitions -- in class order */ + + pos = writeStaticFieldLocations(context, buffer, pos); + /* - * write extra special CUs for deopt targets. these are written out of line from the class - * because they are compiled later and hence inhabit a range that extends beyond the normal - * method address range. + * Write a terminating null attribute. */ - // use a cursor to propagate successive positions across the foreach - Cursor cursor = new Cursor(pos); - instanceClassStream().filter(ClassEntry::hasDeoptCompiledEntries).forEach(classEntry -> { - int newPos = cursor.get(); - /* - * Save the offset of this file's CU so it can be used when writing the aranges section. - */ - setDeoptCUIndex(classEntry, newPos); - int lengthPos = newPos; - newPos = writeCUHeader(buffer, newPos); - log(context, " [0x%08x] Compilation Unit (deopt targets)", newPos); - assert newPos == lengthPos + DW_DIE_HEADER_SIZE; - writeDeoptMethodsCU(context, classEntry, buffer, newPos); - /* - * Backpatch length at lengthPos (excluding length field). - */ - patchLength(lengthPos, buffer, newPos); - cursor.set(newPos); - }); - pos = cursor.get(); + pos = writeAttrNull(buffer, pos); + + /* Fix up the CU length. */ + + patchLength(lengthPos, buffer, pos); return pos; } - private int writeBuiltInUnit(DebugContext context, byte[] buffer, int p) { + private int writeBuiltInTypes(DebugContext context, byte[] buffer, int p) { int pos = p; - int lengthPos = pos; - log(context, " [0x%08x] <0> builtin unit", pos); - pos = writeCUHeader(buffer, pos); - assert pos == lengthPos + DW_DIE_HEADER_SIZE; - int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_builtin_unit; - log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - log(context, " [0x%08x] language %s", pos, "DW_LANG_Java"); - pos = writeAttrData1(DwarfDebugInfo.LANG_ENCODING, buffer, pos); - String compilationDirectory = dwarfSections.getCachePath(); - log(context, " [0x%08x] comp_dir 0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory); - pos = writeStrSectionOffset(compilationDirectory, buffer, pos); - /* - * Using zero as a fallback lineIndex is potentially dangerous, but probably harmless, - * because it will point at some arbitrary data in the lines data. - */ - final int lineIndex = 0; - log(context, " [0x%08x] stmt_list 0x%08x", pos, lineIndex); - pos = writeAttrData4(lineIndex, buffer, pos); - - /* Write child entries for basic Java types. */ + log(context, " [0x%08x] <1> Builtin Types:", pos); + /* Write child entries for primitive Java types. */ pos = primitiveTypeStream().reduce(pos, - (pos1, primitiveTypeEntry) -> { - if (primitiveTypeEntry.getBitCount() > 0) { - return writePrimitiveType(context, primitiveTypeEntry, buffer, pos1); - } else { - return writeVoidType(context, primitiveTypeEntry, buffer, pos1); - } - }, - (oldpos, newpos) -> newpos); + (pos1, primitiveTypeEntry) -> { + if (primitiveTypeEntry.getBitCount() > 0) { + return writePrimitiveType(context, primitiveTypeEntry, buffer, pos1); + } else { + return writeVoidType(context, primitiveTypeEntry, buffer, pos1); + } + }, + (oldpos, newpos) -> newpos); /* Write child entry for object/array header struct. */ @@ -230,16 +223,8 @@ private int writeBuiltInUnit(DebugContext context, byte[] buffer, int p) { /* write class constants for primitive type classes */ pos = primitiveTypeStream().reduce(pos, - (pos1, primitiveTypeEntry) -> writeClassConstantDeclaration(context, primitiveTypeEntry, buffer, pos1), - (oldpos, newpos) -> newpos); - - /* Terminate with null entry. */ - - pos = writeAttrNull(buffer, pos); - - /* Fix up the CU length. */ - - patchLength(lengthPos, buffer, pos); + (pos1, primitiveTypeEntry) -> writeClassConstantDeclaration(context, primitiveTypeEntry, buffer, pos1), + (oldpos, newpos) -> newpos); return pos; } @@ -319,8 +304,8 @@ public int writeHeaderType(DebugContext context, HeaderTypeEntry headerTypeEntry private int writeHeaderFields(DebugContext context, HeaderTypeEntry headerTypeEntry, byte[] buffer, int p) { return headerTypeEntry.fields().reduce(p, - (pos, fieldEntry) -> writeHeaderField(context, fieldEntry, buffer, pos), - (oldPos, newPos) -> newPos); + (pos, fieldEntry) -> writeHeaderField(context, fieldEntry, buffer, pos), + (oldPos, newPos) -> newPos); } private int writeHeaderField(DebugContext context, FieldEntry fieldEntry, byte[] buffer, int p) { @@ -346,131 +331,17 @@ private int writeHeaderField(DebugContext context, FieldEntry fieldEntry, byte[] return writeAttrAccessibility(modifiers, buffer, pos); } - private int writeNonCompiledClasses(DebugContext context, byte[] buffer, int pos) { - log(context, " [0x%08x] non compiled classes", pos); - Cursor cursor = new Cursor(pos); - instanceClassStream().filter(Predicate.not(ClassEntry::hasCompiledEntries)).forEach(classEntry -> { - cursor.set(writeNonCompiledClassUnit(context, classEntry, buffer, cursor.get())); - }); - return cursor.get(); - } - - private int writeNonCompiledClassUnit(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - int lineIndex = getLineIndex(classEntry); - cuStart = pos; - setCUIndex(classEntry, cuStart); - int lengthPos = pos; - log(context, " [0x%08x] non compiled class unit %s", pos, classEntry.getTypeName()); - pos = writeCUHeader(buffer, pos); - assert pos == lengthPos + DW_DIE_HEADER_SIZE; - int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_class_unit2; - log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - log(context, " [0x%08x] language %s", pos, "DW_LANG_Java"); - pos = writeAttrData1(DwarfDebugInfo.LANG_ENCODING, buffer, pos); - log(context, " [0x%08x] use_UTF8", pos); - pos = writeFlag((byte) 1, buffer, pos); - log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); - pos = writeStrSectionOffset(classEntry.getFileName(), buffer, pos); - String compilationDirectory = dwarfSections.getCachePath(); - log(context, " [0x%08x] comp_dir 0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory); - pos = writeStrSectionOffset(compilationDirectory, buffer, pos); - /* Non-compiled classes have no compiled methods so they have no low or high pc. */ - /* However, we still generate a statement list in case they include inlined methods */ - log(context, " [0x%08x] stmt_list 0x%08x", pos, lineIndex); - pos = writeLineSectionOffset(lineIndex, buffer, pos); - - /* if the class has a loader then embed the children in a namespace */ - String loaderId = classEntry.getLoaderId(); - if (!loaderId.isEmpty()) { - pos = writeNameSpace(context, loaderId, buffer, pos); - } - - /* Now write the child DIEs starting with the layout and pointer type. */ - - if (classEntry.isInterface()) { - InterfaceClassEntry interfaceClassEntry = (InterfaceClassEntry) classEntry; - pos = writeInterfaceLayout(context, interfaceClassEntry, buffer, pos); - pos = writeInterfaceType(context, interfaceClassEntry, buffer, pos); - } else { - pos = writeClassLayout(context, classEntry, buffer, pos); - pos = writeClassType(context, classEntry, buffer, pos); - } - - /* Write a declaration for the special Class object pseudo-static field */ - pos = writeClassConstantDeclaration(context, classEntry, buffer, pos); - - /* For a non-compiled class there are no method definitions to write. */ - /* Nor, by the same token are there any abstract inline methods to write. */ - - /* Write all static field definitions. */ - - pos = writeStaticFieldLocations(context, classEntry, buffer, pos); - - /* Terminate children with null entry. */ - - pos = writeAttrNull(buffer, pos); - - /* if we opened a namespace then terminate its children */ - - if (!loaderId.isEmpty()) { - pos = writeAttrNull(buffer, pos); - } - - /* Fix up the CU length. */ - - patchLength(lengthPos, buffer, pos); - - return pos; - } - - private int writeCompiledClasses(DebugContext context, byte[] buffer, int pos) { - log(context, " [0x%08x] compiled classes", pos); + private int writeInstanceClasses(DebugContext context, byte[] buffer, int pos) { + log(context, " [0x%08x] instance classes", pos); Cursor cursor = new Cursor(pos); - instanceClassStream().filter(ClassEntry::hasCompiledEntries).forEach(classEntry -> { - cursor.set(writeCompiledClassUnit(context, classEntry, buffer, cursor.get())); + instanceClassStream().forEach(classEntry -> { + cursor.set(writeInstanceClassInfo(context, classEntry, buffer, cursor.get())); }); return cursor.get(); } - private int writeCompiledClassUnit(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + private int writeInstanceClassInfo(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; - int lineIndex = getLineIndex(classEntry); - String fileName = classEntry.getFileName(); - int lo = classEntry.lowpc(); - int hi = classEntry.hipc(); - // we must have at least one compiled method - assert hi > 0; - int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_class_unit1; - cuStart = pos; - setCUIndex(classEntry, cuStart); - int lengthPos = pos; - log(context, " [0x%08x] compiled class unit %s", pos, classEntry.getTypeName()); - pos = writeCUHeader(buffer, pos); - assert pos == lengthPos + DW_DIE_HEADER_SIZE; - log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - log(context, " [0x%08x] language %s", pos, "DW_LANG_Java"); - pos = writeAttrData1(DwarfDebugInfo.LANG_ENCODING, buffer, pos); - log(context, " [0x%08x] use_UTF8", pos); - pos = writeFlag((byte) 1, buffer, pos); - log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(fileName), fileName); - pos = writeStrSectionOffset(fileName, buffer, pos); - String compilationDirectory = dwarfSections.getCachePath(); - log(context, " [0x%08x] comp_dir 0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory); - pos = writeStrSectionOffset(compilationDirectory, buffer, pos); - /* - * Specify hi and lo for the compile unit which means we also need to ensure methods within - * it are listed in ascending address order. - */ - log(context, " [0x%08x] lo_pc 0x%08x", pos, lo); - pos = writeAttrAddress(lo, buffer, pos); - log(context, " [0x%08x] hi_pc 0x%08x", pos, hi); - pos = writeAttrAddress(hi, buffer, pos); - log(context, " [0x%08x] stmt_list 0x%08x", pos, lineIndex); - pos = writeLineSectionOffset(lineIndex, buffer, pos); - /* if the class has a loader then embed the children in a namespace */ String loaderId = classEntry.getLoaderId(); if (!loaderId.isEmpty()) { @@ -491,21 +362,11 @@ private int writeCompiledClassUnit(DebugContext context, ClassEntry classEntry, /* Write a declaration for the special Class object pseudo-static field */ pos = writeClassConstantDeclaration(context, classEntry, buffer, pos); - /* Write all method locations. */ - - pos = writeMethodLocations(context, classEntry, false, buffer, pos); - /* Write abstract inline methods. */ - pos = writeAbstractInlineMethods(context, classEntry, false, buffer, pos); + // TODO - ensure we only generate per inlined method rather than per class per method inlined by that class - /* Write all static field definitions. */ - - pos = writeStaticFieldLocations(context, classEntry, buffer, pos); - - /* Terminate children with null entry. */ - - pos = writeAttrNull(buffer, pos); + pos = writeAbstractInlineMethods(context, classEntry, buffer, pos); /* if we opened a namespace then terminate its children */ @@ -513,10 +374,6 @@ private int writeCompiledClassUnit(DebugContext context, ClassEntry classEntry, pos = writeAttrNull(buffer, pos); } - /* Fix up the CU length. */ - - patchLength(lengthPos, buffer, pos); - return pos; } @@ -535,6 +392,7 @@ private int writeNameSpace(DebugContext context, String id, byte[] buffer, int p private int writeClassConstantDeclaration(DebugContext context, TypeEntry typeEntry, byte[] buffer, int p) { int pos = p; + log(context, " [0x%08x] class constant", pos); long offset = typeEntry.getClassOffset(); if (offset < 0) { return pos; @@ -592,7 +450,7 @@ private int writeClassLayout(DebugContext context, ClassEntry classEntry, byte[] int size = classEntry.getSize(); log(context, " [0x%08x] byte_size 0x%x", pos, size); pos = writeAttrData2((short) size, buffer, pos); - int fileIdx = classEntry.localFilesIdx(); + int fileIdx = classEntry.getFileIdx(); log(context, " [0x%08x] file 0x%x (%s)", pos, fileIdx, classEntry.getFileName()); pos = writeAttrData2((short) fileIdx, buffer, pos); if (abbrevCode == DwarfDebugInfo.DW_ABBREV_CODE_class_layout2) { @@ -673,8 +531,8 @@ private int writeSuperReference(DebugContext context, int superTypeOffset, Strin private int writeFields(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { return classEntry.fields().filter(DwarfInfoSectionImpl::isManifestedField).reduce(p, - (pos, fieldEntry) -> writeField(context, classEntry, fieldEntry, buffer, pos), - (oldPos, newPos) -> newPos); + (pos, fieldEntry) -> writeField(context, classEntry, fieldEntry, buffer, pos), + (oldPos, newPos) -> newPos); } private static boolean isManifestedField(FieldEntry fieldEntry) { @@ -712,7 +570,7 @@ private int writeField(DebugContext context, StructureTypeEntry entry, FieldEntr /* We may not have a file and line for a field. */ if (hasFile) { assert entry instanceof ClassEntry; - int fileIdx = ((ClassEntry) entry).localFilesIdx(fieldEntry.getFileEntry()); + int fileIdx = fieldEntry.getFileIdx(); assert fileIdx > 0; log(context, " [0x%08x] filename 0x%x (%s)", pos, fileIdx, fieldEntry.getFileName()); pos = writeAttrData2((short) fileIdx, buffer, pos); @@ -745,8 +603,7 @@ private int writeMethodDeclarations(DebugContext context, ClassEntry classEntry, for (MethodEntry method : classEntry.getMethods()) { if (method.isInRange() || method.isInlined()) { /* - * Declare all methods including deopt targets even though they are written in - * separate CUs. + * Declare all methods whether or not they have been compiled or inlined. */ pos = writeMethodDeclaration(context, classEntry, method, buffer, pos); } @@ -776,7 +633,7 @@ private int writeMethodDeclaration(DebugContext context, ClassEntry classEntry, fileEntry = classEntry.getFileEntry(); } assert fileEntry != null; - int fileIdx = classEntry.localFilesIdx(fileEntry); + int fileIdx = fileEntry.getIdx(); log(context, " [0x%08x] file 0x%x (%s)", pos, fileIdx, fileEntry.getFullName()); pos = writeAttrData2((short) fileIdx, buffer, pos); int line = method.getLine(); @@ -841,7 +698,7 @@ private int writeMethodParameterDeclarations(DebugContext context, ClassEntry cl } private int writeMethodParameterDeclaration(DebugContext context, DebugLocalInfo paramInfo, int fileIdx, boolean artificial, int level, byte[] buffer, - int p) { + int p) { int pos = p; log(context, " [0x%08x] method parameter declaration", pos); int abbrevCode; @@ -890,7 +747,7 @@ private int writeMethodLocalDeclarations(DebugContext context, ClassEntry classE } private int writeMethodLocalDeclaration(DebugContext context, DebugLocalInfo paramInfo, int fileIdx, int level, byte[] buffer, - int p) { + int p) { int pos = p; log(context, " [0x%08x] method local declaration", pos); int abbrevCode; @@ -976,8 +833,8 @@ private int writeInterfaceLayout(DebugContext context, InterfaceClassEntry inter private int writeInterfaceImplementors(DebugContext context, InterfaceClassEntry interfaceClassEntry, byte[] buffer, int p) { return interfaceClassEntry.implementors().reduce(p, - (pos, classEntry) -> writeInterfaceImplementor(context, classEntry, buffer, pos), - (oldPos, newPos) -> newPos); + (pos, classEntry) -> writeInterfaceImplementor(context, classEntry, buffer, pos), + (oldPos, newPos) -> newPos); } private int writeInterfaceImplementor(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { @@ -1072,117 +929,32 @@ private int writeInterfaceType(DebugContext context, InterfaceClassEntry interfa return pos; } - private int writeMethodLocations(DebugContext context, ClassEntry classEntry, boolean deoptTargets, byte[] buffer, int p) { - int pos = p; - /* The class's file entry should always be first in the local files list. */ - assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; - - Stream compiledEntries = (deoptTargets ? classEntry.deoptCompiledEntries() : classEntry.normalCompiledEntries()); - pos = compiledEntries.reduce(pos, - (p1, compiledEntry) -> writeMethodLocation(context, compiledEntry, buffer, p1), - (oldPos, newPos) -> newPos); - return pos; - } - - /** - * Go through the subranges and generate concrete debug entries for inlined methods. - */ - private int generateConcreteInlinedMethods(DebugContext context, CompiledMethodEntry compiledEntry, byte[] buffer, int p) { - Range primary = compiledEntry.getPrimary(); - if (primary.isLeaf()) { - return p; - } - int pos = p; - log(context, " [0x%08x] concrete entries [0x%x,0x%x] %s", pos, primary.getLo(), primary.getHi(), primary.getFullMethodName()); - ClassEntry classEntry = compiledEntry.getClassEntry(); - int depth = 0; - Iterator iterator = compiledEntry.topDownRangeIterator(); - while (iterator.hasNext()) { - SubRange subrange = iterator.next(); - if (subrange.isLeaf()) { - // we only generate concrete methods for non-leaf entries - continue; - } - // if we just stepped out of a child range write nulls for each step up - while (depth > subrange.getDepth()) { - pos = writeAttrNull(buffer, pos); - depth--; - } - depth = subrange.getDepth(); - pos = writeInlineSubroutine(context, classEntry, subrange, depth + 2, buffer, pos); - HashMap> varRangeMap = subrange.getVarRangeMap(); - // increment depth to account for parameter and method locations - depth++; - pos = writeMethodParameterLocations(context, classEntry, varRangeMap, subrange, depth + 2, buffer, pos); - pos = writeMethodLocalLocations(context, classEntry, varRangeMap, subrange, depth + 2, buffer, pos); - } - // if we just stepped out of a child range write nulls for each step up - while (depth > 0) { - pos = writeAttrNull(buffer, pos); - depth--; - } - return pos; - } - - private int writeAbstractInlineMethods(DebugContext context, ClassEntry classEntry, boolean deoptTargets, byte[] buffer, int p) { - HashSet inlinedMethods = collectInlinedMethods(context, classEntry, deoptTargets, p); - int pos = p; - for (MethodEntry methodEntry : inlinedMethods) { - setAbstractInlineMethodIndex(classEntry, methodEntry, pos); - pos = writeAbstractInlineMethod(context, classEntry, methodEntry, buffer, pos); - } - return pos; - } - - private HashSet collectInlinedMethods(DebugContext context, ClassEntry classEntry, boolean deoptTargets, int p) { - final HashSet methods = new HashSet<>(); - if (!deoptTargets || classEntry.hasDeoptCompiledEntries()) { - Stream compiledEntries = (deoptTargets ? classEntry.deoptCompiledEntries() : classEntry.normalCompiledEntries()); - compiledEntries.forEach(compiledEntry -> addInlinedMethods(context, compiledEntry, compiledEntry.getPrimary(), methods, p)); - } - return methods; - } - - private void addInlinedMethods(DebugContext context, CompiledMethodEntry compiledEntry, Range primary, HashSet hashSet, int p) { - if (primary.isLeaf()) { - return; - } - verboseLog(context, " [0x%08x] collect abstract inlined methods %s", p, primary.getFullMethodName()); - Iterator iterator = compiledEntry.topDownRangeIterator(); - while (iterator.hasNext()) { - SubRange subrange = iterator.next(); - if (subrange.isLeaf()) { - // we only generate abstract inline methods for non-leaf entries - continue; - } - // the subrange covers an inline call and references the caller method entry. its - // child ranges all reference the same inlined called method. leaf children cover code - // for - // that inlined method. non-leaf children cover code for recursively inlined methods. - // identify the inlined method by looking at the first callee - Range callee = subrange.getFirstCallee(); - MethodEntry methodEntry = callee.getMethodEntry(); - if (hashSet.add(methodEntry)) { - verboseLog(context, " [0x%08x] add abstract inlined method %s", p, methodEntry.getSymbolName()); - } - } + private int writeStaticFieldLocations(DebugContext context, byte[] buffer, int p) { + Cursor cursor = new Cursor(p); + instanceClassStream().forEach(classEntry -> { + cursor.set(writeClassStaticFieldLocations(context, classEntry, buffer, cursor.get())); + }); + return cursor.get(); } - private int writeStaticFieldLocations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + private int writeClassStaticFieldLocations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { /* * Only write locations for static fields that have an offset greater than 0. A negative * offset indicates that the field has been folded into code as an unmaterialized constant. */ - return classEntry.fields().filter(DwarfInfoSectionImpl::isManifestedStaticField).reduce(p, - (pos, fieldEntry) -> writeStaticFieldLocation(context, classEntry, fieldEntry, buffer, pos), - (oldPos, newPos) -> newPos); + Cursor cursor = new Cursor(p); + classEntry.fields().filter(DwarfInfoSectionImpl::isManifestedStaticField) + .forEach(fieldEntry -> { + cursor.set(writeClassStaticFieldLocation(context, classEntry, fieldEntry, buffer, cursor.get())); + }); + return cursor.get(); } private static boolean isManifestedStaticField(FieldEntry fieldEntry) { return Modifier.isStatic(fieldEntry.getModifiers()) && fieldEntry.getOffset() >= 0; } - private int writeStaticFieldLocation(DebugContext context, ClassEntry classEntry, FieldEntry fieldEntry, byte[] buffer, int p) { + private int writeClassStaticFieldLocation(DebugContext context, ClassEntry classEntry, FieldEntry fieldEntry, byte[] buffer, int p) { int pos = p; String fieldName = fieldEntry.fieldName(); int fieldDefinitionOffset = getFieldDeclarationIndex(classEntry, fieldName); @@ -1200,40 +972,17 @@ private int writeStaticFieldLocation(DebugContext context, ClassEntry classEntry return pos; } - private int writeArrayTypes(DebugContext context, byte[] buffer, int pos) { - log(context, " [0x%08x] array classes", pos); - return arrayTypeStream().reduce(pos, - (p, arrayTypeEntry) -> { - return writeArrayTypeUnit(context, arrayTypeEntry, buffer, p); - }, - (oldpos, newpos) -> newpos); + private int writeArrayTypes(DebugContext context, byte[] buffer, int p) { + log(context, " [0x%08x] array classes", p); + Cursor cursor = new Cursor(p); + arrayTypeStream().forEach(arrayTypeEntry -> { + cursor.set(writeArrayTypeInfo(context, arrayTypeEntry, buffer, cursor.get())); + }); + return cursor.get(); } - private int writeArrayTypeUnit(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) { + private int writeArrayTypeInfo(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) { int pos = p; - int lengthPos = pos; - log(context, " [0x%08x] array class unit %s", pos, arrayTypeEntry.getTypeName()); - pos = writeCUHeader(buffer, pos); - assert pos == lengthPos + DW_DIE_HEADER_SIZE; - int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_array_unit; - log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - log(context, " [0x%08x] language %s", pos, "DwarfDebugInfo.DW_LANG_Java"); - pos = writeAttrData1(DwarfDebugInfo.LANG_ENCODING, buffer, pos); - String name = arrayTypeEntry.getTypeName(); - log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); - pos = writeStrSectionOffset(name, buffer, pos); - String compilationDirectory = dwarfSections.getCachePath(); - log(context, " [0x%08x] comp_dir 0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory); - pos = writeStrSectionOffset(compilationDirectory, buffer, pos); - /* - * Using zero as a fallback lineIndex is potentially dangerous, but probably harmless, - * because it will point at some arbitrary data in the lines data. - */ - final int lineIndex = 0; - log(context, " [0x%08x] stmt_list 0x%08x", pos, lineIndex); - pos = writeAttrData4(lineIndex, buffer, pos); - /* if the array base type is a class with a loader then embed the children in a namespace */ String loaderId = arrayTypeEntry.getLoaderId(); if (!loaderId.isEmpty()) { @@ -1254,19 +1003,11 @@ private int writeArrayTypeUnit(DebugContext context, ArrayTypeEntry arrayTypeEnt /* Write a declaration for the special Class object pseudo-static field */ pos = writeClassConstantDeclaration(context, arrayTypeEntry, buffer, pos); - /* - * Write a terminating null attribute. - */ - pos = writeAttrNull(buffer, pos); - /* if we opened a namespace then terminate its children */ if (!loaderId.isEmpty()) { pos = writeAttrNull(buffer, pos); } - /* Fix up the CU length. */ - patchLength(lengthPos, buffer, pos); - return pos; } @@ -1298,9 +1039,12 @@ private int writeArrayLayout(DebugContext context, ArrayTypeEntry arrayTypeEntry } private int writeFields(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) { - return arrayTypeEntry.fields().filter(DwarfInfoSectionImpl::isManifestedField).reduce(p, - (pos, fieldEntry) -> writeField(context, arrayTypeEntry, fieldEntry, buffer, pos), - (oldPos, newPos) -> newPos); + Cursor cursor = new Cursor(p); + arrayTypeEntry.fields().filter(DwarfInfoSectionImpl::isManifestedField) + .forEach( fieldEntry -> { + cursor.set(writeField(context, arrayTypeEntry, fieldEntry, buffer, cursor.get())); + }); + return cursor.get(); } private int writeIndirectArrayLayout(DebugContext context, ArrayTypeEntry arrayTypeEntry, int size, int layoutOffset, byte[] buffer, int p) { @@ -1415,45 +1159,12 @@ private int writeArrayTypes(DebugContext context, ArrayTypeEntry arrayTypeEntry, return pos; } - private int writeDeoptMethodsCU(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - assert classEntry.hasDeoptCompiledEntries(); - int lineIndex = getLineIndex(classEntry); - int lo = classEntry.lowpcDeopt(); - int hi = classEntry.hipcDeopt(); - // we must have at least one compiled deopt method - assert hi > 0 : hi; - int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_class_unit1; - log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - log(context, " [0x%08x] language %s", pos, "DwarfDebugInfo.DW_LANG_Java"); - pos = writeAttrData1(DwarfDebugInfo.LANG_ENCODING, buffer, pos); - log(context, " [0x%08x] use_UTF8", pos); - pos = writeFlag((byte) 1, buffer, pos); - log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); - pos = writeStrSectionOffset(classEntry.getFileName(), buffer, pos); - String compilationDirectory = dwarfSections.getCachePath(); - log(context, " [0x%08x] comp_dir 0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory); - pos = writeStrSectionOffset(compilationDirectory, buffer, pos); - log(context, " [0x%08x] lo_pc 0x%08x", pos, lo); - pos = writeAttrAddress(lo, buffer, pos); - log(context, " [0x%08x] hi_pc 0x%08x", pos, hi); - pos = writeAttrAddress(hi, buffer, pos); - log(context, " [0x%08x] stmt_list 0x%08x", pos, lineIndex); - pos = writeAttrData4(lineIndex, buffer, pos); - - /* Write all method locations. */ - - pos = writeMethodLocations(context, classEntry, true, buffer, pos); - - /* Write abstract inline methods. */ - - pos = writeAbstractInlineMethods(context, classEntry, true, buffer, pos); - - /* - * Write a terminating null attribute. - */ - return writeAttrNull(buffer, pos); + private int writeMethodLocations(DebugContext context, byte[] buffer, int p) { + Cursor cursor = new Cursor(p); + compiledMethodsStream().forEach(compiledMethodEntry -> { + cursor.set(writeMethodLocation(context, compiledMethodEntry, buffer, cursor.get())); + }); + return cursor.get(); } private int writeMethodLocation(DebugContext context, CompiledMethodEntry compiledEntry, byte[] buffer, int p) { @@ -1581,38 +1292,44 @@ private int writeMethodLocalLocation(DebugContext context, Range range, DebugLoc return pos; } - private int writeAbstractInlineMethod(DebugContext context, ClassEntry classEntry, MethodEntry method, byte[] buffer, int p) { + /** + * Go through the subranges and generate concrete debug entries for inlined methods. + */ + private int generateConcreteInlinedMethods(DebugContext context, CompiledMethodEntry compiledEntry, byte[] buffer, int p) { + Range primary = compiledEntry.getPrimary(); + if (primary.isLeaf()) { + return p; + } int pos = p; - log(context, " [0x%08x] abstract inline method %s::%s", pos, classEntry.getTypeName(), method.methodName()); - int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_abstract_inline_method; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - log(context, " [0x%08x] inline 0x%x", pos, DwarfDebugInfo.DW_INL_inlined); - pos = writeAttrData1(DwarfDebugInfo.DW_INL_inlined, buffer, pos); - /* - * Should pass true only if method is non-private. - */ - log(context, " [0x%08x] external true", pos); - pos = writeFlag(DwarfDebugInfo.DW_FLAG_true, buffer, pos); - int methodSpecOffset = getMethodDeclarationIndex(method); - log(context, " [0x%08x] specification 0x%x", pos, methodSpecOffset); - pos = writeInfoSectionOffset(methodSpecOffset, buffer, pos); - /* - * Write parameter and local declarations - */ - FileEntry fileEntry = method.getFileEntry(); - if (fileEntry == null) { - fileEntry = classEntry.getFileEntry(); + log(context, " [0x%08x] concrete entries [0x%x,0x%x] %s", pos, primary.getLo(), primary.getHi(), primary.getFullMethodName()); + ClassEntry classEntry = compiledEntry.getClassEntry(); + int depth = 0; + Iterator iterator = compiledEntry.topDownRangeIterator(); + while (iterator.hasNext()) { + SubRange subrange = iterator.next(); + if (subrange.isLeaf()) { + // we only generate concrete methods for non-leaf entries + continue; + } + // if we just stepped out of a child range write nulls for each step up + while (depth > subrange.getDepth()) { + pos = writeAttrNull(buffer, pos); + depth--; + } + depth = subrange.getDepth(); + pos = writeInlineSubroutine(context, classEntry, subrange, depth + 2, buffer, pos); + HashMap> varRangeMap = subrange.getVarRangeMap(); + // increment depth to account for parameter and method locations + depth++; + pos = writeMethodParameterLocations(context, classEntry, varRangeMap, subrange, depth + 2, buffer, pos); + pos = writeMethodLocalLocations(context, classEntry, varRangeMap, subrange, depth + 2, buffer, pos); } - assert fileEntry != null; - int fileIdx = classEntry.localFilesIdx(fileEntry); - int level = 3; - pos = writeMethodParameterDeclarations(context, classEntry, method, fileIdx, level, buffer, pos); - pos = writeMethodLocalDeclarations(context, classEntry, method, fileIdx, level, buffer, pos); - /* - * Write a terminating null attribute. - */ - return writeAttrNull(buffer, pos); + // if we just stepped out of a child range write nulls for each step up + while (depth > 0) { + pos = writeAttrNull(buffer, pos); + depth--; + } + return pos; } private int writeInlineSubroutine(DebugContext context, ClassEntry classEntry, Range caller, int depth, byte[] buffer, int p) { @@ -1661,9 +1378,85 @@ private int writeInlineSubroutine(DebugContext context, ClassEntry classEntry, R return pos; } + private int writeAbstractInlineMethods(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + HashSet inlinedMethods = collectInlinedMethods(context, classEntry, p); + int pos = p; + for (MethodEntry methodEntry : inlinedMethods) { + setAbstractInlineMethodIndex(classEntry, methodEntry, pos); + pos = writeAbstractInlineMethod(context, classEntry, methodEntry, buffer, pos); + } + return pos; + } + + private HashSet collectInlinedMethods(DebugContext context, ClassEntry classEntry, int p) { + final HashSet methods = new HashSet<>(); + Stream compiledEntries = classEntry.compiledEntries(); + compiledEntries.forEach(compiledEntry -> addInlinedMethods(context, compiledEntry, compiledEntry.getPrimary(), methods, p)); + return methods; + } + + private void addInlinedMethods(DebugContext context, CompiledMethodEntry compiledEntry, Range primary, HashSet hashSet, int p) { + if (primary.isLeaf()) { + return; + } + verboseLog(context, " [0x%08x] collect abstract inlined methods %s", p, primary.getFullMethodName()); + Iterator iterator = compiledEntry.topDownRangeIterator(); + while (iterator.hasNext()) { + SubRange subrange = iterator.next(); + if (subrange.isLeaf()) { + // we only generate abstract inline methods for non-leaf entries + continue; + } + // the subrange covers an inline call and references the caller method entry. its + // child ranges all reference the same inlined called method. leaf children cover code + // for + // that inlined method. non-leaf children cover code for recursively inlined methods. + // identify the inlined method by looking at the first callee + Range callee = subrange.getFirstCallee(); + MethodEntry methodEntry = callee.getMethodEntry(); + if (hashSet.add(methodEntry)) { + verboseLog(context, " [0x%08x] add abstract inlined method %s", p, methodEntry.getSymbolName()); + } + } + } + + private int writeAbstractInlineMethod(DebugContext context, ClassEntry classEntry, MethodEntry method, byte[] buffer, int p) { + int pos = p; + log(context, " [0x%08x] abstract inline method %s::%s", pos, classEntry.getTypeName(), method.methodName()); + int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_abstract_inline_method; + log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + log(context, " [0x%08x] inline 0x%x", pos, DwarfDebugInfo.DW_INL_inlined); + pos = writeAttrData1(DwarfDebugInfo.DW_INL_inlined, buffer, pos); + /* + * Should pass true only if method is non-private. + */ + log(context, " [0x%08x] external true", pos); + pos = writeFlag(DwarfDebugInfo.DW_FLAG_true, buffer, pos); + int methodSpecOffset = getMethodDeclarationIndex(method); + log(context, " [0x%08x] specification 0x%x", pos, methodSpecOffset); + pos = writeInfoSectionOffset(methodSpecOffset, buffer, pos); + /* + * Write parameter and local declarations + */ + FileEntry fileEntry = method.getFileEntry(); + if (fileEntry == null) { + fileEntry = classEntry.getFileEntry(); + } + assert fileEntry != null; + int fileIdx = fileEntry.getIdx(); + int level = 2; + pos = writeMethodParameterDeclarations(context, classEntry, method, fileIdx, level, buffer, pos); + pos = writeMethodLocalDeclarations(context, classEntry, method, fileIdx, level, buffer, pos); + /* + * Write a terminating null attribute. + */ + return writeAttrNull(buffer, pos); + } + private int writeAttrRef4(int reference, byte[] buffer, int p) { - assert cuStart >= 0; - return writeAttrData4(reference - cuStart, buffer, p); + // writes a CU-relative offset but we only have one CU which starts at offset 0 + return writeAttrData4(reference, buffer, p); } private int writeCUHeader(byte[] buffer, int p) { @@ -1841,14 +1634,6 @@ public int writeIndirectOopConversionExpression(boolean isHub, byte[] buffer, in return pos; } - /* - * Attributes of type ref4 which refer to an element in she same CU need to be written as an - * offset relative to the start of the current CU. This field is updated every time writing of a - * CU commences, providing a section offset for the CU which can be subtracted from the section - * offsets that are used to record element positions. - */ - private int cuStart; - /** * The debug_info section depends on loc section. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index 4ed92cf83c87..30c11bc8e3de 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -140,8 +140,11 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { */ private static final byte DW_LNE_define_file = 3; + private int linePrologueSize; + DwarfLineSectionImpl(DwarfDebugInfo dwarfSections) { super(dwarfSections); + linePrologueSize = 0; } @Override @@ -159,27 +162,16 @@ public void createContent() { */ /* - * Write line info for each instance class. We do this even when a class has no compiled - * methods ane hence no line records. This avoids bail outs by tools when a class's methods - * crop up inline-only but the tool still expects a line info entry to provide a file and - * dir table. + * Write line info for all compiled methods. */ - Cursor cursor = new Cursor(); - instanceClassStream().forEach(classEntry -> { - assert classEntry.getFileName().length() != 0; - int startPos = cursor.get(); - setLineIndex(classEntry, startPos); - int headerSize = headerSize(); - int dirTableSize = computeDirTableSize(classEntry); - int fileTableSize = computeFileTableSize(classEntry); - int prologueSize = headerSize + dirTableSize + fileTableSize; - setLinePrologueSize(classEntry, prologueSize); - int lineNumberTableSize = computeLineNUmberTableSize(classEntry); - int totalSize = prologueSize + lineNumberTableSize; - setLineSectionSize(classEntry, totalSize); - cursor.add(totalSize); - }); - byte[] buffer = new byte[cursor.get()]; + int headerSize = headerSize(); + int dirTableSize = computeDirTableSize(); + int fileTableSize = computeFileTableSize(); + int prologueSize = headerSize + dirTableSize + fileTableSize; + setLinePrologueSize(prologueSize); + int lineNumberTableSize = computeLineNUmberTableSize(); + int totalSize = prologueSize + lineNumberTableSize; + byte[] buffer = new byte[totalSize]; super.setContent(buffer); } @@ -215,62 +207,58 @@ private static int headerSize() { return DW_LN_HEADER_SIZE; } - private static int computeDirTableSize(ClassEntry classEntry) { + private int computeDirTableSize() { /* * Table contains a sequence of 'nul'-terminated UTF8 dir name bytes followed by an extra * 'nul'. - * - * For now we assume dir and file names are ASCII byte strings. */ - int dirSize = 0; - for (DirEntry dir : classEntry.getLocalDirs()) { - dirSize += countUTF8Bytes(dir.getPathString()) + 1; - } + Cursor cursor = new Cursor(); + dirStream().forEach( dirEntry -> { + if (dirEntry.getIdx() > 0) { + cursor.add(countUTF8Bytes(dirEntry.getPathString()) + 1); + } + }); /* - * Allow for separator nul. + * Allow for terminator nul. */ - dirSize++; - return dirSize; + cursor.add(1); + return cursor.get(); } - private int computeFileTableSize(ClassEntry classEntry) { + private int computeFileTableSize() { /* * Table contains a sequence of file entries followed by an extra 'nul' * * each file entry consists of a 'nul'-terminated UTF8 file name, a dir entry idx and two 0 * time stamps */ - int fileSize = 0; - for (FileEntry localEntry : classEntry.getLocalFiles()) { - /* - * We want the file base name excluding path. - */ - String baseName = localEntry.getFileName(); + Cursor cursor = new Cursor(); + fileStream().forEach( fileEntry -> { + // We want the file base name excluding path. + String baseName = fileEntry.getFileName(); int length = countUTF8Bytes(baseName); - /* We should never have a null or zero length entry in local files. */ + // We should never have a null or zero length entry in local files. assert length > 0; - fileSize += length + 1; - DirEntry dirEntry = localEntry.getDirEntry(); - int idx = classEntry.localDirsIdx(dirEntry); - fileSize += writeULEB(idx, scratch, 0); - /* - * The two zero timestamps require 1 byte each. - */ - fileSize += 2; - } + cursor.add(length + 1); + // The dir index gets written as a ULEB + int dirIdx = fileEntry.getDirEntry().getIdx(); + cursor.add(writeULEB(dirIdx, scratch, 0)); + // The two zero timestamps require 1 byte each + cursor.add(2); + }); /* * Allow for terminator nul. */ - fileSize++; - return fileSize; + cursor.add(1); + return cursor.get(); } - private int computeLineNUmberTableSize(ClassEntry classEntry) { + private int computeLineNUmberTableSize() { /* * Sigh -- we have to do this by generating the content even though we cannot write it into * a byte[]. */ - return writeLineNumberTable(null, classEntry, null, 0); + return writeLineNumberTable(null, null, 0); } @Override @@ -296,38 +284,31 @@ public void writeContent(DebugContext context) { byte[] buffer = getContent(); - Cursor cursor = new Cursor(); - enableLog(context, cursor.get()); - log(context, " [0x%08x] DEBUG_LINE", cursor.get()); - - instanceClassStream().forEach(classEntry -> { - int pos = cursor.get(); - int startPos = pos; - assert getLineIndex(classEntry) == startPos; - log(context, " [0x%08x] Compile Unit for %s", pos, classEntry.getFileName()); - pos = writeHeader(classEntry, buffer, pos); - log(context, " [0x%08x] headerSize = 0x%08x", pos, pos - startPos); - int dirTablePos = pos; - pos = writeDirTable(context, classEntry, buffer, pos); - log(context, " [0x%08x] dirTableSize = 0x%08x", pos, pos - dirTablePos); - int fileTablePos = pos; - pos = writeFileTable(context, classEntry, buffer, pos); - log(context, " [0x%08x] fileTableSize = 0x%08x", pos, pos - fileTablePos); - int lineNumberTablePos = pos; - pos = writeLineNumberTable(context, classEntry, buffer, pos); - log(context, " [0x%08x] lineNumberTableSize = 0x%x", pos, pos - lineNumberTablePos); - log(context, " [0x%08x] size = 0x%x", pos, pos - startPos); - cursor.set(pos); - }); - assert cursor.get() == buffer.length; - } - - private int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { + int pos = 0; + + enableLog(context, pos); + log(context, " [0x%08x] DEBUG_LINE", pos); + pos = writeHeader(buffer, pos); + log(context, " [0x%08x] headerSize = 0x%08x", pos, pos); + int dirTablePos = pos; + pos = writeDirTable(context, buffer, pos); + log(context, " [0x%08x] dirTableSize = 0x%08x", pos, pos - dirTablePos); + int fileTablePos = pos; + pos = writeFileTable(context, buffer, pos); + log(context, " [0x%08x] fileTableSize = 0x%08x", pos, pos - fileTablePos); + int lineNumberTablePos = pos; + pos = writeLineNumberTable(context, buffer, pos); + log(context, " [0x%08x] lineNumberTableSize = 0x%x", pos, pos - lineNumberTablePos); + log(context, " [0x%08x] size = 0x%x", pos, pos); + assert pos == buffer.length; + } + + private int writeHeader(byte[] buffer, int p) { int pos = p; /* * 4 ubyte length field. */ - pos = writeInt(getLineSectionSize(classEntry) - 4, buffer, pos); + pos = writeInt(buffer.length - 4, buffer, pos); /* * 2 ubyte version is always 2. */ @@ -335,7 +316,7 @@ private int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { /* * 4 ubyte prologue length includes rest of header and dir + file table section. */ - int prologueSize = getLinePrologueSize(classEntry) - (4 + 2 + 4); + int prologueSize = getLinePrologueSize() - (4 + 2 + 4); pos = writeInt(prologueSize, buffer, pos); /* * 1 ubyte min instruction length is always 1. @@ -391,57 +372,58 @@ private int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { return pos; } - private int writeDirTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - verboseLog(context, " [0x%08x] Dir Name", pos); + private int writeDirTable(DebugContext context, byte[] buffer, int p) { + verboseLog(context, " [0x%08x] Dir Name", p); /* - * Write out the list of dirs referenced form this file entry. + * Write out the list of dirs */ - int dirIdx = 1; - for (DirEntry dir : classEntry.getLocalDirs()) { - /* - * write nul terminated string text. - */ - verboseLog(context, " [0x%08x] %-4d %s", pos, dirIdx, dir.getPath()); - pos = writeUTF8StringBytes(dir.getPathString(), buffer, pos); - dirIdx++; - } + Cursor cursor = new Cursor(p); + dirStream().forEach( dirEntry -> { + int dirIdx = dirEntry.getIdx(); + if (dirIdx > 0) { + String dirPath = dirEntry.getPathString(); + verboseLog(context, " [0x%08x] %-4d %s", cursor.get(), dirIdx, dirPath); + cursor.set(writeUTF8StringBytes(dirPath, buffer, cursor.get())); + } + }); /* * Separate dirs from files with a nul. */ - pos = writeByte((byte) 0, buffer, pos); - return pos; + cursor.set(writeByte((byte) 0, buffer, cursor.get())); + return cursor.get(); } - private int writeFileTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - int fileIdx = 1; - verboseLog(context, " [0x%08x] Entry Dir Name", pos); - for (FileEntry localEntry : classEntry.getLocalFiles()) { - /* - * We need the file name minus path, the associated dir index, and 0 for time stamps. - */ - String baseName = localEntry.getFileName(); - DirEntry dirEntry = localEntry.getDirEntry(); - int dirIdx = classEntry.localDirsIdx(dirEntry); + private int writeFileTable(DebugContext context, byte[] buffer, int p) { + verboseLog(context, " [0x%08x] Entry Dir Name", p); + /* + * Write out the list of files + */ + Cursor cursor = new Cursor(p); + fileStream().forEach( fileEntry -> { + int pos = cursor.get(); + String baseName = fileEntry.getFileName(); + DirEntry dirEntry = fileEntry.getDirEntry(); + int fileIdx = fileEntry.getIdx(); + int dirIdx = dirEntry.getIdx(); verboseLog(context, " [0x%08x] %-5d %-5d %s", pos, fileIdx, dirIdx, baseName); pos = writeUTF8StringBytes(baseName, buffer, pos); pos = writeULEB(dirIdx, buffer, pos); pos = writeULEB(0, buffer, pos); pos = writeULEB(0, buffer, pos); - fileIdx++; - } + cursor.set(pos); + + }); /* * Terminate files with a nul. */ - pos = writeByte((byte) 0, buffer, pos); - return pos; + cursor.set(writeByte((byte) 0, buffer, cursor.get())); + return cursor.get(); } private long debugLine = 1; private int debugCopyCount = 0; - private int writeCompiledMethodLineInfo(DebugContext context, ClassEntry classEntry, CompiledMethodEntry compiledEntry, byte[] buffer, int p) { + private int writeCompiledMethodLineInfo(DebugContext context, CompiledMethodEntry compiledEntry, byte[] buffer, int p) { int pos = p; Range primaryRange = compiledEntry.getPrimary(); // the compiled method might be a substitution and not in the file of the class entry @@ -452,7 +434,7 @@ private int writeCompiledMethodLineInfo(DebugContext context, ClassEntry classEn return pos; } String file = fileEntry.getFileName(); - int fileIdx = classEntry.localFilesIdx(fileEntry); + int fileIdx = fileEntry.getIdx(); /* * Each primary represents a method i.e. a contiguous sequence of subranges. For normal * methods we expect the first leaf range to start at offset 0 covering the method prologue. @@ -468,7 +450,7 @@ private int writeCompiledMethodLineInfo(DebugContext context, ClassEntry classEn if (line > 0) { FileEntry firstFileEntry = prologueRange.getFileEntry(); if (firstFileEntry != null) { - fileIdx = classEntry.localFilesIdx(firstFileEntry); + fileIdx = firstFileEntry.getIdx(); } } } @@ -519,7 +501,7 @@ private int writeCompiledMethodLineInfo(DebugContext context, ClassEntry classEn continue; } String subfile = subFileEntry.getFileName(); - int subFileIdx = classEntry.localFilesIdx(subFileEntry); + int subFileIdx = subFileEntry.getIdx(); assert subFileIdx > 0; long subLine = subrange.getLine(); long subAddressLo = subrange.getLo(); @@ -637,24 +619,17 @@ private int writeCompiledMethodLineInfo(DebugContext context, ClassEntry classEn return pos; } - private int writeLineNumberTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - /* - * The class file entry should always be first in the local files list. - */ - assert classEntry.localFilesIdx() == 1; - String className = classEntry.getTypeName(); - String fileName = classEntry.getFileName(); - String classLabel = classEntry.hasCompiledEntries() ? "compiled class" : "non-compiled class"; - log(context, " [0x%08x] %s %s", pos, classLabel, className); - log(context, " [0x%08x] %s file %s", pos, className, fileName); - // generate for both non-deopt and deopt entries so they share the file + dir table - pos = classEntry.compiledEntries().reduce(pos, - (p1, compiledEntry) -> writeCompiledMethodLineInfo(context, classEntry, compiledEntry, buffer, p1), - (oldPos, newPos) -> newPos); - log(context, " [0x%08x] processed %s %s", pos, classLabel, className); - - return pos; + private int writeLineNumberTable(DebugContext context, byte[] buffer, int p) { + Cursor cursor = new Cursor(p); + compiledMethodsStream().forEach( compiledMethod -> { + int pos = cursor.get(); + String methodName = compiledMethod.getPrimary().getFullMethodNameWithParams(); + String fileName = compiledMethod.getClassEntry().getFullFileName(); + log(context, " [0x%08x] %s %s", pos, methodName, fileName); + pos = writeCompiledMethodLineInfo(context, compiledMethod, buffer, pos); + cursor.set(pos); + }); + return cursor.get(); } private static SubRange prologueLeafRange(CompiledMethodEntry compiledEntry) { @@ -870,6 +845,15 @@ private static boolean isFixedAdvancePC(long addressDiff) { return addressDiff >= 0 && addressDiff < 0xffff; } + protected int getLinePrologueSize() { + return linePrologueSize; + } + + protected void setLinePrologueSize(int size) { + assert linePrologueSize == 0 : "prologue size set twice!"; + linePrologueSize = size; + } + /** * The debug_line section depends on debug_str section. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java index ade0f17b6855..c5e859f9407a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java @@ -126,43 +126,13 @@ public void writeContent(DebugContext context) { } private int generateContent(DebugContext context, byte[] buffer) { - int pos = 0; - - pos = writeNormalClassLocations(context, buffer, pos); - pos = writeDeoptClassLocations(context, buffer, pos); - - return pos; - } - - private int writeNormalClassLocations(DebugContext context, byte[] buffer, int pos) { - log(context, " [0x%08x] normal class locations", pos); - Cursor cursor = new Cursor(pos); - instanceClassStream().filter(ClassEntry::hasCompiledEntries).forEach(classEntry -> { - cursor.set(writeMethodLocations(context, classEntry, false, buffer, cursor.get())); + Cursor cursor = new Cursor(); + compiledMethodsStream().forEach( compiledMethod -> { + cursor.set(writeCompiledMethodLocations(context, compiledMethod, buffer, cursor.get())); }); return cursor.get(); } - private int writeDeoptClassLocations(DebugContext context, byte[] buffer, int pos) { - log(context, " [0x%08x] deopt class locations", pos); - Cursor cursor = new Cursor(pos); - instanceClassStream().filter(ClassEntry::hasDeoptCompiledEntries).forEach(classEntry -> { - cursor.set(writeMethodLocations(context, classEntry, true, buffer, cursor.get())); - }); - return cursor.get(); - } - - private int writeMethodLocations(DebugContext context, ClassEntry classEntry, boolean isDeopt, byte[] buffer, int p) { - int pos = p; - if (!isDeopt || classEntry.hasDeoptCompiledEntries()) { - Stream entries = (isDeopt ? classEntry.deoptCompiledEntries() : classEntry.normalCompiledEntries()); - pos = entries.reduce(pos, - (p1, entry) -> writeCompiledMethodLocations(context, entry, buffer, p1), - (oldPos, newPos) -> newPos); - } - return pos; - } - private int writeCompiledMethodLocations(DebugContext context, CompiledMethodEntry compiledEntry, byte[] buffer, int p) { int pos = p; pos = writeTopLevelLocations(context, compiledEntry, buffer, pos); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java index b98d41562d48..46a57e428171 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java @@ -33,6 +33,9 @@ import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.debugentry.ArrayTypeEntry; import com.oracle.objectfile.debugentry.ClassEntry; +import com.oracle.objectfile.debugentry.CompiledMethodEntry; +import com.oracle.objectfile.debugentry.DirEntry; +import com.oracle.objectfile.debugentry.FileEntry; import com.oracle.objectfile.debugentry.HeaderTypeEntry; import com.oracle.objectfile.debugentry.MethodEntry; import com.oracle.objectfile.debugentry.PrimitiveTypeEntry; @@ -713,13 +716,42 @@ protected HeaderTypeEntry headerType() { /** * Retrieve a stream of all instance classes, including interfaces and enums, notified via the * DebugTypeInfo API. - * + * * @return a stream of all instance classes notified via the DebugTypeInfo API. */ protected Stream instanceClassStream() { return dwarfSections.getInstanceClasses().stream(); } + /** + * Retrieve a stream of all compiled methods notified via the DebugTypeInfo API. + * + * @return a stream of all compiled methods notified via the DebugTypeInfo API. + */ + protected Stream compiledMethodsStream() { + return dwarfSections.getCompiledMethods().stream(); + } + + protected int compiledMethodsCount() { + return dwarfSections.getCompiledMethods().size(); + } + + protected Stream fileStream() { + return dwarfSections.getFiles().stream(); + } + + protected int fileCount() { + return dwarfSections.getFiles().size(); + } + + protected Stream dirStream() { + return dwarfSections.getDirs().stream(); + } + + protected int dirCount() { + return dwarfSections.getDirs().size(); + } + /** * Retrieve an iterable for all instance classes, including interfaces and enums, notified via * the DebugTypeInfo API. @@ -771,61 +803,6 @@ protected void setIndirectTypeIndex(TypeEntry typeEntry, int pos) { dwarfSections.setIndirectTypeIndex(typeEntry, pos); } - protected int getCUIndex(ClassEntry classEntry) { - if (!contentByteArrayCreated()) { - return 0; - } - return dwarfSections.getCUIndex(classEntry); - } - - protected void setCUIndex(ClassEntry classEntry, int pos) { - dwarfSections.setCUIndex(classEntry, pos); - } - - protected int getDeoptCUIndex(ClassEntry classEntry) { - if (!contentByteArrayCreated()) { - return 0; - } - return dwarfSections.getDeoptCUIndex(classEntry); - } - - protected void setDeoptCUIndex(ClassEntry classEntry, int pos) { - dwarfSections.setDeoptCUIndex(classEntry, pos); - } - - protected int getLineIndex(ClassEntry classEntry) { - if (!contentByteArrayCreated()) { - return 0; - } - return dwarfSections.getLineIndex(classEntry); - } - - protected void setLineIndex(ClassEntry classEntry, int pos) { - dwarfSections.setLineIndex(classEntry, pos); - } - - protected int getLineSectionSize(ClassEntry classEntry) { - if (!contentByteArrayCreated()) { - return 0; - } - return dwarfSections.getLineSectionSize(classEntry); - } - - protected void setLineSectionSize(ClassEntry classEntry, int pos) { - dwarfSections.setLineSectionSize(classEntry, pos); - } - - protected int getLinePrologueSize(ClassEntry classEntry) { - if (!contentByteArrayCreated()) { - return 0; - } - return dwarfSections.getLinePrologueSize(classEntry); - } - - protected void setLinePrologueSize(ClassEntry classEntry, int pos) { - dwarfSections.setLinePrologueSize(classEntry, pos); - } - protected int getLayoutIndex(ClassEntry classEntry) { if (!contentByteArrayCreated()) { return 0; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java index 4c91a8e8c8de..067eec955972 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java @@ -211,6 +211,11 @@ public int oopAlignment() { return referenceAlignment; } + @Override + public int compiledCodeMax() { + return codeCache.getCodeCacheSize(); + } + @Override public int oopTagsMask() { return tagsMask; From bbf26ea03fd2cb1ea459e145a176fdfb1ed4a23a Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 13 Apr 2023 09:12:32 +0100 Subject: [PATCH 2/9] Minimize generation and indexing of abstract inline methods --- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 8 +- .../objectfile/elf/dwarf/DwarfDebugInfo.java | 91 +++++++-------- .../elf/dwarf/DwarfInfoSectionImpl.java | 108 ++++++------------ .../elf/dwarf/DwarfSectionImpl.java | 32 +++--- 4 files changed, 93 insertions(+), 146 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java index 990c991a69ce..9a8be99b6606 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java @@ -533,11 +533,9 @@ * method_definition DIE, including attributes specified int the latter's child DIEs, * such as parameter and local variable declarations. * - * TODO - check we no longer need to replicate the DIES - * * However, it is actually necessary to replicate the parameter and local variable declarations - * as children of the method definition DIE in order to ensure that gdb is aware of the parameters - * and locals. + * as children of the inline method definition DIE in order to ensure that gdb is aware of the + * parameters and locals. * *
      * @@ -583,8 +581,6 @@ * abstract_origin for any corresponding inlined method DIEs appearing as children * of m. * - * TODO - ensure we only generate per inlined method rather than per class per method inlined by that class - * * The abstract_inline_method DIE should inherit attributes from * the method_definition DIE referenced as its abstract_origin attribute without the * need to repeat them. However, it is actually necessary to replicate the method parameter and diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java index 5f0d06fcee38..83ee5715f23d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java @@ -481,11 +481,6 @@ static class DwarfClassProperties extends DwarfTypeProperties { * Map from field names to info section index for the field declaration. */ private EconomicMap fieldDeclarationIndex; - /** - * Map from method entries to associated abstract inline method index. - */ - private EconomicMap abstractInlineMethodIndex; - /** * Map from method entries to associated method local properties index. */ @@ -496,7 +491,6 @@ static class DwarfClassProperties extends DwarfTypeProperties { this.layoutIndex = -1; this.indirectLayoutIndex = -1; fieldDeclarationIndex = null; - abstractInlineMethodIndex = null; methodLocalPropertiesIndex = null; } } @@ -514,9 +508,21 @@ static class DwarfMethodProperties { */ private int abstractInlineMethodIndex; + /** + * Index of info locations for params/locals belonging to a method + */ + private DwarfLocalProperties normalLocalProperties; + + /** + * Index of info locations for params/locals declared belonging to an abstract inline method + */ + private DwarfLocalProperties inlineLocalProperties; + DwarfMethodProperties() { methodDeclarationIndex = -1; abstractInlineMethodIndex = -1; + normalLocalProperties = null; + inlineLocalProperties = null; } public int getMethodDeclarationIndex() { @@ -538,6 +544,24 @@ public void setAbstractInlineMethodIndex(int pos) { assert abstractInlineMethodIndex == -1 || abstractInlineMethodIndex == pos : "bad inline index"; abstractInlineMethodIndex = pos; } + + public DwarfLocalProperties getLocalProperties(boolean isInlined) { + DwarfLocalProperties localProperties; + if (isInlined) { + localProperties = normalLocalProperties; + } else { + localProperties = inlineLocalProperties; + } + if (localProperties == null) { + localProperties = new DwarfLocalProperties(); + if (isInlined) { + normalLocalProperties = localProperties; + } else { + inlineLocalProperties = localProperties; + } + } + return localProperties; + } } private DwarfTypeProperties addTypeProperties(TypeEntry typeEntry) { @@ -690,27 +714,14 @@ public int getMethodDeclarationIndex(MethodEntry methodEntry) { return methodProperties.getMethodDeclarationIndex(); } - public void setAbstractInlineMethodIndex(ClassEntry classEntry, MethodEntry methodEntry, int pos) { - DwarfClassProperties classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - EconomicMap abstractInlineMethodIndex = classProperties.abstractInlineMethodIndex; - if (abstractInlineMethodIndex == null) { - classProperties.abstractInlineMethodIndex = abstractInlineMethodIndex = EconomicMap.create(); - } - if (abstractInlineMethodIndex.get(methodEntry) != null) { - assert abstractInlineMethodIndex.get(methodEntry) == pos : classEntry.getTypeName() + " & " + methodEntry.getSymbolName(); - } else { - abstractInlineMethodIndex.put(methodEntry, pos); - } + public void setAbstractInlineMethodIndex(MethodEntry methodEntry, int pos) { + DwarfMethodProperties methodProperties = lookupMethodProperties(methodEntry); + methodProperties.setAbstractInlineMethodIndex(pos); } - public int getAbstractInlineMethodIndex(ClassEntry classEntry, MethodEntry methodEntry) { - DwarfClassProperties classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - EconomicMap abstractInlineMethodIndex = classProperties.abstractInlineMethodIndex; - assert abstractInlineMethodIndex != null : classEntry.getTypeName() + " & " + methodEntry.getSymbolName(); - assert abstractInlineMethodIndex.get(methodEntry) != null : classEntry.getTypeName() + " & " + methodEntry.getSymbolName(); - return abstractInlineMethodIndex.get(methodEntry); + public int getAbstractInlineMethodIndex(MethodEntry methodEntry) { + DwarfMethodProperties methodProperties = lookupMethodProperties(methodEntry); + return methodProperties.getAbstractInlineMethodIndex(); } /** @@ -744,35 +755,19 @@ private DwarfLocalProperties addRangeLocalProperties(Range range) { return localProperties; } - public DwarfLocalProperties lookupLocalProperties(ClassEntry classEntry, MethodEntry methodEntry) { - EconomicMap map; - if (classEntry == null) { - map = methodLocalPropertiesIndex; - } else { - DwarfClassProperties classProperties = lookupClassProperties(classEntry); - assert classProperties != null; - map = classProperties.methodLocalPropertiesIndex; - if (map == null) { - map = classProperties.methodLocalPropertiesIndex = EconomicMap.create(); - } - } - DwarfLocalProperties localProperties = map.get(methodEntry); - if (localProperties == null) { - localProperties = new DwarfLocalProperties(); - map.put(methodEntry, localProperties); - } - return localProperties; + public DwarfLocalProperties lookupLocalProperties(MethodEntry methodEntry, boolean isInlined) { + return lookupMethodProperties(methodEntry).getLocalProperties(isInlined); } - public void setMethodLocalIndex(ClassEntry classEntry, MethodEntry methodEntry, DebugLocalInfo localInfo, int index) { - DwarfLocalProperties localProperties = lookupLocalProperties(classEntry, methodEntry); + public void setMethodLocalIndex(MethodEntry methodEntry, boolean isInlined, DebugLocalInfo localInfo, int index) { + DwarfLocalProperties localProperties = lookupLocalProperties(methodEntry, isInlined); localProperties.setIndex(localInfo, index); } - public int getMethodLocalIndex(ClassEntry classEntry, MethodEntry methodEntry, DebugLocalInfo localinfo) { - DwarfLocalProperties localProperties = lookupLocalProperties(classEntry, methodEntry); + public int getMethodLocalIndex(MethodEntry methodEntry, boolean isInlined, DebugLocalInfo localInfo) { + DwarfLocalProperties localProperties = lookupLocalProperties(methodEntry, isInlined); assert localProperties != null : "get of non-existent local index"; - int index = localProperties.getIndex(localinfo); + int index = localProperties.getIndex(localInfo); assert index >= 0 : "get of local index before it was set"; return index; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java index 3518a91ffb11..34fcda69dfec 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java @@ -180,7 +180,7 @@ public int generateContent(DebugContext context, byte[] buffer) { /* Write DIEs for array types. */ - pos = writeArrayTypes(context, buffer, pos); + pos = writeArrays(context, buffer, pos); /* Write all compiled code locations */ @@ -362,12 +362,6 @@ private int writeInstanceClassInfo(DebugContext context, ClassEntry classEntry, /* Write a declaration for the special Class object pseudo-static field */ pos = writeClassConstantDeclaration(context, classEntry, buffer, pos); - /* Write abstract inline methods. */ - - // TODO - ensure we only generate per inlined method rather than per class per method inlined by that class - - pos = writeAbstractInlineMethods(context, classEntry, buffer, pos); - /* if we opened a namespace then terminate its children */ if (!loaderId.isEmpty()) { @@ -607,6 +601,12 @@ private int writeMethodDeclarations(DebugContext context, ClassEntry classEntry, */ pos = writeMethodDeclaration(context, classEntry, method, buffer, pos); } + if (method.isInlined()) { + /* + * We also need an abstract inlined method as a target for any inline tree that includes the method + */ + pos = writeAbstractInlineMethod(context, classEntry, method, buffer, pos); + } } return pos; @@ -670,28 +670,28 @@ private int writeMethodDeclaration(DebugContext context, ClassEntry classEntry, writeInfoSectionOffset(pos, buffer, objectPointerIndex); } /* Write method parameter declarations. */ - pos = writeMethodParameterDeclarations(context, null, method, fileIdx, 3, buffer, pos); + pos = writeMethodParameterDeclarations(context, false, method, fileIdx, 3, buffer, pos); /* write method local declarations */ - pos = writeMethodLocalDeclarations(context, null, method, fileIdx, 3, buffer, pos); + pos = writeMethodLocalDeclarations(context, false, method, fileIdx, 3, buffer, pos); /* * Write a terminating null attribute. */ return writeAttrNull(buffer, pos); } - private int writeMethodParameterDeclarations(DebugContext context, ClassEntry classEntry, MethodEntry method, int fileIdx, int level, byte[] buffer, int p) { + private int writeMethodParameterDeclarations(DebugContext context, boolean isInlined, MethodEntry method, int fileIdx, int level, byte[] buffer, int p) { int pos = p; int refAddr; if (!Modifier.isStatic(method.getModifiers())) { refAddr = pos; DebugLocalInfo paramInfo = method.getThisParam(); - setMethodLocalIndex(classEntry, method, paramInfo, refAddr); + setMethodLocalIndex(method, isInlined, paramInfo, refAddr); pos = writeMethodParameterDeclaration(context, paramInfo, fileIdx, true, level, buffer, pos); } for (int i = 0; i < method.getParamCount(); i++) { refAddr = pos; DebugLocalInfo paramInfo = method.getParam(i); - setMethodLocalIndex(classEntry, method, paramInfo, refAddr); + setMethodLocalIndex(method, isInlined, paramInfo, refAddr); pos = writeMethodParameterDeclaration(context, paramInfo, fileIdx, false, level, buffer, pos); } return pos; @@ -734,13 +734,13 @@ private int writeMethodParameterDeclaration(DebugContext context, DebugLocalInfo return pos; } - private int writeMethodLocalDeclarations(DebugContext context, ClassEntry classEntry, MethodEntry method, int fileIdx, int level, byte[] buffer, int p) { + private int writeMethodLocalDeclarations(DebugContext context, boolean isInlined, MethodEntry method, int fileIdx, int level, byte[] buffer, int p) { int pos = p; int refAddr; for (int i = 0; i < method.getLocalCount(); i++) { refAddr = pos; DebugLocalInfo localInfo = method.getLocal(i); - setMethodLocalIndex(classEntry, method, localInfo, refAddr); + setMethodLocalIndex(method, isInlined, localInfo, refAddr); pos = writeMethodLocalDeclaration(context, localInfo, fileIdx, level, buffer, pos); } return pos; @@ -972,16 +972,16 @@ private int writeClassStaticFieldLocation(DebugContext context, ClassEntry class return pos; } - private int writeArrayTypes(DebugContext context, byte[] buffer, int p) { + private int writeArrays(DebugContext context, byte[] buffer, int p) { log(context, " [0x%08x] array classes", p); Cursor cursor = new Cursor(p); arrayTypeStream().forEach(arrayTypeEntry -> { - cursor.set(writeArrayTypeInfo(context, arrayTypeEntry, buffer, cursor.get())); + cursor.set(writeArray(context, arrayTypeEntry, buffer, cursor.get())); }); return cursor.get(); } - private int writeArrayTypeInfo(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) { + private int writeArray(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) { int pos = p; /* if the array base type is a class with a loader then embed the children in a namespace */ String loaderId = arrayTypeEntry.getLoaderId(); @@ -1188,8 +1188,8 @@ private int writeMethodLocation(DebugContext context, CompiledMethodEntry compil log(context, " [0x%08x] specification 0x%x (%s)", pos, methodSpecOffset, methodKey); pos = writeInfoSectionOffset(methodSpecOffset, buffer, pos); HashMap> varRangeMap = primary.getVarRangeMap(); - pos = writeMethodParameterLocations(context, null, varRangeMap, primary, 2, buffer, pos); - pos = writeMethodLocalLocations(context, null, varRangeMap, primary, 2, buffer, pos); + pos = writeMethodParameterLocations(context, false, varRangeMap, primary, 2, buffer, pos); + pos = writeMethodLocalLocations(context, false, varRangeMap, primary, 2, buffer, pos); if (primary.includesInlineRanges()) { /* * the method has inlined ranges so write concrete inlined method entries as its @@ -1203,7 +1203,7 @@ private int writeMethodLocation(DebugContext context, CompiledMethodEntry compil return writeAttrNull(buffer, pos); } - private int writeMethodParameterLocations(DebugContext context, ClassEntry classEntry, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) { + private int writeMethodParameterLocations(DebugContext context, boolean isInlined, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) { int pos = p; MethodEntry methodEntry; if (range.isPrimary()) { @@ -1214,20 +1214,20 @@ private int writeMethodParameterLocations(DebugContext context, ClassEntry class } if (!Modifier.isStatic(methodEntry.getModifiers())) { DebugLocalInfo thisParamInfo = methodEntry.getThisParam(); - int refAddr = getMethodLocalIndex(classEntry, methodEntry, thisParamInfo); + int refAddr = getMethodLocalIndex(methodEntry, isInlined, thisParamInfo); List ranges = varRangeMap.get(thisParamInfo); pos = writeMethodLocalLocation(context, range, thisParamInfo, refAddr, ranges, depth, true, buffer, pos); } for (int i = 0; i < methodEntry.getParamCount(); i++) { DebugLocalInfo paramInfo = methodEntry.getParam(i); - int refAddr = getMethodLocalIndex(classEntry, methodEntry, paramInfo); + int refAddr = getMethodLocalIndex(methodEntry, isInlined, paramInfo); List ranges = varRangeMap.get(paramInfo); pos = writeMethodLocalLocation(context, range, paramInfo, refAddr, ranges, depth, true, buffer, pos); } return pos; } - private int writeMethodLocalLocations(DebugContext context, ClassEntry classEntry, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) { + private int writeMethodLocalLocations(DebugContext context, boolean isInlined, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) { int pos = p; MethodEntry methodEntry; if (range.isPrimary()) { @@ -1239,7 +1239,7 @@ private int writeMethodLocalLocations(DebugContext context, ClassEntry classEntr int count = methodEntry.getLocalCount(); for (int i = 0; i < count; i++) { DebugLocalInfo localInfo = methodEntry.getLocal(i); - int refAddr = getMethodLocalIndex(classEntry, methodEntry, localInfo); + int refAddr = getMethodLocalIndex(methodEntry, isInlined, localInfo); List ranges = varRangeMap.get(localInfo); pos = writeMethodLocalLocation(context, range, localInfo, refAddr, ranges, depth, false, buffer, pos); } @@ -1317,12 +1317,12 @@ private int generateConcreteInlinedMethods(DebugContext context, CompiledMethodE depth--; } depth = subrange.getDepth(); - pos = writeInlineSubroutine(context, classEntry, subrange, depth + 2, buffer, pos); + pos = writeInlineSubroutine(context, subrange, depth + 2, buffer, pos); HashMap> varRangeMap = subrange.getVarRangeMap(); // increment depth to account for parameter and method locations depth++; - pos = writeMethodParameterLocations(context, classEntry, varRangeMap, subrange, depth + 2, buffer, pos); - pos = writeMethodLocalLocations(context, classEntry, varRangeMap, subrange, depth + 2, buffer, pos); + pos = writeMethodParameterLocations(context, true, varRangeMap, subrange, depth + 2, buffer, pos); + pos = writeMethodLocalLocations(context, true, varRangeMap, subrange, depth + 2, buffer, pos); } // if we just stepped out of a child range write nulls for each step up while (depth > 0) { @@ -1332,7 +1332,7 @@ private int generateConcreteInlinedMethods(DebugContext context, CompiledMethodE return pos; } - private int writeInlineSubroutine(DebugContext context, ClassEntry classEntry, Range caller, int depth, byte[] buffer, int p) { + private int writeInlineSubroutine(DebugContext context, Range caller, int depth, byte[] buffer, int p) { assert !caller.isLeaf(); // the supplied range covers an inline call and references the caller method entry. its // child ranges all reference the same inlined called method. leaf children cover code for @@ -1340,9 +1340,10 @@ private int writeInlineSubroutine(DebugContext context, ClassEntry classEntry, R // identify the inlined method by looking at the first callee Range callee = caller.getFirstCallee(); MethodEntry methodEntry = callee.getMethodEntry(); + ClassEntry classEntry = methodEntry.ownerType(); String methodKey = methodEntry.getSymbolName(); /* the abstract index was written in the method's class entry */ - int abstractOriginIndex = getAbstractInlineMethodIndex(classEntry, methodEntry); + int abstractOriginIndex = getAbstractInlineMethodIndex(methodEntry); int pos = p; log(context, " [0x%08x] concrete inline subroutine [0x%x, 0x%x] %s", pos, caller.getLo(), caller.getHi(), methodKey); @@ -1378,50 +1379,9 @@ private int writeInlineSubroutine(DebugContext context, ClassEntry classEntry, R return pos; } - private int writeAbstractInlineMethods(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { - HashSet inlinedMethods = collectInlinedMethods(context, classEntry, p); - int pos = p; - for (MethodEntry methodEntry : inlinedMethods) { - setAbstractInlineMethodIndex(classEntry, methodEntry, pos); - pos = writeAbstractInlineMethod(context, classEntry, methodEntry, buffer, pos); - } - return pos; - } - - private HashSet collectInlinedMethods(DebugContext context, ClassEntry classEntry, int p) { - final HashSet methods = new HashSet<>(); - Stream compiledEntries = classEntry.compiledEntries(); - compiledEntries.forEach(compiledEntry -> addInlinedMethods(context, compiledEntry, compiledEntry.getPrimary(), methods, p)); - return methods; - } - - private void addInlinedMethods(DebugContext context, CompiledMethodEntry compiledEntry, Range primary, HashSet hashSet, int p) { - if (primary.isLeaf()) { - return; - } - verboseLog(context, " [0x%08x] collect abstract inlined methods %s", p, primary.getFullMethodName()); - Iterator iterator = compiledEntry.topDownRangeIterator(); - while (iterator.hasNext()) { - SubRange subrange = iterator.next(); - if (subrange.isLeaf()) { - // we only generate abstract inline methods for non-leaf entries - continue; - } - // the subrange covers an inline call and references the caller method entry. its - // child ranges all reference the same inlined called method. leaf children cover code - // for - // that inlined method. non-leaf children cover code for recursively inlined methods. - // identify the inlined method by looking at the first callee - Range callee = subrange.getFirstCallee(); - MethodEntry methodEntry = callee.getMethodEntry(); - if (hashSet.add(methodEntry)) { - verboseLog(context, " [0x%08x] add abstract inlined method %s", p, methodEntry.getSymbolName()); - } - } - } - private int writeAbstractInlineMethod(DebugContext context, ClassEntry classEntry, MethodEntry method, byte[] buffer, int p) { int pos = p; + setAbstractInlineMethodIndex(method, pos); log(context, " [0x%08x] abstract inline method %s::%s", pos, classEntry.getTypeName(), method.methodName()); int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_abstract_inline_method; log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode); @@ -1445,9 +1405,9 @@ private int writeAbstractInlineMethod(DebugContext context, ClassEntry classEntr } assert fileEntry != null; int fileIdx = fileEntry.getIdx(); - int level = 2; - pos = writeMethodParameterDeclarations(context, classEntry, method, fileIdx, level, buffer, pos); - pos = writeMethodLocalDeclarations(context, classEntry, method, fileIdx, level, buffer, pos); + int level = 3; + pos = writeMethodParameterDeclarations(context, true, method, fileIdx, level, buffer, pos); + pos = writeMethodLocalDeclarations(context, true, method, fileIdx, level, buffer, pos); /* * Write a terminating null attribute. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java index 46a57e428171..318daa3ce4f7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java @@ -847,50 +847,46 @@ protected int getMethodDeclarationIndex(MethodEntry methodEntry) { return dwarfSections.getMethodDeclarationIndex(methodEntry); } - protected void setAbstractInlineMethodIndex(ClassEntry classEntry, MethodEntry methodEntry, int pos) { - dwarfSections.setAbstractInlineMethodIndex(classEntry, methodEntry, pos); + protected void setAbstractInlineMethodIndex(MethodEntry methodEntry, int pos) { + dwarfSections.setAbstractInlineMethodIndex(methodEntry, pos); } - protected int getAbstractInlineMethodIndex(ClassEntry classEntry, MethodEntry methodEntry) { + protected int getAbstractInlineMethodIndex(MethodEntry methodEntry) { if (!contentByteArrayCreated()) { return 0; } - return dwarfSections.getAbstractInlineMethodIndex(classEntry, methodEntry); + return dwarfSections.getAbstractInlineMethodIndex(methodEntry); } /** * Record the info section offset of a local (or parameter) declaration DIE. The local (or - * parameter) can be a child of a standard method declaration in the CU of its owning class. - * Alternatively, it can be as a child of an abstract inline method declaration in the CU of a - * class into which the original's code needs to be inlined. + * parameter) can be a child of a standard method declaration or of an abstract inline method + * declaration. * - * @param classEntry null if the local declaration belongs to a standard method declaration - * otherwise the entry for the class importing the inline code. * @param methodEntry the method being declared or inlined. + * @param isInlined true if this is a parameter of a standard declaration false if it belongs to an abstract inlined method * @param localInfo the local or param whose index is to be recorded. * @param index the info section offset to be recorded. */ - protected void setMethodLocalIndex(ClassEntry classEntry, MethodEntry methodEntry, DebugLocalInfo localInfo, int index) { - dwarfSections.setMethodLocalIndex(classEntry, methodEntry, localInfo, index); + protected void setMethodLocalIndex(MethodEntry methodEntry, boolean isInlined, DebugLocalInfo localInfo, int index) { + dwarfSections.setMethodLocalIndex(methodEntry, isInlined, localInfo, index); } /** * Retrieve the info section offset of a local (or parameter) declaration DIE. The local (or - * parameter) can be a child of a standard method declaration in the CU of its owning class. - * Alternatively, it can be as a child of an abstract inline method declaration in the CU of a - * class into which the original's code needs to be inlined. + * parameter) can be a child of a standard method declaration or of an abstract inline method + * declaration. * - * @param classEntry null if the local declaration belongs to a standard method declaration - * otherwise the entry for the class importing the inline code. * @param methodEntry the method being declared or imported + * @param isInlined true if this is a parameter of a standard declaration false if it belongs to an abstract inlined method * @param localInfo the local or param whose index is to be retrieved. * @return the associated info section offset. */ - protected int getMethodLocalIndex(ClassEntry classEntry, MethodEntry methodEntry, DebugLocalInfo localInfo) { + protected int getMethodLocalIndex(MethodEntry methodEntry, boolean isInlined, DebugLocalInfo localInfo) { if (!contentByteArrayCreated()) { return 0; } - return dwarfSections.getMethodLocalIndex(classEntry, methodEntry, localInfo); + return dwarfSections.getMethodLocalIndex(methodEntry, isInlined, localInfo); } /** From c04ad1a1512a76be629d5f71b8b0d972cbe67c50 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 13 Apr 2023 10:59:46 +0100 Subject: [PATCH 3/9] Remove redundant method param and lcoal declarations in abstract inline methods. Style and comment layout fixes. --- .../objectfile/debugentry/ClassEntry.java | 4 +- .../objectfile/debugentry/DebugInfoBase.java | 17 +- .../objectfile/debugentry/DirEntry.java | 2 +- .../debugentry/range/PrimaryRange.java | 1 - .../objectfile/debugentry/range/SubRange.java | 1 - .../elf/dwarf/DwarfARangesSectionImpl.java | 9 +- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 410 +++++++++--------- .../objectfile/elf/dwarf/DwarfDebugInfo.java | 37 +- .../elf/dwarf/DwarfFrameSectionImpl.java | 1 - .../elf/dwarf/DwarfInfoSectionImpl.java | 105 ++--- .../elf/dwarf/DwarfLineSectionImpl.java | 13 +- .../elf/dwarf/DwarfLocSectionImpl.java | 6 +- .../elf/dwarf/DwarfSectionImpl.java | 28 +- 13 files changed, 295 insertions(+), 339 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java index 0c85e8b9d252..389c584ad6c6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java @@ -308,8 +308,8 @@ public int lowpc() { /** * Retrieve the highest code section offset for compiled method code belonging to this class. - * The returned value is the offset of the first byte that succeeds the code for that method. - * It is an error to call this for a class entry which has no compiled methods. + * The returned value is the offset of the first byte that succeeds the code for that method. It + * is an error to call this for a class entry which has no compiled methods. * * @return the highest code section offset for compiled method code belonging to this class */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java index 6000297b161a..f6b63932c1ae 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java @@ -110,9 +110,9 @@ public abstract class DebugInfoBase { */ private final StringTable stringTable = new StringTable(); /** - * List of dirs in which files are found to reside. - */ - private final List dirs = new ArrayList<>(); + * List of dirs in which files are found to reside. + */ + private final List dirs = new ArrayList<>(); /** * Index of all dirs in which files are found to reside either as part of substrate/compiler or * user code. @@ -147,8 +147,8 @@ public abstract class DebugInfoBase { */ private ClassEntry objectClass; /** - * List of all top level compiled methods found in debug info. These ought to arrive - * via the debug info API in ascending address range order. + * List of all top level compiled methods found in debug info. These ought to arrive via the + * debug info API in ascending address range order. */ private final List compiledMethods = new ArrayList<>(); /** @@ -461,6 +461,7 @@ private void addPrimaryRange(PrimaryRange primaryRange, DebugCodeInfo debugCodeI CompiledMethodEntry compiledMethod = classEntry.indexPrimary(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); indexCompiledMethod(compiledMethod); } + /** * Recursively creates subranges based on DebugLocationInfo including, and appropriately * linking, nested inline subranges. @@ -532,14 +533,16 @@ private boolean verifyMethodOrder(CompiledMethodEntry next) { PrimaryRange lastRange = last.getPrimary(); PrimaryRange nextRange = next.getPrimary(); if (lastRange.getHi() > nextRange.getLo()) { - assert false : "methods %s [0x%x, 0x%x] and %s [0x%x, 0x%x] presented out of order".formatted(lastRange.getFullMethodName(), lastRange.getLo(), lastRange.getHi(), nextRange.getFullMethodName(), nextRange.getLo(), nextRange.getHi()); + assert false : "methods %s [0x%x, 0x%x] and %s [0x%x, 0x%x] presented out of order".formatted(lastRange.getFullMethodName(), lastRange.getLo(), lastRange.getHi(), + nextRange.getFullMethodName(), nextRange.getLo(), nextRange.getHi()); return false; } } return true; } - final static Path EMPTY_PATH = Paths.get(""); + static final Path EMPTY_PATH = Paths.get(""); + private FileEntry addFileEntry(String fileName, Path filePath) { assert fileName != null; Path fileAsPath; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java index 6edee7d4a1bb..71b4dde797ce 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java @@ -53,7 +53,7 @@ public String getPathString() { } /** - * Retrieve the index of the dir entry in the list of all known dirs + * Retrieve the index of the dir entry in the list of all known dirs. * * @return the index of the file entry. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/PrimaryRange.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/PrimaryRange.java index 405967743f0a..4e4c7fc6ae91 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/PrimaryRange.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/PrimaryRange.java @@ -26,7 +26,6 @@ package com.oracle.objectfile.debugentry.range; -import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.MethodEntry; public class PrimaryRange extends Range { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/SubRange.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/SubRange.java index 8b91202f7d38..8ffe0909a568 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/SubRange.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/SubRange.java @@ -26,7 +26,6 @@ package com.oracle.objectfile.debugentry.range; -import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.MethodEntry; import com.oracle.objectfile.debuginfo.DebugInfoProvider; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index f118ad407886..b53342037758 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -26,17 +26,13 @@ package com.oracle.objectfile.elf.dwarf; -import java.util.List; import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.graalvm.compiler.debug.DebugContext; import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; -import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.CompiledMethodEntry; import com.oracle.objectfile.debugentry.range.Range; @@ -68,7 +64,8 @@ public void createContent() { * *
    • uint16 dwarf_version ..... always 2 * - *
    • uint32 info_offset ....... offset of compilation unit in debug_info -- always 0 + *
    • uint32 info_offset ....... offset of compilation unit in debug_info -- always + * 0 * *
    • uint8 address_size ....... always 8 * @@ -142,7 +139,7 @@ public void writeContent(DebugContext context) { log(context, " [0x%08x] DEBUG_ARANGES", cursor.get()); int lengthPos = cursor.get(); cursor.set(writeHeader(0, buffer, cursor.get())); - compiledMethodsStream().forEach( compiledMethodEntry -> { + compiledMethodsStream().forEach(compiledMethodEntry -> { cursor.set(writeARange(context, compiledMethodEntry, buffer, cursor.get())); }); // write two terminating zeroes diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java index 9a8be99b6606..271e1852a1c3 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java @@ -30,14 +30,15 @@ import org.graalvm.compiler.debug.DebugContext; /** - * Section generator for debug_abbrev section. That section defines the + * Section generator for debug_abbrev section. That section defines the * layout of the DWARF Information Entries (DIEs) used to model Java debug info. Top * level DIEs define Java Compile Units (CUs). Embedded DIEs describe the content of * the CU: types, code, variable, etc. These definitions are used to interpret the DIE - * content inserted into the debug_info section.

      + * content inserted into the debug_info section. + *

      * - * An abbrev table contains abbrev entries for one or more DIEs, the last one being - * a null entry.

      + * An abbrev table contains abbrev entries for one or more DIEs, the last one being a null entry. + *

      * * A null entry consists of just a 0 abbrev code. * @@ -75,16 +76,17 @@ * *

    * - * For the moment we only use one abbrev table and one CU. It employs the following top - * level and nested DIES

    + * For the moment we only use one abbrev table and one CU. It employs the following top level and + * nested DIES + *

    * * Level 0 DIEs * *

      * - *
    • code = null, tag == null - empty terminator + *
    • code = null, tag == null - empty terminator * - *
    • code = class_unit, tag == compile_unit - CU that defines the Java object header + *
    • code = class_unit, tag == compile_unit - CU that defines the Java object header * struct, all Java primitive and object types and all Java compiled code. * *
    @@ -93,54 +95,54 @@ * *
      * - *
    • code = primitive_type, tag == base_type, parent = class_unit - Java primitive type (non-void) + *
    • code = primitive_type, tag == base_type, parent = class_unit - Java primitive type (non-void) * - *
    • code = void_type, tag == unspecified_type, parent = class_unit - Java void type + *
    • code = void_type, tag == unspecified_type, parent = class_unit - Java void type * - *
    • code = object_header, tag == structure_type, parent = class_unit - Java object header + *
    • code = object_header, tag == structure_type, parent = class_unit - Java object header * - *
    • code = class_layout, tag == class_type, parent = class_unit - Java + *
    • code = class_layout, tag == class_type, parent = class_unit - Java * instance type structure definition * - *
    • code = class_pointer, tag == pointer_type, parent = class_unit - Java + *
    • code = class_pointer, tag == pointer_type, parent = class_unit - Java * instance ref type * - *
    • code = method_location, tag == subprogram , parent = class_unit - Java + *
    • code = method_location, tag == subprogram , parent = class_unit - Java * method code definition (i.e. location of code) * - *
    • code = abstract_inline_method, tag == subprogram , parent = class_unit - + *
    • code = abstract_inline_method, tag == subprogram , parent = class_unit - * Java abstract inline method (i.e. proxy for method definition referenced by concrete * inline instance) * - *
    • code = static_field_location, tag == variable, parent = class_unit - Java + *
    • code = static_field_location, tag == variable, parent = class_unit - Java * static field definition (i.e. location of data) * - *
    • code = array_layout, tag == structure_type, parent = array_unit - Java + *
    • code = array_layout, tag == structure_type, parent = array_unit - Java * array type structure definition * - *
    • code = array_pointer, tag == pointer_type, parent = array_unit - Java + *
    • code = array_pointer, tag == pointer_type, parent = array_unit - Java * array ref type * - *
    • code = interface_layout, tag == union_type, parent = class_unit - Java + *
    • code = interface_layout, tag == union_type, parent = class_unit - Java * array type structure definition * - *
    • code = interface_pointer, tag == pointer_type, parent = class_unit - Java + *
    • code = interface_pointer, tag == pointer_type, parent = class_unit - Java * interface ref type * *
    • code = indirect_layout, tag == class_type, parent = class_unit, array_unit, - * interface_unit - wrapper layout attaches address rewriting logic to the layout + * interface_unit - wrapper layout attaches address rewriting logic to the layout * types that it wraps using a data_location attribute * *
    • code = indirect_pointer, tag == pointer_type, parent = class_unit, array_unit, - * interface_unit - indirect ref type used to type indirect oops that encode the + * interface_unit - indirect ref type used to type indirect oops that encode the * address of an object, whether by adding tag bits or representing the address as an offset * from some base address. these are used to type object references stored in static and * instance fields. They are not needed when typing local vars and parameters held in * registers or on the stack as they appear as raw addresses. * *
    • code = namespace, tag == namespace, parent = class_unit, array_unit, - * interface_unit - a wrap-around DIE that is used to embed all the normal level 1 - * DIEs of a class_unit or array_unit in a namespace. This is + * interface_unit - a wrap-around DIE that is used to embed all the normal level 1 + * DIEs of a class_unit or array_unit in a namespace. This is * needed when the corresponding class/interface or array base element type have been loaded * by a loader with a non-empty loader in order to ensure that mangled names for the class * and its members can legitimately employ the loader id as a namespace prefix. Note that @@ -153,30 +155,30 @@ * *
        * - *
      • code = header_field, tag == member, parent = object_header - object/array + *
      • code = header_field, tag == member, parent = object_header - object/array * header field * *
      • code == method_declaration1/2, tag == subprogram, parent = class_layout * - *
      • code = field_declaration1/2/3/4, tag == member, parent = class_layout - instance + *
      • code = field_declaration1/2/3/4, tag == member, parent = class_layout - instance * field declaration (i.e. specification of properties) * *
      • code == super_reference, tag == inheritance, parent = class_layout, - * array_layout - reference to super class layout or to appropriate header struct for - * {code java.lang.Object} or arrays. + * array_layout - reference to super class layout or to appropriate header struct for {code + * java.lang.Object} or arrays. * - *
      • code == interface_implementor, tag == member, parent = interface_layout - * - union member typed using class layout of a given implementing class + *
      • code == interface_implementor, tag == member, parent = interface_layout - union + * member typed using class layout of a given implementing class * *
      • code = inlined_subroutine/inlined_subroutine_with_children, tag == subprogram, * parent = method_location/inlined_subroutine_with_children - provides range and * abstract origin for a concrete inline method * *
      • code == method_parameter_declaration1/2/3, tag == formal_parameter, parent = - * method_declaration1/2, abstract_inline_method - details of method parameters + * method_declaration1/2 - details of method parameters * *
      • code == method_local_declaration1/2, tag == variable, parent = - * method_declaration1/2, abstract_inline_method - details of method local vars + * method_declaration1/2 - details of method local vars * *
      * @@ -185,16 +187,15 @@ *
        * *
      • code == method_local_location, tag == formal_parameter, parent = - * method_location, concrete_inline_method - details of method parameter or local - * locations + * method_location, concrete_inline_method - details of method parameter or local locations * *
      * - * Detailed layouts of the DIEs listed above are as follows:

      + * Detailed layouts of the DIEs listed above are as follows: + *

      * - * A single instance of the level 0 class_unit compile unit provides details - * of the object header struct, all Java primitive and object types and all Java compiled - * code. + * A single instance of the level 0 class_unit compile unit provides details of the + * object header struct, all Java primitive and object types and all Java compiled code. * *

        * @@ -217,10 +218,11 @@ * *
      * - * All other Java derived DIEs are embedded within this top level CU.

      + * All other Java derived DIEs are embedded within this top level CU. + *

      * - * Primitive Types: For each non-void Java primitive type there is a level 1 DIE defining a - * base type + * Primitive Types: For each non-void Java primitive type there is a level 1 DIE defining a base + * type * *

        * @@ -246,10 +248,9 @@ * *
      * - * Header Struct: There is a level 1 DIE defining a structure type which models the - * header information embedded at the start of every instance or array (all instances embed - * the same object header). Child DIEs are employed to define the name, type and layout of - * fields in the header. + * Header Struct: There is a level 1 DIE defining a structure type which models the header + * information embedded at the start of every instance or array (all instances embed the same object + * header). Child DIEs are employed to define the name, type and layout of fields in the header. * *
        * @@ -261,9 +262,9 @@ * *
      * - * Header Data: A level 2 DIE of type member is used to describe the fields of both object - * and array headers. This includes the type tag and other tag bits in all objects and the - * length field in all arrays. + * Header Data: A level 2 DIE of type member is used to describe the fields of both object and array + * headers. This includes the type tag and other tag bits in all objects and the length field in all + * arrays. * *
        * @@ -279,13 +280,14 @@ * *
      * - * Namespace embedding for Java class DIEs:

      + * Namespace embedding for Java class DIEs: + *

      * - * When the class loader associated with a class defined in the Java class - * compile unit has a non-empty loader id string then a namespace DIE is used to wrap - * the level 1 DIEs that define the class layout, methods etc. Otherwise, these children - * are embedded directly in the Java class compile unit. The namespace DIE has a - * single attribute defining the namespace's name as the loader id string. + * When the class loader associated with a class defined in the Java class compile unit has a + * non-empty loader id string then a namespace DIE is used to wrap the level 1 DIEs that define the + * class layout, methods etc. Otherwise, these children are embedded directly in the Java class + * compile unit. The namespace DIE has a single attribute defining the namespace's name as the + * loader id string. * *

    • abbrev_code == namespace, tag == DW_TAG_namespace, parent = class_unit, has_children * @@ -294,17 +296,18 @@ *
    * * Instance Classes: For each instance class type there is a sequence of up to four level 1 DIEs - * defining the class.

    + * defining the class. + *

    * - * Instance Class Structure: Each java class is described by a series of level 1 DIEs. The first - * one describes the class layout. The normal layout does not include a data_location + * Instance Class Structure: Each java class is described by a series of level 1 DIEs. The first one + * describes the class layout. The normal layout does not include a data_location * attribute. However, an alternative layout, including that extra attribute, is provided to deal * with a single special case, java.lang.Class. Oop references to instances of this * class are encoded using tag bits. The data_location attribute defines masking logic * which a debugger can use to decode the oop pointer to a raw address. n.b. this only applies in * the case where normal oop references are raw addresses (no compressed oops, no isolates). If a * heapbase register is being used then decoding logic is encoded for both normal classes and for - * code>java.lang.Class using an indirect layout (see below). + * java.lang.Class using an indirect layout (see below). * *

      * @@ -323,19 +326,20 @@ * *
    * - * Instance Class members: A level 1 class_layout DIE includes a level 2 child for each of - * the class's methods and fields. The first type declares a method but omits details of the - * location of the code that implements the method. The second type declares an instance or - * static field. A class_layout DIE also contains a level 2 DIE specifying the type from + * Instance Class members: A level 1 class_layout DIE includes a level 2 child for each + * of the class's methods and fields. The first type declares a method but omits details of + * the location of the code that implements the method. The second type declares an + * instance or static field. A class_layout DIE also contains a level 2 DIE specifying the type from * which it inherits superclass structure. In the case of class Object structure is * inherited from the object header structure type. * * n.b. Code implementation details for each method (i.e. the method definition) are * provided in an auxiliary level 1 method_location DIE that follows the * class_layout DIE. Instance field declarations need no auxiliary level 1 DIE as all - * relevant details, including size and offset in the instance, are specified in the field declaration - * DIE. Static field locations (i.e. the field definition) are provided in an auxiliary level 1 - * static_field_locationDIE that follows the class_layout DIE. + * relevant details, including size and offset in the instance, are specified in the field + * declaration DIE. Static field locations (i.e. the field definition) are provided in an + * auxiliary level 1 static_field_location DIE that follows the + * class_layout DIE. * *
      * @@ -360,7 +364,7 @@ * *
    • DW_AT_declaration : ....... DW_FORM_flag * - *
    • Dw_AT_object_pointer : .... DW_FORM_ref_addr n.b. only for + *
    • Dw_AT_object_pointer : .... DW_FORM_ref_addr n.b. only for * method_declaration1, points to param 0 DIE * *
    • DW_AT_virtuality : ........ DW_FORM_data1 (for override methods) @@ -393,8 +397,8 @@ *
    • Dw_AT_external : ............... DW_FORM_flag (n.b. only for * field_declaration3/4 static * - *
    • Dw_AT_declaration : ............ DW_FORM_flag n.b. only for - * field_declaration3/4 static + *
    • Dw_AT_declaration : ............ DW_FORM_flag n.b. only for field_declaration3/4 + * static * *
    * @@ -410,9 +414,9 @@ * * * - * Method Parameters: Level 2 method_declaration DIEs may include level 3 DIEs that describe - * their parameters and/or their local variables. n.b. these two DIEs only differ in the value - * of their tag. + * Method Parameters: Level 2 method_declaration DIEs may include level 3 DIEs that describe their + * parameters and/or their local variables. n.b. these two DIEs only differ in the value of their + * tag. * *
      * @@ -421,16 +425,14 @@ * *
    • Dw_AT_name : ... DW_FORM_strp (may be empty string) * - *
    • Dw_AT_file : ... DW_FORM_data1/2 n.b. only for - * method_parameter_declaration2 + *
    • Dw_AT_file : ... DW_FORM_data1/2 n.b. only for method_parameter_declaration2 * - *
    • Dw_AT_line : ... DW_FORM_data1/2 n.b. only for - * method_parameter_declaration2 + *
    • Dw_AT_line : ... DW_FORM_data1/2 n.b. only for method_parameter_declaration2 * *
    • Dw_AT_type : ... DW_FORM_ref_addr * - *
    • Dw_AT_artificial : ... DW_FORM_flag n.b. only for - * method_parameter_declaration1 used for this and access vars + *
    • Dw_AT_artificial : ... DW_FORM_flag n.b. only for method_parameter_declaration1 + * used for this and access vars * *
    • Dw_AT_declaration : ... DW_FORM_flag * @@ -441,11 +443,9 @@ * *
    • Dw_AT_name : ... DW_FORM_strp (may be empty string) * - *
    • Dw_AT_file : ... DW_FORM_data1/2 n.b. only for - * method_parameter_declaration1 + *
    • Dw_AT_file : ... DW_FORM_data1/2 n.b. only for method_parameter_declaration1 * - *
    • Dw_AT_line : ... DW_FORM_data1/2 n.b. only for - * method_parameter_declaration1 + *
    • Dw_AT_line : ... DW_FORM_data1/2 n.b. only for method_parameter_declaration1 * *
    • Dw_AT_type : ... DW_FORM_ref_addr * @@ -453,17 +453,17 @@ * *
    * - * Indirect Instance Class Structure: The level 1 class layout DIE may be followed by a - * level 1 indirect_layout DIE. The indirect layout is only needed when a - * heapbase register is in use (isolates or compressed oops are enabled). This means that - * oop fields will hold encoded oops. The indirect layout defines an empty wrapper class - * which declares the previous layout as its super class. This wrapper type also supplies a - * data_location attribute, ensuring that indirect pointers to the class (see next - * item) are translated to raw addresses. The name of the indirect type is constructed by - * prefixing the class name with DwarfDebugInfo.INDIRECT_PREFIX. This DIE has only - * one child DIE with type super_reference (see above). This effectively embeds the standard - * layout type in the indirect layout as a type compatible referent for the Java oop. The size - * of the indirect layout is the same as the size of the class layout. + * Indirect Instance Class Structure: The level 1 class layout DIE may be followed by a level 1 + * indirect_layout DIE. The indirect layout is only needed when a heapbase register is + * in use (isolates or compressed oops are enabled). This means that oop fields will hold encoded + * oops. The indirect layout defines an empty wrapper class which declares the previous layout as + * its super class. This wrapper type also supplies a data_location attribute, ensuring + * that indirect pointers to the class (see next item) are translated to raw addresses. The name of + * the indirect type is constructed by prefixing the class name with + * DwarfDebugInfo.INDIRECT_PREFIX. This DIE has only one child DIE with type + * super_reference (see above). This effectively embeds the standard layout type in the indirect + * layout as a type compatible referent for the Java oop. The size of the indirect layout is the + * same as the size of the class layout. * *
      * @@ -511,8 +511,9 @@ * * n.b. the name used in the class_layout DIE is the Java class name. This is * deliberately inconsistent with the Java naming where the name refers to the pointer - * type. In consequence when gdb displays Java types and signatures oop references appear as - * pointer types. So, for example the Java String class looks like

      + * type. In consequence when gdb displays Java types and signatures oop references appear as pointer + * types. So, for example the Java String class looks like + *

      * *

        *   class java.lang.String : public java.lang.Object {
      @@ -525,17 +526,13 @@
        *     ...
        * 
      * - * Method Code Locations: For each level 2 method declaration which has been compiled - * as a top-level method (i.e. not just occurring inline) there will be a corresponding level - * 1 method definition DIE providing details of the location of the compiled code. The - * two DIEs are cross-referenced using a specification attribute. - * This cross-reference should imply that the location DIE inherits attributes from the - * method_definition DIE, including attributes specified int the latter's child DIEs, - * such as parameter and local variable declarations. - * - * However, it is actually necessary to replicate the parameter and local variable declarations - * as children of the inline method definition DIE in order to ensure that gdb is aware of the - * parameters and locals. + * Method Code Locations: For each level 2 method declaration which has been compiled as a + * top-level method (i.e. not just occurring inline) there will be a corresponding level 1 method + * definition DIE providing details of the location of the compiled code. The two DIEs are + * cross-referenced using a specification attribute. This cross-reference means that + * the location DIE inherits attributes from the method_definition DIE, including + * attributes specified int the latter's child DIEs, such as parameter and local variable + * declarations. * *
        * @@ -553,15 +550,14 @@ *
      * * Method local locations: A method location may be followed by zero or more - * method_local_location DIEs which identify the in-memory location of - * parameter and/or local values during execution of the compiled code. A - * method_local_location DIE references the corresponding - * method_parameter_declaration or method_local_declaration. - * It also specifies a location list which defines address ranges where the parameter or - * local is valid and provides details of where to find the value of the parameter or local - * in memory. Likewise, an inline concrete method DIE is followed by zero or more - * method_local_location DIEs, providing details of where to find the specification - * of inlined parameters or locals and their value in memory. + * method_local_location DIEs which identify the in-memory location of parameter and/or + * local values during execution of the compiled code. A method_local_location DIE + * references the corresponding method_parameter_declaration or + * method_local_declaration. It also specifies a location list which defines address + * ranges where the parameter or local is valid and provides details of where to find the value of + * the parameter or local in memory. Likewise, an inline concrete method DIE is followed by zero or + * more method_local_location DIEs, providing details of where to find the + * specification of inlined parameters or locals and their value in memory. * *
        * @@ -575,22 +571,22 @@ * *
      * - * Abstract Inline Methods: For any method m' which has been inlined into a - * top level compiled method m there will be an abstract_inline_method - * DIE for m' at level 1 in the Java CU. The declaration serves as the - * abstract_origin for any corresponding inlined method DIEs appearing as children - * of m. - * - * The abstract_inline_method DIE should inherit attributes from - * the method_definition DIE referenced as its abstract_origin attribute without the - * need to repeat them. However, it is actually necessary to replicate the method parameter and - * local declaration DIEs of the specification as children of the abstract_inline_method - * DIE. + * Abstract Inline Methods: For any method m' which has been inlined into a top level + * compiled method m there will be an abstract_inline_method DIE for + * m' at level 1 in the Java CU. The declaration serves as the + * abstract_origin for any corresponding inlined method DIEs appearing as children of + * m. This declaration references the original method declaration via its + * specification and inherits attributes from that original declaration including + * parameter and local declarations. The GNU compiler sometimes replicates the parameter and local + * declarations so they can be referenced from location info in concrete inline methods, ensuring + * that any such reference is local to the compile unit of the method into which the call is + * inlined. There is no need for that with Java as all the declarations are lcoated in one compile + * unit. * *
        * *
      • abbrev_code == DW_ABBREV_CODE_abstract_inline_method, tag == DW_TAG_subprogram, - * has_children + * no_children * *
      • DW_AT_inline : .......... DW_FORM_data1 * @@ -600,21 +596,20 @@ * *
      * - * Concrete Inlined Methods: Concrete inlined method DIEs are nested as a tree of children - * under the method_location DIE for the method into which they have been inlined. Each - * inlined method DIE defines an address range that is a subrange of its parent DIE. A - * method_location DIE occurs at depth 1 in a compile unit (class_unit). So, this means that - * for any method which has been inlined into a compiled method at depth K in the inline - * frame stack there will be a corresponding level 2+K DIE that identifies the method that - * was inlined (by referencing the corresponding abstract inline method DIE) and locates the - * call point by citing the file index and line number of its caller. So, if compiled method - * M inlines a call to m1 at source position f0:l0, m1 inlines a call to method m2 at source - * position f1:l1 and m2 inlines a call to m3 at source position f2:l2 then there will be a - * level 2 DIE for the inline code range derived from m1 referencing the abstract entry for - * m1 with f0 and l0 as file and line, a level 3 DIE for the inline code range derived from - * m2 referencing the abstract entry for m2 with f1 and l1 as file and line and a level 3 - * DIE for the inline code range derived from m3 referencing the abstract entry for m3 with - * f2 and l2 as file and line. + * Concrete Inlined Methods: Concrete inlined method DIEs are nested as a tree of children under the + * method_location DIE for the method into which they have been inlined. Each inlined method DIE + * defines an address range that is a subrange of its parent DIE. A method_location DIE occurs at + * depth 1 in a compile unit (class_unit). So, this means that for any method which has been inlined + * into a compiled method at depth K in the inline frame stack there will be a corresponding level + * 2+K DIE that identifies the method that was inlined (by referencing the corresponding abstract + * inline method DIE) and locates the call point by citing the file index and line number of its + * caller. So, if compiled method M inlines a call to m1 at source position f0:l0, m1 inlines a call + * to method m2 at source position f1:l1 and m2 inlines a call to m3 at source position f2:l2 then + * there will be a level 2 DIE for the inline code range derived from m1 referencing the abstract + * entry for m1 with f0 and l0 as file and line, a level 3 DIE for the inline code range derived + * from m2 referencing the abstract entry for m2 with f1 and l1 as file and line and a level 3 DIE + * for the inline code range derived from m3 referencing the abstract entry for m3 with f2 and l2 as + * file and line. * *
        * @@ -636,8 +631,8 @@ * *
      * - * Static Field Locations: For each static field within the class there is a level 1 - * field definitionDIE providing details of the static field location + * Static Field Locations: For each static field within the class there is a level 1 field + * definition DIE providing details of the static field location * *
        * @@ -652,24 +647,25 @@ * *
      * - * Arrays: For each array type there is a sequence of up to five level 1 DIEs defining the array.

      - * - * Array Layout: The first array DIE describes the array layout. It has three children. The - * first is a super_reference DIE (see above) to class java.lang.Object. - * The other two children are field declarations, a length field that overlays the Java array - * length field and an array data field which aligns with the element 0 of the Java - * array's data area. The data field type is typed (via a later level 1 DIE) as a DWARF - * array, i.e. it is a data block embedded directly in the layout, with a nominal element count - * of 0. The elements of this DWARF array are typed using the DWARF type corresponding to the - * Java array's element type. It is either a Java primitive type or a Java reference type (i.e. - * the pointer type ot the underlying layout type). A nominal array length of zero means that - * this second data field does not actually add any extra size to the array layout. So, all array - * types have the same length.

      - * - * Note that when the base element type of the array is a class whose loader has an - * associated loader id the array type and associated types are embedded in a namespace DIE. This - * is needed because the encoded type name for the array will include a namespace prefix in order to - * guarantee that it remains unique. + * Arrays: For each array type there is a sequence of up to five level 1 DIEs defining the array. + *

      + * + * Array Layout: The first array DIE describes the array layout. It has three children. The first is + * a super_reference DIE (see above) to class java.lang.Object. The other + * two children are field declarations, a length field that overlays the Java array length field and + * an array data field which aligns with the element 0 of the Java array's data area. The data field + * type is typed (via a later level 1 DIE) as a DWARF array, i.e. it is a data block embedded + * directly in the layout, with a nominal element count of 0. The elements of this DWARF array are + * typed using the DWARF type corresponding to the Java array's element type. It is either a Java + * primitive type or a Java reference type (i.e. the pointer type ot the underlying layout type). A + * nominal array length of zero means that this second data field does not actually add any extra + * size to the array layout. So, all array types have the same length. + *

      + * + * Note that when the base element type of the array is a class whose loader has an associated + * loader id the array type and associated types are embedded in a namespace DIE. This is needed + * because the encoded type name for the array will include a namespace prefix in order to guarantee + * that it remains unique. * *

        * @@ -681,19 +677,20 @@ * *
      * - * The immediately following DIE is an indirect_layout (see above) that wraps the array - * layout as its super type (just as with class layouts). The wrapper type supplies a - * data_location attribute, allowing indirect pointers to the array to be translated to raw - * addresses. The name of the indirect array type is constructed by prefixing the array name - * with DwarfDebugInfo.INDIRECT_PREFIX. This DIE has only one child DIE with type - * super_reference (see above). The latter references the array layout DIE, - * effectively embedding the standard array layout type in the indirect layout. The size of - * the indirect layout is the same as the size of the array layout.

      - * - * The third and fourth DIEs define array reference types as a pointers to the underlying - * structure layout types. As with classes, there is an array_pointer type for raw address - * references used to type local and param vars and an indirect_pointer type (see above) for - * array references stored in static and instance fields. + * The immediately following DIE is an indirect_layout (see above) that wraps the array layout as + * its super type (just as with class layouts). The wrapper type supplies a data_location attribute, + * allowing indirect pointers to the array to be translated to raw addresses. The name of the + * indirect array type is constructed by prefixing the array name with + * DwarfDebugInfo.INDIRECT_PREFIX. This DIE has only one child DIE with type + * super_reference (see above). The latter references the array layout DIE, effectively + * embedding the standard array layout type in the indirect layout. The size of the indirect layout + * is the same as the size of the array layout. + *

      + * + * The third and fourth DIEs define array reference types as a pointers to the underlying structure + * layout types. As with classes, there is an array_pointer type for raw address references used to + * type local and param vars and an indirect_pointer type (see above) for array references stored in + * static and instance fields. * *

        * @@ -706,13 +703,13 @@ *
      * * n.b. the name used in the array_layout DIE is the Java array name. This is deliberately - * inconsistent with the Java naming where the name refers to the pointer type. As with - * normal objects an array reference in a Java signature appears as a pointer to an array - * layout when printed by gdb. + * inconsistent with the Java naming where the name refers to the pointer type. As with normal + * objects an array reference in a Java signature appears as a pointer to an array layout when + * printed by gdb. * - * Array members: The level 1 array_layout DIE includes a member field DIE that defines - * the layout of the array data. The type of this embedded field is declared by a fifth - * level 1 DIE, a array_data_type DIE (with DWARF tag array_type). + * Array members: The level 1 array_layout DIE includes a member field DIE that defines the layout + * of the array data. The type of this embedded field is declared by a fifth level 1 DIE, a + * array_data_type DIE (with DWARF tag array_type). * *
        * @@ -724,14 +721,15 @@ * *
      * - * Interfaces: For each interface there is a sequence of DIEs defining the interface.

      + * Interfaces: For each interface there is a sequence of DIEs defining the interface. + *

      * - * Interface Layout and Reference Types: An interface is primarily modeled by a level 1 - * DIE defining its layout as a union of all the layouts for the classes which implement - * the interface. The size of the interface layout is the maximum of the sizes for the - * implementing classes. A DWARF union type is used to ensure that the resulting layout is - * overlay type compatible with all its implementors. This also means that a reference - * to an instance of the interface can be cast to a reference to any of the implementors. + * Interface Layout and Reference Types: An interface is primarily modeled by a level 1 DIE defining + * its layout as a union of all the layouts for the classes which implement the interface. The size + * of the interface layout is the maximum of the sizes for the implementing classes. A DWARF union + * type is used to ensure that the resulting layout is overlay type compatible with all its + * implementors. This also means that a reference to an instance of the interface can be cast to a + * reference to any of the implementors. * *

        * @@ -741,26 +739,26 @@ * *
      * - * A second level 1 DIE provides an indirect layout that wraps the interface layout as its - * super type (just as with class layouts). The wrapper type supplies a data_location - * attribute, allowing indirect pointers to the interface to be translated to raw addresses. - * The name of the indirect interface type is constructed by prefixing the interface name - * with DwarfDebugInfo.INDIRECT_PREFIX. This DIE has only one child DIE with type + * A second level 1 DIE provides an indirect layout that wraps the interface layout as its super + * type (just as with class layouts). The wrapper type supplies a data_location + * attribute, allowing indirect pointers to the interface to be translated to raw addresses. The + * name of the indirect interface type is constructed by prefixing the interface name with + * DwarfDebugInfo.INDIRECT_PREFIX. This DIE has only one child DIE with type * sup[er_reference (see above). The latter references the interface layout DIE, - * effectively embedding the standard interface layout type in the indirect layout. The size - * of the indirect layout is the same as the size of the interface layout. + * effectively embedding the standard interface layout type in the indirect layout. The size of the + * indirect layout is the same as the size of the interface layout. * - * The third and fourth DIEs define interface reference types as a pointers to the - * underlying structure layout types. As with classes, there is an interface_pointer type - * for raw address references used to type local and param vars and an indirect_pointer type - * (see above) for interface references stored in static and instance fields. + * The third and fourth DIEs define interface reference types as a pointers to the underlying + * structure layout types. As with classes, there is an interface_pointer type for raw address + * references used to type local and param vars and an indirect_pointer type (see above) for + * interface references stored in static and instance fields. * * A second level 1 defines a pointer to this layout type. * * n.b. the name used in the interface_layout DIE is the Java array name. This is - * deliberately inconsistent with the Java naming where the name refers to the pointer type. - * As with normal objects an interface reference in a Java signature appears as a pointer to - * an interface layout when printed by gdb. + * deliberately inconsistent with the Java naming where the name refers to the pointer type. As with + * normal objects an interface reference in a Java signature appears as a pointer to an interface + * layout when printed by gdb. * *
        * @@ -772,8 +770,8 @@ * *
      * - * The union type embeds level 2 DIEs with tag member. There is a member for each - * implementing class, typed using the layout. + * The union type embeds level 2 DIEs with tag member. There is a member for each implementing + * class, typed using the layout. * *
        * @@ -788,8 +786,8 @@ *
      * * The union member name is constructed by appending an '_' to the Java* name of the implementing - * class. So, this means that, for example, the Java interface java.lang.CharSequence will - * include members for String, StringBuffer etc as follows + * class. So, this means that, for example, the Java interface java.lang.CharSequence will include + * members for String, StringBuffer etc as follows * *
        *   union java.lang.CharSequence {
      @@ -1338,7 +1336,7 @@ private int writeAbstractInlineMethodAbbrev(@SuppressWarnings("unused") DebugCon
               int pos = p;
               pos = writeAbbrevCode(DwarfDebugInfo.DW_ABBREV_CODE_abstract_inline_method, buffer, pos);
               pos = writeTag(DwarfDebugInfo.DW_TAG_subprogram, buffer, pos);
      -        pos = writeFlag(DwarfDebugInfo.DW_CHILDREN_yes, buffer, pos);
      +        pos = writeFlag(DwarfDebugInfo.DW_CHILDREN_no, buffer, pos);
               pos = writeAttrType(DwarfDebugInfo.DW_AT_inline, buffer, pos);
               pos = writeAttrForm(DwarfDebugInfo.DW_FORM_data1, buffer, pos);
               pos = writeAttrType(DwarfDebugInfo.DW_AT_external, buffer, pos);
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java
      index 83ee5715f23d..6956f1ba5eeb 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java
      @@ -509,20 +509,14 @@ static class DwarfMethodProperties {
               private int abstractInlineMethodIndex;
       
               /**
      -         * Index of info locations for params/locals belonging to a method
      +         * Index of info locations for params/locals belonging to a method.
                */
      -        private DwarfLocalProperties normalLocalProperties;
      -
      -        /**
      -         * Index of info locations for params/locals declared belonging to an abstract inline method
      -         */
      -        private  DwarfLocalProperties inlineLocalProperties;
      +        private DwarfLocalProperties localProperties;
       
               DwarfMethodProperties() {
                   methodDeclarationIndex = -1;
                   abstractInlineMethodIndex = -1;
      -            normalLocalProperties = null;
      -            inlineLocalProperties = null;
      +            localProperties = null;
               }
       
               public int getMethodDeclarationIndex() {
      @@ -545,20 +539,9 @@ public void setAbstractInlineMethodIndex(int pos) {
                   abstractInlineMethodIndex = pos;
               }
       
      -        public DwarfLocalProperties getLocalProperties(boolean isInlined) {
      -            DwarfLocalProperties localProperties;
      -            if (isInlined) {
      -                localProperties = normalLocalProperties;
      -            } else {
      -                localProperties = inlineLocalProperties;
      -            }
      +        public DwarfLocalProperties getLocalProperties() {
                   if (localProperties == null) {
                       localProperties = new DwarfLocalProperties();
      -                if (isInlined) {
      -                    normalLocalProperties = localProperties;
      -                } else {
      -                    inlineLocalProperties = localProperties;
      -                }
                   }
                   return localProperties;
               }
      @@ -755,17 +738,17 @@ private DwarfLocalProperties addRangeLocalProperties(Range range) {
               return localProperties;
           }
       
      -    public DwarfLocalProperties lookupLocalProperties(MethodEntry methodEntry, boolean isInlined) {
      -        return lookupMethodProperties(methodEntry).getLocalProperties(isInlined);
      +    public DwarfLocalProperties lookupLocalProperties(MethodEntry methodEntry) {
      +        return lookupMethodProperties(methodEntry).getLocalProperties();
           }
       
      -    public void setMethodLocalIndex(MethodEntry methodEntry, boolean isInlined, DebugLocalInfo localInfo, int index) {
      -        DwarfLocalProperties localProperties = lookupLocalProperties(methodEntry, isInlined);
      +    public void setMethodLocalIndex(MethodEntry methodEntry, DebugLocalInfo localInfo, int index) {
      +        DwarfLocalProperties localProperties = lookupLocalProperties(methodEntry);
               localProperties.setIndex(localInfo, index);
           }
       
      -    public int getMethodLocalIndex(MethodEntry methodEntry, boolean isInlined, DebugLocalInfo localInfo) {
      -        DwarfLocalProperties localProperties = lookupLocalProperties(methodEntry, isInlined);
      +    public int getMethodLocalIndex(MethodEntry methodEntry, DebugLocalInfo localInfo) {
      +        DwarfLocalProperties localProperties = lookupLocalProperties(methodEntry);
               assert localProperties != null : "get of non-existent local index";
               int index = localProperties.getIndex(localInfo);
               assert index >= 0 : "get of local index before it was set";
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java
      index 562a3fd806b2..e44bd1c2b48a 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java
      @@ -27,7 +27,6 @@
       package com.oracle.objectfile.elf.dwarf;
       
       import com.oracle.objectfile.LayoutDecision;
      -import com.oracle.objectfile.debugentry.ClassEntry;
       import com.oracle.objectfile.debugentry.CompiledMethodEntry;
       import com.oracle.objectfile.debugentry.range.Range;
       import com.oracle.objectfile.debuginfo.DebugInfoProvider;
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java
      index 34fcda69dfec..76a6ca4d5a36 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java
      @@ -29,10 +29,8 @@
       import java.lang.reflect.Modifier;
       import java.util.ArrayList;
       import java.util.HashMap;
      -import java.util.HashSet;
       import java.util.Iterator;
       import java.util.List;
      -import java.util.stream.Stream;
       
       import jdk.vm.ci.meta.JavaConstant;
       import jdk.vm.ci.meta.JavaKind;
      @@ -155,7 +153,8 @@ public int generateContent(DebugContext context, byte[] buffer) {
               log(context, "  [0x%08x]     comp_dir  0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory);
               pos = writeStrSectionOffset(compilationDirectory, buffer, pos);
               /*
      -         * Code addresses start at offset 0 and range up to the limit defined by the code cache size.
      +         * Code addresses start at offset 0 and range up to the limit defined by the code cache
      +         * size.
                */
               int lo = 0;
               int hi = dwarfSections.compiledCodeMax();
      @@ -207,14 +206,14 @@ private int writeBuiltInTypes(DebugContext context, byte[] buffer, int p) {
               /* Write child entries for primitive Java types. */
       
               pos = primitiveTypeStream().reduce(pos,
      -                (pos1, primitiveTypeEntry) -> {
      -                    if (primitiveTypeEntry.getBitCount() > 0) {
      -                        return writePrimitiveType(context, primitiveTypeEntry, buffer, pos1);
      -                    } else {
      -                        return writeVoidType(context, primitiveTypeEntry, buffer, pos1);
      -                    }
      -                },
      -                (oldpos, newpos) -> newpos);
      +                        (pos1, primitiveTypeEntry) -> {
      +                            if (primitiveTypeEntry.getBitCount() > 0) {
      +                                return writePrimitiveType(context, primitiveTypeEntry, buffer, pos1);
      +                            } else {
      +                                return writeVoidType(context, primitiveTypeEntry, buffer, pos1);
      +                            }
      +                        },
      +                        (oldpos, newpos) -> newpos);
       
               /* Write child entry for object/array header struct. */
       
      @@ -223,8 +222,8 @@ private int writeBuiltInTypes(DebugContext context, byte[] buffer, int p) {
               /* write class constants for primitive type classes */
       
               pos = primitiveTypeStream().reduce(pos,
      -                (pos1, primitiveTypeEntry) -> writeClassConstantDeclaration(context, primitiveTypeEntry, buffer, pos1),
      -                (oldpos, newpos) -> newpos);
      +                        (pos1, primitiveTypeEntry) -> writeClassConstantDeclaration(context, primitiveTypeEntry, buffer, pos1),
      +                        (oldpos, newpos) -> newpos);
       
               return pos;
           }
      @@ -304,8 +303,8 @@ public int writeHeaderType(DebugContext context, HeaderTypeEntry headerTypeEntry
       
           private int writeHeaderFields(DebugContext context, HeaderTypeEntry headerTypeEntry, byte[] buffer, int p) {
               return headerTypeEntry.fields().reduce(p,
      -                (pos, fieldEntry) -> writeHeaderField(context, fieldEntry, buffer, pos),
      -                (oldPos, newPos) -> newPos);
      +                        (pos, fieldEntry) -> writeHeaderField(context, fieldEntry, buffer, pos),
      +                        (oldPos, newPos) -> newPos);
           }
       
           private int writeHeaderField(DebugContext context, FieldEntry fieldEntry, byte[] buffer, int p) {
      @@ -525,8 +524,8 @@ private int writeSuperReference(DebugContext context, int superTypeOffset, Strin
       
           private int writeFields(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) {
               return classEntry.fields().filter(DwarfInfoSectionImpl::isManifestedField).reduce(p,
      -                (pos, fieldEntry) -> writeField(context, classEntry, fieldEntry, buffer, pos),
      -                (oldPos, newPos) -> newPos);
      +                        (pos, fieldEntry) -> writeField(context, classEntry, fieldEntry, buffer, pos),
      +                        (oldPos, newPos) -> newPos);
           }
       
           private static boolean isManifestedField(FieldEntry fieldEntry) {
      @@ -603,7 +602,8 @@ private int writeMethodDeclarations(DebugContext context, ClassEntry classEntry,
                   }
                   if (method.isInlined()) {
                       /*
      -                 * We also need an abstract inlined method as a target for any inline tree that includes the method
      +                 * We also need an abstract inlined method as a target for any inline tree that
      +                 * includes the method
                        */
                       pos = writeAbstractInlineMethod(context, classEntry, method, buffer, pos);
                   }
      @@ -670,35 +670,35 @@ private int writeMethodDeclaration(DebugContext context, ClassEntry classEntry,
                   writeInfoSectionOffset(pos, buffer, objectPointerIndex);
               }
               /* Write method parameter declarations. */
      -        pos = writeMethodParameterDeclarations(context, false, method, fileIdx, 3, buffer, pos);
      +        pos = writeMethodParameterDeclarations(context, method, fileIdx, 3, buffer, pos);
               /* write method local declarations */
      -        pos = writeMethodLocalDeclarations(context, false, method, fileIdx, 3, buffer, pos);
      +        pos = writeMethodLocalDeclarations(context, method, fileIdx, 3, buffer, pos);
               /*
                * Write a terminating null attribute.
                */
               return writeAttrNull(buffer, pos);
           }
       
      -    private int writeMethodParameterDeclarations(DebugContext context, boolean isInlined, MethodEntry method, int fileIdx, int level, byte[] buffer, int p) {
      +    private int writeMethodParameterDeclarations(DebugContext context, MethodEntry method, int fileIdx, int level, byte[] buffer, int p) {
               int pos = p;
               int refAddr;
               if (!Modifier.isStatic(method.getModifiers())) {
                   refAddr = pos;
                   DebugLocalInfo paramInfo = method.getThisParam();
      -            setMethodLocalIndex(method, isInlined, paramInfo, refAddr);
      +            setMethodLocalIndex(method, paramInfo, refAddr);
                   pos = writeMethodParameterDeclaration(context, paramInfo, fileIdx, true, level, buffer, pos);
               }
               for (int i = 0; i < method.getParamCount(); i++) {
                   refAddr = pos;
                   DebugLocalInfo paramInfo = method.getParam(i);
      -            setMethodLocalIndex(method, isInlined, paramInfo, refAddr);
      +            setMethodLocalIndex(method, paramInfo, refAddr);
                   pos = writeMethodParameterDeclaration(context, paramInfo, fileIdx, false, level, buffer, pos);
               }
               return pos;
           }
       
           private int writeMethodParameterDeclaration(DebugContext context, DebugLocalInfo paramInfo, int fileIdx, boolean artificial, int level, byte[] buffer,
      -                                                int p) {
      +                    int p) {
               int pos = p;
               log(context, "  [0x%08x] method parameter declaration", pos);
               int abbrevCode;
      @@ -734,20 +734,20 @@ private int writeMethodParameterDeclaration(DebugContext context, DebugLocalInfo
               return pos;
           }
       
      -    private int writeMethodLocalDeclarations(DebugContext context, boolean isInlined, MethodEntry method, int fileIdx, int level, byte[] buffer, int p) {
      +    private int writeMethodLocalDeclarations(DebugContext context, MethodEntry method, int fileIdx, int level, byte[] buffer, int p) {
               int pos = p;
               int refAddr;
               for (int i = 0; i < method.getLocalCount(); i++) {
                   refAddr = pos;
                   DebugLocalInfo localInfo = method.getLocal(i);
      -            setMethodLocalIndex(method, isInlined, localInfo, refAddr);
      +            setMethodLocalIndex(method, localInfo, refAddr);
                   pos = writeMethodLocalDeclaration(context, localInfo, fileIdx, level, buffer, pos);
               }
               return pos;
           }
       
           private int writeMethodLocalDeclaration(DebugContext context, DebugLocalInfo paramInfo, int fileIdx, int level, byte[] buffer,
      -                                            int p) {
      +                    int p) {
               int pos = p;
               log(context, "  [0x%08x] method local declaration", pos);
               int abbrevCode;
      @@ -833,8 +833,8 @@ private int writeInterfaceLayout(DebugContext context, InterfaceClassEntry inter
       
           private int writeInterfaceImplementors(DebugContext context, InterfaceClassEntry interfaceClassEntry, byte[] buffer, int p) {
               return interfaceClassEntry.implementors().reduce(p,
      -                (pos, classEntry) -> writeInterfaceImplementor(context, classEntry, buffer, pos),
      -                (oldPos, newPos) -> newPos);
      +                        (pos, classEntry) -> writeInterfaceImplementor(context, classEntry, buffer, pos),
      +                        (oldPos, newPos) -> newPos);
           }
       
           private int writeInterfaceImplementor(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) {
      @@ -944,9 +944,9 @@ private int writeClassStaticFieldLocations(DebugContext context, ClassEntry clas
                */
               Cursor cursor = new Cursor(p);
               classEntry.fields().filter(DwarfInfoSectionImpl::isManifestedStaticField)
      -                .forEach(fieldEntry ->  {
      -                    cursor.set(writeClassStaticFieldLocation(context, classEntry, fieldEntry, buffer, cursor.get()));
      -                });
      +                        .forEach(fieldEntry -> {
      +                            cursor.set(writeClassStaticFieldLocation(context, classEntry, fieldEntry, buffer, cursor.get()));
      +                        });
               return cursor.get();
           }
       
      @@ -1041,9 +1041,9 @@ private int writeArrayLayout(DebugContext context, ArrayTypeEntry arrayTypeEntry
           private int writeFields(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) {
               Cursor cursor = new Cursor(p);
               arrayTypeEntry.fields().filter(DwarfInfoSectionImpl::isManifestedField)
      -                .forEach( fieldEntry -> {
      -                    cursor.set(writeField(context, arrayTypeEntry, fieldEntry, buffer, cursor.get()));
      -                });
      +                        .forEach(fieldEntry -> {
      +                            cursor.set(writeField(context, arrayTypeEntry, fieldEntry, buffer, cursor.get()));
      +                        });
               return cursor.get();
           }
       
      @@ -1188,8 +1188,8 @@ private int writeMethodLocation(DebugContext context, CompiledMethodEntry compil
               log(context, "  [0x%08x]     specification  0x%x (%s)", pos, methodSpecOffset, methodKey);
               pos = writeInfoSectionOffset(methodSpecOffset, buffer, pos);
               HashMap> varRangeMap = primary.getVarRangeMap();
      -        pos = writeMethodParameterLocations(context, false, varRangeMap, primary, 2, buffer, pos);
      -        pos = writeMethodLocalLocations(context, false, varRangeMap, primary, 2, buffer, pos);
      +        pos = writeMethodParameterLocations(context, varRangeMap, primary, 2, buffer, pos);
      +        pos = writeMethodLocalLocations(context, varRangeMap, primary, 2, buffer, pos);
               if (primary.includesInlineRanges()) {
                   /*
                    * the method has inlined ranges so write concrete inlined method entries as its
      @@ -1203,7 +1203,7 @@ private int writeMethodLocation(DebugContext context, CompiledMethodEntry compil
               return writeAttrNull(buffer, pos);
           }
       
      -    private int writeMethodParameterLocations(DebugContext context, boolean isInlined, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) {
      +    private int writeMethodParameterLocations(DebugContext context, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) {
               int pos = p;
               MethodEntry methodEntry;
               if (range.isPrimary()) {
      @@ -1214,20 +1214,20 @@ private int writeMethodParameterLocations(DebugContext context, boolean isInline
               }
               if (!Modifier.isStatic(methodEntry.getModifiers())) {
                   DebugLocalInfo thisParamInfo = methodEntry.getThisParam();
      -            int refAddr = getMethodLocalIndex(methodEntry, isInlined, thisParamInfo);
      +            int refAddr = getMethodLocalIndex(methodEntry, thisParamInfo);
                   List ranges = varRangeMap.get(thisParamInfo);
                   pos = writeMethodLocalLocation(context, range, thisParamInfo, refAddr, ranges, depth, true, buffer, pos);
               }
               for (int i = 0; i < methodEntry.getParamCount(); i++) {
                   DebugLocalInfo paramInfo = methodEntry.getParam(i);
      -            int refAddr = getMethodLocalIndex(methodEntry, isInlined, paramInfo);
      +            int refAddr = getMethodLocalIndex(methodEntry, paramInfo);
                   List ranges = varRangeMap.get(paramInfo);
                   pos = writeMethodLocalLocation(context, range, paramInfo, refAddr, ranges, depth, true, buffer, pos);
               }
               return pos;
           }
       
      -    private int writeMethodLocalLocations(DebugContext context, boolean isInlined, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) {
      +    private int writeMethodLocalLocations(DebugContext context, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) {
               int pos = p;
               MethodEntry methodEntry;
               if (range.isPrimary()) {
      @@ -1239,7 +1239,7 @@ private int writeMethodLocalLocations(DebugContext context, boolean isInlined, H
               int count = methodEntry.getLocalCount();
               for (int i = 0; i < count; i++) {
                   DebugLocalInfo localInfo = methodEntry.getLocal(i);
      -            int refAddr = getMethodLocalIndex(methodEntry, isInlined, localInfo);
      +            int refAddr = getMethodLocalIndex(methodEntry, localInfo);
                   List ranges = varRangeMap.get(localInfo);
                   pos = writeMethodLocalLocation(context, range, localInfo, refAddr, ranges, depth, false, buffer, pos);
               }
      @@ -1321,8 +1321,8 @@ private int generateConcreteInlinedMethods(DebugContext context, CompiledMethodE
                   HashMap> varRangeMap = subrange.getVarRangeMap();
                   // increment depth to account for parameter and method locations
                   depth++;
      -            pos = writeMethodParameterLocations(context, true, varRangeMap, subrange, depth + 2, buffer, pos);
      -            pos = writeMethodLocalLocations(context, true, varRangeMap, subrange, depth + 2, buffer, pos);
      +            pos = writeMethodParameterLocations(context, varRangeMap, subrange, depth + 2, buffer, pos);
      +            pos = writeMethodLocalLocations(context, varRangeMap, subrange, depth + 2, buffer, pos);
               }
               // if we just stepped out of a child range write nulls for each step up
               while (depth > 0) {
      @@ -1396,22 +1396,7 @@ private int writeAbstractInlineMethod(DebugContext context, ClassEntry classEntr
               int methodSpecOffset = getMethodDeclarationIndex(method);
               log(context, "  [0x%08x]     specification  0x%x", pos, methodSpecOffset);
               pos = writeInfoSectionOffset(methodSpecOffset, buffer, pos);
      -        /*
      -         * Write parameter and local declarations
      -         */
      -        FileEntry fileEntry = method.getFileEntry();
      -        if (fileEntry == null) {
      -            fileEntry = classEntry.getFileEntry();
      -        }
      -        assert fileEntry != null;
      -        int fileIdx = fileEntry.getIdx();
      -        int level = 3;
      -        pos = writeMethodParameterDeclarations(context, true, method, fileIdx, level, buffer, pos);
      -        pos = writeMethodLocalDeclarations(context, true, method, fileIdx, level, buffer, pos);
      -        /*
      -         * Write a terminating null attribute.
      -         */
      -        return writeAttrNull(buffer, pos);
      +        return pos;
           }
       
           private int writeAttrRef4(int reference, byte[] buffer, int p) {
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java
      index 30c11bc8e3de..5c658aedaaa5 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java
      @@ -34,7 +34,6 @@
       import com.oracle.objectfile.LayoutDecision;
       import com.oracle.objectfile.LayoutDecisionMap;
       import com.oracle.objectfile.ObjectFile;
      -import com.oracle.objectfile.debugentry.ClassEntry;
       import com.oracle.objectfile.debugentry.CompiledMethodEntry;
       import com.oracle.objectfile.debugentry.DirEntry;
       import com.oracle.objectfile.debugentry.FileEntry;
      @@ -213,7 +212,7 @@ private int computeDirTableSize() {
                * 'nul'.
                */
               Cursor cursor = new Cursor();
      -        dirStream().forEach( dirEntry -> {
      +        dirStream().forEach(dirEntry -> {
                   if (dirEntry.getIdx() > 0) {
                       cursor.add(countUTF8Bytes(dirEntry.getPathString()) + 1);
                   }
      @@ -233,8 +232,8 @@ private int computeFileTableSize() {
                * time stamps
                */
               Cursor cursor = new Cursor();
      -        fileStream().forEach( fileEntry -> {
      -             // We want the file base name excluding path.
      +        fileStream().forEach(fileEntry -> {
      +            // We want the file base name excluding path.
                   String baseName = fileEntry.getFileName();
                   int length = countUTF8Bytes(baseName);
                   // We should never have a null or zero length entry in local files.
      @@ -378,7 +377,7 @@ private int writeDirTable(DebugContext context, byte[] buffer, int p) {
                * Write out the list of dirs
                */
               Cursor cursor = new Cursor(p);
      -        dirStream().forEach( dirEntry -> {
      +        dirStream().forEach(dirEntry -> {
                   int dirIdx = dirEntry.getIdx();
                   if (dirIdx > 0) {
                       String dirPath = dirEntry.getPathString();
      @@ -399,7 +398,7 @@ private int writeFileTable(DebugContext context, byte[] buffer, int p) {
                * Write out the list of files
                */
               Cursor cursor = new Cursor(p);
      -        fileStream().forEach( fileEntry -> {
      +        fileStream().forEach(fileEntry -> {
                   int pos = cursor.get();
                   String baseName = fileEntry.getFileName();
                   DirEntry dirEntry = fileEntry.getDirEntry();
      @@ -621,7 +620,7 @@ private int writeCompiledMethodLineInfo(DebugContext context, CompiledMethodEntr
       
           private int writeLineNumberTable(DebugContext context, byte[] buffer, int p) {
               Cursor cursor = new Cursor(p);
      -        compiledMethodsStream().forEach( compiledMethod -> {
      +        compiledMethodsStream().forEach(compiledMethod -> {
                   int pos = cursor.get();
                   String methodName = compiledMethod.getPrimary().getFullMethodNameWithParams();
                   String fileName = compiledMethod.getClassEntry().getFullFileName();
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java
      index c5e859f9407a..b358ec91baea 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java
      @@ -35,7 +35,6 @@
       import java.util.List;
       import java.util.Map;
       import java.util.Set;
      -import java.util.stream.Stream;
       
       import com.oracle.objectfile.debugentry.range.SubRange;
       import org.graalvm.compiler.debug.DebugContext;
      @@ -44,7 +43,6 @@
       import com.oracle.objectfile.LayoutDecision;
       import com.oracle.objectfile.LayoutDecisionMap;
       import com.oracle.objectfile.ObjectFile;
      -import com.oracle.objectfile.debugentry.ClassEntry;
       import com.oracle.objectfile.debugentry.CompiledMethodEntry;
       import com.oracle.objectfile.debugentry.range.Range;
       import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLocalInfo;
      @@ -127,8 +125,8 @@ public void writeContent(DebugContext context) {
       
           private int generateContent(DebugContext context, byte[] buffer) {
               Cursor cursor = new Cursor();
      -        compiledMethodsStream().forEach( compiledMethod -> {
      -             cursor.set(writeCompiledMethodLocations(context, compiledMethod, buffer, cursor.get()));
      +        compiledMethodsStream().forEach(compiledMethod -> {
      +            cursor.set(writeCompiledMethodLocations(context, compiledMethod, buffer, cursor.get()));
               });
               return cursor.get();
           }
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java
      index 318daa3ce4f7..36fef2e67aa9 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java
      @@ -733,7 +733,7 @@ protected Stream compiledMethodsStream() {
           }
       
           protected int compiledMethodsCount() {
      -        return  dwarfSections.getCompiledMethods().size();
      +        return dwarfSections.getCompiledMethods().size();
           }
       
           protected Stream fileStream() {
      @@ -741,7 +741,7 @@ protected Stream fileStream() {
           }
       
           protected int fileCount() {
      -        return  dwarfSections.getFiles().size();
      +        return dwarfSections.getFiles().size();
           }
       
           protected Stream dirStream() {
      @@ -749,7 +749,7 @@ protected Stream dirStream() {
           }
       
           protected int dirCount() {
      -        return  dwarfSections.getDirs().size();
      +        return dwarfSections.getDirs().size();
           }
       
           /**
      @@ -859,34 +859,30 @@ protected int getAbstractInlineMethodIndex(MethodEntry methodEntry) {
           }
       
           /**
      -     * Record the info section offset of a local (or parameter) declaration DIE. The local (or
      -     * parameter) can be a child of a standard method declaration or of an abstract inline method
      -     * declaration.
      +     * Record the info section offset of a local (or parameter) declaration DIE appearing as a child
      +     * of a standard method declaration.
            * 
            * @param methodEntry the method being declared or inlined.
      -     * @param isInlined true if this is a parameter of a standard declaration false if it belongs to an abstract inlined method
            * @param localInfo the local or param whose index is to be recorded.
            * @param index the info section offset to be recorded.
            */
      -    protected void setMethodLocalIndex(MethodEntry methodEntry, boolean isInlined, DebugLocalInfo localInfo, int index) {
      -        dwarfSections.setMethodLocalIndex(methodEntry, isInlined, localInfo, index);
      +    protected void setMethodLocalIndex(MethodEntry methodEntry, DebugLocalInfo localInfo, int index) {
      +        dwarfSections.setMethodLocalIndex(methodEntry, localInfo, index);
           }
       
           /**
      -     * Retrieve the info section offset of a local (or parameter) declaration DIE. The local (or
      -     * parameter) can be a child of a standard method declaration or of an abstract inline method
      -     * declaration.
      -     * 
      +     * Retrieve the info section offset of a local (or parameter) declaration DIE appearing as a
      +     * child of a standard method declaration.
      +     *
            * @param methodEntry the method being declared or imported
      -     * @param isInlined true if this is a parameter of a standard declaration false if it belongs to an abstract inlined method
            * @param localInfo the local or param whose index is to be retrieved.
            * @return the associated info section offset.
            */
      -    protected int getMethodLocalIndex(MethodEntry methodEntry, boolean isInlined, DebugLocalInfo localInfo) {
      +    protected int getMethodLocalIndex(MethodEntry methodEntry, DebugLocalInfo localInfo) {
               if (!contentByteArrayCreated()) {
                   return 0;
               }
      -        return dwarfSections.getMethodLocalIndex(methodEntry, isInlined, localInfo);
      +        return dwarfSections.getMethodLocalIndex(methodEntry, localInfo);
           }
       
           /**
      
      From 8e4cde59743f685c25dafb8bbd10d5fd9a48e901 Mon Sep 17 00:00:00 2001
      From: Andrew Dinn 
      Date: Thu, 13 Apr 2023 11:47:30 +0100
      Subject: [PATCH 4/9] Style fixes.
      
      ---
       .../com/oracle/objectfile/debugentry/DebugInfoBase.java  | 9 +++++----
       .../com/oracle/objectfile/debugentry/range/Range.java    | 2 +-
       .../objectfile/elf/dwarf/DwarfARangesSectionImpl.java    | 2 +-
       .../com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java  | 5 -----
       .../objectfile/elf/dwarf/DwarfInfoSectionImpl.java       | 2 --
       5 files changed, 7 insertions(+), 13 deletions(-)
      
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java
      index f6b63932c1ae..575552a609ec 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java
      @@ -545,16 +545,17 @@ private boolean verifyMethodOrder(CompiledMethodEntry next) {
       
           private FileEntry addFileEntry(String fileName, Path filePath) {
               assert fileName != null;
      +        Path dirPath = filePath;
               Path fileAsPath;
               if (filePath != null) {
      -            fileAsPath = filePath.resolve(fileName);
      +            fileAsPath = dirPath.resolve(fileName);
               } else {
                   fileAsPath = Paths.get(fileName);
      -            filePath = EMPTY_PATH;
      +            dirPath = EMPTY_PATH;
               }
               FileEntry fileEntry = filesIndex.get(fileAsPath);
               if (fileEntry == null) {
      -            DirEntry dirEntry = ensureDirEntry(filePath);
      +            DirEntry dirEntry = ensureDirEntry(dirPath);
                   /* Ensure file and cachepath are added to the debug_str section. */
                   uniqueDebugString(fileName);
                   uniqueDebugString(cachePath);
      @@ -563,7 +564,7 @@ private FileEntry addFileEntry(String fileName, Path filePath) {
                   /* Index the file entry by file path. */
                   filesIndex.put(fileAsPath, fileEntry);
               } else {
      -            assert fileEntry.getDirEntry().getPath().equals(filePath);
      +            assert fileEntry.getDirEntry().getPath().equals(dirPath);
               }
               return fileEntry;
           }
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/Range.java
      index f669eabdc684..2cfe82d53193 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/Range.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/Range.java
      @@ -213,7 +213,7 @@ public FileEntry getFileEntry() {
       
           public int getFileIndex() {
               return getFileEntry().getIdx();
      -    };
      +    }
       
           public int getModifiers() {
               return methodEntry.getModifiers();
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java
      index b53342037758..f84c4083bb9f 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java
      @@ -146,7 +146,7 @@ public void writeContent(DebugContext context) {
               cursor.set(writeLong(0, buffer, cursor.get()));
               cursor.set(writeLong(0, buffer, cursor.get()));
               patchLength(lengthPos, buffer, cursor.get());
      -        assert cursor.get() == buffer.length;
      +        assert cursor.get() == size;
           }
       
           private int writeHeader(int cuIndex, byte[] buffer, int p) {
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java
      index 6956f1ba5eeb..47903f53726b 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java
      @@ -481,17 +481,12 @@ static class DwarfClassProperties extends DwarfTypeProperties {
                * Map from field names to info section index for the field declaration.
                */
               private EconomicMap fieldDeclarationIndex;
      -        /**
      -         * Map from method entries to associated method local properties index.
      -         */
      -        private EconomicMap methodLocalPropertiesIndex;
       
               DwarfClassProperties(StructureTypeEntry entry) {
                   super(entry);
                   this.layoutIndex = -1;
                   this.indirectLayoutIndex = -1;
                   fieldDeclarationIndex = null;
      -            methodLocalPropertiesIndex = null;
               }
           }
       
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java
      index 76a6ca4d5a36..acbe20066676 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java
      @@ -1302,7 +1302,6 @@ private int generateConcreteInlinedMethods(DebugContext context, CompiledMethodE
               }
               int pos = p;
               log(context, "  [0x%08x] concrete entries [0x%x,0x%x] %s", pos, primary.getLo(), primary.getHi(), primary.getFullMethodName());
      -        ClassEntry classEntry = compiledEntry.getClassEntry();
               int depth = 0;
               Iterator iterator = compiledEntry.topDownRangeIterator();
               while (iterator.hasNext()) {
      @@ -1340,7 +1339,6 @@ private int writeInlineSubroutine(DebugContext context, Range caller, int depth,
               // identify the inlined method by looking at the first callee
               Range callee = caller.getFirstCallee();
               MethodEntry methodEntry = callee.getMethodEntry();
      -        ClassEntry classEntry = methodEntry.ownerType();
               String methodKey = methodEntry.getSymbolName();
               /* the abstract index was written in the method's class entry */
               int abstractOriginIndex = getAbstractInlineMethodIndex(methodEntry);
      
      From b260ef87fefccfcf6a40036c46d4ce8d20172fb3 Mon Sep 17 00:00:00 2001
      From: Andrew Dinn 
      Date: Thu, 13 Apr 2023 11:54:05 +0100
      Subject: [PATCH 5/9] More style fixes.
      
      ---
       .../com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java   | 8 --------
       1 file changed, 8 deletions(-)
      
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java
      index 47903f53726b..d00af24f69fc 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java
      @@ -340,14 +340,6 @@ public class DwarfDebugInfo extends DebugInfoBase {
            */
           private final EconomicMap methodPropertiesIndex = EconomicMap.create();
       
      -    /**
      -     * A collection of local variable properties associated with a generated method record,
      -     * potentially including a method which is abstract (hence why it is not indexed off the primary
      -     * range).
      -     */
      -
      -    private final EconomicMap methodLocalPropertiesIndex = EconomicMap.create();
      -
           /**
            * A collection of local variable properties associated with an inlined subrange.
            */
      
      From f22930e0c0699c535932ff4aeb056a3f67bc04cb Mon Sep 17 00:00:00 2001
      From: Andrew Dinn 
      Date: Thu, 13 Apr 2023 12:07:51 +0100
      Subject: [PATCH 6/9] Yet more style fixes.
      
      ---
       .../elf/dwarf/DwarfAbbrevSectionImpl.java     | 85 ++++++++++---------
       1 file changed, 43 insertions(+), 42 deletions(-)
      
      diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java
      index 271e1852a1c3..931025e66cbf 100644
      --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java
      +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java
      @@ -30,11 +30,11 @@
       import org.graalvm.compiler.debug.DebugContext;
       
       /**
      - * Section generator for debug_abbrev section. That section defines the
      - * layout of the DWARF Information Entries (DIEs) used to model Java debug info. Top
      - * level DIEs define Java Compile Units (CUs). Embedded DIEs describe the content of
      - * the CU: types, code, variable, etc. These definitions are used to interpret the DIE
      - * content inserted into the debug_info section.
      + * Section generator for debug_abbrev section. That section defines the layout of the
      + * DWARF Information Entries (DIEs) used to model Java debug info. Top level DIEs define Java
      + * Compile Units (CUs). Embedded DIEs describe the content of the CU: types, code, variable, etc.
      + * These definitions are used to interpret the DIE content inserted into the debug_info
      + * section.
        * 

      * * An abbrev table contains abbrev entries for one or more DIEs, the last one being a null entry. @@ -95,59 +95,60 @@ * *

        * - *
      • code = primitive_type, tag == base_type, parent = class_unit - Java primitive type (non-void) + *
      • code = primitive_type, tag == base_type, parent = class_unit - Java primitive + * type (non-void) * *
      • code = void_type, tag == unspecified_type, parent = class_unit - Java void type * - *
      • code = object_header, tag == structure_type, parent = class_unit - Java object header + *
      • code = object_header, tag == structure_type, parent = class_unit - Java object + * header * - *
      • code = class_layout, tag == class_type, parent = class_unit - Java - * instance type structure definition + *
      • code = class_layout, tag == class_type, parent = class_unit - Java instance type + * structure definition * - *
      • code = class_pointer, tag == pointer_type, parent = class_unit - Java - * instance ref type + *
      • code = class_pointer, tag == pointer_type, parent = class_unit - Java instance + * ref type * - *
      • code = method_location, tag == subprogram , parent = class_unit - Java - * method code definition (i.e. location of code) + *
      • code = method_location, tag == subprogram , parent = class_unit - Java method + * code definition (i.e. location of code) * - *
      • code = abstract_inline_method, tag == subprogram , parent = class_unit - - * Java abstract inline method (i.e. proxy for method definition referenced by concrete - * inline instance) + *
      • code = abstract_inline_method, tag == subprogram , parent = class_unit - Java + * abstract inline method (i.e. proxy for method definition referenced by concrete inline instance) * - *
      • code = static_field_location, tag == variable, parent = class_unit - Java - * static field definition (i.e. location of data) + *
      • code = static_field_location, tag == variable, parent = class_unit - Java static + * field definition (i.e. location of data) * - *
      • code = array_layout, tag == structure_type, parent = array_unit - Java - * array type structure definition + *
      • code = array_layout, tag == structure_type, parent = array_unit - Java array + * type structure definition * - *
      • code = array_pointer, tag == pointer_type, parent = array_unit - Java - * array ref type + *
      • code = array_pointer, tag == pointer_type, parent = array_unit - Java array ref + * type * - *
      • code = interface_layout, tag == union_type, parent = class_unit - Java - * array type structure definition + *
      • code = interface_layout, tag == union_type, parent = class_unit - Java array + * type structure definition * *
      • code = interface_pointer, tag == pointer_type, parent = class_unit - Java * interface ref type * *
      • code = indirect_layout, tag == class_type, parent = class_unit, array_unit, - * interface_unit - wrapper layout attaches address rewriting logic to the layout - * types that it wraps using a data_location attribute + * interface_unit - wrapper layout attaches address rewriting logic to the layout types that + * it wraps using a data_location attribute * *
      • code = indirect_pointer, tag == pointer_type, parent = class_unit, array_unit, - * interface_unit - indirect ref type used to type indirect oops that encode the - * address of an object, whether by adding tag bits or representing the address as an offset - * from some base address. these are used to type object references stored in static and - * instance fields. They are not needed when typing local vars and parameters held in - * registers or on the stack as they appear as raw addresses. + * interface_unit - indirect ref type used to type indirect oops that encode the address of + * an object, whether by adding tag bits or representing the address as an offset from some base + * address. these are used to type object references stored in static and instance fields. They are + * not needed when typing local vars and parameters held in registers or on the stack as they appear + * as raw addresses. * *
      • code = namespace, tag == namespace, parent = class_unit, array_unit, - * interface_unit - a wrap-around DIE that is used to embed all the normal level 1 - * DIEs of a class_unit or array_unit in a namespace. This is - * needed when the corresponding class/interface or array base element type have been loaded - * by a loader with a non-empty loader in order to ensure that mangled names for the class - * and its members can legitimately employ the loader id as a namespace prefix. Note that - * use of a namespace wrapper DIE causes all the embedded level 1+ DIEs documented above and - * all their children to be generated at a level one greater than documented here. + * interface_unit - a wrap-around DIE that is used to embed all the normal level 1 DIEs of a + * class_unit or array_unit in a namespace. This is needed when the + * corresponding class/interface or array base element type have been loaded by a loader with a + * non-empty loader in order to ensure that mangled names for the class and its members can + * legitimately employ the loader id as a namespace prefix. Note that use of a namespace wrapper DIE + * causes all the embedded level 1+ DIEs documented above and all their children to be generated at + * a level one greater than documented here. * *
      * @@ -155,8 +156,8 @@ * *
        * - *
      • code = header_field, tag == member, parent = object_header - object/array - * header field + *
      • code = header_field, tag == member, parent = object_header - object/array header + * field * *
      • code == method_declaration1/2, tag == subprogram, parent = class_layout * @@ -364,8 +365,8 @@ * *
      • DW_AT_declaration : ....... DW_FORM_flag * - *
      • Dw_AT_object_pointer : .... DW_FORM_ref_addr n.b. only for - * method_declaration1, points to param 0 DIE + *
      • Dw_AT_object_pointer : .... DW_FORM_ref_addr n.b. only for method_declaration1, + * points to param 0 DIE * *
      • DW_AT_virtuality : ........ DW_FORM_data1 (for override methods) * From 8858d7948143429d733ceb82019111f10342349e Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 13 Apr 2023 14:52:51 +0100 Subject: [PATCH 7/9] Remove redundant abstract inline method DIEs --- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 60 ++----------- .../objectfile/elf/dwarf/DwarfDebugInfo.java | 84 +++++++------------ .../elf/dwarf/DwarfInfoSectionImpl.java | 29 +------ .../elf/dwarf/DwarfSectionImpl.java | 11 --- 4 files changed, 36 insertions(+), 148 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java index 931025e66cbf..56696551584b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java @@ -112,9 +112,6 @@ *
      • code = method_location, tag == subprogram , parent = class_unit - Java method * code definition (i.e. location of code) * - *
      • code = abstract_inline_method, tag == subprogram , parent = class_unit - Java - * abstract inline method (i.e. proxy for method definition referenced by concrete inline instance) - * *
      • code = static_field_location, tag == variable, parent = class_unit - Java static * field definition (i.e. location of data) * @@ -572,44 +569,19 @@ * *
      * - * Abstract Inline Methods: For any method m' which has been inlined into a top level - * compiled method m there will be an abstract_inline_method DIE for - * m' at level 1 in the Java CU. The declaration serves as the - * abstract_origin for any corresponding inlined method DIEs appearing as children of - * m. This declaration references the original method declaration via its - * specification and inherits attributes from that original declaration including - * parameter and local declarations. The GNU compiler sometimes replicates the parameter and local - * declarations so they can be referenced from location info in concrete inline methods, ensuring - * that any such reference is local to the compile unit of the method into which the call is - * inlined. There is no need for that with Java as all the declarations are lcoated in one compile - * unit. - * - *
        - * - *
      • abbrev_code == DW_ABBREV_CODE_abstract_inline_method, tag == DW_TAG_subprogram, - * no_children - * - *
      • DW_AT_inline : .......... DW_FORM_data1 - * - *
      • DW_AT_external : ........ DW_FORM_flag - * - *
      • DW_AT_specification : ... DW_FORM_ref_addr - * - *
      - * * Concrete Inlined Methods: Concrete inlined method DIEs are nested as a tree of children under the * method_location DIE for the method into which they have been inlined. Each inlined method DIE * defines an address range that is a subrange of its parent DIE. A method_location DIE occurs at * depth 1 in a compile unit (class_unit). So, this means that for any method which has been inlined * into a compiled method at depth K in the inline frame stack there will be a corresponding level - * 2+K DIE that identifies the method that was inlined (by referencing the corresponding abstract - * inline method DIE) and locates the call point by citing the file index and line number of its + * 2+K DIE that identifies the method that was inlined (by referencing the corresponding method + * declaration DIE) and locates the call point by citing the file index and line number of its * caller. So, if compiled method M inlines a call to m1 at source position f0:l0, m1 inlines a call * to method m2 at source position f1:l1 and m2 inlines a call to m3 at source position f2:l2 then - * there will be a level 2 DIE for the inline code range derived from m1 referencing the abstract - * entry for m1 with f0 and l0 as file and line, a level 3 DIE for the inline code range derived - * from m2 referencing the abstract entry for m2 with f1 and l1 as file and line and a level 3 DIE - * for the inline code range derived from m3 referencing the abstract entry for m3 with f2 and l2 as + * there will be a level 2 DIE for the inline code range derived from m1 referencing the declaration + * DIE for m1 with f0 and l0 as file and line, a level 3 DIE for the inline code range derived + * from m2 referencing the declaration DIE for m2 with f1 and l1 as file and line and a level 3 DIE + * for the inline code range derived from m3 referencing the declaration DIE for m3 with f2 and l2 as * file and line. * *
        @@ -863,7 +835,6 @@ public int writeAbbrevs(DebugContext context, byte[] buffer, int p) { pos = writeHeaderFieldAbbrev(context, buffer, pos); pos = writeArrayDataTypeAbbrev(context, buffer, pos); pos = writeMethodLocationAbbrev(context, buffer, pos); - pos = writeAbstractInlineMethodAbbrev(context, buffer, pos); pos = writeStaticFieldLocationAbbrev(context, buffer, pos); pos = writeSuperReferenceAbbrev(context, buffer, pos); pos = writeInterfaceImplementorAbbrev(context, buffer, pos); @@ -1333,25 +1304,6 @@ private int writeMethodLocationAbbrev(@SuppressWarnings("unused") DebugContext c return pos; } - private int writeAbstractInlineMethodAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { - int pos = p; - pos = writeAbbrevCode(DwarfDebugInfo.DW_ABBREV_CODE_abstract_inline_method, buffer, pos); - pos = writeTag(DwarfDebugInfo.DW_TAG_subprogram, buffer, pos); - pos = writeFlag(DwarfDebugInfo.DW_CHILDREN_no, buffer, pos); - pos = writeAttrType(DwarfDebugInfo.DW_AT_inline, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_data1, buffer, pos); - pos = writeAttrType(DwarfDebugInfo.DW_AT_external, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_flag, buffer, pos); - pos = writeAttrType(DwarfDebugInfo.DW_AT_specification, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_ref_addr, buffer, pos); - /* - * Now terminate. - */ - pos = writeAttrType(DwarfDebugInfo.DW_AT_null, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_null, buffer, pos); - return pos; - } - private int writeStaticFieldLocationAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { int pos = p; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java index d00af24f69fc..bf1ecd76b86f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java @@ -80,40 +80,39 @@ public class DwarfDebugInfo extends DebugInfoBase { public static final int DW_ABBREV_CODE_class_layout2 = 7; public static final int DW_ABBREV_CODE_class_pointer = 8; public static final int DW_ABBREV_CODE_method_location = 9; - public static final int DW_ABBREV_CODE_abstract_inline_method = 10; - public static final int DW_ABBREV_CODE_static_field_location = 11; - public static final int DW_ABBREV_CODE_array_layout = 12; - public static final int DW_ABBREV_CODE_array_pointer = 13; - public static final int DW_ABBREV_CODE_interface_layout = 14; - public static final int DW_ABBREV_CODE_interface_pointer = 15; - public static final int DW_ABBREV_CODE_indirect_layout = 16; - public static final int DW_ABBREV_CODE_indirect_pointer = 17; + public static final int DW_ABBREV_CODE_static_field_location = 10; + public static final int DW_ABBREV_CODE_array_layout = 11; + public static final int DW_ABBREV_CODE_array_pointer = 12; + public static final int DW_ABBREV_CODE_interface_layout = 13; + public static final int DW_ABBREV_CODE_interface_pointer = 14; + public static final int DW_ABBREV_CODE_indirect_layout = 15; + public static final int DW_ABBREV_CODE_indirect_pointer = 16; /* Level 2 DIEs. */ - public static final int DW_ABBREV_CODE_method_declaration = 18; - public static final int DW_ABBREV_CODE_method_declaration_static = 19; - public static final int DW_ABBREV_CODE_field_declaration1 = 20; - public static final int DW_ABBREV_CODE_field_declaration2 = 21; - public static final int DW_ABBREV_CODE_field_declaration3 = 22; - public static final int DW_ABBREV_CODE_field_declaration4 = 23; - public static final int DW_ABBREV_CODE_class_constant = 24; - public static final int DW_ABBREV_CODE_header_field = 25; - public static final int DW_ABBREV_CODE_array_data_type = 26; - public static final int DW_ABBREV_CODE_super_reference = 27; - public static final int DW_ABBREV_CODE_interface_implementor = 28; + public static final int DW_ABBREV_CODE_method_declaration = 17; + public static final int DW_ABBREV_CODE_method_declaration_static = 18; + public static final int DW_ABBREV_CODE_field_declaration1 = 19; + public static final int DW_ABBREV_CODE_field_declaration2 = 20; + public static final int DW_ABBREV_CODE_field_declaration3 = 21; + public static final int DW_ABBREV_CODE_field_declaration4 = 22; + public static final int DW_ABBREV_CODE_class_constant = 23; + public static final int DW_ABBREV_CODE_header_field = 24; + public static final int DW_ABBREV_CODE_array_data_type = 25; + public static final int DW_ABBREV_CODE_super_reference = 26; + public static final int DW_ABBREV_CODE_interface_implementor = 27; /* Level 2+K DIEs (where inline depth K >= 0) */ - public static final int DW_ABBREV_CODE_inlined_subroutine = 29; - public static final int DW_ABBREV_CODE_inlined_subroutine_with_children = 30; + public static final int DW_ABBREV_CODE_inlined_subroutine = 28; + public static final int DW_ABBREV_CODE_inlined_subroutine_with_children = 29; /* Level 2 DIEs. */ - public static final int DW_ABBREV_CODE_method_parameter_declaration1 = 31; - public static final int DW_ABBREV_CODE_method_parameter_declaration2 = 32; - public static final int DW_ABBREV_CODE_method_parameter_declaration3 = 33; - public static final int DW_ABBREV_CODE_method_local_declaration1 = 34; - public static final int DW_ABBREV_CODE_method_local_declaration2 = 35; + public static final int DW_ABBREV_CODE_method_parameter_declaration1 = 30; + public static final int DW_ABBREV_CODE_method_parameter_declaration2 = 31; + public static final int DW_ABBREV_CODE_method_parameter_declaration3 = 32; + public static final int DW_ABBREV_CODE_method_local_declaration1 = 33; + public static final int DW_ABBREV_CODE_method_local_declaration2 = 34; /* Level 3 DIEs. */ - public static final int DW_ABBREV_CODE_method_parameter_location1 = 36; - public static final int DW_ABBREV_CODE_method_parameter_location2 = 37; - public static final int DW_ABBREV_CODE_method_local_location1 = 38; - public static final int DW_ABBREV_CODE_method_local_location2 = 39; + public static final int DW_ABBREV_CODE_method_parameter_location1 = 35; + public static final int DW_ABBREV_CODE_method_parameter_location2 = 36; + public static final int DW_ABBREV_CODE_method_local_location1 = 37; + public static final int DW_ABBREV_CODE_method_local_location2 = 38; /* * Define all the Dwarf tags we need for our DIEs. @@ -490,10 +489,6 @@ static class DwarfMethodProperties { * The index in the info section at which the method's declaration resides. */ private int methodDeclarationIndex; - /** - * The index in the info section at which the method's abstract inline declaration resides. - */ - private int abstractInlineMethodIndex; /** * Index of info locations for params/locals belonging to a method. @@ -502,7 +497,6 @@ static class DwarfMethodProperties { DwarfMethodProperties() { methodDeclarationIndex = -1; - abstractInlineMethodIndex = -1; localProperties = null; } @@ -511,21 +505,11 @@ public int getMethodDeclarationIndex() { return methodDeclarationIndex; } - public int getAbstractInlineMethodIndex() { - assert abstractInlineMethodIndex >= 0 : "unset inline index"; - return abstractInlineMethodIndex; - } - public void setMethodDeclarationIndex(int pos) { assert methodDeclarationIndex == -1 || methodDeclarationIndex == pos : "bad declaration index"; methodDeclarationIndex = pos; } - public void setAbstractInlineMethodIndex(int pos) { - assert abstractInlineMethodIndex == -1 || abstractInlineMethodIndex == pos : "bad inline index"; - abstractInlineMethodIndex = pos; - } - public DwarfLocalProperties getLocalProperties() { if (localProperties == null) { localProperties = new DwarfLocalProperties(); @@ -684,16 +668,6 @@ public int getMethodDeclarationIndex(MethodEntry methodEntry) { return methodProperties.getMethodDeclarationIndex(); } - public void setAbstractInlineMethodIndex(MethodEntry methodEntry, int pos) { - DwarfMethodProperties methodProperties = lookupMethodProperties(methodEntry); - methodProperties.setAbstractInlineMethodIndex(pos); - } - - public int getAbstractInlineMethodIndex(MethodEntry methodEntry) { - DwarfMethodProperties methodProperties = lookupMethodProperties(methodEntry); - return methodProperties.getAbstractInlineMethodIndex(); - } - /** * A class used to associate properties with a specific param or local whether top level or * inline. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java index acbe20066676..09da31a1d06e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java @@ -600,13 +600,6 @@ private int writeMethodDeclarations(DebugContext context, ClassEntry classEntry, */ pos = writeMethodDeclaration(context, classEntry, method, buffer, pos); } - if (method.isInlined()) { - /* - * We also need an abstract inlined method as a target for any inline tree that - * includes the method - */ - pos = writeAbstractInlineMethod(context, classEntry, method, buffer, pos); - } } return pos; @@ -1341,7 +1334,7 @@ private int writeInlineSubroutine(DebugContext context, Range caller, int depth, MethodEntry methodEntry = callee.getMethodEntry(); String methodKey = methodEntry.getSymbolName(); /* the abstract index was written in the method's class entry */ - int abstractOriginIndex = getAbstractInlineMethodIndex(methodEntry); + int abstractOriginIndex = getMethodDeclarationIndex(methodEntry); int pos = p; log(context, " [0x%08x] concrete inline subroutine [0x%x, 0x%x] %s", pos, caller.getLo(), caller.getHi(), methodKey); @@ -1377,26 +1370,6 @@ private int writeInlineSubroutine(DebugContext context, Range caller, int depth, return pos; } - private int writeAbstractInlineMethod(DebugContext context, ClassEntry classEntry, MethodEntry method, byte[] buffer, int p) { - int pos = p; - setAbstractInlineMethodIndex(method, pos); - log(context, " [0x%08x] abstract inline method %s::%s", pos, classEntry.getTypeName(), method.methodName()); - int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_abstract_inline_method; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - log(context, " [0x%08x] inline 0x%x", pos, DwarfDebugInfo.DW_INL_inlined); - pos = writeAttrData1(DwarfDebugInfo.DW_INL_inlined, buffer, pos); - /* - * Should pass true only if method is non-private. - */ - log(context, " [0x%08x] external true", pos); - pos = writeFlag(DwarfDebugInfo.DW_FLAG_true, buffer, pos); - int methodSpecOffset = getMethodDeclarationIndex(method); - log(context, " [0x%08x] specification 0x%x", pos, methodSpecOffset); - pos = writeInfoSectionOffset(methodSpecOffset, buffer, pos); - return pos; - } - private int writeAttrRef4(int reference, byte[] buffer, int p) { // writes a CU-relative offset but we only have one CU which starts at offset 0 return writeAttrData4(reference, buffer, p); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java index 36fef2e67aa9..ff26a7f8496c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java @@ -847,17 +847,6 @@ protected int getMethodDeclarationIndex(MethodEntry methodEntry) { return dwarfSections.getMethodDeclarationIndex(methodEntry); } - protected void setAbstractInlineMethodIndex(MethodEntry methodEntry, int pos) { - dwarfSections.setAbstractInlineMethodIndex(methodEntry, pos); - } - - protected int getAbstractInlineMethodIndex(MethodEntry methodEntry) { - if (!contentByteArrayCreated()) { - return 0; - } - return dwarfSections.getAbstractInlineMethodIndex(methodEntry); - } - /** * Record the info section offset of a local (or parameter) declaration DIE appearing as a child * of a standard method declaration. From 8428e0e3bc9df9a1bb66ee03e1536b7cecac3c1d Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 13 Apr 2023 15:56:52 +0100 Subject: [PATCH 8/9] Even more style fixes --- .../oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java index 56696551584b..7da1fd1f55aa 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java @@ -579,9 +579,9 @@ * caller. So, if compiled method M inlines a call to m1 at source position f0:l0, m1 inlines a call * to method m2 at source position f1:l1 and m2 inlines a call to m3 at source position f2:l2 then * there will be a level 2 DIE for the inline code range derived from m1 referencing the declaration - * DIE for m1 with f0 and l0 as file and line, a level 3 DIE for the inline code range derived - * from m2 referencing the declaration DIE for m2 with f1 and l1 as file and line and a level 3 DIE - * for the inline code range derived from m3 referencing the declaration DIE for m3 with f2 and l2 as + * DIE for m1 with f0 and l0 as file and line, a level 3 DIE for the inline code range derived from + * m2 referencing the declaration DIE for m2 with f1 and l1 as file and line and a level 3 DIE for + * the inline code range derived from m3 referencing the declaration DIE for m3 with f2 and l2 as * file and line. * *
          From d52edf94ed7d994931758cb5a7087cbca4f27ef4 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 14 Apr 2023 10:06:05 +0100 Subject: [PATCH 9/9] Respond to review feedback --- .../objectfile/debugentry/ClassEntry.java | 2 +- .../debugentry/CompiledMethodEntry.java | 8 ++++---- .../objectfile/debugentry/DebugInfoBase.java | 11 ----------- .../oracle/objectfile/debugentry/DirEntry.java | 4 ++-- .../objectfile/debugentry/FileEntry.java | 6 +++--- .../debugentry/InterfaceClassEntry.java | 2 +- .../objectfile/debugentry/LoaderEntry.java | 2 +- .../objectfile/debugentry/MemberEntry.java | 2 +- .../objectfile/debugentry/MethodEntry.java | 6 +++--- .../debugentry/PrimitiveTypeEntry.java | 6 +++--- .../objectfile/debugentry/StringEntry.java | 2 +- .../debugentry/StructureTypeEntry.java | 2 +- .../objectfile/debugentry/TypeEntry.java | 4 ++-- .../objectfile/elf/dwarf/DwarfDebugInfo.java | 18 +++++++++--------- .../elf/dwarf/DwarfInfoSectionImpl.java | 2 +- .../objectfile/elf/dwarf/DwarfSectionImpl.java | 4 ++-- 16 files changed, 35 insertions(+), 46 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java index 389c584ad6c6..dd4a51e8e259 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java @@ -62,7 +62,7 @@ public class ClassEntry extends StructureTypeEntry { /** * Details of the associated file. */ - private FileEntry fileEntry; + private final FileEntry fileEntry; /** * Details of the associated loader. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/CompiledMethodEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/CompiledMethodEntry.java index 8f02ad5ba107..b8d34393677a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/CompiledMethodEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/CompiledMethodEntry.java @@ -41,19 +41,19 @@ public class CompiledMethodEntry { /** * The primary range detailed by this object. */ - private PrimaryRange primary; + private final PrimaryRange primary; /** * Details of the class owning this range. */ - private ClassEntry classEntry; + private final ClassEntry classEntry; /** * Details of of compiled method frame size changes. */ - private List frameSizeInfos; + private final List frameSizeInfos; /** * Size of compiled method frame. */ - private int frameSize; + private final int frameSize; public CompiledMethodEntry(PrimaryRange primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { this.primary = primary; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java index 575552a609ec..52d11ce818bf 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java @@ -716,17 +716,6 @@ public boolean isHubClassEntry(ClassEntry classEntry) { return classEntry.getTypeName().equals(DwarfDebugInfo.HUB_TYPE_NAME); } - public int classLayoutAbbrevCode(ClassEntry classEntry) { - if (!useHeapBase & isHubClassEntry(classEntry)) { - /* - * This layout adds special logic to remove tag bits from indirect pointers to this - * type. - */ - return DwarfDebugInfo.DW_ABBREV_CODE_class_layout2; - } - return DwarfDebugInfo.DW_ABBREV_CODE_class_layout1; - } - public ClassEntry getHubClassEntry() { return hubClassEntry; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java index 71b4dde797ce..ddfbf7da5bcd 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java @@ -36,8 +36,8 @@ * into directory tables once only rather than once per file. */ public class DirEntry { - private Path path; - private int idx; + private final Path path; + private final int idx; public DirEntry(Path path, int idx) { this.path = path; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java index 9eb99d3a72c2..d14ccf92af4d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java @@ -30,9 +30,9 @@ * Tracks debug info associated with a Java source file. */ public class FileEntry { - private String fileName; - private DirEntry dirEntry; - private int idx; + private final String fileName; + private final DirEntry dirEntry; + private final int idx; public FileEntry(String fileName, DirEntry dirEntry, int idx) { this.fileName = fileName; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/InterfaceClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/InterfaceClassEntry.java index 1faedc08c870..d939d27513e7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/InterfaceClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/InterfaceClassEntry.java @@ -36,7 +36,7 @@ import java.util.stream.Stream; public class InterfaceClassEntry extends ClassEntry { - private List implementors; + private final List implementors; public InterfaceClassEntry(String className, FileEntry fileEntry, int size) { super(className, fileEntry, size); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/LoaderEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/LoaderEntry.java index 21822f3b3253..f3390e29e802 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/LoaderEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/LoaderEntry.java @@ -32,7 +32,7 @@ * need to be embedded in debug info that identifies class and method names. */ public class LoaderEntry { - String loaderId; + private final String loaderId; public LoaderEntry(String id) { loaderId = id; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MemberEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MemberEntry.java index f907ad72d936..603e1ddee1f6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MemberEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MemberEntry.java @@ -32,7 +32,7 @@ */ public abstract class MemberEntry { protected FileEntry fileEntry; - protected int line; + protected final int line; protected final String memberName; protected final StructureTypeEntry ownerType; protected final TypeEntry valueType; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MethodEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MethodEntry.java index e5a61b0abf67..a5dd64a23f8f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MethodEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MethodEntry.java @@ -51,9 +51,9 @@ public class MethodEntry extends MemberEntry { static final int INLINED = 1 << 2; static final int IS_OVERRIDE = 1 << 3; static final int IS_CONSTRUCTOR = 1 << 4; - int flags; - int vtableOffset = -1; - final String symbolName; + private int flags; + private final int vtableOffset; + private final String symbolName; public MethodEntry(DebugInfoBase debugInfoBase, DebugMethodInfo debugMethodInfo, FileEntry fileEntry, int line, String methodName, ClassEntry ownerType, diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimitiveTypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimitiveTypeEntry.java index be58fb280e9a..5a7d7c69d18f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimitiveTypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimitiveTypeEntry.java @@ -36,9 +36,9 @@ import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugPrimitiveTypeInfo.FLAG_SIGNED; public class PrimitiveTypeEntry extends TypeEntry { - char typeChar; - int flags; - int bitCount; + private char typeChar; + private int flags; + private int bitCount; public PrimitiveTypeEntry(String typeName, int size) { super(typeName, size); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java index b984a63e02d1..01eb6fb9de38 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java @@ -31,7 +31,7 @@ * be located in the debug_string section and, if so, tracks the offset at which it gets written. */ public class StringEntry { - private String string; + private final String string; private int offset; private boolean addToStrSection; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StructureTypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StructureTypeEntry.java index b08b8c8038fc..a242db7c3d89 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StructureTypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StructureTypeEntry.java @@ -43,7 +43,7 @@ public abstract class StructureTypeEntry extends TypeEntry { /** * Details of fields located in this instance. */ - protected List fields; + protected final List fields; public StructureTypeEntry(String typeName, int size) { super(typeName, size); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/TypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/TypeEntry.java index 6c46fa995f04..c2d77a7b3183 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/TypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/TypeEntry.java @@ -41,7 +41,7 @@ public abstract class TypeEntry { /** * The name of this type. */ - protected String typeName; + protected final String typeName; /** * The offset of the java.lang.Class instance for this class in the image heap or -1 if no such @@ -52,7 +52,7 @@ public abstract class TypeEntry { /** * The size of an occurrence of this type in bytes. */ - protected int size; + protected final int size; protected TypeEntry(String typeName, int size) { this.typeName = typeName; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java index bf1ecd76b86f..13a6d680d2bd 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java @@ -310,22 +310,22 @@ public class DwarfDebugInfo extends DebugInfoBase { */ public static final String HUB_TYPE_NAME = "java.lang.Class"; - private DwarfStrSectionImpl dwarfStrSection; - private DwarfAbbrevSectionImpl dwarfAbbrevSection; - private DwarfInfoSectionImpl dwarfInfoSection; - private DwarfLocSectionImpl dwarfLocSection; - private DwarfARangesSectionImpl dwarfARangesSection; - private DwarfLineSectionImpl dwarfLineSection; - private DwarfFrameSectionImpl dwarfFameSection; + private final DwarfStrSectionImpl dwarfStrSection; + private final DwarfAbbrevSectionImpl dwarfAbbrevSection; + private final DwarfInfoSectionImpl dwarfInfoSection; + private final DwarfLocSectionImpl dwarfLocSection; + private final DwarfARangesSectionImpl dwarfARangesSection; + private final DwarfLineSectionImpl dwarfLineSection; + private final DwarfFrameSectionImpl dwarfFameSection; public final ELFMachine elfMachine; /** * Register used to hold the heap base. */ - private byte heapbaseRegister; + private final byte heapbaseRegister; /** * Register used to hold the current thread. */ - private byte threadRegister; + private final byte threadRegister; /** * A collection of properties associated with each generated type record indexed by type name. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java index 09da31a1d06e..8ea419d2fd80 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java @@ -63,7 +63,7 @@ public class DwarfInfoSectionImpl extends DwarfSectionImpl { /** * The name of a special DWARF struct type used to model an object header. */ - public static final String OBJECT_HEADER_STRUCT_NAME = "_objhdr"; + private static final String OBJECT_HEADER_STRUCT_NAME = "_objhdr"; /** * An info header section always contains a fixed number of bytes. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java index ff26a7f8496c..d9a029ee5dc9 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java @@ -63,7 +63,7 @@ public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { // auxiliary class used to track byte array positions protected class Cursor { - int pos; + private int pos; public Cursor() { this(0); @@ -90,7 +90,7 @@ public int get() { } } - protected DwarfDebugInfo dwarfSections; + protected final DwarfDebugInfo dwarfSections; protected boolean debug = false; protected long debugTextBase = 0; protected long debugAddress = 0;