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 package jdk.tools.jaotc;
25 
26 import jdk.tools.jaotc.binformat.BinaryContainer;
27 import jdk.tools.jaotc.binformat.Relocation;
28 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
29 
30 import jdk.vm.ci.code.BytecodePosition;
31 import jdk.vm.ci.code.VirtualObject;
32 import jdk.vm.ci.code.site.Call;
33 import jdk.vm.ci.code.site.Infopoint;
34 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
35 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
36 import jdk.vm.ci.meta.InvokeTarget;
37 
38 final class InfopointProcessor {
39 
40     private final DataBuilder dataBuilder;
41 
42     private final BinaryContainer binaryContainer;
43 
InfopointProcessor(DataBuilder dataBuilder)44     InfopointProcessor(DataBuilder dataBuilder) {
45         this.dataBuilder = dataBuilder;
46         this.binaryContainer = dataBuilder.getBinaryContainer();
47     }
48 
49     /**
50      * Parse an {@link Infopoint} generated by the compiler and create all needed binary section
51      * constructs.
52      *
53      * @param methodInfo compiled method info
54      * @param info info point being processed
55      */
process(CompiledMethodInfo methodInfo, Infopoint info)56     void process(CompiledMethodInfo methodInfo, Infopoint info) {
57         switch (info.reason) {
58             case CALL:
59                 // All calls in compiled code need a symbol and relocation entry.
60                 processCallInfoPoint(methodInfo, (Call) info);
61                 break;
62             case SAFEPOINT:
63             case IMPLICIT_EXCEPTION:
64             case METHOD_START:
65             case METHOD_END:
66             case BYTECODE_POSITION:
67                 break;
68             default:
69                 throw new InternalError("Unknown info point reason: " + info.reason);
70         }
71         if (info.debugInfo == null) {
72             return;
73         }
74         BytecodePosition bcp = info.debugInfo.getBytecodePosition();
75         if (bcp == null) {
76             return;
77         }
78         recordScopeKlasses(methodInfo, bcp, info.debugInfo.getVirtualObjectMapping());
79     }
80 
recordScopeKlasses(CompiledMethodInfo methodInfo, BytecodePosition bcp, VirtualObject[] vos)81     private void recordScopeKlasses(CompiledMethodInfo methodInfo, BytecodePosition bcp, VirtualObject[] vos) {
82         BytecodePosition caller = bcp.getCaller();
83         if (caller != null) {
84             recordScopeKlasses(methodInfo, caller, vos);
85         }
86 
87         HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod) bcp.getMethod();
88         HotSpotResolvedObjectType klass = m.getDeclaringClass();
89         methodInfo.addDependentKlassData(binaryContainer, klass);
90 
91         if (vos == null) {
92             return;
93         }
94         for (VirtualObject vo : vos) {
95             HotSpotResolvedObjectType vk = (HotSpotResolvedObjectType) vo.getType();
96             methodInfo.addDependentKlassData(binaryContainer, vk);
97         }
98 
99     }
100 
101     /**
102      * Process Call info points in Graal generated compilation result. We want to create one of the
103      * following relocations: .text -> .hotspot.plt.linkage - Java method to Java method call .text
104      * -> .text - Java method / Graal stub to Graal stub call .text -> .plt - Java method / Graal
105      * stub to VM method call.
106      *
107      * @param methodInfo compiled method info
108      * @param call call
109      */
processCallInfoPoint(CompiledMethodInfo methodInfo, Call call)110     private void processCallInfoPoint(CompiledMethodInfo methodInfo, Call call) {
111         CallSiteRelocationInfo callSiteRelocation = getCallSiteRelocationInfo(call);
112         CallSiteRelocationSymbol callSiteRelocationSymbol = getCallSiteRelocationSymbol(methodInfo, call, callSiteRelocation);
113 
114         Relocation relocation = new Relocation(methodInfo.getTextSectionOffset() + call.pcOffset, callSiteRelocation.type, call.size, binaryContainer.getCodeContainer(),
115                         callSiteRelocationSymbol.symbol);
116         binaryContainer.addRelocation(relocation);
117     }
118 
119     /**
120      * Get information about the call site. Name of the callee and relocation call type.
121      */
getCallSiteRelocationInfo(Call call)122     private static CallSiteRelocationInfo getCallSiteRelocationInfo(Call call) {
123         InvokeTarget callTarget = call.target;
124         if (callTarget instanceof HotSpotResolvedJavaMethod) {
125             return new JavaCallSiteRelocationInfo(call, (HotSpotResolvedJavaMethod) callTarget);
126         } else if (callTarget instanceof HotSpotForeignCallLinkage) {
127             return new ForeignCallSiteRelocationInfo(call, (HotSpotForeignCallLinkage) callTarget);
128         } else {
129             throw new InternalError("Unhandled call type found in infopoint: " + callTarget);
130         }
131     }
132 
133     /**
134      * Return a relocation symbol for the given call site.
135      */
getCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation)136     private CallSiteRelocationSymbol getCallSiteRelocationSymbol(CompiledMethodInfo mi, Call call, CallSiteRelocationInfo callSiteRelocation) {
137         switch (callSiteRelocation.type) {
138             case STUB_CALL_DIRECT:
139                 return new StubDirectCallSiteRelocationSymbol(callSiteRelocation, binaryContainer);
140             case FOREIGN_CALL_INDIRECT_GOT:
141                 return new ForeignGotCallSiteRelocationSymbol(mi, call, callSiteRelocation, dataBuilder);
142             default:
143                 return new JavaCallSiteRelocationSymbol(mi, call, callSiteRelocation, binaryContainer);
144         }
145     }
146 
147 }
148