1 /*
2 * Copyright (c) 1997, 2026, 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 #ifndef SHARE_CODE_COMPILEDIC_HPP
26 #define SHARE_CODE_COMPILEDIC_HPP
27
28 #include "code/nativeInst.hpp"
29 #include "interpreter/linkResolver.hpp"
30 #include "runtime/safepointVerifiers.hpp"
31
32 //-----------------------------------------------------------------------------
33 // The CompiledIC represents a compiled inline cache.
34 //
35 // It's safe to transition from any state to any state. Typically an inline cache starts
36 // in the clean state, meaning it will resolve the call when called. Then it typically
37 // transitions to monomorphic, assuming the first dynamic receiver will be the only one
38 // observed. If that speculation fails, we transition to megamorphic.
39 //
40 class CompiledIC;
41 class CompiledICProtectionBehaviour;
42 class nmethod;
43
44 class CompiledICLocker: public StackObj {
45 nmethod* _method;
46 CompiledICProtectionBehaviour* _behaviour;
47 bool _locked;
48 NoSafepointVerifier _nsv;
49
50 public:
51 CompiledICLocker(nmethod* method);
52 ~CompiledICLocker();
53 static bool is_safe(nmethod* nm);
54 static bool is_safe(address code);
55 };
56
57 // A CompiledICData is a helper object for the inline cache implementation.
58 // It comprises:
59 // (1) The first receiver klass and its selected method
60 // (2) Itable call metadata
61
62 class CompiledICData : public CHeapObj<mtCode> {
63 friend class VMStructs;
64
65 Method* volatile _speculated_method;
66 uintptr_t volatile _speculated_klass;
67 Klass* _itable_defc_klass;
68 Klass* _itable_refc_klass;
69 bool _is_initialized;
70
71 bool is_speculated_klass_unloaded() const;
72
73 public:
74 // Constructor
75 CompiledICData();
76
77 // accessors
78 Klass* speculated_klass() const;
79 Method* speculated_method() const { return _speculated_method; }
80 Klass* itable_defc_klass() const { return _itable_defc_klass; }
81 Klass* itable_refc_klass() const { return _itable_refc_klass; }
82
83 static ByteSize speculated_method_offset() { return byte_offset_of(CompiledICData, _speculated_method); }
84 static ByteSize speculated_klass_offset() { return byte_offset_of(CompiledICData, _speculated_klass); }
85
86 static ByteSize itable_defc_klass_offset() { return byte_offset_of(CompiledICData, _itable_defc_klass); }
87 static ByteSize itable_refc_klass_offset() { return byte_offset_of(CompiledICData, _itable_refc_klass); }
88
89 void initialize(CallInfo* call_info, Klass* receiver_klass);
90
91 bool is_initialized() const { return _is_initialized; }
92
93 // GC Support
94 void clean_metadata();
95 void metadata_do(MetadataClosure* cl);
96 };
97
98 class CompiledIC: public ResourceObj {
99 private:
100 nmethod* _method;
101 CompiledICData* _data;
102 NativeCall* _call;
103
104 CompiledIC(RelocIterator* iter);
105
106 // CompiledICData wrappers
107 void ensure_initialized(CallInfo* call_info, Klass* receiver_klass);
108 bool is_speculated_klass(Klass* receiver_klass);
109
110 // Inline cache states
111 void set_to_monomorphic(bool caller_is_c1);
112 void set_to_megamorphic(CallInfo* call_info, bool caller_is_c1);
113
114 public:
115 // conversion (machine PC to CompiledIC*)
116 friend CompiledIC* CompiledIC_before(nmethod* nm, address return_addr);
117 friend CompiledIC* CompiledIC_at(nmethod* nm, address call_site);
118 friend CompiledIC* CompiledIC_at(Relocation* call_site);
119 friend CompiledIC* CompiledIC_at(RelocIterator* reloc_iter);
120
121 CompiledICData* data() const;
122
123 // State
124 bool is_clean() const;
125 bool is_monomorphic() const;
126 bool is_megamorphic() const;
127
128 address end_of_call() const { return _call->return_address(); }
129
130 // MT-safe patching of inline caches. Note: Only safe to call is_xxx when holding the CompiledICLocker
131 // so you are guaranteed that no patching takes place. The same goes for verify.
132 void set_to_clean();
133 void update(CallInfo* call_info, Klass* receiver_klass, bool caller_is_c1);
134
135 // GC support
136 void clean_metadata();
137 void metadata_do(MetadataClosure* cl);
138
139 // Location
140 address instruction_address() const { return _call->instruction_address(); }
141 address destination() const { return _call->destination(); }
142
143 // Misc
144 void print() PRODUCT_RETURN;
145 void verify() PRODUCT_RETURN;
146 };
147
148 CompiledIC* CompiledIC_before(nmethod* nm, address return_addr);
149 CompiledIC* CompiledIC_at(nmethod* nm, address call_site);
150 CompiledIC* CompiledIC_at(Relocation* call_site);
151 CompiledIC* CompiledIC_at(RelocIterator* reloc_iter);
152
153 //-----------------------------------------------------------------------------
154 // The CompiledDirectCall represents a call to a method in the compiled code
155 //
156 //
157 // -----<----- Clean ----->-----
158 // / \
159 // / \
160 // compiled code <------------> interpreted code
161 //
162 // Clean: Calls directly to runtime method for fixup
163 // Compiled code: Calls directly to compiled code
164 // Interpreted code: Calls to stub that set Method* reference
165 //
166 //
167
168 class CompiledDirectCall : public ResourceObj {
169 private:
170 friend class CompiledIC;
171 friend class DirectNativeCallWrapper;
172
173 // Also used by CompiledIC
174 void set_to_interpreted(const methodHandle& callee, address entry);
175 void verify_mt_safe(const methodHandle& callee, address entry,
176 NativeMovConstReg* method_holder,
177 NativeJump* jump) PRODUCT_RETURN;
178 address instruction_address() const { return _call->instruction_address(); }
179 void set_destination_mt_safe(address dest) { _call->set_destination_mt_safe(dest); }
180
181 NativeCall* _call;
182
183 CompiledDirectCall(NativeCall* call) : _call(call) {}
184
185 public:
186 // Returns null if CodeBuffer::expand fails
187 static address emit_to_interp_stub(MacroAssembler *masm, address mark = nullptr);
188 static int to_interp_stub_size();
189 static int to_trampoline_stub_size();
190 static int reloc_to_interp_stub();
191
192 static inline CompiledDirectCall* before(address return_addr) {
193 CompiledDirectCall* st = new CompiledDirectCall(nativeCall_before(return_addr));
194 if (VerifyInlineCaches) st->verify();
195 return st;
196 }
197
198 static inline CompiledDirectCall* at(address native_call) {
199 CompiledDirectCall* st = new CompiledDirectCall(nativeCall_at(native_call));
200 if (VerifyInlineCaches) st->verify();
201 return st;
202 }
203
204 static inline CompiledDirectCall* at(Relocation* call_site) {
205 return at(call_site->addr());
206 }
207
208 // Delegation
209 address destination() const { return _call->destination(); }
210 address end_of_call() const { return _call->return_address(); }
211
212 // Clean static call (will force resolving on next use)
213 void set_to_clean();
214
215 void set(const methodHandle& callee_method, bool caller_is_c1);
216
217 // State
218 bool is_clean() const;
219 bool is_call_to_interpreted() const;
220 bool is_call_to_compiled() const;
221
222 // Stub support
223 static address find_stub_for(address instruction);
224 address find_stub();
225 static void set_stub_to_clean(static_stub_Relocation* static_stub);
226
227 // Misc.
228 void print() PRODUCT_RETURN;
229 void verify() PRODUCT_RETURN;
230 };
231
232 #endif // SHARE_CODE_COMPILEDIC_HPP