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 7dc4e567b0df..0e49c67a21be 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,7 +26,7 @@ package com.oracle.objectfile.debugentry; -import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFieldInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugMethodInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; @@ -35,9 +35,11 @@ import org.graalvm.compiler.debug.DebugContext; import java.nio.file.Path; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.ListIterator; import java.util.Map; /** @@ -51,7 +53,7 @@ public class ClassEntry extends StructureTypeEntry { /** * Details of this class's interfaces. */ - protected LinkedList interfaces; + protected List interfaces; /** * Details of the associated file. */ @@ -64,7 +66,7 @@ public class ClassEntry extends StructureTypeEntry { * A list recording details of all primary ranges included in this class sorted by ascending * address range. */ - private LinkedList primaryEntries; + private List primaryEntries; /** * An index identifying primary ranges which have already been encountered. */ @@ -76,7 +78,7 @@ public class ClassEntry extends StructureTypeEntry { /** * A list of the same files. */ - private LinkedList localFiles; + private List localFiles; /** * An index of all primary and secondary dirs referenced from this class's compilation unit. */ @@ -84,7 +86,7 @@ public class ClassEntry extends StructureTypeEntry { /** * A list of the same dirs. */ - private LinkedList localDirs; + private List localDirs; /** * This flag is true iff the entry includes methods that are deopt targets. */ @@ -92,14 +94,16 @@ public class ClassEntry extends StructureTypeEntry { public ClassEntry(String className, FileEntry fileEntry, int size) { super(className, size); - this.interfaces = new LinkedList<>(); + this.interfaces = new ArrayList<>(); this.fileEntry = fileEntry; + // methods is a sorted list and we want to be able to add more elements to it while keeping it sorted, + // so a LinkedList seems more appropriate than an ArrayList. (see getMethodEntry) this.methods = new LinkedList<>(); - this.primaryEntries = new LinkedList<>(); + this.primaryEntries = new ArrayList<>(); this.primaryIndex = new HashMap<>(); - this.localFiles = new LinkedList<>(); + this.localFiles = new ArrayList<>(); this.localFilesIndex = new HashMap<>(); - this.localDirs = new LinkedList<>(); + this.localDirs = new ArrayList<>(); this.localDirsIndex = new HashMap<>(); if (fileEntry != null) { localFiles.add(fileEntry); @@ -134,7 +138,9 @@ public void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInf /* Add details of fields and field types */ debugInstanceTypeInfo.fieldInfoProvider().forEach(debugFieldInfo -> this.processField(debugFieldInfo, debugInfoBase, debugContext)); /* Add details of methods and method types */ - debugInstanceTypeInfo.methodInfoProvider().forEach(methodFieldInfo -> this.processMethod(methodFieldInfo, debugInfoBase, debugContext)); + debugInstanceTypeInfo.methodInfoProvider().forEach(methodFieldInfo -> this.methods.add(this.processMethod(methodFieldInfo, debugInfoBase, debugContext))); + /* Sort methods to improve lookup speed */ + this.methods.sort(MethodEntry::compareTo); } public void indexPrimary(Range primary, List frameSizeInfos, int frameSize) { @@ -227,7 +233,7 @@ public FileEntry getFileEntry() { return fileEntry; } - public LinkedList getPrimaryEntries() { + public List getPrimaryEntries() { return primaryEntries; } @@ -236,11 +242,11 @@ public Object primaryIndexFor(Range primaryRange) { return primaryIndex.get(primaryRange); } - public LinkedList getLocalDirs() { + public List getLocalDirs() { return localDirs; } - public LinkedList getLocalFiles() { + public List getLocalFiles() { return localFiles; } @@ -267,7 +273,7 @@ private void processInterface(String interfaceName, DebugInfoBase debugInfoBase, interfaceClassEntry.addImplementor(this, debugContext); } - protected void processMethod(DebugMethodInfo debugMethodInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) { + protected MethodEntry processMethod(DebugMethodInfo debugMethodInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) { String methodName = debugInfoBase.uniqueDebugString(debugMethodInfo.name()); String resultTypeName = TypeEntry.canonicalize(debugMethodInfo.valueType()); int modifiers = debugMethodInfo.modifiers(); @@ -294,11 +300,11 @@ protected void processMethod(DebugMethodInfo debugMethodInfo, DebugInfoBase debu * substitution */ FileEntry methodFileEntry = debugInfoBase.ensureFileEntry(fileName, filePath, cachePath); - methods.add(new MethodEntry(methodFileEntry, methodName, this, resultType, paramTypeArray, paramNameArray, modifiers)); + return new MethodEntry(methodFileEntry, methodName, this, resultType, paramTypeArray, paramNameArray, modifiers, debugMethodInfo.isDeoptTarget()); } @Override - protected FieldEntry addField(DebugInfoProvider.DebugFieldInfo debugFieldInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) { + protected FieldEntry addField(DebugFieldInfo debugFieldInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) { FieldEntry fieldEntry = super.addField(debugFieldInfo, debugInfoBase, debugContext); FileEntry fieldFileEntry = fieldEntry.getFileEntry(); if (fieldFileEntry != null) { @@ -335,27 +341,39 @@ public ClassEntry getSuperClass() { return superClass; } - public Range makePrimaryRange(String methodName, String symbolName, String paramSignature, String returnTypeName, StringTable stringTable, FileEntry primaryFileEntry, int lo, - int hi, int primaryLine, - int modifiers, boolean isDeoptTarget) { - FileEntry fileEntryToUse = primaryFileEntry; + public Range makePrimaryRange(String symbolName, StringTable stringTable, MethodEntry method, int lo, int hi, int primaryLine) { + FileEntry fileEntryToUse = method.fileEntry; if (fileEntryToUse == null) { - /* - * Search for a matching method to supply the file entry or failing that use the one - * from this class. - */ - for (MethodEntry methodEntry : methods) { - if (methodEntry.match(methodName, paramSignature, returnTypeName)) { - /* maybe the method's file entry */ - fileEntryToUse = methodEntry.getFileEntry(); - break; - } - } - if (fileEntryToUse == null) { - /* Last chance is the class's file entry. */ - fileEntryToUse = this.fileEntry; + /* Last chance is the class's file entry. */ + fileEntryToUse = this.fileEntry; + } + return new Range(symbolName, stringTable, method, fileEntryToUse, lo, hi, primaryLine); + } + + public MethodEntry getMethodEntry(DebugMethodInfo debugMethodInfo, DebugInfoBase debugInfoBase, DebugContext debugContext) { + assert listIsSorted(methods); + String methodName = debugInfoBase.uniqueDebugString(debugMethodInfo.name()); + String paramSignature = debugMethodInfo.paramSignature(); + String returnTypeName = debugMethodInfo.valueType(); + ListIterator methodIterator = methods.listIterator(); + while (methodIterator.hasNext()) { + MethodEntry methodEntry = methodIterator.next(); + int comparisonResult = methodEntry.compareTo(methodName, paramSignature, returnTypeName); + if (comparisonResult == 0) { + return methodEntry; + } else if (comparisonResult > 0) { + methodIterator.previous(); + break; } } - return new Range(this.typeName, methodName, symbolName, paramSignature, returnTypeName, stringTable, fileEntryToUse, lo, hi, primaryLine, modifiers, isDeoptTarget); + MethodEntry newMethodEntry = processMethod(debugMethodInfo, debugInfoBase, debugContext); + methodIterator.add(newMethodEntry); + return newMethodEntry; + } + + private static boolean listIsSorted(List list) { + List copy = new ArrayList<>(list); + copy.sort(MethodEntry::compareTo); + return list.equals(copy); } } 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 3a4117403b3e..b15cd4e1860d 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,8 +29,9 @@ import java.nio.ByteOrder; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; +import java.util.List; import java.util.Map; import org.graalvm.compiler.debug.DebugContext; @@ -89,7 +90,7 @@ public abstract class DebugInfoBase { /** * List of class entries detailing class info for primary ranges. */ - private LinkedList types = new LinkedList<>(); + private List types = new ArrayList<>(); /** * index of already seen classes. */ @@ -97,7 +98,7 @@ public abstract class DebugInfoBase { /** * List of class entries detailing class info for primary ranges. */ - private LinkedList primaryClasses = new LinkedList<>(); + private List primaryClasses = new ArrayList<>(); /** * index of already seen classes. */ @@ -109,7 +110,7 @@ public abstract class DebugInfoBase { /** * List of of files which contain primary or secondary ranges. */ - private LinkedList files = new LinkedList<>(); + private List files = new ArrayList<>(); /** * Flag set to true if heap references are stored as addresses relative to a heap base register * otherwise false. @@ -236,40 +237,35 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { */ String fileName = debugCodeInfo.fileName(); Path filePath = debugCodeInfo.filePath(); - Path cachePath = debugCodeInfo.cachePath(); - String className = TypeEntry.canonicalize(debugCodeInfo.className()); - String methodName = debugCodeInfo.methodName(); + String className = TypeEntry.canonicalize(debugCodeInfo.ownerType()); + String methodName = debugCodeInfo.name(); String symbolName = debugCodeInfo.symbolNameForMethod(); - String paramSignature = debugCodeInfo.paramSignature(); - String returnTypeName = TypeEntry.canonicalize(debugCodeInfo.returnTypeName()); int lo = debugCodeInfo.addressLo(); int hi = debugCodeInfo.addressHi(); int primaryLine = debugCodeInfo.line(); - boolean isDeoptTarget = debugCodeInfo.isDeoptTarget(); - int modifiers = debugCodeInfo.getModifiers(); /* Search for a method defining this primary range. */ ClassEntry classEntry = ensureClassEntry(className); - FileEntry fileEntry = ensureFileEntry(fileName, filePath, cachePath); - Range primaryRange = classEntry.makePrimaryRange(methodName, symbolName, paramSignature, returnTypeName, stringTable, fileEntry, lo, hi, primaryLine, modifiers, isDeoptTarget); + MethodEntry methodEntry = classEntry.getMethodEntry(debugCodeInfo, this, debugContext); + Range primaryRange = classEntry.makePrimaryRange(symbolName, stringTable, methodEntry, lo, hi, primaryLine); debugContext.log(DebugContext.INFO_LEVEL, "PrimaryRange %s.%s %s %s:%d [0x%x, 0x%x]", className, methodName, filePath, fileName, primaryLine, lo, hi); classEntry.indexPrimary(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { String fileNameAtLine = debugLineInfo.fileName(); Path filePathAtLine = debugLineInfo.filePath(); - String classNameAtLine = TypeEntry.canonicalize(debugLineInfo.className()); - String methodNameAtLine = debugLineInfo.methodName(); + String classNameAtLine = TypeEntry.canonicalize(debugLineInfo.ownerType()); + String methodNameAtLine = debugLineInfo.name(); String symbolNameAtLine = debugLineInfo.symbolNameForMethod(); int loAtLine = lo + debugLineInfo.addressLo(); int hiAtLine = lo + debugLineInfo.addressHi(); int line = debugLineInfo.line(); - Path cachePathAtLine = debugLineInfo.cachePath(); /* * 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. */ - FileEntry subFileEntry = ensureFileEntry(fileNameAtLine, filePathAtLine, cachePathAtLine); - Range subRange = new Range(classNameAtLine, methodNameAtLine, symbolNameAtLine, stringTable, subFileEntry, loAtLine, hiAtLine, line, primaryRange); + ClassEntry subClassEntry = ensureClassEntry(classNameAtLine); + MethodEntry subMethodEntry = subClassEntry.getMethodEntry(debugLineInfo, this, debugContext); + Range subRange = new Range(symbolNameAtLine, stringTable, subMethodEntry, loAtLine, hiAtLine, line, primaryRange); classEntry.indexSubRange(subRange); try (DebugContext.Scope s = debugContext.scope("Subranges")) { debugContext.log(DebugContext.VERBOSE_LEVEL, "SubRange %s.%s %s %s:%d 0x%x, 0x%x]", classNameAtLine, methodNameAtLine, filePathAtLine, fileNameAtLine, line, loAtLine, hiAtLine); @@ -431,16 +427,16 @@ public ByteOrder getByteOrder() { return byteOrder; } - public LinkedList getTypes() { + public List getTypes() { return types; } - public LinkedList getPrimaryClasses() { + public List getPrimaryClasses() { return primaryClasses; } @SuppressWarnings("unused") - public LinkedList getFiles() { + public List getFiles() { return files; } 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 9b929ca6332d..9318a068b235 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 @@ -31,7 +31,7 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; import org.graalvm.compiler.debug.DebugContext; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; @@ -40,7 +40,7 @@ public class InterfaceClassEntry extends ClassEntry { public InterfaceClassEntry(String className, FileEntry fileEntry, int size) { super(className, fileEntry, size); - implementors = new LinkedList<>(); + implementors = new ArrayList<>(); } @Override 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 7b84995d6cd5..cca95588a76e 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,16 +26,18 @@ package com.oracle.objectfile.debugentry; -public class MethodEntry extends MemberEntry { - TypeEntry[] paramTypes; - String[] paramNames; +public class MethodEntry extends MemberEntry implements Comparable { + final TypeEntry[] paramTypes; + final String[] paramNames; + final boolean isDeoptTarget; - public MethodEntry(FileEntry fileEntry, String methodName, ClassEntry ownerType, TypeEntry valueType, TypeEntry[] paramTypes, String[] paramNames, int modifiers) { + public MethodEntry(FileEntry fileEntry, String methodName, ClassEntry ownerType, TypeEntry valueType, TypeEntry[] paramTypes, String[] paramNames, int modifiers, boolean isDeoptTarget) { super(fileEntry, methodName, ownerType, valueType, modifiers); assert ((paramTypes == null && paramNames == null) || (paramTypes != null && paramNames != null && paramTypes.length == paramNames.length)); this.paramTypes = paramTypes; this.paramNames = paramNames; + this.isDeoptTarget = isDeoptTarget; } public String methodName() { @@ -72,26 +74,60 @@ public String getParamName(int idx) { return paramNames[idx]; } - public boolean match(String methodName, String paramSignature, String returnTypeName) { - if (!methodName.equals(this.memberName)) { - return false; + public int compareTo(String methodName, String paramSignature, String returnTypeName) { + int nameComparison = memberName.compareTo(methodName); + if (nameComparison != 0) { + return nameComparison; } - if (!returnTypeName.equals(valueType.getTypeName())) { - return false; - } - int paramCount = getParamCount(); - if (paramCount == 0) { - return paramSignature.trim().length() == 0; + int typeComparison = valueType.getTypeName().compareTo(returnTypeName); + if (typeComparison != 0) { + return typeComparison; } String[] paramTypeNames = paramSignature.split((",")); - if (paramCount != paramTypeNames.length) { - return false; + int length; + if (paramSignature.trim().length() == 0) { + length = 0; + } else { + length = paramTypeNames.length; + } + int paramCountComparison = getParamCount() - length; + if (paramCountComparison != 0) { + return paramCountComparison; + } + for (int i = 0; i < getParamCount(); i++) { + int paraComparison = getParamTypeName(i).compareTo(paramTypeNames[i].trim()); + if (paraComparison != 0) { + return paraComparison; + } + } + return 0; + } + + public boolean isDeoptTarget() { + return isDeoptTarget; + } + + @Override + public int compareTo(MethodEntry other) { + assert other != null; + int nameComparison = methodName().compareTo(other.methodName()); + if (nameComparison != 0) { + return nameComparison; + } + int typeComparison = valueType.getTypeName().compareTo(other.valueType.getTypeName()); + if (typeComparison != 0) { + return typeComparison; + } + int paramCountComparison = getParamCount() - other.getParamCount(); + if (paramCountComparison != 0) { + return paramCountComparison; } - for (int i = 0; i < paramCount; i++) { - if (!paramTypeNames[i].trim().equals(getParamTypeName(i))) { - return false; + for (int i = 0; i < getParamCount(); i++) { + int paramComparison = getParamTypeName(i).compareTo(other.getParamTypeName(i)); + if (paramComparison != 0) { + return paramComparison; } } - return true; + return 0; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java index 53aaa5a2b7d6..c61e3428d140 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java @@ -28,7 +28,7 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; /** @@ -59,7 +59,7 @@ public class PrimaryEntry { public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { this.primary = primary; this.classEntry = classEntry; - this.subranges = new LinkedList<>(); + this.subranges = new ArrayList<>(); this.frameSizeInfos = frameSizeInfos; this.frameSize = frameSize; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index 9834420f2915..dd82d22565b1 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -34,62 +34,49 @@ public class Range { private static final String CLASS_DELIMITER = "."; - private FileEntry fileEntry; - private String className; - private String methodName; - private String symbolName; - private String paramSignature; - private String returnTypeName; - private String fullMethodName; - private String fullMethodNameWithParams; - private int lo; - private int hi; - private int line; - private boolean isDeoptTarget; - private int modifiers; + private final FileEntry fileEntry; + private MethodEntry methodEntry; + private final String symbolName; + private final String fullMethodNameWithParams; + private final int lo; + private final int hi; + private final int line; /* * This is null for a primary range. */ - private Range primary; + private final Range primary; /* * Create a primary range. */ - public Range(String className, String methodName, String symbolName, String paramSignature, String returnTypeName, StringTable stringTable, FileEntry fileEntry, int lo, int hi, int line, - int modifiers, boolean isDeoptTarget) { - this(className, methodName, symbolName, paramSignature, returnTypeName, stringTable, fileEntry, lo, hi, line, modifiers, isDeoptTarget, null); + public Range(String symbolName, StringTable stringTable, MethodEntry methodEntry, FileEntry fileEntry, int lo, int hi, int line) { + this(symbolName, stringTable, methodEntry, fileEntry, lo, hi, line, null); } /* * Create a secondary range. */ - public Range(String className, String methodName, String symbolName, StringTable stringTable, FileEntry fileEntry, int lo, int hi, int line, - Range primary) { - this(className, methodName, symbolName, "", "", stringTable, fileEntry, lo, hi, line, 0, false, primary); + public Range(String symbolName, StringTable stringTable, MethodEntry methodEntry, int lo, int hi, int line, Range primary) { + this(symbolName, stringTable, methodEntry, methodEntry.fileEntry, lo, hi, line, primary); } /* * Create a primary or secondary range. */ - private Range(String className, String methodName, String symbolName, String paramSignature, String returnTypeName, StringTable stringTable, FileEntry fileEntry, int lo, int hi, int line, - int modifiers, boolean isDeoptTarget, Range primary) { + private Range(String symbolName, StringTable stringTable, MethodEntry methodEntry, FileEntry fileEntry, int lo, int hi, int line, + Range primary) { this.fileEntry = fileEntry; if (fileEntry != null) { stringTable.uniqueDebugString(fileEntry.getFileName()); stringTable.uniqueDebugString(fileEntry.getPathName()); } - this.className = stringTable.uniqueString(className); - this.methodName = stringTable.uniqueString(methodName); + assert methodEntry != null; + this.methodEntry = methodEntry; this.symbolName = stringTable.uniqueString(symbolName); - this.paramSignature = stringTable.uniqueString(paramSignature); - this.returnTypeName = stringTable.uniqueString(returnTypeName); - this.fullMethodName = stringTable.uniqueString(constructClassAndMethodName()); this.fullMethodNameWithParams = stringTable.uniqueString(constructClassAndMethodNameWithParams()); this.lo = lo; this.hi = hi; this.line = line; - this.isDeoptTarget = isDeoptTarget; - this.modifiers = modifiers; this.primary = primary; } @@ -106,11 +93,11 @@ public Range getPrimary() { } public String getClassName() { - return className; + return methodEntry.ownerType.typeName; } public String getMethodName() { - return methodName; + return methodEntry.memberName; } public String getSymbolName() { @@ -130,7 +117,7 @@ public int getLine() { } public String getFullMethodName() { - return fullMethodName; + return constructClassAndMethodName(); } public String getFullMethodNameWithParams() { @@ -138,28 +125,28 @@ public String getFullMethodNameWithParams() { } public boolean isDeoptTarget() { - return isDeoptTarget; + return methodEntry.isDeoptTarget; } private String getExtendedMethodName(boolean includeClass, boolean includeParams, boolean includeReturnType) { StringBuilder builder = new StringBuilder(); - if (includeReturnType && returnTypeName.length() > 0) { - builder.append(returnTypeName); + if (includeReturnType && methodEntry.valueType.typeName.length() > 0) { + builder.append(methodEntry.valueType.typeName); builder.append(' '); } - if (includeClass && className != null) { - builder.append(className); + if (includeClass && getClassName() != null) { + builder.append(getClassName()); builder.append(CLASS_DELIMITER); } - builder.append(methodName); + builder.append(getMethodName()); if (includeParams) { builder.append('('); - builder.append(paramSignature); + builder.append(String.join(", ", methodEntry.paramNames)); builder.append(')'); } if (includeReturnType) { builder.append(" "); - builder.append(returnTypeName); + builder.append(methodEntry.valueType.typeName); } return builder.toString(); } @@ -173,23 +160,19 @@ private String constructClassAndMethodNameWithParams() { } public String getMethodReturnTypeName() { - return returnTypeName; + return methodEntry.valueType.typeName; } - public String getParamSignature() { - return paramSignature; + public TypeEntry[] getParamTypes() { + return methodEntry.paramTypes; } public FileEntry getFileEntry() { return fileEntry; } - public void setFileEntry(FileEntry fileEntry) { - this.fileEntry = fileEntry; - } - public int getModifiers() { - return modifiers; + return methodEntry.modifiers; } @Override 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 dcc80a0eb71f..d678b09029a8 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 @@ -31,7 +31,7 @@ import java.lang.reflect.Modifier; import java.nio.file.Path; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; @@ -47,7 +47,7 @@ public abstract class StructureTypeEntry extends TypeEntry { public StructureTypeEntry(String typeName, int size) { super(typeName, size); - this.fields = new LinkedList<>(); + this.fields = new ArrayList<>(); } public Stream fields() { 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 e98b94c817a8..5c5729de8eb2 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 @@ -201,32 +201,38 @@ interface DebugFieldInfo extends DebugMemberInfo { } interface DebugMethodInfo extends DebugMemberInfo { - List paramTypes(); - - List paramNames(); - } - - /** - * Access details of a specific compiled method. - */ - interface DebugCodeInfo extends DebugFileInfo { - void debugContext(Consumer action); + /** + * @return a string identifying the method parameters. + */ + String paramSignature(); /** - * @return the fully qualified name of the class owning the compiled method. + * @return an array of Strings identifying the method parameters. */ - String className(); + List paramTypes(); /** - * @return the name of the compiled method including signature. + * @return an array of Strings with the method parameters' names. */ - String methodName(); + List paramNames(); /** * @return the symbolNameForMethod string */ String symbolNameForMethod(); + /** + * @return true if this method has been compiled in as a deoptimization target + */ + boolean isDeoptTarget(); + } + + /** + * Access details of a specific compiled method. + */ + interface DebugCodeInfo extends DebugMethodInfo { + void debugContext(Consumer action); + /** * @return the lowest address containing code generated for the method represented as an * offset into the code segment. @@ -250,16 +256,6 @@ interface DebugCodeInfo extends DebugFileInfo { */ Stream lineInfoProvider(); - /** - * @return a string identifying the method parameters. - */ - String paramSignature(); - - /** - * @return a string identifying the method return type. - */ - String returnTypeName(); - /** * @return the size of the method frame between prologue and epilogue. */ @@ -270,13 +266,6 @@ interface DebugCodeInfo extends DebugFileInfo { * to an empty frame */ List getFrameSizeChanges(); - - /** - * @return true if this method has been compiled in as a deoptimization target - */ - boolean isDeoptTarget(); - - int getModifiers(); } /** @@ -302,22 +291,7 @@ interface DebugDataInfo { * Access details of code generated for a specific outer or inlined method at a given line * number. */ - interface DebugLineInfo extends DebugFileInfo { - /** - * @return the fully qualified name of the class owning the outer or inlined method. - */ - String className(); - - /** - * @return the name of the outer or inlined method including signature. - */ - String methodName(); - - /** - * @return the symbolNameForMethod string - */ - String symbolNameForMethod(); - + interface DebugLineInfo extends DebugMethodInfo { /** * @return the lowest address containing code generated for an outer or inlined code segment * reported at this line represented as an offset into the code segment. 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 02fad181804b..e24cda20f423 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 @@ -34,7 +34,7 @@ import com.oracle.objectfile.debugentry.Range; import org.graalvm.compiler.debug.DebugContext; -import java.util.LinkedList; +import java.util.List; import java.util.Map; /** @@ -102,7 +102,7 @@ public void createContent() { * Align to 2 * address size. */ pos += DW_AR_HEADER_PAD_SIZE; - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + List classPrimaryEntries = classEntry.getPrimaryEntries(); if (classEntry.includesDeoptTarget()) { /* Deopt targets are in a higher address range so delay emit for them. */ for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) { @@ -123,7 +123,7 @@ public void createContent() { * Align to 2 * address size. */ pos += DW_AR_HEADER_PAD_SIZE; - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + List classPrimaryEntries = classEntry.getPrimaryEntries(); for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) { if (classPrimaryEntry.getPrimary().isDeoptTarget()) { pos += 2 * 8; @@ -167,7 +167,7 @@ public void writeContent(DebugContext context) { int lastpos = pos; int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; int cuIndex = getCUIndex(classEntry); - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + List classPrimaryEntries = classEntry.getPrimaryEntries(); /* * Count only real methods, omitting deopt targets. */ @@ -218,7 +218,7 @@ public void writeContent(DebugContext context) { int lastpos = pos; int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; int cuIndex = getDeoptCUIndex(classEntry); - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + List classPrimaryEntries = classEntry.getPrimaryEntries(); /* * Count only linkage stubs. */ 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 4f501d4738dd..00e88b8626d7 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 @@ -27,7 +27,7 @@ package com.oracle.objectfile.elf.dwarf; import java.lang.reflect.Modifier; -import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; @@ -439,7 +439,7 @@ private int writePrimaryClassUnit(DebugContext context, ClassEntry classEntry, b String compilationDirectory = classEntry.getCachePath(); log(context, " [0x%08x] comp_dir 0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory); pos = writeAttrStrp(compilationDirectory, buffer, pos); - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + List classPrimaryEntries = classEntry.getPrimaryEntries(); /* * Specify hi and lo for the compile unit which means we also need to ensure methods within * it are listed in ascending address order. @@ -654,7 +654,7 @@ private int writeField(DebugContext context, StructureTypeEntry entry, FieldEntr private int writeMethodDeclarations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + List classPrimaryEntries = classEntry.getPrimaryEntries(); for (PrimaryEntry primaryEntry : classPrimaryEntries) { Range range = primaryEntry.getPrimary(); /* @@ -724,18 +724,14 @@ private int writeMethodParameterDeclarations(DebugContext context, ClassEntry cl if (!Modifier.isStatic(range.getModifiers())) { pos = writeMethodParameterDeclaration(context, "this", classEntry.getTypeName(), true, isSpecification, buffer, pos); } - String paramsString = range.getParamSignature(); - if (!paramsString.isEmpty()) { - String[] paramTypes = paramsString.split(","); - for (int i = 0; i < paramTypes.length; i++) { - String paramName = uniqueDebugString(""); - String paramTypeName = paramTypes[i].trim(); - FileEntry fileEntry = range.getFileEntry(); - if (fileEntry != null) { - pos = writeMethodParameterDeclaration(context, paramName, paramTypeName, false, isSpecification, buffer, pos); - } else { - pos = writeMethodParameterDeclaration(context, paramTypeName, paramTypeName, false, isSpecification, buffer, pos); - } + for (TypeEntry paramType : range.getParamTypes()) { + String paramTypeName = paramType.getTypeName(); + String paramName = uniqueDebugString(""); + FileEntry fileEntry = range.getFileEntry(); + if (fileEntry != null) { + pos = writeMethodParameterDeclaration(context, paramName, paramTypeName, false, isSpecification, buffer, pos); + } else { + pos = writeMethodParameterDeclaration(context, paramTypeName, paramTypeName, false, isSpecification, buffer, pos); } } return pos; @@ -917,7 +913,7 @@ private int writeInterfaceType(DebugContext context, InterfaceClassEntry interfa private int writeMethodLocations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + List classPrimaryEntries = classEntry.getPrimaryEntries(); for (PrimaryEntry primaryEntry : classPrimaryEntries) { Range range = primaryEntry.getPrimary(); if (!range.isDeoptTarget()) { @@ -1185,7 +1181,7 @@ private int writeArrayTypes(DebugContext context, ArrayTypeEntry arrayTypeEntry, private int writeDeoptMethodsCU(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; assert classEntry.includesDeoptTarget(); - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + List classPrimaryEntries = classEntry.getPrimaryEntries(); String fileName = classEntry.getFileName(); int lineIndex = getLineIndex(classEntry); int abbrevCode = (fileName.length() > 0 ? DwarfDebugInfo.DW_ABBREV_CODE_class_unit1 : DwarfDebugInfo.DW_ABBREV_CODE_class_unit2); @@ -1270,10 +1266,10 @@ private int writeCUHeader(byte[] buffer, int p) { } } - private static int findLo(LinkedList classPrimaryEntries, boolean isDeoptTargetCU) { + private static int findLo(List classPrimaryEntries, boolean isDeoptTargetCU) { if (!isDeoptTargetCU) { /* First entry is the one we want. */ - return classPrimaryEntries.getFirst().getPrimary().getLo(); + return classPrimaryEntries.get(0).getPrimary().getLo(); } else { /* Need the first entry which is a deopt target. */ for (PrimaryEntry primaryEntry : classPrimaryEntries) { @@ -1288,10 +1284,10 @@ private static int findLo(LinkedList classPrimaryEntries, boolean return 0; } - private static int findHi(LinkedList classPrimaryEntries, boolean includesDeoptTarget, boolean isDeoptTargetCU) { + private static int findHi(List classPrimaryEntries, boolean includesDeoptTarget, boolean isDeoptTargetCU) { if (isDeoptTargetCU || !includesDeoptTarget) { /* Either way the last entry is the one we want. */ - return classPrimaryEntries.getLast().getPrimary().getHi(); + return classPrimaryEntries.get(classPrimaryEntries.size() - 1).getPrimary().getHi(); } else { /* Need the last entry which is not a deopt target. */ int hi = 0; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java index a644b10ec30e..2c75d3df49ec 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 @@ -30,12 +30,14 @@ import java.lang.reflect.Modifier; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.function.Consumer; import java.util.stream.Stream; +import jdk.vm.ci.meta.JavaType; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.core.common.CompressEncoding; @@ -250,6 +252,13 @@ private static ResolvedJavaType getOriginal(ResolvedJavaType javaType) { return null; } + private static String toJavaName(JavaType javaType) { + if (javaType instanceof HostedType) { + return getJavaType((HostedType) javaType, true).toJavaName(); + } + return javaType.toJavaName(); + } + private final Path cachePath = SubstrateOptions.getDebugInfoSourceCacheRoot(); private abstract class NativeImageDebugFileInfo implements DebugFileInfo { @@ -679,11 +688,17 @@ public String valueType() { return hostedMethod.getSignature().getReturnType(null).toJavaName(); } + @Override + public String paramSignature() { + return hostedMethod.format("%P"); + } + @Override public List paramTypes() { - LinkedList paramTypes = new LinkedList<>(); Signature signature = hostedMethod.getSignature(); - for (int i = 0; i < signature.getParameterCount(false); i++) { + int parameterCount = signature.getParameterCount(false); + List paramTypes = new ArrayList<>(parameterCount); + for (int i = 0; i < parameterCount; i++) { paramTypes.add(signature.getParameterType(i, null).toJavaName()); } return paramTypes; @@ -692,14 +707,25 @@ public List paramTypes() { @Override public List paramNames() { /* Can only provide blank names for now. */ - LinkedList paramNames = new LinkedList<>(); Signature signature = hostedMethod.getSignature(); - for (int i = 0; i < signature.getParameterCount(false); i++) { + int parameterCount = signature.getParameterCount(false); + List paramNames = new ArrayList<>(parameterCount); + for (int i = 0; i < parameterCount; i++) { paramNames.add(""); } return paramNames; } + @Override + public String symbolNameForMethod() { + return NativeImage.localSymbolNameForMethod(hostedMethod); + } + + @Override + public boolean isDeoptTarget() { + return hostedMethod.isDeoptTarget(); + } + @Override public int modifiers() { return hostedMethod.getModifiers(); @@ -858,12 +884,12 @@ public void debugContext(Consumer action) { } @Override - public String className() { + public String ownerType() { return getJavaType(hostedMethod, true).toJavaName(); } @Override - public String methodName() { + public String name() { ResolvedJavaMethod targetMethod = hostedMethod.getWrapped().getWrapped(); if (targetMethod instanceof SubstitutionMethod) { targetMethod = ((SubstitutionMethod) targetMethod).getOriginal(); @@ -894,7 +920,7 @@ public String paramSignature() { } @Override - public String returnTypeName() { + public String valueType() { return hostedMethod.format("%R"); } @@ -958,11 +984,35 @@ public List getFrameSizeChanges() { @Override public boolean isDeoptTarget() { - return methodName().endsWith(HostedMethod.METHOD_NAME_DEOPT_SUFFIX); + return hostedMethod.isDeoptTarget(); } @Override - public int getModifiers() { + public List paramTypes() { + Signature signature = hostedMethod.getSignature(); + int parameterCount = signature.getParameterCount(false); + List paramTypes = new ArrayList<>(parameterCount); + for (int i = 0; i < parameterCount; i++) { + JavaType parameterType = signature.getParameterType(i, null); + paramTypes.add(toJavaName(parameterType)); + } + return paramTypes; + } + + @Override + public List paramNames() { + /* Can only provide blank names for now. */ + Signature signature = hostedMethod.getSignature(); + int parameterCount = signature.getParameterCount(false); + List paramNames = new ArrayList<>(parameterCount); + for (int i = 0; i < parameterCount; i++) { + paramNames.add(""); + } + return paramNames; + } + + @Override + public int modifiers() { return hostedMethod.getModifiers(); } } @@ -1022,12 +1072,16 @@ public Path cachePath() { } @Override - public String className() { - return method.format("%H"); + public String ownerType() { + if (method instanceof HostedMethod) { + return getJavaType((HostedMethod) method, true).toJavaName(); + } else { + return method.getDeclaringClass().toJavaName(); + } } @Override - public String methodName() { + public String name() { ResolvedJavaMethod targetMethod = method; while (targetMethod instanceof WrappedJavaMethod) { targetMethod = ((WrappedJavaMethod) targetMethod).getWrapped(); @@ -1057,11 +1111,29 @@ public String methodName() { return name; } + @Override + public String valueType() { + return method.format("%R"); + } + + @Override + public String paramSignature() { + return method.format("%P"); + } + @Override public String symbolNameForMethod() { return NativeImage.localSymbolNameForMethod(method); } + @Override + public boolean isDeoptTarget() { + if (method instanceof HostedMethod) { + return ((HostedMethod) method).isDeoptTarget(); + } + return name().endsWith(HostedMethod.METHOD_NAME_DEOPT_SUFFIX); + } + @Override public int addressLo() { return lo; @@ -1081,6 +1153,35 @@ public int line() { return -1; } + @Override + public List paramTypes() { + Signature signature = method.getSignature(); + int parameterCount = signature.getParameterCount(false); + List paramTypes = new ArrayList<>(parameterCount); + for (int i = 0; i < parameterCount; i++) { + JavaType parameterType = signature.getParameterType(i, null); + paramTypes.add(toJavaName(parameterType)); + } + return paramTypes; + } + + @Override + public List paramNames() { + /* Can only provide blank names for now. */ + Signature signature = method.getSignature(); + int parameterCount = signature.getParameterCount(false); + List paramNames = new ArrayList<>(parameterCount); + for (int i = 0; i < parameterCount; i++) { + paramNames.add(""); + } + return paramNames; + } + + @Override + public int modifiers() { + return method.getModifiers(); + } + @SuppressWarnings("try") private void computeFullFilePath() { ResolvedJavaType declaringClass = method.getDeclaringClass();