/* * Copyright (c) 2016, 2017, 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 stubs = new HashMap<>(); /** * List of referenced classes. */ private HashSet 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")) { // FIXME: This is very ugly. // The mark is at the end of a group of three instructions: // adrp; add; ldr adjOffset += 12; } else { // TODO: 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; } }