1 /* 2 * Copyright (c) 2016, 2020, 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 MetadataBuilder(DataBuilder dataBuilder)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 */ processMetadata(List<AOTCompiledClass> classes, AOTCompiledClass stubCompiledCode)63 void processMetadata(List<AOTCompiledClass> classes, AOTCompiledClass stubCompiledCode) { 64 for (AOTCompiledClass c : classes) { 65 processMetadataClass(c); 66 } 67 processMetadataClass(stubCompiledCode); 68 } 69 processMetadataClass(AOTCompiledClass c)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 */ createMethodMetadata(AOTCompiledClass compiledClass)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 // this may be null as the field does not exist before JDK 13 102 byte[] implicitExceptionBytes = HotSpotGraalServices.getImplicitExceptionBytes(metaData); 103 byte[] exceptionBytes = metaData.exceptionBytes(); 104 105 // create a global symbol at this position for this method 106 NativeOrderOutputStream metadataStream = new NativeOrderOutputStream(); 107 108 // get the code size 109 int codeSize = methodInfo.getCodeSize(); 110 111 // get code offsets 112 CodeOffsets co = CodeOffsets.buildFrom(methodInfo.getCompilationResult().getMarks()); 113 int unverifiedEntry = co.entry(); 114 int verifiedEntry = co.verifiedEntry(); 115 int exceptionHandler = co.exceptionHandler(); 116 int deoptHandler = co.deoptHandler(); 117 int deoptMHHandler = co.deoptMHHandler(); 118 int frameSize = methodInfo.getCompilationResult().getTotalFrameSize(); 119 StackSlot deoptRescueSlot = methodInfo.getCompilationResult().getCustomStackArea(); 120 int origPcOffset = deoptRescueSlot != null ? deoptRescueSlot.getOffset(frameSize) : -1; 121 122 // get stubs offset 123 int stubsOffset = methodInfo.getStubsOffset(); 124 125 int offset = addMetadataEntries(binaryContainer, metaData, methodInfo); 126 methodInfo.setMetadataGotOffset(offset); 127 methodInfo.setMetadataGotSize(metaData.metadataEntries().length); 128 int unsafeAccess = methodInfo.getCompilationResult().hasUnsafeAccess() ? 1 : 0; 129 try { 130 // calculate total size of the container 131 NativeOrderOutputStream.PatchableInt totalSize = metadataStream.patchableInt(); 132 133 // @formatter:off 134 metadataStream.putInt(codeSize). 135 putInt(unverifiedEntry). 136 putInt(verifiedEntry). 137 putInt(exceptionHandler). 138 putInt(deoptHandler). 139 putInt(deoptMHHandler). 140 putInt(stubsOffset). 141 putInt(frameSize). 142 putInt(origPcOffset). 143 putInt(unsafeAccess); 144 // @formatter:on 145 146 NativeOrderOutputStream.PatchableInt pcDescOffset = metadataStream.patchableInt(); 147 NativeOrderOutputStream.PatchableInt scopeOffset = metadataStream.patchableInt(); 148 NativeOrderOutputStream.PatchableInt relocationOffset = metadataStream.patchableInt(); 149 NativeOrderOutputStream.PatchableInt exceptionOffset = metadataStream.patchableInt(); 150 NativeOrderOutputStream.PatchableInt implictTableOffset = null; 151 if (implicitExceptionBytes != null) { 152 implictTableOffset = metadataStream.patchableInt(); 153 } 154 NativeOrderOutputStream.PatchableInt oopMapOffset = metadataStream.patchableInt(); 155 metadataStream.align(8); 156 157 pcDescOffset.set(metadataStream.position()); 158 metadataStream.put(pcDesc).align(8); 159 160 scopeOffset.set(metadataStream.position()); 161 metadataStream.put(scopeDesc).align(8); 162 163 relocationOffset.set(metadataStream.position()); 164 metadataStream.put(relocationInfo).align(8); 165 166 exceptionOffset.set(metadataStream.position()); 167 metadataStream.put(exceptionBytes).align(8); 168 169 if (implicitExceptionBytes != null) { 170 implictTableOffset.set(metadataStream.position()); 171 metadataStream.put(implicitExceptionBytes).align(8); 172 } 173 174 // oopmaps should be last 175 oopMapOffset.set(metadataStream.position()); 176 metadataStream.put(oopMapInfo).align(8); 177 178 totalSize.set(metadataStream.position()); 179 180 byte[] data = metadataStream.array(); 181 182 methodMetadataContainer.appendBytes(data, 0, data.length); 183 } catch (Exception e) { 184 throw new InternalError("Exception occurred during compilation of " + methodInfo.getMethodInfo().getSymbolName(), e); 185 } 186 methodInfo.clearCompileData(); // Clear unused anymore compilation data 187 } 188 } 189 addMetadataEntries(BinaryContainer binaryContainer, HotSpotMetaData metaData, CompiledMethodInfo methodInfo)190 private static int addMetadataEntries(BinaryContainer binaryContainer, HotSpotMetaData metaData, CompiledMethodInfo methodInfo) { 191 Object[] metaDataEntries = metaData.metadataEntries(); 192 193 if (metaDataEntries.length == 0) { 194 return 0; 195 } 196 197 int metadataGotSlotsStart = binaryContainer.getMetadataGotContainer().getByteStreamSize(); // binaryContainer.reserveMetadataGOTSlots(metaDataEntries.length); 198 199 for (int index = 0; index < metaDataEntries.length; index++) { 200 Object ref = metaDataEntries[index]; 201 String name = metadataName(ref); 202 // Create GOT cells for klasses referenced in metadata 203 addMetadataEntry(binaryContainer, name); 204 // We should already have added entries for this klass 205 assert AOTCompiledClass.getAOTKlassData(getType(ref)) != null; 206 assert methodInfo.getDependentKlassData(getType(ref)) != null; 207 } 208 209 return metadataGotSlotsStart; 210 } 211 addMetadataEntry(BinaryContainer binaryContainer, String name)212 private static void addMetadataEntry(BinaryContainer binaryContainer, String name) { 213 int stringOffset = binaryContainer.addMetaspaceName(name); 214 binaryContainer.addMetadataGotEntry(stringOffset); 215 } 216 217 /** 218 * Process {@link Infopoint}s, {@link Mark}s and {@link DataPatch}es generated by the compiler 219 * to create all needed binary section constructs. 220 * 221 * @param compiledClass compilation result 222 */ processInfopointsAndMarks(AOTCompiledClass compiledClass)223 private void processInfopointsAndMarks(AOTCompiledClass compiledClass) { 224 ArrayList<CompiledMethodInfo> compiledMethods = compiledClass.getCompiledMethods(); 225 226 MarkProcessor markProcessor = new MarkProcessor(dataBuilder); 227 DataPatchProcessor dataPatchProcessor = new DataPatchProcessor(dataBuilder); 228 InfopointProcessor infopointProcessor = new InfopointProcessor(dataBuilder); 229 230 for (CompiledMethodInfo methodInfo : compiledMethods) { 231 CompilationResult compilationResult = methodInfo.getCompilationResult(); 232 String targetSymbol = "state.M" + methodInfo.getCodeId(); 233 String gotName = "got." + targetSymbol; 234 GotSymbol symbol = binaryContainer.getMethodStateContainer().createGotSymbol(gotName); 235 assert (symbol.getIndex() == methodInfo.getCodeId()) : "wrong offset"; 236 237 for (Infopoint infoPoint : compilationResult.getInfopoints()) { 238 infopointProcessor.process(methodInfo, infoPoint); 239 } 240 241 for (CompilationResult.CodeMark mark : compilationResult.getMarks()) { 242 markProcessor.process(methodInfo, mark); 243 } 244 245 for (DataPatch dataPatch : compilationResult.getDataPatches()) { 246 dataPatchProcessor.process(methodInfo, dataPatch); 247 } 248 } 249 } 250 251 } 252