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..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. */ @@ -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(); - } - - /** - * 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(); + return compiledEntries.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/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 217ed977107c..1d79c97c6bf6 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,16 +200,21 @@ 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. */ private ClassEntry hubClassEntry; + @SuppressWarnings("this-escape") public DebugInfoBase(ByteOrder byteOrder) { this.byteOrder = byteOrder; this.useHeapBase = true; @@ -210,6 +225,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 +286,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 +339,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 +458,11 @@ 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,27 +522,50 @@ 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; + } + + static final Path EMPTY_PATH = Paths.get(""); + 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); + 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); - 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(dirPath); } return fileEntry; } @@ -545,8 +598,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 +627,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); @@ -656,17 +717,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 4b31fb754d62..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,10 +36,12 @@ * into directory tables once only rather than once per file. */ public class DirEntry { - private Path path; + private final Path path; + private final 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..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,12 +30,14 @@ * Tracks debug info associated with a Java source file. */ public class FileEntry { - private String fileName; - private DirEntry dirEntry; + private final String fileName; + private final DirEntry dirEntry; + private final 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/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 1522a5a951a1..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; @@ -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/MethodEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/MethodEntry.java index 8cb273077488..d583784898ad 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; @SuppressWarnings("this-escape") public MethodEntry(DebugInfoBase debugInfoBase, DebugMethodInfo debugMethodInfo, 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/debugentry/range/PrimaryRange.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/range/PrimaryRange.java index 5a75dd4837d0..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 { @@ -46,12 +45,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..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 @@ -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 958edac5eff8..6c8f9a1fc669 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; @@ -75,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..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 @@ -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; @@ -60,7 +56,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 +64,8 @@ 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 +89,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 +132,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() == size; } private int writeHeader(int cuIndex, byte[] buffer, int p) { @@ -215,25 +170,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..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 @@ -30,806 +30,762 @@ 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 = 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 - details of method parameters + * + *
    • code == method_local_declaration1/2, tag == variable, parent = + * method_declaration1/2 - 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 + * 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_location DIE 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 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. + * + *
      + * + *
    • 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 + * + *
    + * + * 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 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 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. + * + *
      + * + *
    • 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 + * definition 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 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 +812,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,15 +825,16 @@ 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); 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); @@ -920,37 +875,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 +888,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 +992,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 +1012,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); @@ -1401,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_yes, 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 cf9478296b0e..a7a8f66fcc9e 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,49 @@ 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_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 = 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 = 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 = 31; - public static final int DW_ABBREV_CODE_inlined_subroutine_with_children = 32; + 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 = 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 = 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 = 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 = 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. @@ -314,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. @@ -343,14 +339,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. */ @@ -473,14 +461,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. */ @@ -489,44 +469,16 @@ 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. */ 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. - */ - private EconomicMap methodLocalPropertiesIndex; 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; } } @@ -538,14 +490,15 @@ 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. + * Index of info locations for params/locals belonging to a method. */ - private int abstractInlineMethodIndex; + private DwarfLocalProperties localProperties; DwarfMethodProperties() { methodDeclarationIndex = -1; - abstractInlineMethodIndex = -1; + localProperties = null; } public int getMethodDeclarationIndex() { @@ -553,19 +506,16 @@ 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(); + } + return localProperties; } } @@ -654,37 +604,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; @@ -715,55 +634,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); @@ -799,29 +669,6 @@ 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 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); - } - /** * A class used to associate properties with a specific param or local whether top level or * inline. @@ -853,35 +700,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) { + return lookupMethodProperties(methodEntry).getLocalProperties(); } - public void setMethodLocalIndex(ClassEntry classEntry, MethodEntry methodEntry, DebugLocalInfo localInfo, int index) { - DwarfLocalProperties localProperties = lookupLocalProperties(classEntry, methodEntry); + public void setMethodLocalIndex(MethodEntry methodEntry, DebugLocalInfo localInfo, int index) { + DwarfLocalProperties localProperties = lookupLocalProperties(methodEntry); localProperties.setIndex(localInfo, index); } - public int getMethodLocalIndex(ClassEntry classEntry, MethodEntry methodEntry, DebugLocalInfo localinfo) { - DwarfLocalProperties localProperties = lookupLocalProperties(classEntry, methodEntry); + 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); + 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/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index 81192c206839..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; @@ -152,17 +151,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..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 @@ -29,11 +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 java.util.function.Predicate; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -66,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. @@ -75,7 +72,6 @@ public class DwarfInfoSectionImpl extends DwarfSectionImpl { public DwarfInfoSectionImpl(DwarfDebugInfo dwarfSections) { super(dwarfSections); - cuStart = -1; } @Override @@ -138,80 +134,76 @@ byte computeEncoding(int flags, int bitCount) { public int generateContent(DebugContext context, byte[] buffer) { int pos = 0; + // 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); + /* + * 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 entries for all the types known to the generator. */ + /* Write DIEs for primitive types and header struct */ - pos = writeBuiltInUnit(context, buffer, pos); + pos = writeBuiltInTypes(context, buffer, pos); /* - * Write class units for non-compiled instance classes i.e. ones which don't have any - * compiled methods. + * Write DIEs for all instance classes, which includes interfaces and enums */ - pos = writeNonCompiledClasses(context, buffer, pos); + pos = writeInstanceClasses(context, buffer, pos); - /* - * Write class units for compiled instance classes i.e. ones which have associated compiled - * methods. - */ + /* Write DIEs for array types. */ + + pos = writeArrays(context, buffer, pos); + + /* Write all compiled code locations */ - pos = writeCompiledClasses(context, buffer, pos); + pos = writeMethodLocations(context, buffer, pos); - /* Write class units for array types. */ + /* Write all static field definitions -- in class order */ - pos = writeArrayTypes(context, buffer, pos); + 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) -> { @@ -233,14 +225,6 @@ private int writeBuiltInUnit(DebugContext context, byte[] buffer, int p) { (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); - return pos; } @@ -346,131 +330,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,32 +361,12 @@ 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); - - /* 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; } @@ -535,6 +385,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 +443,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) { @@ -712,7 +563,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 +596,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 +626,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(); @@ -813,28 +663,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, method, fileIdx, 3, buffer, pos); /* write method local declarations */ - pos = writeMethodLocalDeclarations(context, null, 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, ClassEntry classEntry, 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(classEntry, method, 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(classEntry, method, paramInfo, refAddr); + setMethodLocalIndex(method, paramInfo, refAddr); pos = writeMethodParameterDeclaration(context, paramInfo, fileIdx, false, level, buffer, pos); } return pos; @@ -877,13 +727,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, 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, localInfo, refAddr); pos = writeMethodLocalDeclaration(context, localInfo, fileIdx, level, buffer, pos); } return pos; @@ -1072,117 +922,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 +965,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 writeArrays(DebugContext context, byte[] buffer, int p) { + log(context, " [0x%08x] array classes", p); + Cursor cursor = new Cursor(p); + arrayTypeStream().forEach(arrayTypeEntry -> { + cursor.set(writeArray(context, arrayTypeEntry, buffer, cursor.get())); + }); + return cursor.get(); } - private int writeArrayTypeUnit(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) { + private int writeArray(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 +996,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 +1032,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 +1152,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) { @@ -1477,8 +1181,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, 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 @@ -1492,7 +1196,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, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) { int pos = p; MethodEntry methodEntry; if (range.isPrimary()) { @@ -1503,20 +1207,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, 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, 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, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) { int pos = p; MethodEntry methodEntry; if (range.isPrimary()) { @@ -1528,7 +1232,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, localInfo); List ranges = varRangeMap.get(localInfo); pos = writeMethodLocalLocation(context, range, localInfo, refAddr, ranges, depth, false, buffer, pos); } @@ -1581,41 +1285,46 @@ 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()); + 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, subrange, depth + 2, buffer, pos); + HashMap> varRangeMap = subrange.getVarRangeMap(); + // increment depth to account for parameter and method locations + depth++; + pos = writeMethodParameterLocations(context, varRangeMap, subrange, depth + 2, buffer, pos); + pos = writeMethodLocalLocations(context, 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) { + 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 @@ -1625,7 +1334,7 @@ private int writeInlineSubroutine(DebugContext context, ClassEntry classEntry, R MethodEntry methodEntry = callee.getMethodEntry(); String methodKey = methodEntry.getSymbolName(); /* the abstract index was written in the method's class entry */ - int abstractOriginIndex = getAbstractInlineMethodIndex(classEntry, 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); @@ -1662,8 +1371,8 @@ private int writeInlineSubroutine(DebugContext context, ClassEntry classEntry, R } 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 +1550,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..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; @@ -140,8 +139,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 +161,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 +206,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 +283,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 +315,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 +371,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 +433,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 +449,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 +500,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 +618,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 +844,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..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; @@ -126,43 +124,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..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 @@ -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; @@ -60,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); @@ -87,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; @@ -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; @@ -870,50 +847,31 @@ protected int getMethodDeclarationIndex(MethodEntry methodEntry) { return dwarfSections.getMethodDeclarationIndex(methodEntry); } - protected void setAbstractInlineMethodIndex(ClassEntry classEntry, MethodEntry methodEntry, int pos) { - dwarfSections.setAbstractInlineMethodIndex(classEntry, methodEntry, pos); - } - - protected int getAbstractInlineMethodIndex(ClassEntry classEntry, MethodEntry methodEntry) { - if (!contentByteArrayCreated()) { - return 0; - } - return dwarfSections.getAbstractInlineMethodIndex(classEntry, 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. + * Record the info section offset of a local (or parameter) declaration DIE appearing as a child + * of a standard 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 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, 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 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. - * - * @param classEntry null if the local declaration belongs to a standard method declaration - * otherwise the entry for the class importing the inline code. + * 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 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, DebugLocalInfo localInfo) { if (!contentByteArrayCreated()) { return 0; } - return dwarfSections.getMethodLocalIndex(classEntry, methodEntry, localInfo); + return dwarfSections.getMethodLocalIndex(methodEntry, localInfo); } /** 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;