1 /*
   2  * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 
  26 package jdk.tools.jaotc;
  27 
  28 import static jdk.tools.jaotc.AOTCompiledClass.getType;
  29 import static jdk.tools.jaotc.AOTCompiledClass.metadataName;
  30 
  31 import java.util.ArrayList;
  32 import java.util.List;
  33 
  34 import org.graalvm.compiler.code.CompilationResult;
  35 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
  36 import org.graalvm.compiler.hotspot.HotSpotGraalServices;
  37 
  38 import jdk.tools.jaotc.binformat.BinaryContainer;
  39 import jdk.tools.jaotc.binformat.ByteContainer;
  40 import jdk.tools.jaotc.binformat.GotSymbol;
  41 import jdk.tools.jaotc.utils.NativeOrderOutputStream;
  42 import jdk.vm.ci.code.StackSlot;
  43 import jdk.vm.ci.code.site.DataPatch;
  44 import jdk.vm.ci.code.site.Infopoint;
  45 import jdk.vm.ci.code.site.Mark;
  46 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
  47 import jdk.vm.ci.hotspot.HotSpotMetaData;
  48 
  49 final class MetadataBuilder {
  50 
  51     private final DataBuilder dataBuilder;
  52 
  53     private final BinaryContainer binaryContainer;
  54 
  55     MetadataBuilder(DataBuilder dataBuilder) {
  56         this.dataBuilder = dataBuilder;
  57         this.binaryContainer = dataBuilder.getBinaryContainer();
  58     }
  59 
  60     /**
  61      * Process compiled methods and create method metadata.
  62      */
  63     void processMetadata(List<AOTCompiledClass> classes, AOTCompiledClass stubCompiledCode) {
  64         for (AOTCompiledClass c : classes) {
  65             processMetadataClass(c);
  66         }
  67         processMetadataClass(stubCompiledCode);
  68     }
  69 
  70     private void processMetadataClass(AOTCompiledClass c) {
  71         processInfopointsAndMarks(c);
  72         createMethodMetadata(c);
  73     }
  74 
  75     /**
  76      * Add metadata for each of the compiled methods in {@code compiledClass} to read-only section
  77      * of {@code binaryContainer}.
  78      *
  79      * @param compiledClass AOT Graal compilation result
  80      */
  81     private void createMethodMetadata(AOTCompiledClass compiledClass) {
  82         HotSpotGraalRuntimeProvider runtime = dataBuilder.getBackend().getRuntime();
  83         ByteContainer methodMetadataContainer = binaryContainer.getMethodMetadataContainer();
  84 
  85         // For each of the compiled java methods, create records holding information about them.
  86         for (CompiledMethodInfo methodInfo : compiledClass.getCompiledMethods()) {
  87             // Get the current offset in the methodmetadata container.
  88             final int startOffset = methodMetadataContainer.getByteStreamSize();
  89             assert startOffset % 8 == 0 : "Must be aligned on 8";
  90 
  91             methodInfo.setMetadataOffset(startOffset);
  92 
  93             HotSpotCompiledCode compiledMethod = methodInfo.compiledCode();
  94             // pc and scope description
  95             HotSpotMetaData metaData = new HotSpotMetaData(runtime.getTarget(), compiledMethod);
  96 
  97             byte[] pcDesc = metaData.pcDescBytes();
  98             byte[] scopeDesc = metaData.scopesDescBytes();
  99             byte[] relocationInfo = metaData.relocBytes();
 100             byte[] oopMapInfo = metaData.oopMaps();
 101             byte[] implicitExceptionBytes = HotSpotGraalServices.getImplicitExceptionBytes(metaData);
 102 
 103             // create a global symbol at this position for this method
 104             NativeOrderOutputStream metadataStream = new NativeOrderOutputStream();
 105 
 106             // get the code size
 107             int codeSize = methodInfo.getCodeSize();
 108 
 109             // get code offsets
 110             CodeOffsets co = CodeOffsets.buildFrom(methodInfo.getCompilationResult().getMarks());
 111             int unverifiedEntry = co.entry();
 112             int verifiedEntry = co.verifiedEntry();
 113             int exceptionHandler = co.exceptionHandler();
 114             int deoptHandler = co.deoptHandler();
 115             int frameSize = methodInfo.getCompilationResult().getTotalFrameSize();
 116             StackSlot deoptRescueSlot = methodInfo.getCompilationResult().getCustomStackArea();
 117             int origPcOffset = deoptRescueSlot != null ? deoptRescueSlot.getOffset(frameSize) : -1;
 118 
 119             // get stubs offset
 120             int stubsOffset = methodInfo.getStubsOffset();
 121 
 122             int offset = addMetadataEntries(binaryContainer, metaData, methodInfo);
 123             methodInfo.setMetadataGotOffset(offset);
 124             methodInfo.setMetadataGotSize(metaData.metadataEntries().length);
 125             int unsafeAccess = methodInfo.getCompilationResult().hasUnsafeAccess() ? 1 : 0;
 126             try {
 127                 // calculate total size of the container
 128                 NativeOrderOutputStream.PatchableInt totalSize = metadataStream.patchableInt();
 129 
 130                 // @formatter:off
 131                 metadataStream.putInt(codeSize).
 132                                putInt(unverifiedEntry).
 133                                putInt(verifiedEntry).
 134                                putInt(exceptionHandler).
 135                                putInt(deoptHandler).
 136                                putInt(stubsOffset).
 137                                putInt(frameSize).
 138                                putInt(origPcOffset).
 139                                putInt(unsafeAccess);
 140                 // @formatter:on
 141 
 142                 NativeOrderOutputStream.PatchableInt pcDescOffset = metadataStream.patchableInt();
 143                 NativeOrderOutputStream.PatchableInt scopeOffset = metadataStream.patchableInt();
 144                 NativeOrderOutputStream.PatchableInt relocationOffset = metadataStream.patchableInt();
 145                 NativeOrderOutputStream.PatchableInt exceptionOffset = metadataStream.patchableInt();
 146                 NativeOrderOutputStream.PatchableInt implictTableOffset = null;
 147                 if (implicitExceptionBytes != null) {
 148                     implictTableOffset = metadataStream.patchableInt();
 149                 }
 150                 NativeOrderOutputStream.PatchableInt oopMapOffset = metadataStream.patchableInt();
 151                 metadataStream.align(8);
 152 
 153                 pcDescOffset.set(metadataStream.position());
 154                 metadataStream.put(pcDesc).align(8);
 155 
 156                 scopeOffset.set(metadataStream.position());
 157                 metadataStream.put(scopeDesc).align(8);
 158 
 159                 relocationOffset.set(metadataStream.position());
 160                 metadataStream.put(relocationInfo).align(8);
 161 
 162                 exceptionOffset.set(metadataStream.position());
 163                 metadataStream.put(metaData.exceptionBytes()).align(8);
 164 
 165                 if (implicitExceptionBytes != null) {
 166                     implictTableOffset.set(metadataStream.position());
 167                     metadataStream.put(implicitExceptionBytes).align(8);
 168                 }
 169 
 170                 // oopmaps should be last
 171                 oopMapOffset.set(metadataStream.position());
 172                 metadataStream.put(oopMapInfo).align(8);
 173 
 174                 totalSize.set(metadataStream.position());
 175 
 176                 byte[] data = metadataStream.array();
 177 
 178                 methodMetadataContainer.appendBytes(data, 0, data.length);
 179             } catch (Exception e) {
 180                 throw new InternalError("Exception occurred during compilation of " + methodInfo.getMethodInfo().getSymbolName(), e);
 181             }
 182             methodInfo.clearCompileData(); // Clear unused anymore compilation data
 183         }
 184     }
 185 
 186     private static int addMetadataEntries(BinaryContainer binaryContainer, HotSpotMetaData metaData, CompiledMethodInfo methodInfo) {
 187         Object[] metaDataEntries = metaData.metadataEntries();
 188 
 189         if (metaDataEntries.length == 0) {
 190             return 0;
 191         }
 192 
 193         int metadataGotSlotsStart = binaryContainer.getMetadataGotContainer().getByteStreamSize(); // binaryContainer.reserveMetadataGOTSlots(metaDataEntries.length);
 194 
 195         for (int index = 0; index < metaDataEntries.length; index++) {
 196             Object ref = metaDataEntries[index];
 197             String name = metadataName(ref);
 198             // Create GOT cells for klasses referenced in metadata
 199             addMetadataEntry(binaryContainer, name);
 200             // We should already have added entries for this klass
 201             assert AOTCompiledClass.getAOTKlassData(getType(ref)) != null;
 202             assert methodInfo.getDependentKlassData(getType(ref)) != null;
 203         }
 204 
 205         return metadataGotSlotsStart;
 206     }
 207 
 208     private static void addMetadataEntry(BinaryContainer binaryContainer, String name) {
 209         int stringOffset = binaryContainer.addMetaspaceName(name);
 210         binaryContainer.addMetadataGotEntry(stringOffset);
 211     }
 212 
 213     /**
 214      * Process {@link Infopoint}s, {@link Mark}s and {@link DataPatch}es generated by the compiler
 215      * to create all needed binary section constructs.
 216      *
 217      * @param compiledClass compilation result
 218      */
 219     private void processInfopointsAndMarks(AOTCompiledClass compiledClass) {
 220         ArrayList<CompiledMethodInfo> compiledMethods = compiledClass.getCompiledMethods();
 221 
 222         MarkProcessor markProcessor = new MarkProcessor(dataBuilder);
 223         DataPatchProcessor dataPatchProcessor = new DataPatchProcessor(dataBuilder);
 224         InfopointProcessor infopointProcessor = new InfopointProcessor(dataBuilder);
 225 
 226         for (CompiledMethodInfo methodInfo : compiledMethods) {
 227             CompilationResult compilationResult = methodInfo.getCompilationResult();
 228             String targetSymbol = "state.M" + methodInfo.getCodeId();
 229             String gotName = "got." + targetSymbol;
 230             GotSymbol symbol = binaryContainer.getMethodStateContainer().createGotSymbol(gotName);
 231             assert (symbol.getIndex() == methodInfo.getCodeId()) : "wrong offset";
 232 
 233             for (Infopoint infoPoint : compilationResult.getInfopoints()) {
 234                 infopointProcessor.process(methodInfo, infoPoint);
 235             }
 236 
 237             for (Mark mark : compilationResult.getMarks()) {
 238                 markProcessor.process(methodInfo, mark);
 239             }
 240 
 241             for (DataPatch dataPatch : compilationResult.getDataPatches()) {
 242                 dataPatchProcessor.process(methodInfo, dataPatch);
 243             }
 244         }
 245     }
 246 
 247 }