blob: 1a73472c928e635e87eff3c70958ed881234d9f7 [file] [log] [blame]
/*
* 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.ArrayList;
import java.util.List;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ByteContainer;
import jdk.tools.jaotc.binformat.GotSymbol;
import jdk.tools.jaotc.utils.NativeOrderOutputStream;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.DataPatch;
import jdk.vm.ci.code.site.Infopoint;
import jdk.vm.ci.code.site.Mark;
import jdk.vm.ci.hotspot.HotSpotCompiledCode;
import jdk.vm.ci.hotspot.HotSpotMetaData;
import static jdk.tools.jaotc.AOTCompiledClass.getType;
import static jdk.tools.jaotc.AOTCompiledClass.metadataName;
final class MetadataBuilder {
private final DataBuilder dataBuilder;
private final BinaryContainer binaryContainer;
MetadataBuilder(DataBuilder dataBuilder) {
this.dataBuilder = dataBuilder;
this.binaryContainer = dataBuilder.getBinaryContainer();
}
/**
* Process compiled methods and create method metadata.
*/
void processMetadata(List<AOTCompiledClass> classes, AOTCompiledClass stubCompiledCode) {
for (AOTCompiledClass c : classes) {
processMetadataClass(c);
}
processMetadataClass(stubCompiledCode);
}
private void processMetadataClass(AOTCompiledClass c) {
processInfopointsAndMarks(c);
createMethodMetadata(c);
}
/**
* Add metadata for each of the compiled methods in {@code compiledClass} to read-only section
* of {@code binaryContainer}.
*
* @param compiledClass AOT Graal compilation result
*/
private void createMethodMetadata(AOTCompiledClass compiledClass) {
HotSpotGraalRuntimeProvider runtime = dataBuilder.getBackend().getRuntime();
ByteContainer methodMetadataContainer = binaryContainer.getMethodMetadataContainer();
// For each of the compiled java methods, create records holding information about them.
for (CompiledMethodInfo methodInfo : compiledClass.getCompiledMethods()) {
// Get the current offset in the methodmetadata container.
final int startOffset = methodMetadataContainer.getByteStreamSize();
assert startOffset % 8 == 0 : "Must be aligned on 8";
methodInfo.setMetadataOffset(startOffset);
HotSpotCompiledCode compiledMethod = methodInfo.compiledCode();
// pc and scope description
HotSpotMetaData metaData = new HotSpotMetaData(runtime.getTarget(), compiledMethod);
byte[] pcDesc = metaData.pcDescBytes();
byte[] scopeDesc = metaData.scopesDescBytes();
byte[] relocationInfo = metaData.relocBytes();
byte[] oopMapInfo = metaData.oopMaps();
// create a global symbol at this position for this method
NativeOrderOutputStream metadataStream = new NativeOrderOutputStream();
// get the code size
int codeSize = methodInfo.getCodeSize();
// get code offsets
CodeOffsets co = CodeOffsets.buildFrom(methodInfo.getCompilationResult().getMarks());
int unverifiedEntry = co.entry();
int verifiedEntry = co.verifiedEntry();
int exceptionHandler = co.exceptionHandler();
int deoptHandler = co.deoptHandler();
int frameSize = methodInfo.getCompilationResult().getTotalFrameSize();
StackSlot deoptRescueSlot = methodInfo.getCompilationResult().getCustomStackArea();
int origPcOffset = deoptRescueSlot != null ? deoptRescueSlot.getOffset(frameSize) : -1;
// get stubs offset
int stubsOffset = methodInfo.getStubsOffset();
int offset = addMetadataEntries(binaryContainer, metaData, methodInfo);
methodInfo.setMetadataGotOffset(offset);
methodInfo.setMetadataGotSize(metaData.metadataEntries().length);
int unsafeAccess = methodInfo.getCompilationResult().hasUnsafeAccess() ? 1 : 0;
try {
// calculate total size of the container
NativeOrderOutputStream.PatchableInt totalSize = metadataStream.patchableInt();
// @formatter:off
metadataStream.putInt(codeSize).
putInt(unverifiedEntry).
putInt(verifiedEntry).
putInt(exceptionHandler).
putInt(deoptHandler).
putInt(stubsOffset).
putInt(frameSize).
putInt(origPcOffset).
putInt(unsafeAccess);
// @formatter:on
NativeOrderOutputStream.PatchableInt pcDescOffset = metadataStream.patchableInt();
NativeOrderOutputStream.PatchableInt scopeOffset = metadataStream.patchableInt();
NativeOrderOutputStream.PatchableInt relocationOffset = metadataStream.patchableInt();
NativeOrderOutputStream.PatchableInt exceptionOffset = metadataStream.patchableInt();
NativeOrderOutputStream.PatchableInt oopMapOffset = metadataStream.patchableInt();
metadataStream.align(8);
pcDescOffset.set(metadataStream.position());
metadataStream.put(pcDesc).align(8);
scopeOffset.set(metadataStream.position());
metadataStream.put(scopeDesc).align(8);
relocationOffset.set(metadataStream.position());
metadataStream.put(relocationInfo).align(8);
exceptionOffset.set(metadataStream.position());
metadataStream.put(metaData.exceptionBytes()).align(8);
// oopmaps should be last
oopMapOffset.set(metadataStream.position());
metadataStream.put(oopMapInfo).align(8);
totalSize.set(metadataStream.position());
byte[] data = metadataStream.array();
methodMetadataContainer.appendBytes(data, 0, data.length);
} catch (Exception e) {
throw new InternalError("Exception occurred during compilation of " + methodInfo.getMethodInfo().getSymbolName(), e);
}
methodInfo.clearCompileData(); // Clear unused anymore compilation data
}
}
private static int addMetadataEntries(BinaryContainer binaryContainer, HotSpotMetaData metaData, CompiledMethodInfo methodInfo) {
Object[] metaDataEntries = metaData.metadataEntries();
if (metaDataEntries.length == 0) {
return 0;
}
int metadataGotSlotsStart = binaryContainer.getMetadataGotContainer().getByteStreamSize(); // binaryContainer.reserveMetadataGOTSlots(metaDataEntries.length);
for (int index = 0; index < metaDataEntries.length; index++) {
Object ref = metaDataEntries[index];
String name = metadataName(ref);
// Create GOT cells for klasses referenced in metadata
addMetadataEntry(binaryContainer, name);
// We should already have added entries for this klass
assert AOTCompiledClass.getAOTKlassData(getType(ref)) != null;
assert methodInfo.getDependentKlassData(getType(ref)) != null;
}
return metadataGotSlotsStart;
}
private static void addMetadataEntry(BinaryContainer binaryContainer, String name) {
int stringOffset = binaryContainer.addMetaspaceName(name);
binaryContainer.addMetadataGotEntry(stringOffset);
}
/**
* Process {@link Infopoint}s, {@link Mark}s and {@link DataPatch}es generated by the compiler
* to create all needed binary section constructs.
*
* @param compiledClass compilation result
*/
private void processInfopointsAndMarks(AOTCompiledClass compiledClass) {
ArrayList<CompiledMethodInfo> compiledMethods = compiledClass.getCompiledMethods();
MarkProcessor markProcessor = new MarkProcessor(dataBuilder);
DataPatchProcessor dataPatchProcessor = new DataPatchProcessor(dataBuilder);
InfopointProcessor infopointProcessor = new InfopointProcessor(dataBuilder);
for (CompiledMethodInfo methodInfo : compiledMethods) {
CompilationResult compilationResult = methodInfo.getCompilationResult();
String targetSymbol = "state.M" + methodInfo.getCodeId();
String gotName = "got." + targetSymbol;
GotSymbol symbol = binaryContainer.getMethodStateContainer().createGotSymbol(gotName);
assert (symbol.getIndex() == methodInfo.getCodeId()) : "wrong offset";
for (Infopoint infoPoint : compilationResult.getInfopoints()) {
infopointProcessor.process(methodInfo, infoPoint);
}
for (Mark mark : compilationResult.getMarks()) {
markProcessor.process(methodInfo, mark);
}
for (DataPatch dataPatch : compilationResult.getDataPatches()) {
dataPatchProcessor.process(methodInfo, dataPatch);
}
}
}
}