diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ArrayTypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ArrayTypeEntry.java index 3b2d3b75128e..10f4bdfa7b3a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ArrayTypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ArrayTypeEntry.java @@ -29,6 +29,7 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugArrayTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; +import jdk.vm.ci.meta.ResolvedJavaType; import org.graalvm.compiler.debug.DebugContext; public class ArrayTypeEntry extends StructureTypeEntry { @@ -48,13 +49,13 @@ public DebugTypeKind typeKind() { @Override public void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInfo, DebugContext debugContext) { DebugArrayTypeInfo debugArrayTypeInfo = (DebugArrayTypeInfo) debugTypeInfo; - String elementTypeName = TypeEntry.canonicalize(debugArrayTypeInfo.elementType()); - this.elementType = debugInfoBase.lookupTypeEntry(elementTypeName); + ResolvedJavaType eltType = debugArrayTypeInfo.elementType(); + this.elementType = debugInfoBase.lookupTypeEntry(eltType); this.baseSize = debugArrayTypeInfo.baseSize(); this.lengthOffset = debugArrayTypeInfo.lengthOffset(); /* Add details of fields and field types */ debugArrayTypeInfo.fieldInfoProvider().forEach(debugFieldInfo -> this.processField(debugFieldInfo, debugInfoBase, debugContext)); - debugContext.log("typename %s element type %s base size %d length offset %d\n", typeName, elementTypeName, baseSize, lengthOffset); + debugContext.log("typename %s element type %s base size %d length offset %d\n", typeName, this.elementType.getTypeName(), baseSize, lengthOffset); } public TypeEntry getElementType() { 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 5a2af5ebfbbf..58344ce941f4 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 @@ -32,6 +32,8 @@ import java.util.List; import java.util.Map; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; import org.graalvm.compiler.debug.DebugContext; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFieldInfo; @@ -64,9 +66,10 @@ public class ClassEntry extends StructureTypeEntry { */ protected List methods; /** - * An index of all currently known methods keyed by the unique local symbol name of the method. + * An index of all currently known methods keyed by the unique, associated, identifying + * ResolvedJavaMethod. */ - private Map methodsIndex; + private Map methodsIndex; /** * A list recording details of all primary ranges included in this class sorted by ascending * address range. @@ -127,18 +130,21 @@ public DebugTypeKind typeKind() { @Override public void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInfo, DebugContext debugContext) { - assert TypeEntry.canonicalize(debugTypeInfo.typeName()).equals(typeName); + assert debugTypeInfo.typeName().equals(typeName); DebugInstanceTypeInfo debugInstanceTypeInfo = (DebugInstanceTypeInfo) debugTypeInfo; /* Add details of super and interface classes */ - String superName = debugInstanceTypeInfo.superName(); - if (superName != null) { - superName = TypeEntry.canonicalize(superName); + ResolvedJavaType superType = debugInstanceTypeInfo.superClass(); + String superName; + if (superType != null) { + superName = superType.toJavaName(); + } else { + superName = ""; } debugContext.log("typename %s adding super %s\n", typeName, superName); - if (superName != null) { - this.superClass = debugInfoBase.lookupClassEntry(superName); + if (superType != null) { + this.superClass = debugInfoBase.lookupClassEntry(superType); } - debugInstanceTypeInfo.interfaces().forEach(interfaceName -> processInterface(interfaceName, debugInfoBase, debugContext)); + debugInstanceTypeInfo.interfaces().forEach(interfaceType -> processInterface(interfaceType, debugInfoBase, debugContext)); /* Add details of fields and field types */ debugInstanceTypeInfo.fieldInfoProvider().forEach(debugFieldInfo -> this.processField(debugFieldInfo, debugInfoBase, debugContext)); /* Add details of methods and method types */ @@ -177,11 +183,10 @@ public void indexSubRange(Range subrange) { } } - private void indexMethodEntry(MethodEntry methodEntry) { - String methodName = methodEntry.getSymbolName(); - assert methodsIndex.get(methodName) == null : methodName; + private void indexMethodEntry(MethodEntry methodEntry, ResolvedJavaMethod idMethod) { + assert methodsIndex.get(idMethod) == null : methodEntry.getSymbolName(); methods.add(methodEntry); - methodsIndex.put(methodName, methodEntry); + methodsIndex.put(idMethod, methodEntry); } private void indexLocalFileEntry(FileEntry localFileEntry) { @@ -273,9 +278,10 @@ public String getCachePath() { return ""; } - private void processInterface(String interfaceName, DebugInfoBase debugInfoBase, DebugContext debugContext) { + private void processInterface(ResolvedJavaType interfaceType, DebugInfoBase debugInfoBase, DebugContext debugContext) { + String interfaceName = interfaceType.toJavaName(); debugContext.log("typename %s adding interface %s\n", typeName, interfaceName); - ClassEntry entry = debugInfoBase.lookupClassEntry(TypeEntry.canonicalize(interfaceName)); + ClassEntry entry = debugInfoBase.lookupClassEntry(interfaceType); assert entry instanceof InterfaceClassEntry; InterfaceClassEntry interfaceClassEntry = (InterfaceClassEntry) entry; interfaces.add(interfaceClassEntry); @@ -284,17 +290,18 @@ private void processInterface(String interfaceName, DebugInfoBase debugInfoBase, protected MethodEntry processMethod(DebugMethodInfo debugMethodInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) { String methodName = debugMethodInfo.name(); - String resultTypeName = TypeEntry.canonicalize(debugMethodInfo.valueType()); + ResolvedJavaType resultType = debugMethodInfo.valueType(); + String resultTypeName = resultType.toJavaName(); int modifiers = debugMethodInfo.modifiers(); DebugLocalInfo[] paramInfos = debugMethodInfo.getParamInfo(); DebugLocalInfo thisParam = debugMethodInfo.getThisParamInfo(); int paramCount = paramInfos.length; debugContext.log("typename %s adding %s method %s %s(%s)\n", typeName, memberModifiers(modifiers), resultTypeName, methodName, formatParams(paramInfos)); - TypeEntry resultType = debugInfoBase.lookupTypeEntry(resultTypeName); + TypeEntry resultTypeEntry = debugInfoBase.lookupTypeEntry(resultType); TypeEntry[] typeEntries = new TypeEntry[paramCount]; for (int i = 0; i < paramCount; i++) { - typeEntries[i] = debugInfoBase.lookupTypeEntry(TypeEntry.canonicalize(paramInfos[i].typeName())); + typeEntries[i] = debugInfoBase.lookupTypeEntry(paramInfos[i].valueType()); } /* * n.b. the method file may differ from the owning class file when the method is a @@ -302,8 +309,8 @@ protected MethodEntry processMethod(DebugMethodInfo debugMethodInfo, DebugInfoBa */ FileEntry methodFileEntry = debugInfoBase.ensureFileEntry(debugMethodInfo); MethodEntry methodEntry = new MethodEntry(debugInfoBase, debugMethodInfo, methodFileEntry, methodName, - this, resultType, typeEntries, paramInfos, thisParam); - indexMethodEntry(methodEntry); + this, resultTypeEntry, typeEntries, paramInfos, thisParam); + indexMethodEntry(methodEntry, debugMethodInfo.idMethod()); return methodEntry; } @@ -345,7 +352,7 @@ public ClassEntry getSuperClass() { public MethodEntry ensureMethodEntryForDebugRangeInfo(DebugRangeInfo debugRangeInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) { - MethodEntry methodEntry = methodsIndex.get(debugRangeInfo.symbolNameForMethod()); + MethodEntry methodEntry = methodsIndex.get(debugRangeInfo.idMethod()); if (methodEntry == null) { methodEntry = processMethod(debugRangeInfo, debugInfoBase, debugContext); } else { 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 39f12125b386..cae5c20fb575 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 @@ -72,7 +72,7 @@ public abstract class DebugInfoBase { * * An alternative traversal option is * - * 1) by top level class (String id) + * 1) by top level class (unique ResolvedJavaType id) * * 2) by top level compiled method (primary Range) within a class ordered by ascending address * @@ -83,6 +83,18 @@ public abstract class DebugInfoBase { * means we can treat each class as a compilation unit, allowing data common to all methods of * the class to be shared. * + * Just as an aside, for full disclosure, this is not strictly the full story. Sometimes a class + * can include speculatively optimized, compiled methods plus deopt fallback compiled variants + * of those same methods. In such cases the normal and/or speculatively compiled methods occupy + * one contiguous range and deopt methods occupy a separate higher range. The current + * compilation strategy ensures that the union across all classes of the normal/speculative + * ranges and the union across all classes of the deopt ranges lie in two distinct intervals + * where the highest address in the first union is strictly less than the lowest address in the + * second union. The implication is twofold. An address order traversal requires generating + * details for classes, methods and non-deopt primary ranges before generating details for the + * deopt primary ranges. The former details need to be generated in a distinct CU from deopt + * method details. + * * A third option appears to be to traverse via files, then top level class within file etc. * Unfortunately, files cannot be treated as the compilation unit. A file F may contain multiple * classes, say C1 and C2. There is no guarantee that methods for some other class C' in file F' @@ -96,17 +108,22 @@ public abstract class DebugInfoBase { */ private List types = new ArrayList<>(); /** - * index of already seen classes. + * Index of already seen classes keyed by the unique, associated, identifying ResolvedJavaType + * or, in the single special case of the TypeEntry for the Java header structure, by key null. */ - private Map typesIndex = new HashMap<>(); + private Map typesIndex = new HashMap<>(); /** * List of class entries detailing class info for primary ranges. */ private List primaryClasses = new ArrayList<>(); /** - * index of already seen classes. + * Index of already seen classes. */ private Map primaryClassesIndex = new HashMap<>(); + /** + * Handle on class entry for java.lang.Object. + */ + private ClassEntry objectClass; /** * Index of files which contain primary or secondary ranges. */ @@ -213,7 +230,8 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { /* Create all the types. */ debugInfoProvider.typeInfoProvider().forEach(debugTypeInfo -> debugTypeInfo.debugContext((debugContext) -> { - String typeName = TypeEntry.canonicalize(debugTypeInfo.typeName()); + ResolvedJavaType idType = debugTypeInfo.idType(); + String typeName = debugTypeInfo.typeName(); typeName = stringTable.uniqueDebugString(typeName); DebugTypeKind typeKind = debugTypeInfo.typeKind(); int byteSize = debugTypeInfo.size(); @@ -222,16 +240,17 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { String fileName = debugTypeInfo.fileName(); Path filePath = debugTypeInfo.filePath(); Path cachePath = debugTypeInfo.cachePath(); - addTypeEntry(typeName, fileName, filePath, cachePath, byteSize, typeKind); + addTypeEntry(idType, typeName, fileName, filePath, cachePath, byteSize, typeKind); })); /* Now we can cross reference static and instance field details. */ debugInfoProvider.typeInfoProvider().forEach(debugTypeInfo -> debugTypeInfo.debugContext((debugContext) -> { - String typeName = TypeEntry.canonicalize(debugTypeInfo.typeName()); + ResolvedJavaType idType = debugTypeInfo.idType(); + String typeName = debugTypeInfo.typeName(); DebugTypeKind typeKind = debugTypeInfo.typeKind(); debugContext.log(DebugContext.INFO_LEVEL, "Process %s type %s ", typeKind.toString(), typeName); - TypeEntry typeEntry = lookupTypeEntry(typeName); + TypeEntry typeEntry = lookupTypeEntry(idType); typeEntry.addDebugInfo(this, debugTypeInfo, debugContext); })); @@ -309,12 +328,15 @@ private TypeEntry createTypeEntry(String typeName, String fileName, Path filePat return typeEntry; } - private TypeEntry addTypeEntry(String typeName, String fileName, Path filePath, Path cachePath, int size, DebugTypeKind typeKind) { - TypeEntry typeEntry = typesIndex.get(typeName); + private TypeEntry addTypeEntry(ResolvedJavaType idType, String typeName, String fileName, Path filePath, Path cachePath, int size, DebugTypeKind typeKind) { + TypeEntry typeEntry = typesIndex.get(idType); if (typeEntry == null) { typeEntry = createTypeEntry(typeName, fileName, filePath, cachePath, size, typeKind); types.add(typeEntry); - typesIndex.put(typeName, typeEntry); + typesIndex.put(idType, typeEntry); + if (typeName.equals("java.lang.Object")) { + objectClass = (ClassEntry) typeEntry; + } } else { if (!(typeEntry.isClass())) { assert ((ClassEntry) typeEntry).getFileName().equals(fileName); @@ -323,22 +345,26 @@ private TypeEntry addTypeEntry(String typeName, String fileName, Path filePath, return typeEntry; } - public TypeEntry lookupTypeEntry(String typeName) { - TypeEntry typeEntry = typesIndex.get(typeName); + public TypeEntry lookupTypeEntry(ResolvedJavaType type) { + TypeEntry typeEntry = typesIndex.get(type); if (typeEntry == null) { - throw new RuntimeException("type entry not found " + typeName); + throw new RuntimeException("type entry not found " + type.getName()); } return typeEntry; } - ClassEntry lookupClassEntry(String typeName) { - TypeEntry typeEntry = typesIndex.get(typeName); + ClassEntry lookupClassEntry(ResolvedJavaType type) { + TypeEntry typeEntry = typesIndex.get(type); if (typeEntry == null || !(typeEntry.isClass())) { - throw new RuntimeException("class entry not found " + typeName); + throw new RuntimeException("class entry not found " + type.getName()); } return (ClassEntry) typeEntry; } + public ClassEntry lookupObjectClass() { + return objectClass; + } + /** * Recursively creates subranges based on DebugLocationInfo including, and appropriately * linking, nested inline subranges. @@ -360,7 +386,7 @@ private Range addSubrange(DebugLocationInfo locationInfo, Range primaryRange, Cl DebugLocationInfo callerLocationInfo = locationInfo.getCaller(); boolean isTopLevel = callerLocationInfo == null; assert (!isTopLevel || (locationInfo.name().equals(primaryRange.getMethodName()) && - TypeEntry.canonicalize(locationInfo.ownerType().toJavaName()).equals(primaryRange.getClassName()))); + locationInfo.ownerType().toJavaName().equals(primaryRange.getClassName()))); Range caller = (isTopLevel ? primaryRange : subRangeIndex.get(callerLocationInfo)); // the frame tree is walked topdown so inline ranges should always have a caller range assert caller != null; @@ -396,13 +422,13 @@ private ClassEntry ensureClassEntry(ResolvedJavaType type) { /* See if we already have an entry. */ ClassEntry classEntry = primaryClassesIndex.get(type); if (classEntry == null) { - TypeEntry typeEntry = typesIndex.get(TypeEntry.canonicalize(type.toJavaName())); + TypeEntry typeEntry = typesIndex.get(type); assert (typeEntry != null && typeEntry.isClass()); classEntry = (ClassEntry) typeEntry; primaryClasses.add(classEntry); primaryClassesIndex.put(type, classEntry); } - assert (classEntry.getTypeName().equals(TypeEntry.canonicalize(type.toJavaName()))); + assert (classEntry.getTypeName().equals(type.toJavaName())); return classEntry; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/EnumClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/EnumClassEntry.java index cfe8272e0b6a..a6cbaf1bb2ff 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/EnumClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/EnumClassEntry.java @@ -26,7 +26,7 @@ package com.oracle.objectfile.debugentry; -import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugEnumTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; import org.graalvm.compiler.debug.DebugContext; @@ -42,7 +42,7 @@ public DebugTypeKind typeKind() { } @Override - public void addDebugInfo(DebugInfoBase debugInfoBase, DebugInfoProvider.DebugTypeInfo debugTypeInfo, DebugContext debugContext) { + public void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInfo, DebugContext debugContext) { assert debugTypeInfo instanceof DebugEnumTypeInfo; super.addDebugInfo(debugInfoBase, debugTypeInfo, debugContext); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/HeaderTypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/HeaderTypeEntry.java index 6d3ff469f802..2dc9da5af94f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/HeaderTypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/HeaderTypeEntry.java @@ -45,7 +45,7 @@ public DebugTypeKind typeKind() { @Override public void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInfo, DebugContext debugContext) { - assert TypeEntry.canonicalize(debugTypeInfo.typeName()).equals(typeName); + assert debugTypeInfo.typeName().equals(typeName); DebugHeaderTypeInfo debugHeaderTypeInfo = (DebugHeaderTypeInfo) debugTypeInfo; debugHeaderTypeInfo.fieldInfoProvider().forEach(debugFieldInfo -> this.processField(debugFieldInfo, debugInfoBase, debugContext)); } 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 dc134445792a..ef21e4f2fc4e 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 @@ -36,6 +36,7 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugMethodInfo; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaType; public class MethodEntry extends MemberEntry { private final TypeEntry[] paramTypes; @@ -285,6 +286,11 @@ private static class DebugLocalInfoWrapper implements DebugLocalInfo { this.line = value.line(); } + @Override + public ResolvedJavaType valueType() { + return value.valueType(); + } + @Override public String name() { return value.name(); 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 45eaa5436c1d..b95d55f270ea 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 @@ -27,6 +27,7 @@ package com.oracle.objectfile.debugentry; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFieldInfo; +import jdk.vm.ci.meta.ResolvedJavaType; import org.graalvm.compiler.debug.DebugContext; import java.lang.reflect.Modifier; @@ -60,19 +61,20 @@ protected void processField(DebugFieldInfo debugFieldInfo, DebugInfoBase debugIn protected FieldEntry addField(DebugFieldInfo debugFieldInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) { String fieldName = debugInfoBase.uniqueDebugString(debugFieldInfo.name()); - String valueTypeName = TypeEntry.canonicalize(debugFieldInfo.valueType()); + ResolvedJavaType valueType = debugFieldInfo.valueType(); + String valueTypeName = valueType.toJavaName(); int fieldSize = debugFieldInfo.size(); int fieldoffset = debugFieldInfo.offset(); int fieldModifiers = debugFieldInfo.modifiers(); debugContext.log("typename %s adding %s field %s type %s size %s at offset 0x%x\n", typeName, memberModifiers(fieldModifiers), fieldName, valueTypeName, fieldSize, fieldoffset); - TypeEntry valueType = debugInfoBase.lookupTypeEntry(valueTypeName); + TypeEntry valueTypeEntry = debugInfoBase.lookupTypeEntry(valueType); /* * n.b. the field file may differ from the owning class file when the field is a * substitution */ FileEntry fileEntry = debugInfoBase.ensureFileEntry(debugFieldInfo); - FieldEntry fieldEntry = new FieldEntry(fileEntry, fieldName, this, valueType, fieldSize, fieldoffset, fieldModifiers); + FieldEntry fieldEntry = new FieldEntry(fileEntry, fieldName, this, valueTypeEntry, fieldSize, fieldoffset, fieldModifiers); fields.add(fieldEntry); return fieldEntry; } 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 afbbf01e117d..16190562185b 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 @@ -96,8 +96,4 @@ public boolean isStructure() { } public abstract void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInfo, DebugContext debugContext); - - public static String canonicalize(String typeName) { - return typeName.replace(" ", "__"); - } } 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 7619c6140560..db10586430a0 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 @@ -33,6 +33,7 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; import org.graalvm.compiler.debug.DebugContext; @@ -71,7 +72,7 @@ public interface DebugInfoProvider { /** * An interface implemented by items that can be located in a file. */ - interface DebugFileInfo { + public interface DebugFileInfo { /** * @return the name of the file containing a file element excluding any path. */ @@ -90,7 +91,9 @@ interface DebugFileInfo { Path cachePath(); } - interface DebugTypeInfo extends DebugFileInfo { + public interface DebugTypeInfo extends DebugFileInfo { + ResolvedJavaType idType(); + enum DebugTypeKind { PRIMITIVE, ENUM, @@ -132,35 +135,35 @@ public String toString() { int size(); } - interface DebugInstanceTypeInfo extends DebugTypeInfo { + public interface DebugInstanceTypeInfo extends DebugTypeInfo { int headerSize(); Stream fieldInfoProvider(); Stream methodInfoProvider(); - String superName(); + ResolvedJavaType superClass(); - Stream interfaces(); + Stream interfaces(); } - interface DebugEnumTypeInfo extends DebugInstanceTypeInfo { + public interface DebugEnumTypeInfo extends DebugInstanceTypeInfo { } - interface DebugInterfaceTypeInfo extends DebugInstanceTypeInfo { + public interface DebugInterfaceTypeInfo extends DebugInstanceTypeInfo { } - interface DebugArrayTypeInfo extends DebugTypeInfo { + public interface DebugArrayTypeInfo extends DebugTypeInfo { int baseSize(); int lengthOffset(); - String elementType(); + ResolvedJavaType elementType(); Stream fieldInfoProvider(); } - interface DebugPrimitiveTypeInfo extends DebugTypeInfo { + public interface DebugPrimitiveTypeInfo extends DebugTypeInfo { /* * NUMERIC excludes LOGICAL types boolean and void */ @@ -181,27 +184,27 @@ interface DebugPrimitiveTypeInfo extends DebugTypeInfo { int flags(); } - interface DebugHeaderTypeInfo extends DebugTypeInfo { + public interface DebugHeaderTypeInfo extends DebugTypeInfo { Stream fieldInfoProvider(); } - interface DebugMemberInfo extends DebugFileInfo { + public interface DebugMemberInfo extends DebugFileInfo { String name(); - String valueType(); + ResolvedJavaType valueType(); int modifiers(); } - interface DebugFieldInfo extends DebugMemberInfo { + public interface DebugFieldInfo extends DebugMemberInfo { int offset(); int size(); } - interface DebugMethodInfo extends DebugMemberInfo { + public interface DebugMethodInfo extends DebugMemberInfo { /** * @return an array of DebugLocalInfo objects holding details of this method's parameters */ @@ -246,17 +249,27 @@ interface DebugMethodInfo extends DebugMemberInfo { /* * Return the unique type that owns this method.

- * + * * @return the unique type that owns this method */ ResolvedJavaType ownerType(); + + /* + * Return the unique identifier for this method. The result can be used to unify details of + * methods presented via interface DebugTypeInfo with related details of compiled methods + * presented via interface DebugRangeInfo and of call frame methods presented via interface + * DebugLocationInfo.

+ * + * @return the unique identifier for this method + */ + ResolvedJavaMethod idMethod(); } /** * Access details of a compiled top level or inline method producing the code in a specific * {@link com.oracle.objectfile.debugentry.Range}. */ - interface DebugRangeInfo extends DebugMethodInfo { + public interface DebugRangeInfo extends DebugMethodInfo { /** * @return the lowest address containing code generated for an outer or inlined code segment @@ -280,7 +293,7 @@ interface DebugRangeInfo extends DebugMethodInfo { /** * Access details of a specific compiled method. */ - interface DebugCodeInfo extends DebugRangeInfo { + public interface DebugCodeInfo extends DebugRangeInfo { void debugContext(Consumer action); /** @@ -304,7 +317,7 @@ interface DebugCodeInfo extends DebugRangeInfo { /** * Access details of a specific heap object. */ - interface DebugDataInfo { + public interface DebugDataInfo { void debugContext(Consumer action); String getProvenance(); @@ -324,7 +337,7 @@ interface DebugDataInfo { * Access details of code generated for a specific outer or inlined method at a given line * number. */ - interface DebugLocationInfo extends DebugRangeInfo { + public interface DebugLocationInfo extends DebugRangeInfo { /** * @return the {@link DebugLocationInfo} of the nested inline caller-line */ @@ -341,7 +354,9 @@ interface DebugLocationInfo extends DebugRangeInfo { * A DebugLocalInfo details a local or parameter variable recording its name and type, the * (abstract machine) local slot index it resides in and the number of slots it occupies. */ - interface DebugLocalInfo { + public interface DebugLocalInfo { + ResolvedJavaType valueType(); + String name(); String typeName(); @@ -360,7 +375,7 @@ interface DebugLocalInfo { * frame. The value may be undefined. If not then the instance records its type and either its * (constant) value or the register or stack location in which the value resides. */ - interface DebugLocalValueInfo extends DebugLocalInfo { + public interface DebugLocalValueInfo extends DebugLocalInfo { enum LocalKind { UNDEFINED, REGISTER, @@ -379,7 +394,7 @@ enum LocalKind { JavaConstant constantValue(); } - interface DebugFrameSizeChange { + public interface DebugFrameSizeChange { enum Type { EXTEND, CONTRACT 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 500e1c4172ab..03d3b482f5ea 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 @@ -327,7 +327,25 @@ public class DwarfDebugInfo extends DebugInfoBase { * n.b. this collection includes entries for the structure types used to define the object and * array headers which do not have an associated TypeEntry. */ - private HashMap propertiesIndex; + private HashMap typePropertiesIndex; + + /** + * A collection of method properties associated with each generated method record. + */ + private HashMap methodPropertiesIndex; + + /** + * 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 HashMap methodLocalPropertiesIndex; + + /** + * A collection of local variable properties associated with an inlined subrange. + */ + private HashMap rangeLocalPropertiesIndex; public DwarfDebugInfo(ELFMachine elfMachine, ByteOrder byteOrder) { super(byteOrder); @@ -348,7 +366,8 @@ public DwarfDebugInfo(ELFMachine elfMachine, ByteOrder byteOrder) { this.heapbaseRegister = rheapbase_x86; this.threadRegister = rthread_x86; } - propertiesIndex = new HashMap<>(); + typePropertiesIndex = new HashMap<>(); + methodPropertiesIndex = new HashMap<>(); methodLocalPropertiesIndex = new HashMap<>(); rangeLocalPropertiesIndex = new HashMap<>(); } @@ -480,14 +499,6 @@ static class DwarfClassProperties extends DwarfTypeProperties { * Map from field names to info section index for the field declaration. */ private HashMap fieldDeclarationIndex; - /** - * Map from method names to info section index for the field declaration. - */ - private HashMap methodDeclarationIndex; - /** - * Map from method names to info section index for the field declaration. - */ - private HashMap abstractInlineMethodIndex; DwarfClassProperties(StructureTypeEntry entry) { super(entry); @@ -499,35 +510,76 @@ static class DwarfClassProperties extends DwarfTypeProperties { this.linePrologueSize = -1; this.lineSectionSize = -1; fieldDeclarationIndex = null; - methodDeclarationIndex = null; - abstractInlineMethodIndex = null; + } + } + + /** + * A class used to associate properties with a specific method. + */ + static class DwarfMethodProperties { + /** + * The index in the info section at which the method's declaration resides. + */ + private int methodDeclarationIndex; + /** + * The index in the info section at which the method's abstract inline declaration resides. + */ + private int abstractInlineMethodIndex; + + DwarfMethodProperties() { + methodDeclarationIndex = -1; + abstractInlineMethodIndex = -1; + } + + public int getMethodDeclarationIndex() { + assert methodDeclarationIndex >= 0 : "unset declaration index"; + 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; } } private DwarfTypeProperties addTypeProperties(TypeEntry typeEntry) { assert typeEntry != null; assert !typeEntry.isClass(); - String typeName = typeEntry.getTypeName(); - assert propertiesIndex.get(typeName) == null; + assert typePropertiesIndex.get(typeEntry) == null; DwarfTypeProperties typeProperties = new DwarfTypeProperties(typeEntry); - this.propertiesIndex.put(typeName, typeProperties); + this.typePropertiesIndex.put(typeEntry, typeProperties); return typeProperties; } private DwarfClassProperties addClassProperties(StructureTypeEntry entry) { - String typeName = entry.getTypeName(); - assert propertiesIndex.get(typeName) == null; + assert typePropertiesIndex.get(entry) == null; DwarfClassProperties classProperties = new DwarfClassProperties(entry); - this.propertiesIndex.put(typeName, classProperties); + this.typePropertiesIndex.put(entry, classProperties); return classProperties; } + private DwarfMethodProperties addMethodProperties(MethodEntry methodEntry) { + assert methodPropertiesIndex.get(methodEntry) == null; + DwarfMethodProperties methodProperties = new DwarfMethodProperties(); + this.methodPropertiesIndex.put(methodEntry, methodProperties); + return methodProperties; + } + private DwarfTypeProperties lookupTypeProperties(TypeEntry typeEntry) { if (typeEntry instanceof ClassEntry) { return lookupClassProperties((ClassEntry) typeEntry); } else { - String typeName = typeEntry.getTypeName(); - DwarfTypeProperties typeProperties = propertiesIndex.get(typeName); + DwarfTypeProperties typeProperties = typePropertiesIndex.get(typeEntry); if (typeProperties == null) { typeProperties = addTypeProperties(typeEntry); } @@ -536,8 +588,7 @@ private DwarfTypeProperties lookupTypeProperties(TypeEntry typeEntry) { } private DwarfClassProperties lookupClassProperties(StructureTypeEntry entry) { - String typeName = entry.getTypeName(); - DwarfTypeProperties typeProperties = propertiesIndex.get(typeName); + DwarfTypeProperties typeProperties = typePropertiesIndex.get(entry); assert typeProperties == null || typeProperties instanceof DwarfClassProperties; DwarfClassProperties classProperties = (DwarfClassProperties) typeProperties; if (classProperties == null) { @@ -546,20 +597,12 @@ private DwarfClassProperties lookupClassProperties(StructureTypeEntry entry) { return classProperties; } - private DwarfTypeProperties lookupTypeProperties(String typeName) { - DwarfTypeProperties typeProperties = propertiesIndex.get(typeName); - assert typeProperties != null; - assert typeProperties.getTypeEntry().getTypeName().equals(typeName); - return typeProperties; - } - - @SuppressWarnings("unused") - private DwarfClassProperties lookupClassProperties(String typeName) { - DwarfTypeProperties classProperties = propertiesIndex.get(typeName); - assert classProperties != null; - assert classProperties.getClass() == DwarfClassProperties.class; - assert classProperties.getTypeEntry().getTypeName().equals(typeName); - return (DwarfClassProperties) classProperties; + private DwarfMethodProperties lookupMethodProperties(MethodEntry methodEntry) { + DwarfMethodProperties methodProperties = methodPropertiesIndex.get(methodEntry); + if (methodProperties == null) { + methodProperties = addMethodProperties(methodEntry); + } + return methodProperties; } void setTypeIndex(TypeEntry typeEntry, int idx) { @@ -568,8 +611,8 @@ void setTypeIndex(TypeEntry typeEntry, int idx) { typeProperties.setTypeInfoIndex(idx); } - int getTypeIndex(String typeName) { - DwarfTypeProperties typeProperties = lookupTypeProperties(typeName); + int getTypeIndex(TypeEntry typeEntry) { + DwarfTypeProperties typeProperties = lookupTypeProperties(typeEntry); return getTypeIndex(typeProperties); } @@ -584,8 +627,8 @@ void setIndirectTypeIndex(TypeEntry typeEntry, int idx) { typeProperties.setIndirectTypeInfoIndex(idx); } - int getIndirectTypeIndex(String typeName) { - DwarfTypeProperties typeProperties = lookupTypeProperties(typeName); + int getIndirectTypeIndex(TypeEntry typeEntry) { + DwarfTypeProperties typeProperties = lookupTypeProperties(typeEntry); return getIndirectTypeIndex(typeProperties); } @@ -729,54 +772,24 @@ public int getFieldDeclarationIndex(StructureTypeEntry entry, String fieldName) return fieldDeclarationIndex.get(fieldName); } - public void setMethodDeclarationIndex(ClassEntry classEntry, String methodName, int pos) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - HashMap methodDeclarationIndex = classProperties.methodDeclarationIndex; - if (methodDeclarationIndex == null) { - classProperties.methodDeclarationIndex = methodDeclarationIndex = new HashMap<>(); - } - if (methodDeclarationIndex.get(methodName) != null) { - assert methodDeclarationIndex.get(methodName) == pos : classEntry.getTypeName() + methodName; - } else { - methodDeclarationIndex.put(methodName, pos); - } + public void setMethodDeclarationIndex(MethodEntry methodEntry, int pos) { + DwarfMethodProperties methodProperties = lookupMethodProperties(methodEntry); + methodProperties.setMethodDeclarationIndex(pos); } - public int getMethodDeclarationIndex(ClassEntry classEntry, String methodName) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - HashMap methodDeclarationIndex = classProperties.methodDeclarationIndex; - assert methodDeclarationIndex != null : classEntry.getTypeName() + methodName; - assert methodDeclarationIndex.get(methodName) != null : classEntry.getTypeName() + methodName; - return methodDeclarationIndex.get(methodName); + public int getMethodDeclarationIndex(MethodEntry methodEntry) { + DwarfMethodProperties methodProperties = lookupMethodProperties(methodEntry); + return methodProperties.getMethodDeclarationIndex(); } - public void setAbstractInlineMethodIndex(ClassEntry classEntry, String methodName, int pos) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - HashMap abstractInlineMethodIndex = classProperties.abstractInlineMethodIndex; - if (abstractInlineMethodIndex == null) { - classProperties.abstractInlineMethodIndex = abstractInlineMethodIndex = new HashMap<>(); - } - if (abstractInlineMethodIndex.get(methodName) != null) { - assert abstractInlineMethodIndex.get(methodName) == pos : classEntry.getTypeName() + methodName; - } else { - abstractInlineMethodIndex.put(methodName, pos); - } + public void setAbstractInlineMethodIndex(MethodEntry methodEntry, int pos) { + DwarfMethodProperties methodProperties = lookupMethodProperties(methodEntry); + methodProperties.setAbstractInlineMethodIndex(pos); } - public int getAbstractInlineMethodIndex(ClassEntry classEntry, String methodName) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - HashMap abstractInlineMethodIndex = classProperties.abstractInlineMethodIndex; - assert abstractInlineMethodIndex != null : classEntry.getTypeName() + methodName; - assert abstractInlineMethodIndex.get(methodName) != null : classEntry.getTypeName() + methodName; - return abstractInlineMethodIndex.get(methodName); + public int getAbstractInlineMethodIndex(MethodEntry methodEntry) { + DwarfMethodProperties methodProperties = lookupMethodProperties(methodEntry); + return methodProperties.getAbstractInlineMethodIndex(); } /** @@ -804,10 +817,6 @@ void setIndex(DebugLocalInfo localInfo, int index) { } } - private HashMap methodLocalPropertiesIndex; - - private HashMap rangeLocalPropertiesIndex; - private DwarfLocalProperties addMethodLocalProperties(MethodEntry methodEntry) { DwarfLocalProperties localProperties = new DwarfLocalProperties(); methodLocalPropertiesIndex.put(methodEntry, localProperties); 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 281ef3a4b4f3..134a127f6e8f 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 @@ -309,16 +309,15 @@ private int writeHeaderField(DebugContext context, FieldEntry fieldEntry, byte[] int pos = p; String fieldName = fieldEntry.fieldName(); TypeEntry valueType = fieldEntry.getValueType(); - String valueTypeName = valueType.getTypeName(); /* use the indirect type for the field so pointers get translated */ - int valueTypeIdx = getIndirectTypeIndex(valueTypeName); + int valueTypeIdx = getIndirectTypeIndex(valueType); log(context, " [0x%08x] header field", pos); int abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_header_field; log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode); pos = writeAbbrevCode(abbrevCode, buffer, pos); log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(fieldName), fieldName); pos = writeAttrStrp(fieldName, buffer, pos); - log(context, " [0x%08x] type 0x%x (%s)", pos, valueTypeIdx, valueTypeName); + log(context, " [0x%08x] type 0x%x (%s)", pos, valueTypeIdx, valueType.getTypeName()); pos = writeAttrRefAddr(valueTypeIdx, buffer, pos); byte offset = (byte) fieldEntry.getOffset(); int size = fieldEntry.getSize(); @@ -520,7 +519,8 @@ private int writeClassLayout(DebugContext context, ClassEntry classEntry, byte[] } else { /* Inherit layout from object header. */ superName = OBJECT_HEADER_STRUCT_NAME; - superTypeOffset = getTypeIndex(superName); + TypeEntry headerType = lookupType(null); + superTypeOffset = getTypeIndex(headerType); } /* Now write the child fields. */ pos = writeSuperReference(context, superTypeOffset, superName, buffer, pos); @@ -625,10 +625,10 @@ private int writeField(DebugContext context, StructureTypeEntry entry, FieldEntr pos = writeAttrData2((short) fileIdx, buffer, pos); /* At present we definitely don't have line numbers. */ } - String valueTypeName = fieldEntry.getValueType().getTypeName(); + TypeEntry valueType = fieldEntry.getValueType(); /* use the indirect type for the field so pointers get translated if needed */ - int typeIdx = getIndirectTypeIndex(valueTypeName); - log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, valueTypeName); + int typeIdx = getIndirectTypeIndex(valueType); + log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, valueType.getTypeName()); pos = writeAttrRefAddr(typeIdx, buffer, pos); if (!isStatic) { int memberOffset = fieldEntry.getOffset(); @@ -665,7 +665,7 @@ private int writeMethodDeclarations(DebugContext context, ClassEntry classEntry, private int writeMethodDeclaration(DebugContext context, ClassEntry classEntry, MethodEntry method, byte[] buffer, int p) { int pos = p; String methodKey = method.getSymbolName(); - setMethodDeclarationIndex(classEntry, methodKey, pos); + setMethodDeclarationIndex(method, pos); int modifiers = method.getModifiers(); boolean isStatic = Modifier.isStatic(modifiers); log(context, " [0x%08x] method declaration %s", pos, methodKey); @@ -685,9 +685,9 @@ private int writeMethodDeclaration(DebugContext context, ClassEntry classEntry, int fileIdx = classEntry.localFilesIdx(fileEntry); log(context, " [0x%08x] file 0x%x (%s)", pos, fileIdx, fileEntry.getFullName()); pos = writeAttrData2((short) fileIdx, buffer, pos); - String returnTypeName = method.getValueType().getTypeName(); - int retTypeIdx = getTypeIndex(returnTypeName); - log(context, " [0x%08x] type 0x%x (%s)", pos, retTypeIdx, returnTypeName); + TypeEntry returnType = method.getValueType(); + int retTypeIdx = getTypeIndex(returnType); + log(context, " [0x%08x] type 0x%x (%s)", pos, retTypeIdx, returnType.getTypeName()); pos = writeAttrRefAddr(retTypeIdx, buffer, pos); log(context, " [0x%08x] artificial %s", pos, method.isDeopt() ? "true" : "false"); pos = writeFlag((method.isDeopt() ? (byte) 1 : (byte) 0), buffer, pos); @@ -745,7 +745,7 @@ private int writeMethodParameterDeclaration(DebugContext context, DebugLocalInfo log(context, " [0x%08x] method parameter declaration", pos); int abbrevCode; String paramName = paramInfo.name(); - String paramTypeName = paramInfo.typeName(); + TypeEntry paramType = lookupType(paramInfo.valueType()); int line = paramInfo.line(); if (artificial) { abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_method_parameter_declaration1; @@ -764,8 +764,8 @@ private int writeMethodParameterDeclaration(DebugContext context, DebugLocalInfo log(context, " [0x%08x] line 0x%x", pos, line); pos = writeAttrData2((short) line, buffer, pos); } - int typeIdx = getTypeIndex(paramTypeName); - log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, paramTypeName); + int typeIdx = getTypeIndex(paramType); + log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, paramType.getTypeName()); pos = writeAttrRefAddr(typeIdx, buffer, pos); if (abbrevCode == DwarfDebugInfo.DW_ABBREV_CODE_method_parameter_declaration1) { log(context, " [0x%08x] artificial true", pos); @@ -794,7 +794,7 @@ private int writeMethodLocalDeclaration(DebugContext context, DebugLocalInfo par log(context, " [0x%08x] method local declaration", pos); int abbrevCode; String paramName = paramInfo.name(); - String paramTypeName = paramInfo.typeName(); + TypeEntry paramType = lookupType(paramInfo.valueType()); int line = paramInfo.line(); if (line >= 0) { abbrevCode = DwarfDebugInfo.DW_ABBREV_CODE_method_local_declaration1; @@ -811,8 +811,8 @@ private int writeMethodLocalDeclaration(DebugContext context, DebugLocalInfo par log(context, " [0x%08x] line 0x%x", pos, line); pos = writeAttrData2((short) line, buffer, pos); } - int typeIdx = getTypeIndex(paramTypeName); - log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, paramTypeName); + int typeIdx = getTypeIndex(paramType); + log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, paramType.getTypeName()); pos = writeAttrRefAddr(typeIdx, buffer, pos); log(context, " [0x%08x] declaration true", pos); pos = writeFlag((byte) 1, buffer, pos); @@ -981,7 +981,7 @@ private int writeMethodLocations(DebugContext context, ClassEntry classEntry, bo if (primary.isDeoptTarget() != deoptTargets) { continue; } - pos = writeMethodLocation(context, classEntry, primaryEntry, buffer, pos); + pos = writeMethodLocation(context, primaryEntry, buffer, pos); } return pos; } @@ -990,9 +990,8 @@ private int writeAbstractInlineMethods(DebugContext context, ClassEntry classEnt int pos = p; for (MethodEntry method : classEntry.getMethods()) { if (method.isInlined()) { - String methodKey = method.getSymbolName(); - setAbstractInlineMethodIndex(classEntry, methodKey, pos); - pos = writeAbstractInlineMethod(context, classEntry, method, buffer, pos); + setAbstractInlineMethodIndex(method, pos); + pos = writeAbstractInlineMethod(context, method, buffer, pos); } } return pos; @@ -1185,7 +1184,7 @@ private int writeArrayDataType(DebugContext context, TypeEntry elementType, byte pos = writeAttrData1((byte) size, buffer, pos); String elementTypeName = elementType.getTypeName(); /* use the indirect type for the element type so pointers get translated */ - int elementTypeIdx = getIndirectTypeIndex(elementTypeName); + int elementTypeIdx = getIndirectTypeIndex(elementType); log(context, " [0x%08x] type idx 0x%x (%s)", pos, elementTypeIdx, elementTypeName); pos = writeAttrRefAddr(elementTypeIdx, buffer, pos); return pos; @@ -1214,8 +1213,9 @@ private int writeArrayElementField(DebugContext context, int offset, int arrayDa private int writeArraySuperReference(DebugContext context, byte[] buffer, int p) { int pos = p; /* Arrays all inherit from java.lang.Object */ - String superName = "java.lang.Object"; - TypeEntry objectType = lookupType(superName); + TypeEntry objectType = lookupObjectClass(); + String superName = objectType.getTypeName(); + assert objectType != null; assert objectType instanceof ClassEntry; int superOffset = getLayoutIndex((ClassEntry) objectType); return writeSuperReference(context, superOffset, superName, buffer, pos); @@ -1296,7 +1296,7 @@ private int writeDeoptMethodsCU(DebugContext context, ClassEntry classEntry, byt return writeAttrNull(buffer, pos); } - private int writeMethodLocation(DebugContext context, ClassEntry classEntry, PrimaryEntry primaryEntry, byte[] buffer, int p) { + private int writeMethodLocation(DebugContext context, PrimaryEntry primaryEntry, byte[] buffer, int p) { int pos = p; Range primary = primaryEntry.getPrimary(); log(context, " [0x%08x] method location", pos); @@ -1313,7 +1313,7 @@ private int writeMethodLocation(DebugContext context, ClassEntry classEntry, Pri log(context, " [0x%08x] external true", pos); pos = writeFlag(DwarfDebugInfo.DW_FLAG_true, buffer, pos); String methodKey = primary.getSymbolName(); - int methodSpecOffset = getMethodDeclarationIndex(classEntry, methodKey); + int methodSpecOffset = getMethodDeclarationIndex(primary.getMethodEntry()); log(context, " [0x%08x] specification 0x%x (%s)", pos, methodSpecOffset, methodKey); pos = writeAttrRefAddr(methodSpecOffset, buffer, pos); HashMap> varRangeMap = primary.getVarRangeMap(); @@ -1420,7 +1420,7 @@ private int writeMethodLocalLocation(DebugContext context, Range range, DebugLoc return pos; } - private int writeAbstractInlineMethod(DebugContext context, ClassEntry classEntry, MethodEntry method, byte[] buffer, int p) { + private int writeAbstractInlineMethod(DebugContext context, MethodEntry method, byte[] buffer, int p) { int pos = p; String methodKey = method.getSymbolName(); log(context, " [0x%08x] abstract inline method %s", pos, method.getSymbolName()); @@ -1434,7 +1434,7 @@ private int writeAbstractInlineMethod(DebugContext context, ClassEntry classEntr */ log(context, " [0x%08x] external true", pos); pos = writeFlag(DwarfDebugInfo.DW_FLAG_true, buffer, pos); - int methodSpecOffset = getMethodDeclarationIndex(classEntry, methodKey); + int methodSpecOffset = getMethodDeclarationIndex(method); log(context, " [0x%08x] specification 0x%x (%s)", pos, methodSpecOffset, methodKey); pos = writeAttrRefAddr(methodSpecOffset, buffer, pos); /* @@ -1451,10 +1451,9 @@ private int writeInlineSubroutine(DebugContext context, Range caller, int depth, // identify the inlined method by looking at the first callee Range callee = caller.getFirstCallee(); MethodEntry methodEntry = callee.getMethodEntry(); - ClassEntry methodClassEntry = methodEntry.ownerType(); String methodKey = methodEntry.getSymbolName(); /* the abstract index was written in the method's class entry */ - int specificationIndex = getAbstractInlineMethodIndex(methodClassEntry, methodKey); + int specificationIndex = getAbstractInlineMethodIndex(methodEntry); int pos = p; log(context, " [0x%08x] concrete inline subroutine [0x%x, 0x%x] %s", pos, caller.getLo(), caller.getHi(), methodKey); 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 b16facf67b83..4ce7aeaf6c20 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 @@ -40,6 +40,7 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLocalValueInfo; import com.oracle.objectfile.elf.ELFMachine; import com.oracle.objectfile.elf.ELFObjectFile; +import jdk.vm.ci.meta.ResolvedJavaType; import org.graalvm.compiler.debug.DebugContext; import java.nio.ByteOrder; @@ -607,26 +608,30 @@ protected String uniqueDebugString(String str) { return dwarfSections.uniqueDebugString(str); } - protected TypeEntry lookupType(String typeName) { - return dwarfSections.lookupTypeEntry(typeName); + protected TypeEntry lookupType(ResolvedJavaType type) { + return dwarfSections.lookupTypeEntry(type); } - protected int getTypeIndex(String typeName) { + protected TypeEntry lookupObjectClass() { + return dwarfSections.lookupObjectClass(); + } + + protected int getTypeIndex(TypeEntry typeEntry) { if (!contentByteArrayCreated()) { return 0; } - return dwarfSections.getTypeIndex(typeName); + return dwarfSections.getTypeIndex(typeEntry); } protected void setTypeIndex(TypeEntry typeEntry, int pos) { dwarfSections.setTypeIndex(typeEntry, pos); } - protected int getIndirectTypeIndex(String typeName) { + protected int getIndirectTypeIndex(TypeEntry typeEntry) { if (!contentByteArrayCreated()) { return 0; } - return dwarfSections.getIndirectTypeIndex(typeName); + return dwarfSections.getIndirectTypeIndex(typeEntry); } protected void setIndirectTypeIndex(TypeEntry typeEntry, int pos) { @@ -721,26 +726,26 @@ protected int getFieldDeclarationIndex(StructureTypeEntry entry, String fieldNam return dwarfSections.getFieldDeclarationIndex(entry, fieldName); } - protected void setMethodDeclarationIndex(ClassEntry classEntry, String methodName, int pos) { - dwarfSections.setMethodDeclarationIndex(classEntry, methodName, pos); + protected void setMethodDeclarationIndex(MethodEntry methodEntry, int pos) { + dwarfSections.setMethodDeclarationIndex(methodEntry, pos); } - protected int getMethodDeclarationIndex(ClassEntry classEntry, String methodName) { + protected int getMethodDeclarationIndex(MethodEntry methodEntry) { if (!contentByteArrayCreated()) { return 0; } - return dwarfSections.getMethodDeclarationIndex(classEntry, methodName); + return dwarfSections.getMethodDeclarationIndex(methodEntry); } - protected void setAbstractInlineMethodIndex(ClassEntry classEntry, String methodName, int pos) { - dwarfSections.setAbstractInlineMethodIndex(classEntry, methodName, pos); + protected void setAbstractInlineMethodIndex(MethodEntry methodEntry, int pos) { + dwarfSections.setAbstractInlineMethodIndex(methodEntry, pos); } - protected int getAbstractInlineMethodIndex(ClassEntry classEntry, String methodName) { + protected int getAbstractInlineMethodIndex(MethodEntry methodEntry) { if (!contentByteArrayCreated()) { return 0; } - return dwarfSections.getAbstractInlineMethodIndex(classEntry, methodName); + return dwarfSections.getAbstractInlineMethodIndex(methodEntry); } protected void setMethodLocalIndex(MethodEntry methodEntry, DebugLocalInfo localInfo, int index) { 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 0121fb28006e..f0ea9563e5b0 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 @@ -68,7 +68,6 @@ import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.image.ImageHeapPartition; import com.oracle.svm.core.meta.SubstrateObjectConstant; -import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod; import com.oracle.svm.hosted.annotation.CustomSubstitutionType; import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.image.sources.SourceManager; @@ -108,6 +107,7 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.Value; +import java.util.HashMap; /** * Implementation of the DebugInfoProvider API interface that allows type, code and heap data info @@ -127,6 +127,8 @@ class NativeImageDebugInfoProvider implements DebugInfoProvider { int referenceStartOffset; private final Set allOverrides; HostedType wordBaseType; + HostedType hubType; + HashMap javaKindToHostedType; NativeImageDebugInfoProvider(DebugContext debugContext, NativeImageCodeCache codeCache, NativeImageHeap heap, HostedMetaAccess metaAccess) { super(); @@ -158,6 +160,28 @@ class NativeImageDebugInfoProvider implements DebugInfoProvider { .filter(Predicate.not(m::equals))) .collect(Collectors.toSet()); wordBaseType = metaAccess.lookupJavaType(WordBase.class); + hubType = metaAccess.lookupJavaType(Class.class); + javaKindToHostedType = initJavaKindToHostedTypes(metaAccess); + } + + private static HashMap initJavaKindToHostedTypes(HostedMetaAccess metaAccess) { + HashMap map = new HashMap<>(); + for (JavaKind kind : JavaKind.values()) { + Class clazz; + switch (kind) { + case Illegal: + clazz = null; + break; + case Object: + clazz = java.lang.Object.class; + break; + default: + clazz = kind.toJavaClass(); + } + HostedType javaType = clazz != null ? metaAccess.lookupJavaType(clazz) : null; + map.put(kind, javaType); + } + return map; } @Override @@ -259,7 +283,7 @@ protected static ResolvedJavaType getDeclaringClass(HostedMethod hostedMethod, b } // we want a substituted target if there is one. if there is a substitution at the end of // the method chain fetch the annotated target class - ResolvedJavaMethod javaMethod = getOriginal(hostedMethod); + ResolvedJavaMethod javaMethod = getAnnotatedOrOriginal(hostedMethod); return javaMethod.getDeclaringClass(); } @@ -284,30 +308,40 @@ private static ResolvedJavaType getOriginal(HostedType hostedType) { return javaType; } - private static ResolvedJavaMethod getOriginal(HostedMethod hostedMethod) { + private static ResolvedJavaMethod getAnnotatedOrOriginal(HostedMethod hostedMethod) { ResolvedJavaMethod javaMethod = hostedMethod.getWrapped().getWrapped(); + // This method is only used when identifying the modifiers or the declaring class + // of a HostedMethod. Normally the method unwraps to the underlying JVMCI method + // which is the one that provides bytecode to the compiler as well as, line numbers + // and local info. If we unwrap to a SubstitutionMethod then we use the annotated + // method, not the JVMCI method that the annotation refers to since that will be the + // one providing the bytecode etc used by the compiler. If we unwrap to any other, + // custom substitution method we simply use it rather than dereferencing to the + // original. The difference is that the annotated method's bytecode will be used to + // replace the original and the debugger needs to use it to identify the file and access + // permissions. A custom substitution may exist alongside the original, as is the case + // with some uses for reflection. So, we don't want to conflate the custom substituted + // method and the original. In this latter case the method code will be synthesized without + // reference to the bytecode of the original. Hence there is no associated file and the + // permissions need to be determined from the custom substitution method itself. + if (javaMethod instanceof SubstitutionMethod) { SubstitutionMethod substitutionMethod = (SubstitutionMethod) javaMethod; javaMethod = substitutionMethod.getAnnotated(); - } else if (javaMethod instanceof CustomSubstitutionMethod) { - javaMethod = ((CustomSubstitutionMethod) javaMethod).getOriginal(); } return javaMethod; } private static int getOriginalModifiers(HostedMethod hostedMethod) { - return getOriginal(hostedMethod).getModifiers(); - } - - private static String toJavaName(JavaType javaType) { - if (javaType instanceof HostedType) { - return getDeclaringClass((HostedType) javaType, true).toJavaName(); - } - return javaType.toJavaName(); + return getAnnotatedOrOriginal(hostedMethod).getModifiers(); } private final Path cachePath = SubstrateOptions.getDebugInfoSourceCacheRoot(); + private HostedType hostedTypeForKind(JavaKind kind) { + return javaKindToHostedType.get(kind); + } + private abstract class NativeImageDebugFileInfo implements DebugFileInfo { private final Path fullFilePath; @@ -410,6 +444,12 @@ public String toJavaName(@SuppressWarnings("hiding") HostedType hostedType) { return getDeclaringClass(hostedType, true).toJavaName(); } + @Override + public ResolvedJavaType idType() { + // always use the original type for establishing identity + return getOriginal(hostedType); + } + @Override public String typeName() { return toJavaName(hostedType); @@ -446,11 +486,17 @@ private class NativeImageHeaderTypeInfo implements DebugHeaderTypeInfo { this.fieldInfos = new LinkedList<>(); } - void addField(String name, String valueType, int offset, @SuppressWarnings("hiding") int size) { + void addField(String name, ResolvedJavaType valueType, int offset, @SuppressWarnings("hiding") int size) { NativeImageDebugHeaderFieldInfo fieldinfo = new NativeImageDebugHeaderFieldInfo(name, valueType, offset, size); fieldInfos.add(fieldinfo); } + @Override + public ResolvedJavaType idType() { + // The header type is unique in that it does not have an associated ResolvedJavaType + return null; + } + @SuppressWarnings("try") @Override public void debugContext(Consumer action) { @@ -499,12 +545,12 @@ public Stream fieldInfoProvider() { private class NativeImageDebugHeaderFieldInfo implements DebugFieldInfo { private final String name; - private final String valueType; + private final ResolvedJavaType valueType; private final int offset; private final int size; private final int modifiers; - NativeImageDebugHeaderFieldInfo(String name, String valueType, int offset, int size) { + NativeImageDebugHeaderFieldInfo(String name, ResolvedJavaType valueType, int offset, int size) { this.name = name; this.valueType = valueType; this.offset = offset; @@ -518,7 +564,10 @@ public String name() { } @Override - public String valueType() { + public ResolvedJavaType valueType() { + if (valueType instanceof HostedType) { + return getOriginal((HostedType) valueType); + } return valueType; } @@ -557,7 +606,6 @@ private Stream computeHeaderTypeInfo() { List infos = new LinkedList<>(); int hubOffset = getObjectLayout().getHubOffset(); int hubFieldSize = referenceSize; - String hubTypeName = "java.lang.Class"; int idHashOffset = getObjectLayout().getIdentityHashCodeOffset(); int idHashSize = getObjectLayout().sizeInBytes(JavaKind.Int); int objHeaderSize = getObjectLayout().getMinimumInstanceObjectSize(); @@ -565,9 +613,9 @@ private Stream computeHeaderTypeInfo() { /* We need array headers for all Java kinds */ NativeImageHeaderTypeInfo objHeader = new NativeImageHeaderTypeInfo("_objhdr", objHeaderSize); - objHeader.addField("hub", hubTypeName, hubOffset, hubFieldSize); + objHeader.addField("hub", hubType, hubOffset, hubFieldSize); if (idHashOffset > 0) { - objHeader.addField("idHash", "int", idHashOffset, idHashSize); + objHeader.addField("idHash", javaKindToHostedType.get(JavaKind.Int), idHashOffset, idHashSize); } infos.add(objHeader); @@ -618,22 +666,22 @@ public Stream methodInfoProvider() { } @Override - public String superName() { + public ResolvedJavaType superClass() { HostedClass superClass = hostedType.getSuperclass(); /* - * HostedType wraps an AnalysisType and both HostedType and AnalysisType punt calls to - * getSourceFilename to the wrapped class so for consistency we need to do the path - * lookup relative to the doubly unwrapped HostedType. + * Unwrap the hosted type's super class to the original to provide the correct identity + * type. */ if (superClass != null) { - return getDeclaringClass(superClass, true).toJavaName(); + return getOriginal(superClass); } return null; } @Override - public Stream interfaces() { - return Arrays.stream(hostedType.getInterfaces()).map(this::toJavaName); + public Stream interfaces() { + // map through getOriginal so we can use the result as an id type + return Arrays.stream(hostedType.getInterfaces()).map(interfaceType -> getOriginal(interfaceType)); } private NativeImageDebugFieldInfo createDebugFieldInfo(HostedField field) { @@ -662,9 +710,8 @@ public String name() { } @Override - public String valueType() { - HostedType valueType = field.getType(); - return toJavaName(valueType); + public ResolvedJavaType valueType() { + return getOriginal(field.getType()); } @Override @@ -740,10 +787,10 @@ private class NativeImageDebugArrayTypeInfo extends NativeImageDebugTypeInfo imp int arrayLengthSize = getObjectLayout().sizeInBytes(JavaKind.Int); assert arrayLengthOffset + arrayLengthSize <= headerSize; - addField("len", "int", arrayLengthOffset, arrayLengthSize); + addField("len", javaKindToHostedType.get(JavaKind.Int), arrayLengthOffset, arrayLengthSize); } - void addField(String name, String valueType, int offset, @SuppressWarnings("hiding") int size) { + void addField(String name, ResolvedJavaType valueType, int offset, @SuppressWarnings("hiding") int size) { NativeImageDebugHeaderFieldInfo fieldinfo = new NativeImageDebugHeaderFieldInfo(name, valueType, offset, size); fieldInfos.add(fieldinfo); } @@ -764,9 +811,9 @@ public int lengthOffset() { } @Override - public String elementType() { + public ResolvedJavaType elementType() { HostedType elementType = arrayClass.getComponentType(); - return toJavaName(elementType); + return getOriginal(elementType); } @Override @@ -881,6 +928,20 @@ private ResolvedJavaMethod promoteAnalysisToHosted(ResolvedJavaMethod m) { return m; } + private ResolvedJavaMethod originalMethod() { + // unwrap to an original method as far as we can + ResolvedJavaMethod targetMethod = method; + while (targetMethod instanceof WrappedJavaMethod) { + targetMethod = ((WrappedJavaMethod) targetMethod).getWrapped(); + } + // if we hit a substitution then we can translate to the original + // for identity otherwise we use whatever we unwrapped to. + if (targetMethod instanceof SubstitutionMethod) { + targetMethod = ((SubstitutionMethod) targetMethod).getOriginal(); + } + return targetMethod; + } + /** * Return the unique type that owns this method. *

@@ -931,17 +992,16 @@ public ResolvedJavaType ownerType() { return result; } + @Override + public ResolvedJavaMethod idMethod() { + // translating to the original ensures we equate a + // substituted method with the original in case we ever see both + return originalMethod(); + } + @Override public String name() { - ResolvedJavaMethod targetMethod = method; - while (targetMethod instanceof WrappedJavaMethod) { - targetMethod = ((WrappedJavaMethod) targetMethod).getWrapped(); - } - if (targetMethod instanceof SubstitutionMethod) { - targetMethod = ((SubstitutionMethod) targetMethod).getOriginal(); - } else if (targetMethod instanceof CustomSubstitutionMethod) { - targetMethod = ((CustomSubstitutionMethod) targetMethod).getOriginal(); - } + ResolvedJavaMethod targetMethod = originalMethod(); String name = targetMethod.getName(); if (name.equals("")) { if (method instanceof HostedMethod) { @@ -963,8 +1023,12 @@ public String name() { } @Override - public String valueType() { - return toJavaName(method.getSignature().getReturnType(null)); + public ResolvedJavaType valueType() { + ResolvedJavaType resultType = (ResolvedJavaType) method.getSignature().getReturnType(null); + if (resultType instanceof HostedType) { + return getOriginal((HostedType) resultType); + } + return resultType; } @Override @@ -2074,12 +2138,14 @@ public class NativeImageDebugLocalValueInfo implements DebugLocalValueInfo { this(name, Value.ILLEGAL, 0, kind, type, slot, line); } - NativeImageDebugLocalValueInfo(String name, JavaValue value, int framesize, JavaKind kind, ResolvedJavaType type, int slot, int line) { + NativeImageDebugLocalValueInfo(String name, JavaValue value, int framesize, JavaKind kind, ResolvedJavaType resolvedType, int slot, int line) { this.name = name; this.kind = kind; - this.type = type; this.slot = slot; this.line = line; + // if we don't have a type default it for the JavaKind + // it may still end up null when kind is Undefined. + this.type = (resolvedType != null ? resolvedType : hostedTypeForKind(kind)); if (value instanceof RegisterValue) { this.localKind = LocalKind.REGISTER; this.value = new NativeImageDebugRegisterValue((RegisterValue) value); @@ -2125,6 +2191,14 @@ public class NativeImageDebugLocalValueInfo implements DebugLocalValueInfo { this.value = value; } + @Override + public ResolvedJavaType valueType() { + if (type != null && type instanceof HostedType) { + return getOriginal((HostedType) type); + } + return type; + } + @Override public boolean equals(Object o) { if (!(o instanceof NativeImageDebugLocalValueInfo)) { @@ -2166,14 +2240,8 @@ public String name() { @Override public String typeName() { - if (type != null) { - return toJavaName(type); - } - if (kind == JavaKind.Object) { - return "java.lang.Object"; - } else { - return kind.getJavaName(); - } + ResolvedJavaType valueType = valueType(); + return (valueType == null ? "" : valueType().toJavaName()); } @Override