Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport][22.3] c++ compatible mangling support #5333

Merged
merged 7 commits into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 70 additions & 66 deletions substratevm/mx.substratevm/testhello.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,15 @@ public void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInf
public TypeEntry getElementType() {
return elementType;
}

public String getLoaderId() {
TypeEntry type = elementType;
while (type.isArray()) {
type = ((ArrayTypeEntry) type).elementType;
}
if (type.isClass()) {
return ((ClassEntry) type).getLoaderId();
}
return "";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ public class ClassEntry extends StructureTypeEntry {
* Details of the associated file.
*/
private FileEntry fileEntry;
/**
* Details of the associated loader.
*/
private LoaderEntry loader;
/**
* Details of methods located in this instance.
*/
Expand Down Expand Up @@ -108,6 +112,7 @@ public ClassEntry(String className, FileEntry fileEntry, int size) {
super(className, size);
this.interfaces = new ArrayList<>();
this.fileEntry = fileEntry;
this.loader = null;
this.methods = new ArrayList<>();
this.methodsIndex = new HashMap<>();
this.normalCompiledEntries = new ArrayList<>();
Expand Down Expand Up @@ -150,6 +155,10 @@ public void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInf
if (superType != null) {
this.superClass = debugInfoBase.lookupClassEntry(superType);
}
String loaderName = debugInstanceTypeInfo.loaderName();
if (!loaderName.isEmpty()) {
this.loader = debugInfoBase.ensureLoaderEntry(loaderName);
}
debugInstanceTypeInfo.interfaces().forEach(interfaceType -> processInterface(interfaceType, debugInfoBase, debugContext));
/* Add details of fields and field types */
debugInstanceTypeInfo.fieldInfoProvider().forEach(debugFieldInfo -> this.processField(debugFieldInfo, debugInfoBase, debugContext));
Expand Down Expand Up @@ -256,6 +265,10 @@ public FileEntry getFileEntry() {
return fileEntry;
}

public String getLoaderId() {
return (loader != null ? loader.getLoaderId() : "");
}

/**
* Retrieve a stream of all compiled method entries for this class, including both normal and
* deopt fallback compiled methods.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ public abstract class DebugInfoBase {
* Index of files which contain primary or secondary ranges keyed by path.
*/
private Map<Path, FileEntry> filesIndex = new HashMap<>();

/**
* List of all loaders associated with classes included in the image.
*/
private List<LoaderEntry> loaders = new ArrayList<>();

/**
* Index of all loaders associated with classes included in the image.
*/
private Map<String, LoaderEntry> loaderIndex = new HashMap<>();

/**
* Flag set to true if heap references are stored as addresses relative to a heap base register
* otherwise false.
Expand Down Expand Up @@ -501,6 +512,15 @@ private DirEntry ensureDirEntry(Path filePath) {
return dirEntry;
}

protected LoaderEntry ensureLoaderEntry(String loaderId) {
LoaderEntry loaderEntry = loaderIndex.get(loaderId);
if (loaderEntry == null) {
loaderEntry = new LoaderEntry(uniqueDebugString(loaderId));
loaderIndex.put(loaderEntry.getLoaderId(), loaderEntry);
}
return loaderEntry;
}

/* Accessors to query the debug info model. */
public ByteOrder getByteOrder() {
return byteOrder;
Expand All @@ -524,6 +544,15 @@ public FileEntry findFile(Path fullFileName) {
return filesIndex.get(fullFileName);
}

public List<LoaderEntry> getLoaders() {
return loaders;
}

@SuppressWarnings("unused")
public LoaderEntry findLoader(String id) {
return loaderIndex.get(id);
}

public StringTable getStringTable() {
return stringTable;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.objectfile.debugentry;

/**
* A LoaderEntry is used to record a unique id string for the class loader asscoiated with classes
* that can be susceptible to repeat definitions. In such cases the loader id can be used when
* constructing a unique linker symbol for methods and static fields of the class. That same id may
* need to be embedded in debug info that identifies class and method names.
*/
public class LoaderEntry {
String loaderId;

public LoaderEntry(String id) {
loaderId = id;
}

public String getLoaderId() {
return loaderId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ public String toString() {
public interface DebugInstanceTypeInfo extends DebugTypeInfo {
int headerSize();

String loaderName();

Stream<DebugFieldInfo> fieldInfoProvider();

Stream<DebugMethodInfo> methodInfoProvider();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,15 @@ public void createContent() {
* instance fields. They are not needed when typing local vars and parameters held in
* registers or on the stack as they appear as raw addresses.
*
* <li><code>code = namespace, tag = namespace, parent = class_unit, array_unit,
* interface_unit<code> - a wrap-around DIE that is used to embed all the normal level 1
* DIEs of a <code>class_unit</code> or <code>array_unit</code_unit> in a namespace. This is
* needed when the corresponding class/interface or array base element type have been loaded
* by a loader with a non-empty loader in order to ensure that mangled names for the class
* and its members can legitimately employ the loader id as a namespace prefix. Note that
* use of a namespace wrapper DIE causes all the embedded level 1+ DIEs documented above and
* all their children to be generated at a level one greater than documented here.
*
* </ul>
*
* <ul>
Expand Down Expand Up @@ -198,7 +207,18 @@ public void createContent() {
*
* Details of each specific DIE contents are as follows:
*
* Primitive Types: For each non-void Java primitive type there is a level 0 DIE defining a
* A single instance of the level 0 <code>builtin_unit</code> compile unit provides details
* of all Java primitive types and of the struct type which describes the layout of object
* headers, including array headers.
*
* <li><code>abbrev_code == builtin_unit, tag == DW_TAG_compilation_unit,
* has_children</code>
*
* <li><code>DW_AT_language : ... DW_FORM_data1</code>
*
* </ul>
*
* Primitive Types: For each non-void Java primitive type there is a level 1 DIE defining a
* base type
*
* <ul>
Expand All @@ -225,7 +245,7 @@ public void createContent() {
*
* </ul>
*
* Header: There is a level 0 DIE defining structure types used to define the various types
* Header: There is a level 1 DIE defining structure types used to define the various types
* of header structure embedded at the start of every instance or array. All instances embed
* the same object header. Array headers embed the object header as a parent type, allowing
* an array to be viewed as a type of object. Multiple array headers structures are defined
Expand All @@ -243,7 +263,7 @@ public void createContent() {
*
* </ul>
*
* Header Data: A level 1 DIE of type member is used to describe the fields of both object
* Header Data: A level 2 DIE of type member is used to describe the fields of both object
* and array headers. This includes the type tag and other tag bits in all objects, the
* length field in all arrays and any padding bytes needed to complete the layout.
*
Expand Down Expand Up @@ -290,6 +310,20 @@ public void createContent() {
*
* </ul>
*
* Namespace embedding:
*
* When the class loader associated with a class defined in a <code>class_unit</code>
* compile unit has a non-empty loader id string then a namespace DIE is used to wrap all
* its child DIEs. Otherwise the children are embedded directly. The namespace DIE has a
* single attribute defining the namespace's name as the loader id string.
*
* <li><code>abbrev_code == namespace, tag == DW_TAG_namespace, has_children</code>
*
* <li><code>DW_AT_name : ....... DW_FORM_strp</code>
*
* </ul>
*
*
* Instance Class Structure: Each class_unit DIE contains a series of level 1 DIEs. The
* first one describes the class layout. The normal layout does not include a data_location
* attribute. However, an alternative layout, including that extra attribute, is provided to
Expand Down Expand Up @@ -663,10 +697,15 @@ public void createContent() {
*
* Array Structure: Each array_unit DIE contains four level 1 DIEs. The first one describes
* the array layout. It has only one child, a super_reference DIE (see above) that
* references the appropriate array header type for an obnject aray or primitive array of
* references the appropriate array header type for an object array or primitive array of
* the relevant primitive type). The size of the array layout is the same as the size of the
* array header.
*
* Note that when the base element type of the array is a class whose loader has an
* associated loader id the array's children are embedded in a namespace DIE. This is needed
* because the encoded type name for the array will include a namespace prefix in order to
* guarantee that it remains unique.
*
* <ul>
*
* <li><code>abbrev_code == array_layout, tag == DW_TAG_class_type, has_children</code>
Expand Down Expand Up @@ -825,6 +864,8 @@ public int writeAbbrevs(DebugContext context, byte[] buffer, int p) {
pos = writeVoidTypeAbbrev(context, buffer, pos);
pos = writeObjectHeaderAbbrev(context, buffer, pos);

pos = writeNamespaceAbbrev(context, buffer, pos);

pos = writeClassLayoutAbbrevs(context, buffer, pos);
pos = writeClassReferenceAbbrev(context, buffer, pos);
pos = writeMethodDeclarationAbbrevs(context, buffer, pos);
Expand Down Expand Up @@ -1002,6 +1043,21 @@ private int writeObjectHeaderAbbrev(@SuppressWarnings("unused") DebugContext con
return pos;
}

private int writeNamespaceAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) {
int pos = p;
pos = writeAbbrevCode(DwarfDebugInfo.DW_ABBREV_CODE_namespace, buffer, pos);
pos = writeTag(DwarfDebugInfo.DW_TAG_namespace, buffer, pos);
pos = writeFlag(DwarfDebugInfo.DW_CHILDREN_yes, buffer, pos);
pos = writeAttrType(DwarfDebugInfo.DW_AT_name, buffer, pos);
pos = writeAttrForm(DwarfDebugInfo.DW_FORM_strp, buffer, pos);
/*
* Now terminate.
*/
pos = writeAttrType(DwarfDebugInfo.DW_AT_null, buffer, pos);
pos = writeAttrForm(DwarfDebugInfo.DW_FORM_null, buffer, pos);
return pos;
}

private int writeClassLayoutAbbrevs(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) {
int pos = p;
pos = writeClassLayoutAbbrev(context, DwarfDebugInfo.DW_ABBREV_CODE_class_layout1, buffer, pos);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,43 +78,44 @@ public class DwarfDebugInfo extends DebugInfoBase {
public static final int DW_ABBREV_CODE_primitive_type = 5;
public static final int DW_ABBREV_CODE_void_type = 6;
public static final int DW_ABBREV_CODE_object_header = 7;
public static final int DW_ABBREV_CODE_class_layout1 = 8;
public static final int DW_ABBREV_CODE_class_layout2 = 9;
public static final int DW_ABBREV_CODE_class_pointer = 10;
public static final int DW_ABBREV_CODE_method_location = 11;
public static final int DW_ABBREV_CODE_abstract_inline_method = 12;
public static final int DW_ABBREV_CODE_static_field_location = 13;
public static final int DW_ABBREV_CODE_array_layout = 14;
public static final int DW_ABBREV_CODE_array_pointer = 15;
public static final int DW_ABBREV_CODE_interface_layout = 16;
public static final int DW_ABBREV_CODE_interface_pointer = 17;
public static final int DW_ABBREV_CODE_indirect_layout = 18;
public static final int DW_ABBREV_CODE_indirect_pointer = 19;
public static final int DW_ABBREV_CODE_namespace = 8;
public static final int DW_ABBREV_CODE_class_layout1 = 9;
public static final int DW_ABBREV_CODE_class_layout2 = 10;
public static final int DW_ABBREV_CODE_class_pointer = 11;
public static final int DW_ABBREV_CODE_method_location = 12;
public static final int DW_ABBREV_CODE_abstract_inline_method = 13;
public static final int DW_ABBREV_CODE_static_field_location = 14;
public static final int DW_ABBREV_CODE_array_layout = 15;
public static final int DW_ABBREV_CODE_array_pointer = 16;
public static final int DW_ABBREV_CODE_interface_layout = 17;
public static final int DW_ABBREV_CODE_interface_pointer = 18;
public static final int DW_ABBREV_CODE_indirect_layout = 19;
public static final int DW_ABBREV_CODE_indirect_pointer = 20;
/* Level 2 DIEs. */
public static final int DW_ABBREV_CODE_method_declaration = 20;
public static final int DW_ABBREV_CODE_method_declaration_static = 21;
public static final int DW_ABBREV_CODE_field_declaration1 = 22;
public static final int DW_ABBREV_CODE_field_declaration2 = 23;
public static final int DW_ABBREV_CODE_field_declaration3 = 24;
public static final int DW_ABBREV_CODE_field_declaration4 = 25;
public static final int DW_ABBREV_CODE_header_field = 26;
public static final int DW_ABBREV_CODE_array_data_type = 27;
public static final int DW_ABBREV_CODE_super_reference = 28;
public static final int DW_ABBREV_CODE_interface_implementor = 29;
public static final int DW_ABBREV_CODE_method_declaration = 21;
public static final int DW_ABBREV_CODE_method_declaration_static = 22;
public static final int DW_ABBREV_CODE_field_declaration1 = 23;
public static final int DW_ABBREV_CODE_field_declaration2 = 24;
public static final int DW_ABBREV_CODE_field_declaration3 = 25;
public static final int DW_ABBREV_CODE_field_declaration4 = 26;
public static final int DW_ABBREV_CODE_header_field = 27;
public static final int DW_ABBREV_CODE_array_data_type = 28;
public static final int DW_ABBREV_CODE_super_reference = 29;
public static final int DW_ABBREV_CODE_interface_implementor = 30;
/* Level 2+K DIEs (where inline depth K >= 0) */
public static final int DW_ABBREV_CODE_inlined_subroutine = 30;
public static final int DW_ABBREV_CODE_inlined_subroutine_with_children = 31;
public static final int DW_ABBREV_CODE_inlined_subroutine = 31;
public static final int DW_ABBREV_CODE_inlined_subroutine_with_children = 32;
/* Level 2 DIEs. */
public static final int DW_ABBREV_CODE_method_parameter_declaration1 = 32;
public static final int DW_ABBREV_CODE_method_parameter_declaration2 = 33;
public static final int DW_ABBREV_CODE_method_parameter_declaration3 = 34;
public static final int DW_ABBREV_CODE_method_local_declaration1 = 35;
public static final int DW_ABBREV_CODE_method_local_declaration2 = 36;
public static final int DW_ABBREV_CODE_method_parameter_declaration1 = 33;
public static final int DW_ABBREV_CODE_method_parameter_declaration2 = 34;
public static final int DW_ABBREV_CODE_method_parameter_declaration3 = 35;
public static final int DW_ABBREV_CODE_method_local_declaration1 = 36;
public static final int DW_ABBREV_CODE_method_local_declaration2 = 37;
/* Level 3 DIEs. */
public static final int DW_ABBREV_CODE_method_parameter_location1 = 37;
public static final int DW_ABBREV_CODE_method_parameter_location2 = 38;
public static final int DW_ABBREV_CODE_method_local_location1 = 39;
public static final int DW_ABBREV_CODE_method_local_location2 = 40;
public static final int DW_ABBREV_CODE_method_parameter_location1 = 38;
public static final int DW_ABBREV_CODE_method_parameter_location2 = 39;
public static final int DW_ABBREV_CODE_method_local_location1 = 40;
public static final int DW_ABBREV_CODE_method_local_location2 = 41;

/*
* Define all the Dwarf tags we need for our DIEs.
Expand All @@ -131,6 +132,7 @@ public class DwarfDebugInfo extends DebugInfoBase {
public static final int DW_TAG_base_type = 0x24;
public static final int DW_TAG_subprogram = 0x2e;
public static final int DW_TAG_variable = 0x34;
public static final int DW_TAG_namespace = 0x39;
public static final int DW_TAG_unspecified_type = 0x3b;
public static final int DW_TAG_inlined_subroutine = 0x1d;

Expand Down Expand Up @@ -208,6 +210,11 @@ public class DwarfDebugInfo extends DebugInfoBase {
* Value for DW_AT_language attribute with form DATA1.
*/
public static final byte DW_LANG_Java = 0xb;
/**
* This field defines the value used for the DW_AT_language attribute of compile units.
*
*/
public static final byte LANG_ENCODING = DW_LANG_Java;
/*
* Values for {@link DW_AT_inline} attribute with form DATA1.
*/
Expand Down
Loading