/*
 * Copyright (c) 2016, 2020, Oracle and/or its affiliates. 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.
 *
 * 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 jdk.tools.jaotc;

import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicInteger;

import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.hotspot.HotSpotMarkId;

import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
import jdk.vm.ci.code.site.Call;
import jdk.vm.ci.hotspot.HotSpotCompiledCode;
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;

final class CompiledMethodInfo {

    static final String archStr = System.getProperty("os.arch").toLowerCase();

    private static final int UNINITIALIZED_OFFSET = -1;

    private static class AOTMethodOffsets {
        
Offset in metaspace names section.
/** * Offset in metaspace names section. */
private int nameOffset;
Offset in the text section at which compiled code starts.
/** * Offset in the text section at which compiled code starts. */
private int textSectionOffset;
Offset in the metadata section.
/** * Offset in the metadata section. */
private int metadataOffset;
Offset to the metadata in the GOT table.
/** * Offset to the metadata in the GOT table. */
private int metadataGotOffset;
Size of the metadata.
/** * Size of the metadata. */
private int metadataGotSize;
The sequential number corresponding to the order of methods code in code buffer.
/** * The sequential number corresponding to the order of methods code in code buffer. */
private int codeId; AOTMethodOffsets() { this.nameOffset = UNINITIALIZED_OFFSET; this.textSectionOffset = UNINITIALIZED_OFFSET; this.metadataOffset = UNINITIALIZED_OFFSET; this.metadataGotOffset = UNINITIALIZED_OFFSET; this.metadataGotSize = -1; this.codeId = -1; } void addMethodOffsets(ReadOnlyDataContainer container, String name) { verify(name); // @formatter:off /* * The offsets layout should match AOTMethodOffsets structure in AOT JVM runtime */ // Add the offset to the name in the .metaspace.names section container.appendInt(nameOffset). // Add the offset to the code in the .text section appendInt(textSectionOffset). // Add the offset to the metadata in the .method.metadata section appendInt(metadataOffset). // Add the offset to the metadata in the .metadata.got section appendInt(metadataGotOffset). // Add the size of the metadata appendInt(metadataGotSize). // Add code ID. appendInt(codeId); // @formatter:on } private void verify(String name) { assert nameOffset >= 0 : "incorrect nameOffset: " + nameOffset + " for method: " + name; assert textSectionOffset > 0 : "incorrect textSectionOffset: " + textSectionOffset + " for method: " + name; assert metadataOffset >= 0 : "incorrect metadataOffset: " + metadataOffset + " for method: " + name; assert metadataGotOffset >= 0 : "incorrect metadataGotOffset: " + metadataGotOffset + " for method: " + name; assert metadataGotSize >= 0 : "incorrect metadataGotSize: " + metadataGotSize + " for method: " + name; assert codeId >= 0 : "incorrect codeId: " + codeId + " for method: " + name; } protected void setNameOffset(int offset) { nameOffset = offset; } protected void setTextSectionOffset(int textSectionOffset) { this.textSectionOffset = textSectionOffset; } protected int getTextSectionOffset() { return textSectionOffset; } protected void setCodeId(int codeId) { this.codeId = codeId; } protected int getCodeId() { return codeId; } protected void setMetadataOffset(int offset) { metadataOffset = offset; } protected void setMetadataGotOffset(int metadataGotOffset) { this.metadataGotOffset = metadataGotOffset; } protected void setMetadataGotSize(int length) { this.metadataGotSize = length; } }
Method name.
/** * Method name. */
private String name;
Result of graal compilation.
/** * Result of graal compilation. */
private CompilationResult compilationResult;
HotSpotResolvedJavaMethod or Stub corresponding to the compilation result.
/** * HotSpotResolvedJavaMethod or Stub corresponding to the compilation result. */
private JavaMethodInfo methodInfo;
Compiled code from installation.
/** * Compiled code from installation. */
private HotSpotCompiledCode code;
Offset to stubs.
/** * Offset to stubs. */
private int stubsOffset;
The total size in bytes of the stub section.
/** * The total size in bytes of the stub section. */
private int totalStubSize;
Method's offsets.
/** * Method's offsets. */
private AOTMethodOffsets methodOffsets;
List of stubs (PLT trampoline).
/** * List of stubs (PLT trampoline). */
private HashMap<String, StubInformation> stubs = new HashMap<>();
List of referenced classes.
/** * List of referenced classes. */
private HashSet<AOTKlassData> dependentKlasses = new HashSet<>();
Methods count used to generate unique global method id.
/** * Methods count used to generate unique global method id. */
private static final AtomicInteger methodsCount = new AtomicInteger(); CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) { this.name = methodInfo.getNameAndSignature(); this.compilationResult = compilationResult; this.methodInfo = methodInfo; this.stubsOffset = UNINITIALIZED_OFFSET; this.methodOffsets = new AOTMethodOffsets(); } String name() { return name; } void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) { this.methodOffsets.setNameOffset(binaryContainer.addMetaspaceName(name)); this.methodOffsets.addMethodOffsets(container, name); for (AOTKlassData data : dependentKlasses) { data.addDependentMethod(this); } } CompilationResult getCompilationResult() { return compilationResult; } JavaMethodInfo getMethodInfo() { return methodInfo; } void setTextSectionOffset(int textSectionOffset) { methodOffsets.setTextSectionOffset(textSectionOffset); } public int getTextSectionOffset() { return methodOffsets.getTextSectionOffset(); } void setCodeId() { methodOffsets.setCodeId(CompiledMethodInfo.getNextCodeId()); } int getCodeId() { return this.methodOffsets.getCodeId(); } static int getMethodsCount() { return methodsCount.get(); } static int getNextCodeId() { return methodsCount.getAndIncrement(); } int getCodeSize() { return stubsOffset + getStubCodeSize(); } int getStubCodeSize() { return totalStubSize; } void setMetadataOffset(int offset) { this.methodOffsets.setMetadataOffset(offset); }
Offset into the code of this method where the stub section starts.
/** * Offset into the code of this method where the stub section starts. */
void setStubsOffset(int offset) { stubsOffset = offset; } int getStubsOffset() { return stubsOffset; } void setMetadataGotOffset(int metadataGotOffset) { this.methodOffsets.setMetadataGotOffset(metadataGotOffset); } void setMetadataGotSize(int length) { this.methodOffsets.setMetadataGotSize(length); } void addStubCode(String call, StubInformation stub) { stubs.put(call, stub); totalStubSize += stub.getSize(); } StubInformation getStubFor(String call) { StubInformation stub = stubs.get(call); assert stub != null : "missing stub for call " + call; stub.verify(); return stub; } void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) { AOTKlassData klassData = AOTCompiledClass.addFingerprintKlassData(binaryContainer, type); dependentKlasses.add(klassData); } AOTKlassData getDependentKlassData(HotSpotResolvedObjectType type) { AOTKlassData klassData = AOTCompiledClass.getAOTKlassData(type); if (dependentKlasses.contains(klassData)) { return klassData; } return null; } boolean hasMark(Call call, HotSpotMarkId id) { assert id == HotSpotMarkId.INVOKESTATIC || id == HotSpotMarkId.INVOKESPECIAL; CompilationResult.CodeMark mark = compilationResult.getAssociatedMark(call); if (mark != null) { return mark.id == id; } return false; } String asTag() { return "[" + methodInfo.getSymbolName() + "]"; } HotSpotCompiledCode compiledCode() { if (code == null) { code = methodInfo.compiledCode(compilationResult); } return code; } // Free memory void clear() { this.dependentKlasses = null; this.name = null; } void clearCompileData() { this.code = null; this.stubs = null; this.compilationResult = null; this.methodInfo = null; } }