blob: bdb08b5f28bfb335d79dec51f99782319e73ae12 [file] [log] [blame]
/*
* Copyright (c) 2016, 2018, 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.concurrent.atomic.AtomicInteger;
import java.util.HashMap;
import java.util.HashSet;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
import org.graalvm.compiler.code.CompilationResult;
import jdk.vm.ci.code.site.Mark;
import jdk.vm.ci.code.site.Site;
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.
*/
private int nameOffset;
/**
* Offset in the text section at which compiled code starts.
*/
private int textSectionOffset;
/**
* Offset in the metadata section.
*/
private int metadataOffset;
/**
* Offset to the metadata in the GOT table.
*/
private int metadataGotOffset;
/**
* Size of the metadata.
*/
private int metadataGotSize;
/**
* 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
*/
private String name;
/**
* Result of graal compilation.
*/
private CompilationResult compilationResult;
/**
* HotSpotResolvedJavaMethod or Stub corresponding to the compilation result.
*/
private JavaMethodInfo methodInfo;
/**
* Compiled code from installation.
*/
private HotSpotCompiledCode code;
/**
* Offset to stubs.
*/
private int stubsOffset;
/**
* The total size in bytes of the stub section.
*/
private int totalStubSize;
/**
* Method's offsets.
*/
private AOTMethodOffsets methodOffsets;
/**
* List of stubs (PLT trampoline).
*/
private HashMap<String, StubInformation> stubs = new HashMap<>();
/**
* List of referenced classes.
*/
private HashSet<AOTKlassData> dependentKlasses = new HashSet<>();
/**
* 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.
*/
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(Site call, MarkId id) {
for (Mark m : compilationResult.getMarks()) {
int adjOffset = m.pcOffset;
if (archStr.equals("aarch64")) {
// The mark is at the end of a group of three instructions:
// adrp; add; ldr
adjOffset += 12;
} else {
// X64-specific code.
// Call instructions are aligned to 8
// bytes - 1 on x86 to patch address atomically,
adjOffset = (adjOffset & (-8)) + 7;
}
// Mark points before aligning nops.
if ((call.pcOffset == adjOffset) && MarkId.getEnum((int) m.id) == id) {
return true;
}
}
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;
}
}