/* * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #ifndef SHARE_CODE_COMPILEDIC_HPP #define SHARE_CODE_COMPILEDIC_HPP #include "code/nativeInst.hpp" #include "interpreter/linkResolver.hpp" #include "runtime/safepointVerifiers.hpp" //----------------------------------------------------------------------------- // The CompiledIC represents a compiled inline cache. // // It's safe to transition from any state to any state. Typically an inline cache starts // in the clean state, meaning it will resolve the call when called. Then it typically // transitions to monomorphic, assuming the first dynamic receiver will be the only one // observed. If that speculation fails, we transition to megamorphic. // class CompiledIC; class CompiledICProtectionBehaviour; class nmethod; class CompiledICLocker: public StackObj { nmethod* _method; CompiledICProtectionBehaviour* _behaviour; bool _locked; NoSafepointVerifier _nsv; public: CompiledICLocker(nmethod* method); ~CompiledICLocker(); static bool is_safe(nmethod* nm); static bool is_safe(address code); }; // A CompiledICData is a helper object for the inline cache implementation. // It comprises: // (1) The first receiver klass and its selected method // (2) Itable call metadata class CompiledICData : public CHeapObj { friend class VMStructs; Method* volatile _speculated_method; uintptr_t volatile _speculated_klass; Klass* _itable_defc_klass; Klass* _itable_refc_klass; bool _is_initialized; bool is_speculated_klass_unloaded() const; public: // Constructor CompiledICData(); // accessors Klass* speculated_klass() const; Method* speculated_method() const { return _speculated_method; } Klass* itable_defc_klass() const { return _itable_defc_klass; } Klass* itable_refc_klass() const { return _itable_refc_klass; } static ByteSize speculated_method_offset() { return byte_offset_of(CompiledICData, _speculated_method); } static ByteSize speculated_klass_offset() { return byte_offset_of(CompiledICData, _speculated_klass); } static ByteSize itable_defc_klass_offset() { return byte_offset_of(CompiledICData, _itable_defc_klass); } static ByteSize itable_refc_klass_offset() { return byte_offset_of(CompiledICData, _itable_refc_klass); } void initialize(CallInfo* call_info, Klass* receiver_klass); bool is_initialized() const { return _is_initialized; } // GC Support void clean_metadata(); void metadata_do(MetadataClosure* cl); }; class CompiledIC: public ResourceObj { private: nmethod* _method; CompiledICData* _data; NativeCall* _call; CompiledIC(RelocIterator* iter); // CompiledICData wrappers void ensure_initialized(CallInfo* call_info, Klass* receiver_klass); bool is_speculated_klass(Klass* receiver_klass); // Inline cache states void set_to_monomorphic(); void set_to_megamorphic(CallInfo* call_info); public: // conversion (machine PC to CompiledIC*) friend CompiledIC* CompiledIC_before(nmethod* nm, address return_addr); friend CompiledIC* CompiledIC_at(nmethod* nm, address call_site); friend CompiledIC* CompiledIC_at(Relocation* call_site); friend CompiledIC* CompiledIC_at(RelocIterator* reloc_iter); CompiledICData* data() const; // State bool is_clean() const; bool is_monomorphic() const; bool is_megamorphic() const; address end_of_call() const { return _call->return_address(); } // MT-safe patching of inline caches. Note: Only safe to call is_xxx when holding the CompiledICLocker // so you are guaranteed that no patching takes place. The same goes for verify. void set_to_clean(); void update(CallInfo* call_info, Klass* receiver_klass); // GC support void clean_metadata(); void metadata_do(MetadataClosure* cl); // Location address instruction_address() const { return _call->instruction_address(); } address destination() const { return _call->destination(); } // Misc void print() PRODUCT_RETURN; void verify() PRODUCT_RETURN; }; CompiledIC* CompiledIC_before(nmethod* nm, address return_addr); CompiledIC* CompiledIC_at(nmethod* nm, address call_site); CompiledIC* CompiledIC_at(Relocation* call_site); CompiledIC* CompiledIC_at(RelocIterator* reloc_iter); //----------------------------------------------------------------------------- // The CompiledDirectCall represents a call to a method in the compiled code // // // -----<----- Clean ----->----- // / \ // / \ // compilled code <------------> interpreted code // // Clean: Calls directly to runtime method for fixup // Compiled code: Calls directly to compiled code // Interpreted code: Calls to stub that set Method* reference // // class CompiledDirectCall : public ResourceObj { private: friend class CompiledIC; friend class DirectNativeCallWrapper; // Also used by CompiledIC void set_to_interpreted(const methodHandle& callee, address entry); void verify_mt_safe(const methodHandle& callee, address entry, NativeMovConstReg* method_holder, NativeJump* jump) PRODUCT_RETURN; address instruction_address() const { return _call->instruction_address(); } void set_destination_mt_safe(address dest) { _call->set_destination_mt_safe(dest); } NativeCall* _call; CompiledDirectCall(NativeCall* call) : _call(call) {} public: // Returns null if CodeBuffer::expand fails static address emit_to_interp_stub(MacroAssembler *masm, address mark = nullptr); static int to_interp_stub_size(); static int to_trampoline_stub_size(); static int reloc_to_interp_stub(); static inline CompiledDirectCall* before(address return_addr) { CompiledDirectCall* st = new CompiledDirectCall(nativeCall_before(return_addr)); if (VerifyInlineCaches) st->verify(); return st; } static inline CompiledDirectCall* at(address native_call) { CompiledDirectCall* st = new CompiledDirectCall(nativeCall_at(native_call)); if (VerifyInlineCaches) st->verify(); return st; } static inline CompiledDirectCall* at(Relocation* call_site) { return at(call_site->addr()); } // Delegation address destination() const { return _call->destination(); } address end_of_call() const { return _call->return_address(); } // Clean static call (will force resolving on next use) void set_to_clean(); void set(const methodHandle& callee_method); // State bool is_clean() const; bool is_call_to_interpreted() const; bool is_call_to_compiled() const; // Stub support static address find_stub_for(address instruction); address find_stub(); static void set_stub_to_clean(static_stub_Relocation* static_stub); // Misc. void print() PRODUCT_RETURN; void verify() PRODUCT_RETURN; }; #endif // SHARE_CODE_COMPILEDIC_HPP