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 }