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