| /* |
| * 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); |
| } |
| } |
| } |
| |
| } |