jdk/src/hotspot/share/code/compiledIC.hpp
2025-07-02 05:38:28 +00:00

234 lines
7.8 KiB
C++

/*
* Copyright (c) 1997, 2024, 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* method);
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<mtCode> {
friend class VMStructs;
friend class JVMCIVMStructs;
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