mirror of
https://github.com/openjdk/jdk.git
synced 2026-08-05 23:54:13 +00:00
Co-authored-by: Tobias Hartmann <thartmann@openjdk.org> Co-authored-by: Mikael Vidstedt <mikael@openjdk.org> Reviewed-by: kvn, thartmann, liach, stefank, coleenp, erikj, vlivanov, cjplummer, alanb
233 lines
7.8 KiB
C++
233 lines
7.8 KiB
C++
/*
|
|
* 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<mtCode> {
|
|
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
|