1 /*
   2  * Copyright (c) 2016, 2017, 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 package jdk.tools.jaotc;
  25 
  26 import java.util.ArrayList;
  27 import java.util.List;
  28 
  29 import jdk.tools.jaotc.binformat.BinaryContainer;
  30 import jdk.tools.jaotc.binformat.ByteContainer;
  31 import jdk.tools.jaotc.binformat.GotSymbol;
  32 import jdk.tools.jaotc.utils.NativeOrderOutputStream;
  33 import org.graalvm.compiler.code.CompilationResult;
  34 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
  35 
  36 import jdk.vm.ci.code.StackSlot;
  37 import jdk.vm.ci.code.site.DataPatch;
  38 import jdk.vm.ci.code.site.Infopoint;
  39 import jdk.vm.ci.code.site.Mark;
  40 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
  41 import jdk.vm.ci.hotspot.HotSpotMetaData;
  42 
  43 final class MetadataBuilder {
  44 
  45     private final DataBuilder dataBuilder;
  46 
  47     private final BinaryContainer binaryContainer;
  48 
  49     MetadataBuilder(DataBuilder dataBuilder) {
  50         this.dataBuilder = dataBuilder;
  51         this.binaryContainer = dataBuilder.getBinaryContainer();
  52     }
  53 
  54     /**
  55      * Process compiled methods and create method metadata.
  56      */
  57     void processMetadata(List<AOTCompiledClass> classes, AOTCompiledClass stubCompiledCode) {
  58         for (AOTCompiledClass c : classes) {
  59             processMetadataClass(c);
  60         }
  61         processMetadataClass(stubCompiledCode);
  62     }
  63 
  64     private void processMetadataClass(AOTCompiledClass c) {
  65         processInfopointsAndMarks(c);
  66         createMethodMetadata(c);
  67     }
  68 
  69     /**
  70      * Add metadata for each of the compiled methods in {@code compiledClass} to read-only section
  71      * of {@code binaryContainer}.
  72      *
  73      * @param compiledClass AOT Graal compilation result
  74      */
  75     private void createMethodMetadata(AOTCompiledClass compiledClass) {
  76         HotSpotGraalRuntimeProvider runtime = dataBuilder.getBackend().getRuntime();
  77         ByteContainer methodMetadataContainer = binaryContainer.getMethodMetadataContainer();
  78 
  79         // For each of the compiled java methods, create records holding information about them.
  80         for (CompiledMethodInfo methodInfo : compiledClass.getCompiledMethods()) {
  81             // Get the current offset in the methodmetadata container.
  82             final int startOffset = methodMetadataContainer.getByteStreamSize();
  83             assert startOffset % 8 == 0 : "Must be aligned on 8";
  84 
  85             methodInfo.setMetadataOffset(startOffset);
  86 
  87             HotSpotCompiledCode compiledMethod = methodInfo.compiledCode();
  88             // pc and scope description
  89             HotSpotMetaData metaData = new HotSpotMetaData(runtime.getTarget(), compiledMethod);
  90 
  91             byte[] pcDesc = metaData.pcDescBytes();
  92             byte[] scopeDesc = metaData.scopesDescBytes();
  93             byte[] relocationInfo = metaData.relocBytes();
  94             byte[] oopMapInfo = metaData.oopMaps();
  95 
  96             // create a global symbol at this position for this method
  97             NativeOrderOutputStream metadataStream = new NativeOrderOutputStream();
  98 
  99             // get the code size
 100             int codeSize = methodInfo.getCodeSize();
 101 
 102             // get code offsets
 103             CodeOffsets co = CodeOffsets.buildFrom(methodInfo.getCompilationResult().getMarks());
 104             int unverifiedEntry = co.entry();
 105             int verifiedEntry = co.verifiedEntry();
 106             int exceptionHandler = co.exceptionHandler();
 107             int deoptHandler = co.deoptHandler();
 108             int frameSize = methodInfo.getCompilationResult().getTotalFrameSize();
 109             StackSlot deoptRescueSlot = methodInfo.getCompilationResult().getCustomStackArea();
 110             int origPcOffset = deoptRescueSlot != null ? deoptRescueSlot.getOffset(frameSize) : -1;
 111 
 112             // get stubs offset
 113             int stubsOffset = methodInfo.getStubsOffset();
 114 
 115             int offset = addMetadataEntries(binaryContainer, metaData, methodInfo);
 116             methodInfo.setMetadataGotOffset(offset);
 117             methodInfo.setMetadataGotSize(metaData.metadataEntries().length);
 118             int unsafeAccess = methodInfo.getCompilationResult().hasUnsafeAccess() ? 1 : 0;
 119             try {
 120                 // calculate total size of the container
 121                 NativeOrderOutputStream.PatchableInt totalSize = metadataStream.patchableInt();
 122 
 123                 // @formatter:off
 124                 metadataStream.putInt(codeSize).
 125                                putInt(unverifiedEntry).
 126                                putInt(verifiedEntry).
 127                                putInt(exceptionHandler).
 128                                putInt(deoptHandler).
 129                                putInt(stubsOffset).
 130                                putInt(frameSize).
 131                                putInt(origPcOffset).
 132                                putInt(unsafeAccess);
 133                 // @formatter:on
 134 
 135                 NativeOrderOutputStream.PatchableInt pcDescOffset = metadataStream.patchableInt();
 136                 NativeOrderOutputStream.PatchableInt scopeOffset = metadataStream.patchableInt();
 137                 NativeOrderOutputStream.PatchableInt relocationOffset = metadataStream.patchableInt();
 138                 NativeOrderOutputStream.PatchableInt exceptionOffset = metadataStream.patchableInt();
 139                 NativeOrderOutputStream.PatchableInt oopMapOffset = metadataStream.patchableInt();
 140                 metadataStream.align(8);
 141 
 142                 pcDescOffset.set(metadataStream.position());
 143                 metadataStream.put(pcDesc).align(8);
 144 
 145                 scopeOffset.set(metadataStream.position());
 146                 metadataStream.put(scopeDesc).align(8);
 147 
 148                 relocationOffset.set(metadataStream.position());
 149                 metadataStream.put(relocationInfo).align(8);
 150 
 151                 exceptionOffset.set(metadataStream.position());
 152                 metadataStream.put(metaData.exceptionBytes()).align(8);
 153 
 154                 // oopmaps should be last
 155                 oopMapOffset.set(metadataStream.position());
 156                 metadataStream.put(oopMapInfo).align(8);
 157 
 158                 totalSize.set(metadataStream.position());
 159 
 160                 byte[] data = metadataStream.array();
 161 
 162                 methodMetadataContainer.appendBytes(data, 0, data.length);
 163             } catch (Exception e) {
 164                 throw new InternalError("Exception occurred during compilation of " + methodInfo.getMethodInfo().getSymbolName(), e);
 165             }
 166             methodInfo.clearCompileData(); // Clear unused anymore compilation data
 167         }
 168     }
 169 
 170     private static int addMetadataEntries(BinaryContainer binaryContainer, HotSpotMetaData metaData, CompiledMethodInfo methodInfo) {
 171         String[] metaDataEntries = metaData.metadataEntries();
 172 
 173         if (metaDataEntries.length == 0) {
 174             return 0;
 175         }
 176 
 177         int metadataGotSlotsStart = binaryContainer.getMetadataGotContainer().getByteStreamSize(); // binaryContainer.reserveMetadataGOTSlots(metaDataEntries.length);
 178 
 179         for (int index = 0; index < metaDataEntries.length; index++) {
 180             String name = metaDataEntries[index];
 181             addMetadataEntry(binaryContainer, name);
 182             // Create GOT cells for klasses referenced in metadata
 183             String klassName = name;
 184             int len = name.length();
 185             int parenthesesIndex = name.lastIndexOf('(', len - 1);
 186             if (parenthesesIndex > 0) {  // Method name
 187                 int dotIndex = name.lastIndexOf('.', parenthesesIndex - 1);
 188                 assert dotIndex > 0 : "method's full name should have '.' : " + name;
 189                 klassName = name.substring(0, dotIndex);
 190             }
 191             // We should already have added entries for this klass
 192             assert AOTCompiledClass.getAOTKlassData(klassName) != null;
 193             assert methodInfo.getDependentKlassData(klassName) != null;
 194         }
 195 
 196         return metadataGotSlotsStart;
 197     }
 198 
 199     private static void addMetadataEntry(BinaryContainer binaryContainer, String name) {
 200         int stringOffset = binaryContainer.addMetaspaceName(name);
 201         binaryContainer.addMetadataGotEntry(stringOffset);
 202     }
 203 
 204     /**
 205      * Process {@link Infopoint}s, {@link Mark}s and {@link DataPatch}es generated by the compiler
 206      * to create all needed binary section constructs.
 207      *
 208      * @param compiledClass compilation result
 209      */
 210     private void processInfopointsAndMarks(AOTCompiledClass compiledClass) {
 211         ArrayList<CompiledMethodInfo> compiledMethods = compiledClass.getCompiledMethods();
 212 
 213         MarkProcessor markProcessor = new MarkProcessor(dataBuilder);
 214         DataPatchProcessor dataPatchProcessor = new DataPatchProcessor(dataBuilder);
 215         InfopointProcessor infopointProcessor = new InfopointProcessor(dataBuilder);
 216 
 217         for (CompiledMethodInfo methodInfo : compiledMethods) {
 218             CompilationResult compilationResult = methodInfo.getCompilationResult();
 219             String targetSymbol = "state.M" + methodInfo.getCodeId();
 220             String gotName = "got." + targetSymbol;
 221             GotSymbol symbol = binaryContainer.getMethodStateContainer().createGotSymbol(gotName);
 222             assert (symbol.getIndex() == methodInfo.getCodeId()) : "wrong offset";
 223 
 224             for (Infopoint infoPoint : compilationResult.getInfopoints()) {
 225                 infopointProcessor.process(methodInfo, infoPoint);
 226             }
 227 
 228             for (Mark mark : compilationResult.getMarks()) {
 229                 markProcessor.process(methodInfo, mark);
 230             }
 231 
 232             for (DataPatch dataPatch : compilationResult.getDataPatches()) {
 233                 dataPatchProcessor.process(methodInfo, dataPatch);
 234             }
 235         }
 236     }
 237 
 238 }