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
24package jdk.tools.jaotc;
25
26import java.util.concurrent.atomic.AtomicInteger;
27import java.util.HashMap;
28import java.util.Map;
29
30import jdk.tools.jaotc.binformat.BinaryContainer;
31import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
32import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
33import org.graalvm.compiler.code.CompilationResult;
34
35import jdk.vm.ci.code.site.Mark;
36import jdk.vm.ci.code.site.Site;
37import jdk.vm.ci.hotspot.HotSpotCompiledCode;
38import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
39
40final class CompiledMethodInfo {
41
42    private static final int UNINITIALIZED_OFFSET = -1;
43
44    private static class AOTMethodOffsets {
45        /**
46         * Offset in metaspace names section.
47         */
48        private int nameOffset;
49
50        /**
51         * Offset in the text section at which compiled code starts.
52         */
53        private int textSectionOffset;
54
55        /**
56         * Offset in the metadata section.
57         */
58        private int metadataOffset;
59
60        /**
61         * Offset to the metadata in the GOT table.
62         */
63        private int metadataGotOffset;
64
65        /**
66         * Size of the metadata.
67         */
68        private int metadataGotSize;
69
70        /**
71         * The sequential number corresponding to the order of methods code in code buffer.
72         */
73        private int codeId;
74
75        AOTMethodOffsets() {
76            this.nameOffset = UNINITIALIZED_OFFSET;
77            this.textSectionOffset = UNINITIALIZED_OFFSET;
78            this.metadataOffset = UNINITIALIZED_OFFSET;
79            this.metadataGotOffset = UNINITIALIZED_OFFSET;
80            this.metadataGotSize = -1;
81            this.codeId = -1;
82        }
83
84        void addMethodOffsets(ReadOnlyDataContainer container, String name) {
85            verify(name);
86            // @formatter:off
87            /*
88             * The offsets layout should match AOTMethodOffsets structure in AOT JVM runtime
89             */
90                      // Add the offset to the name in the .metaspace.names section
91            container.appendInt(nameOffset).
92                      // Add the offset to the code in the .text section
93                      appendInt(textSectionOffset).
94                      // Add the offset to the metadata in the .method.metadata section
95                      appendInt(metadataOffset).
96                      // Add the offset to the metadata in the .metadata.got section
97                      appendInt(metadataGotOffset).
98                      // Add the size of the metadata
99                      appendInt(metadataGotSize).
100                      // Add code ID.
101                      appendInt(codeId);
102            // @formatter:on
103        }
104
105        private void verify(String name) {
106            assert nameOffset >= 0 : "incorrect nameOffset: " + nameOffset + " for method: " + name;
107            assert textSectionOffset > 0 : "incorrect textSectionOffset: " + textSectionOffset + " for method: " + name;
108            assert metadataOffset >= 0 : "incorrect metadataOffset: " + metadataOffset + " for method: " + name;
109            assert metadataGotOffset >= 0 : "incorrect metadataGotOffset: " + metadataGotOffset + " for method: " + name;
110            assert metadataGotSize >= 0 : "incorrect metadataGotSize: " + metadataGotSize + " for method: " + name;
111            assert codeId >= 0 : "incorrect codeId: " + codeId + " for method: " + name;
112        }
113
114        protected void setNameOffset(int offset) {
115            nameOffset = offset;
116        }
117
118        protected void setTextSectionOffset(int textSectionOffset) {
119            this.textSectionOffset = textSectionOffset;
120        }
121
122        protected int getTextSectionOffset() {
123            return textSectionOffset;
124        }
125
126        protected void setCodeId(int codeId) {
127            this.codeId = codeId;
128        }
129
130        protected int getCodeId() {
131            return codeId;
132        }
133
134        protected void setMetadataOffset(int offset) {
135            metadataOffset = offset;
136        }
137
138        protected void setMetadataGotOffset(int metadataGotOffset) {
139            this.metadataGotOffset = metadataGotOffset;
140        }
141
142        protected void setMetadataGotSize(int length) {
143            this.metadataGotSize = length;
144        }
145    }
146
147    /**
148     * Method name
149     */
150    private String name;
151
152    /**
153     * Result of graal compilation.
154     */
155    private CompilationResult compilationResult;
156
157    /**
158     * HotSpotResolvedJavaMethod or Stub corresponding to the compilation result.
159     */
160    private JavaMethodInfo methodInfo;
161
162    /**
163     * Compiled code from installation.
164     */
165    private HotSpotCompiledCode code;
166
167    /**
168     * Offset to stubs.
169     */
170    private int stubsOffset;
171
172    /**
173     * The total size in bytes of the stub section.
174     */
175    private int totalStubSize;
176
177    /**
178     * Method's offsets.
179     */
180    private AOTMethodOffsets methodOffsets;
181
182    /**
183     * List of stubs (PLT trampoline).
184     */
185    private Map<String, StubInformation> stubs = new HashMap<>();
186
187    /**
188     * List of referenced classes.
189     */
190    private Map<String, AOTKlassData> dependentKlasses = new HashMap<>();
191
192    /**
193     * Methods count used to generate unique global method id.
194     */
195    private static final AtomicInteger methodsCount = new AtomicInteger();
196
197    CompiledMethodInfo(CompilationResult compilationResult, JavaMethodInfo methodInfo) {
198        this.name = methodInfo.getNameAndSignature();
199        this.compilationResult = compilationResult;
200        this.methodInfo = methodInfo;
201        this.stubsOffset = UNINITIALIZED_OFFSET;
202        this.methodOffsets = new AOTMethodOffsets();
203    }
204
205    String name() {
206        return name;
207    }
208
209    void addMethodOffsets(BinaryContainer binaryContainer, ReadOnlyDataContainer container) {
210        this.methodOffsets.setNameOffset(binaryContainer.addMetaspaceName(name));
211        this.methodOffsets.addMethodOffsets(container, name);
212        for (AOTKlassData data : dependentKlasses.values()) {
213            data.addDependentMethod(this);
214        }
215    }
216
217    CompilationResult getCompilationResult() {
218        return compilationResult;
219    }
220
221    JavaMethodInfo getMethodInfo() {
222        return methodInfo;
223    }
224
225    void setTextSectionOffset(int textSectionOffset) {
226        methodOffsets.setTextSectionOffset(textSectionOffset);
227    }
228
229    public int getTextSectionOffset() {
230        return methodOffsets.getTextSectionOffset();
231    }
232
233    void setCodeId() {
234        methodOffsets.setCodeId(CompiledMethodInfo.getNextCodeId());
235    }
236
237    int getCodeId() {
238        return this.methodOffsets.getCodeId();
239    }
240
241    static int getMethodsCount() {
242        return methodsCount.get();
243    }
244
245    static int getNextCodeId() {
246        return methodsCount.getAndIncrement();
247    }
248
249    int getCodeSize() {
250        return stubsOffset + getStubCodeSize();
251    }
252
253    int getStubCodeSize() {
254        return totalStubSize;
255    }
256
257    void setMetadataOffset(int offset) {
258        this.methodOffsets.setMetadataOffset(offset);
259    }
260
261    /**
262     * Offset into the code of this method where the stub section starts.
263     */
264    void setStubsOffset(int offset) {
265        stubsOffset = offset;
266    }
267
268    int getStubsOffset() {
269        return stubsOffset;
270    }
271
272    void setMetadataGotOffset(int metadataGotOffset) {
273        this.methodOffsets.setMetadataGotOffset(metadataGotOffset);
274    }
275
276    void setMetadataGotSize(int length) {
277        this.methodOffsets.setMetadataGotSize(length);
278    }
279
280    void addStubCode(String call, StubInformation stub) {
281        stubs.put(call, stub);
282        totalStubSize += stub.getSize();
283    }
284
285    StubInformation getStubFor(String call) {
286        StubInformation stub = stubs.get(call);
287        assert stub != null : "missing stub for call " + call;
288        stub.verify();
289        return stub;
290    }
291
292    void addDependentKlassData(BinaryContainer binaryContainer, HotSpotResolvedObjectType type) {
293        AOTKlassData klassData = AOTCompiledClass.addFingerprintKlassData(binaryContainer, type);
294        String klassName = type.getName();
295
296        if (dependentKlasses.containsKey(klassName)) {
297            assert dependentKlasses.get(klassName) == klassData : "duplicated data for klass: " + klassName;
298        } else {
299            dependentKlasses.put(klassName, klassData);
300        }
301    }
302
303    AOTKlassData getDependentKlassData(String klassName) {
304        return dependentKlasses.get(klassName);
305    }
306
307    boolean hasMark(Site call, MarkId id) {
308        for (Mark m : compilationResult.getMarks()) {
309            // TODO: X64-specific code.
310            // Call instructions are aligned to 8
311            // bytes - 1 on x86 to patch address atomically,
312            int adjOffset = (m.pcOffset & (-8)) + 7;
313            // Mark points before aligning nops.
314            if ((call.pcOffset == adjOffset) && MarkId.getEnum((int) m.id) == id) {
315                return true;
316            }
317        }
318        return false;
319    }
320
321    String asTag() {
322        return "[" + methodInfo.getSymbolName() + "]";
323    }
324
325    HotSpotCompiledCode compiledCode() {
326        if (code == null) {
327            code = methodInfo.compiledCode(compilationResult);
328        }
329        return code;
330    }
331
332    // Free memory
333    void clear() {
334        this.dependentKlasses = null;
335        this.name = null;
336    }
337
338    void clearCompileData() {
339        this.code = null;
340        this.stubs = null;
341        this.compilationResult = null;
342        this.methodInfo = null;
343    }
344}
345