package jdk.tools.jaotc;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
import org.graalvm.compiler.hotspot.stubs.Stub;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ByteContainer;
import jdk.tools.jaotc.binformat.HeaderContainer;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
import jdk.vm.ci.hotspot.VMField;
final class DataBuilder {
private final Main main;
private final HotSpotHostBackend backend;
private final List<AOTCompiledClass> classes;
private final BinaryContainer binaryContainer;
private static final HashMap<Long, String> vmAddresses = new HashMap<>();
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());
}
private static void fillVMAddresses(HotSpotVMConfigStore config) {
for (VMField vmField : config.getFields().values()) {
if (vmField.value != null && vmField.value instanceof Long) {
final long address = (Long) vmField.value;
String value = vmField.name;
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);
}
}
}
static String getVMFunctionNameForAddress(long address) {
return vmAddresses.get(address);
}
HotSpotHostBackend getBackend() {
return backend;
}
BinaryContainer getBinaryContainer() {
return binaryContainer;
}
@SuppressWarnings("try")
void prepareData(DebugContext debug) throws Exception {
try (Timer t = new Timer(main, "Parsing compiled code")) {
CodeSectionProcessor codeSectionProcessor = new CodeSectionProcessor(this);
for (AOTCompiledClass c : classes) {
c.addAOTKlassData(binaryContainer);
codeSectionProcessor.process(c);
}
}
AOTCompiledClass stubCompiledCode = retrieveStubCode(debug);
try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) {
main.printer.printMemoryUsage();
System.gc();
}
MetadataBuilder metadataBuilder = null;
try (Timer t = new Timer(main, "Processing metadata")) {
metadataBuilder = new MetadataBuilder(this);
metadataBuilder.processMetadata(classes, stubCompiledCode);
}
try (Timer t = main.options.verbose ? new Timer(main, "Freeing memory") : null) {
main.printer.printMemoryUsage();
System.gc();
}
try (Timer t = new Timer(main, "Preparing stubs binary")) {
prepareStubsBinary(stubCompiledCode);
}
try (Timer t = new Timer(main, "Preparing compiled binary")) {
prepareCompiledBinary();
}
}
@SuppressWarnings("try")
private AOTCompiledClass retrieveStubCode(DebugContext debug) {
ArrayList<CompiledMethodInfo> stubs = new ArrayList<>();
HotSpotForeignCallsProvider foreignCallsProvider = backend.getProviders().getForeignCalls();
for (Stub stub : foreignCallsProvider.getStubs()) {
try (DebugContext.Scope scope = debug.scope("CompileStubs")) {
CompilationResult result = stub.getCompilationResult(debug, backend);
CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend, debug.getOptions()));
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;
}
private void prepareCompiledBinary() {
for (AOTCompiledClass c : classes) {
c.putMethodsData(binaryContainer);
}
AOTCompiledClass.putAOTKlassData(binaryContainer);
HeaderContainer header = binaryContainer.getHeaderContainer();
header.setClassesCount(AOTCompiledClass.getClassesCount());
header.setMethodsCount(CompiledMethodInfo.getMethodsCount());
ByteContainer bc = binaryContainer.getKlassesGotContainer();
header.setKlassesGotSize((bc.getByteStreamSize() / 8));
bc = binaryContainer.getMetadataGotContainer();
header.setMetadataGotSize((bc.getByteStreamSize() / 8));
bc = binaryContainer.getOopGotContainer();
header.setOopGotSize((bc.getByteStreamSize() / 8));
}
private void prepareStubsBinary(AOTCompiledClass compiledClass) {
ArrayList<CompiledMethodInfo> compiledStubs = compiledClass.getCompiledMethods();
int cntStubs = compiledStubs.size();
BinaryContainer.addMethodsCount(cntStubs, binaryContainer.getStubsOffsetsContainer());
for (CompiledMethodInfo methodInfo : compiledStubs) {
methodInfo.addMethodOffsets(binaryContainer, binaryContainer.getStubsOffsetsContainer());
}
}
}