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