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