blob: 350ee46921a2cb718432be6ecc6284174808d97e [file] [log] [blame]
/*
* Copyright (c) 2016, 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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ByteContainer;
import jdk.tools.jaotc.binformat.HeaderContainer;
import jdk.tools.jaotc.utils.Timer;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.Debug.Scope;
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
import org.graalvm.compiler.hotspot.stubs.Stub;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
import jdk.vm.ci.hotspot.VMField;
class DataBuilder {
private final Main main;
private final HotSpotHostBackend backend;
private final List<AOTCompiledClass> classes;
/**
* Target-independent container in which text symbols and code bytes are created.
*/
private final BinaryContainer binaryContainer;
private final HashMap<Long, String> vmAddresses = new HashMap<>();
public DataBuilder(Main main, HotSpotHostBackend backend, List<AOTCompiledClass> classes, BinaryContainer binaryContainer) {
this.main = main;
this.backend = backend;
this.classes = classes;
this.binaryContainer = binaryContainer;
fillVMAddresses(HotSpotJVMCIRuntime.runtime().getConfigStore());
}
/**
* Returns a value-name map of all {@link VMField} fields.
*/
private void fillVMAddresses(HotSpotVMConfigStore config) {
for (VMField vmField : config.getFields().values()) {
if (vmField.value != null) {
final long address = vmField.value;
String value = vmField.name;
/*
* Some fields don't contain addresses but integer values. At least don't add zero
* entries to avoid matching null addresses.
*/
if (address != 0) {
vmAddresses.put(address, value);
}
}
}
for (Entry<String, Long> vmAddress : config.getAddresses().entrySet()) {
final long address = vmAddress.getValue();
String value = vmAddress.getKey();
String old = vmAddresses.put(address, value);
if (old != null) {
throw new InternalError("already in map: address: " + address + ", current: " + value + ", old: " + old);
}
}
}
/**
* Get the C/C++ function name associated with the foreign call target {@code address}.
*
* @param address native address
* @return C/C++ functio name associated with the native address
*/
public String getVMFunctionNameForAddress(long address) {
return vmAddresses.get(address);
}
/**
* Returns the host backend used for this compilation.
*
* @return host backend
*/
public HotSpotHostBackend getBackend() {
return backend;
}
/**
* Returns the binary container for this compilation.
*
* @return binary container
*/
public BinaryContainer getBinaryContainer() {
return binaryContainer;
}
/**
* Prepare data with all compiled classes and stubs.
*
* @throws Exception
*/
@SuppressWarnings("try")
public void prepareData() throws Exception {
try (Timer t = new Timer(main, "Parsing compiled code")) {
/*
* Copy compiled code into code section container and calls stubs (PLT trampoline).
*/
CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this);
for (AOTCompiledClass c : classes) {
// For each class we need 2 GOT slots:
// first - for initialized klass
// second - only for loaded klass
c.addAOTKlassData(binaryContainer);
codeSectionProcessor.process(c);
}
}
AOTCompiledClass stubCompiledCode = retrieveStubCode();
// Free memory!
try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) {
main.printMemoryUsage();
System.gc();
}
MetadataBuilder metadataBuilder = null;
try (Timer t = new Timer(main, "Processing metadata")) {
/*
* Generate metadata for compiled code and copy it into metadata section. Create
* relocation information for all references (call, constants, etc) in compiled code.
*/
metadataBuilder = new MetadataBuilder(this);
metadataBuilder.processMetadata(classes, stubCompiledCode);
}
// Free memory!
try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) {
main.printMemoryUsage();
System.gc();
}
try (Timer t = new Timer(main, "Preparing stubs binary")) {
prepareStubsBinary(stubCompiledCode);
}
try (Timer t = new Timer(main, "Preparing compiled binary")) {
// Should be called after Stubs because they can set dependent klasses.
prepareCompiledBinary(metadataBuilder);
}
}
/**
* Get all stubs from Graal and add them to the code section.
*/
@SuppressWarnings("try")
private AOTCompiledClass retrieveStubCode() {
ArrayList<CompiledMethodInfo> stubs = new ArrayList<>();
for (Stub stub : Stub.getStubs()) {
try (Scope scope = Debug.scope("CompileStubs")) {
CompilationResult result = stub.getCompilationResult(backend);
CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend));
stubs.add(cm);
} catch (Throwable e) {
throw Debug.handle(e);
}
}
AOTCompiledClass stubCompiledCode = new AOTCompiledClass(stubs);
CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this);
codeSectionProcessor.process(stubCompiledCode);
return stubCompiledCode;
}
/**
* Prepare metaspace.offsets section.
*/
private void prepareCompiledBinary(MetadataBuilder metadataBuilder) {
for (AOTCompiledClass c : classes) {
// Create records for compiled AOT methods.
c.putMethodsData(binaryContainer);
}
// Create records for compiled AOT classes.
AOTCompiledClass.putAOTKlassData(binaryContainer);
// Fill in AOTHeader
HeaderContainer header = binaryContainer.getHeaderContainer();
header.setClassesCount(AOTCompiledClass.getClassesCount());
header.setMethodsCount(CompiledMethodInfo.getMethodsCount());
// Record size of got sections
ByteContainer bc = binaryContainer.getMetaspaceGotContainer();
header.setMetaspaceGotSize((bc.getByteStreamSize() / 8));
bc = binaryContainer.getMetadataGotContainer();
header.setMetadataGotSize((bc.getByteStreamSize() / 8));
bc = binaryContainer.getOopGotContainer();
header.setOopGotSize((bc.getByteStreamSize() / 8));
}
/**
* Prepare stubs.offsets section.
*/
private void prepareStubsBinary(AOTCompiledClass compiledClass) {
// For each of the compiled stubs, create records holding information about
// them.
ArrayList<CompiledMethodInfo> compiledStubs = compiledClass.getCompiledMethods();
int cntStubs = compiledStubs.size();
binaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer());
for (CompiledMethodInfo methodInfo : compiledStubs) {
// Note, stubs have different offsets container.
methodInfo.addMethodOffsets(binaryContainer, binaryContainer.getStubsOffsetsContainer());
}
}
}