/* * Copyright (c) 2000, 2022, 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. *
*/
// The MethodData object collects counts and other profile information // during zeroth-tier (interpreter) and third-tier (C1 with full profiling) // execution. // // The profile is used later by compilation heuristics. Some heuristics // enable use of aggressive (or "heroic") optimizations. An aggressive // optimization often has a down-side, a corner case that it handles // poorly, but which is thought to be rare. The profile provides // evidence of this rarity for a given method or even BCI. It allows // the compiler to back out of the optimization at places where it // has historically been a poor choice. Other heuristics try to use // specific information gathered about types observed at a given site. // // All data in the profile is approximate. It is expected to be accurate // on the whole, but the system expects occasional inaccuraces, due to // counter overflow, multiprocessor races during data collection, space // limitations, missing MDO blocks, etc. Bad or missing data will degrade // optimization quality but will not affect correctness. Also, each MDO // is marked with its birth-date ("creation_mileage") which can be used // to assess the quality ("maturity") of its data. // // Short (<32-bit) counters are designed to overflow to a known "saturated" // state. Also, certain recorded per-BCI events are given one-bit counters // which overflow to a saturated state which applied to all counters at // that BCI. In other words, there is a small lattice which approximates // the ideal of an infinite-precision counter for each event at each BCI, // and the lattice quickly "bottoms out" in a state where all counters // are taken to be indefinitely large. // // The reader will find many data races in profile gathering code, starting // with invocation counter incrementation. None of these races harm correct // execution of the compiled code.
// forward decl class ProfileData;
// DataLayout // // Overlay for generic profiling data. class DataLayout { friendclass VMStructs; friendclass JVMCIVMStructs;
private: // Every data layout begins with a header. This header // contains a tag, which is used to indicate the size/layout // of the data, 8 bits of flags, which can be used in any way, // 32 bits of trap history (none/one reason/many reasons), // and a bci, which is used to tie this piece of data to a // specific bci in the bytecodes. union {
u8 _bits; struct {
u1 _tag;
u1 _flags;
u2 _bci;
u4 _traps;
} _struct;
} _header;
// The data layout has an arbitrary number of cells, each sized // to accommodate a pointer or an integer.
intptr_t _cells[1];
// Some types of data layouts need a length field. staticbool needs_array_len(u1 tag);
enum { // The trap state breaks down as [recompile:1 | reason:31]. // This further breakdown is defined in deoptimization.cpp. // See Deoptimization::trap_state_reason for an assert that // trap_bits is big enough to hold reasons < Reason_RECORDED_LIMIT. // // The trap_state is collected only if ProfileTraps is true.
trap_bits = 1+31, // 31: enough to distinguish [0..Reason_RECORDED_LIMIT].
trap_mask = -1,
first_flag = 0
};
// Return 32 bits of trap state. // The state tells if traps with zero, one, or many reasons have occurred. // It also tells whether zero or many recompilations have occurred. // The associated trap histogram in the MDO itself tells whether // traps are common or not. If a BCI shows that a trap X has // occurred, and the MDO shows N occurrences of X, we make the // simplifying assumption that all N occurrences can be blamed // on that BCI.
uint trap_state() const { return _header._struct._traps;
}
void set_trap_state(uint new_state) {
assert(ProfileTraps, "used only under +ProfileTraps");
uint old_flags = _header._struct._traps;
_header._struct._traps = new_state | old_flags;
}
// Low-level support for code generation. static ByteSize header_offset() { return byte_offset_of(DataLayout, _header);
} static ByteSize tag_offset() { return byte_offset_of(DataLayout, _header._struct._tag);
} static ByteSize flags_offset() { return byte_offset_of(DataLayout, _header._struct._flags);
} static ByteSize bci_offset() { return byte_offset_of(DataLayout, _header._struct._bci);
} static ByteSize cell_offset(int index) { return byte_offset_of(DataLayout, _cells) + in_ByteSize(index * cell_size);
} // Return a value which, when or-ed as a byte into _flags, sets the flag. static u1 flag_number_to_constant(u1 flag_number) {
DataLayout temp; temp.set_header(0);
temp.set_flag_at(flag_number); return temp._header._struct._flags;
} // Return a value which, when or-ed as a word into _header, sets the flag. static u8 flag_mask_to_header_mask(uint byte_constant) {
DataLayout temp; temp.set_header(0);
temp._header._struct._flags = byte_constant; return temp._header._bits;
}
ProfileData* data_in();
int size_in_bytes() { int cells = cell_count();
assert(cells >= 0, "invalid number of cells"); return DataLayout::compute_size_in_bytes(cells);
} int cell_count();
// GC support void clean_weak_klass_links(bool always_clean);
};
// ProfileData class hierarchy class ProfileData; class BitData; class CounterData; class ReceiverTypeData; class VirtualCallData; class VirtualCallTypeData; class RetData; class CallTypeData; class JumpData; class BranchData; class ArrayData; class MultiBranchData; class ArgInfoData; class ParametersTypeData; class SpeculativeTrapData;
// ProfileData // // A ProfileData object is created to refer to a section of profiling // data in a structured way. class ProfileData : public ResourceObj { friendclass TypeEntries; friendclass ReturnTypeEntry; friendclass TypeStackSlotEntries; private: enum {
tab_width_one = 16,
tab_width_two = 36
};
// This is a pointer to a section of profiling data.
DataLayout* _data;
// Subclass specific initialization virtualvoid post_initialize(BytecodeStream* stream, MethodData* mdo) {}
// GC support virtualvoid clean_weak_klass_links(bool always_clean) {}
// CI translation: ProfileData can represent both MethodDataOop data // as well as CIMethodData data. This function is provided for translating // an oop in a ProfileData to the ci equivalent. Generally speaking, // most ProfileData don't require any translation, so we provide the null // translation here, and the required translators are in the ci subclasses. virtualvoid translate_from(const ProfileData* data) {}
// The null_seen flag bit is specially known to the interpreter. // Consulting it allows the compiler to avoid setting up null_check traps. bool null_seen() { return flag_at(null_seen_flag); } void set_null_seen() { set_flag_at(null_seen_flag); }
#if INCLUDE_JVMCI // true if an exception was thrown at the specific BCI bool exception_seen() { return flag_at(exception_seen_flag); } void set_exception_seen() { set_flag_at(exception_seen_flag); } #endif
// Code generation support staticint null_seen_byte_constant() { return flag_number_to_constant(null_seen_flag);
}
void print_data_on(outputStream* st, constchar* extra = NULL) const;
};
// JumpData // // A JumpData is used to access profiling information for a direct // branch. It is a counter, used for counting the number of branches, // plus a data displacement, used for realigning the data pointer to // the corresponding target bci. class JumpData : public ProfileData { friendclass VMStructs; friendclass JVMCIVMStructs; protected: enum {
taken_off_set,
displacement_off_set,
jump_cell_count
};
// Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo);
void print_data_on(outputStream* st, constchar* extra = NULL) const;
};
// Entries in a ProfileData object to record types: it can either be // none (no profile), unknown (conflicting profile data) or a klass if // a single one is seen. Whether a null reference was seen is also // recorded. No counter is associated with the type and a single type // is tracked (unlike VirtualCallData). class TypeEntries {
public:
// A single cell is used to record information for a type: // - the cell is initialized to 0 // - when a type is discovered it is stored in the cell // - bit zero of the cell is used to record whether a null reference // was encountered or not // - bit 1 is set to record a conflict in the type information
protected: // ProfileData object these entries are part of
ProfileData* _pd; // offset within the ProfileData object where the entries start constint _base_off;
// Type entries used for arguments passed at a call and parameters on // method entry. 2 cells per entry: one for the type encoded as in // TypeEntries and one initialized with the stack slot where the // profiled object is to be found so that the interpreter can locate // it quickly. class TypeStackSlotEntries : public TypeEntries {
// offset of cell for stack slot for entry i within ProfileData object int stack_slot_offset(int i) const { return _base_off + stack_slot_local_offset(i);
}
constint _number_of_entries;
// offset of cell for type for entry i within ProfileData object int type_offset_in_cells(int i) const { return _base_off + type_local_offset(i);
}
public:
TypeStackSlotEntries(int base_off, int nb_entries)
: TypeEntries(base_off), _number_of_entries(nb_entries) {}
staticint compute_cell_count(Symbol* signature, bool include_receiver, int max);
int number_of_entries() const { return _number_of_entries; }
// offset of cell for stack slot for entry i within this block of cells for a TypeStackSlotEntries staticint stack_slot_local_offset(int i) { return i * per_arg_cell_count + stack_slot_entry;
}
// offset of cell for type for entry i within this block of cells for a TypeStackSlotEntries staticint type_local_offset(int i) { return i * per_arg_cell_count + type_entry;
}
// stack slot for entry i
uint stack_slot(int i) const {
assert(i >= 0 && i < _number_of_entries, "oob"); return _pd->uint_at(stack_slot_offset(i));
}
// set stack slot for entry i void set_stack_slot(int i, uint num) {
assert(i >= 0 && i < _number_of_entries, "oob");
_pd->set_uint_at(stack_slot_offset(i), num);
}
// type for entry i
intptr_t type(int i) const {
assert(i >= 0 && i < _number_of_entries, "oob"); return _pd->intptr_at(type_offset_in_cells(i));
}
// set type for entry i void set_type(int i, intptr_t k) {
assert(i >= 0 && i < _number_of_entries, "oob");
_pd->set_intptr_at(type_offset_in_cells(i), k);
}
// GC support void clean_weak_klass_links(bool always_clean);
void print_data_on(outputStream* st) const;
};
// Entries to collect type information at a call: contains arguments // (TypeStackSlotEntries), a return type (ReturnTypeEntry) and a // number of cells. Because the number of cells for the return type is // smaller than the number of cells for the type of an arguments, the // number of cells is used to tell how many arguments are profiled and // whether a return value is profiled. See has_arguments() and // has_return(). class TypeEntriesAtCall { private: staticint stack_slot_local_offset(int i) { return header_cell_count() + TypeStackSlotEntries::stack_slot_local_offset(i);
}
staticvoid initialize(DataLayout* dl, int base, int cell_count) { int off = base + cell_count_local_offset();
dl->set_cell_at(off, cell_count - base - header_cell_count());
}
// CallTypeData // // A CallTypeData is used to access profiling information about a non // virtual call for which we collect type information about arguments // and return value. class CallTypeData : public CounterData { private: // entries for arguments if any
TypeStackSlotEntries _args; // entry for return type if any
ReturnTypeEntry _ret;
int cell_count_global_offset() const { return CounterData::static_cell_count() + TypeEntriesAtCall::cell_count_local_offset();
}
// number of cells not counting the header int cell_count_no_header() const { return uint_at(cell_count_global_offset());
}
void check_number_of_arguments(int total) {
assert(number_of_arguments() == total, "should be set in DataLayout::initialize");
}
public:
CallTypeData(DataLayout* layout) :
CounterData(layout),
_args(CounterData::static_cell_count()+TypeEntriesAtCall::header_cell_count(), number_of_arguments()),
_ret(cell_count() - ReturnTypeEntry::static_cell_count())
{
assert(layout->tag() == DataLayout::call_type_data_tag, "wrong type"); // Some compilers (VC++) don't want this passed in member initialization list
_args.set_profile_data(this);
_ret.set_profile_data(this);
}
const TypeStackSlotEntries* args() const {
assert(has_arguments(), "no profiling of arguments"); return &_args;
}
const ReturnTypeEntry* ret() const {
assert(has_return(), "no profiling of return value"); return &_ret;
}
int number_of_arguments() const { return cell_count_no_header() / TypeStackSlotEntries::per_arg_count();
}
void set_argument_type(int i, Klass* k) {
assert(has_arguments(), "no arguments!");
intptr_t current = _args.type(i);
_args.set_type(i, TypeEntries::with_status(k, current));
}
void set_return_type(Klass* k) {
assert(has_return(), "no return!");
intptr_t current = _ret.type();
_ret.set_type(TypeEntries::with_status(k, current));
}
// An entry for a return value takes less space than an entry for an // argument so if the number of cells exceeds the number of cells // needed for an argument, this object contains type information for // at least one argument. bool has_arguments() const { bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count();
assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); return res;
}
// An entry for a return value takes less space than an entry for an // argument, so if the remainder of the number of cells divided by // the number of cells for an argument is not null, a return value // is profiled in this object. bool has_return() const { bool res = (cell_count_no_header() % TypeStackSlotEntries::per_arg_count()) != 0;
assert (!res || TypeEntriesAtCall::return_profiling_enabled(), "no profiling of return values"); return res;
}
// GC support virtualvoid clean_weak_klass_links(bool always_clean) { if (has_arguments()) {
_args.clean_weak_klass_links(always_clean);
} if (has_return()) {
_ret.clean_weak_klass_links(always_clean);
}
}
virtualvoid print_data_on(outputStream* st, constchar* extra = NULL) const;
};
// ReceiverTypeData // // A ReceiverTypeData is used to access profiling information about a // dynamic type check. It consists of a counter which counts the total times // that the check is reached, and a series of (Klass*, count) pairs // which are used to store a type profile for the receiver of the check. class ReceiverTypeData : public CounterData { friendclass VMStructs; friendclass JVMCIVMStructs; protected: enum { #if INCLUDE_JVMCI // Description of the different counters // ReceiverTypeData for instanceof/checkcast/aastore: // count is decremented for failed type checks // JVMCI only: nonprofiled_count is incremented on type overflow // VirtualCallData for invokevirtual/invokeinterface: // count is incremented on type overflow // JVMCI only: nonprofiled_count is incremented on method overflow
// JVMCI is interested in knowing the percentage of type checks involving a type not explicitly in the profile
nonprofiled_count_off_set = counter_cell_count,
receiver0_offset, #else
receiver0_offset = counter_cell_count, #endif
count0_offset,
receiver_type_row_cell_count = (count0_offset + 1) - receiver0_offset
};
void clear_row(uint row) {
assert(row < row_limit(), "oob"); // Clear total count - indicator of polymorphic call site. // The site may look like as monomorphic after that but // it allow to have more accurate profiling information because // there was execution phase change since klasses were unloaded. // If the site is still polymorphic then MDO will be updated // to reflect it. But it could be the case that the site becomes // only bimorphic. Then keeping total count not 0 will be wrong. // Even if we use monomorphic (when it is not) for compilation // we will only have trap, deoptimization and recompile again // with updated MDO after executing method in Interpreter. // An additional receiver will be recorded in the cleaned row // during next call execution. // // Note: our profiling logic works with empty rows in any slot. // We do sorting a profiling info (ciCallProfile) for compilation. //
set_count(0);
set_receiver(row, NULL);
set_receiver_count(row, 0); #if INCLUDE_JVMCI if (!this->is_VirtualCallData()) { // if this is a ReceiverTypeData for JVMCI, the nonprofiled_count // must also be reset (see "Description of the different counters" above)
set_nonprofiled_count(0);
} #endif
}
// VirtualCallData // // A VirtualCallData is used to access profiling information about a // virtual call. For now, it has nothing more than a ReceiverTypeData. class VirtualCallData : public ReceiverTypeData { public:
VirtualCallData(DataLayout* layout) : ReceiverTypeData(layout) {
assert(layout->tag() == DataLayout::virtual_call_data_tag ||
layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type");
}
staticint static_cell_count() { // At this point we could add more profile state, e.g., for arguments. // But for now it's the same size as the base record type. return ReceiverTypeData::static_cell_count();
}
// VirtualCallTypeData // // A VirtualCallTypeData is used to access profiling information about // a virtual call for which we collect type information about // arguments and return value. class VirtualCallTypeData : public VirtualCallData { private: // entries for arguments if any
TypeStackSlotEntries _args; // entry for return type if any
ReturnTypeEntry _ret;
int cell_count_global_offset() const { return VirtualCallData::static_cell_count() + TypeEntriesAtCall::cell_count_local_offset();
}
// number of cells not counting the header int cell_count_no_header() const { return uint_at(cell_count_global_offset());
}
void check_number_of_arguments(int total) {
assert(number_of_arguments() == total, "should be set in DataLayout::initialize");
}
public:
VirtualCallTypeData(DataLayout* layout) :
VirtualCallData(layout),
_args(VirtualCallData::static_cell_count()+TypeEntriesAtCall::header_cell_count(), number_of_arguments()),
_ret(cell_count() - ReturnTypeEntry::static_cell_count())
{
assert(layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); // Some compilers (VC++) don't want this passed in member initialization list
_args.set_profile_data(this);
_ret.set_profile_data(this);
}
const TypeStackSlotEntries* args() const {
assert(has_arguments(), "no profiling of arguments"); return &_args;
}
const ReturnTypeEntry* ret() const {
assert(has_return(), "no profiling of return value"); return &_ret;
}
int number_of_arguments() const { return cell_count_no_header() / TypeStackSlotEntries::per_arg_count();
}
void set_argument_type(int i, Klass* k) {
assert(has_arguments(), "no arguments!");
intptr_t current = _args.type(i);
_args.set_type(i, TypeEntries::with_status(k, current));
}
void set_return_type(Klass* k) {
assert(has_return(), "no return!");
intptr_t current = _ret.type();
_ret.set_type(TypeEntries::with_status(k, current));
}
// An entry for a return value takes less space than an entry for an // argument, so if the remainder of the number of cells divided by // the number of cells for an argument is not null, a return value // is profiled in this object. bool has_return() const { bool res = (cell_count_no_header() % TypeStackSlotEntries::per_arg_count()) != 0;
assert (!res || TypeEntriesAtCall::return_profiling_enabled(), "no profiling of return values"); return res;
}
// An entry for a return value takes less space than an entry for an // argument so if the number of cells exceeds the number of cells // needed for an argument, this object contains type information for // at least one argument. bool has_arguments() const { bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count();
assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); return res;
}
// GC support virtualvoid clean_weak_klass_links(bool always_clean) {
ReceiverTypeData::clean_weak_klass_links(always_clean); if (has_arguments()) {
_args.clean_weak_klass_links(always_clean);
} if (has_return()) {
_ret.clean_weak_klass_links(always_clean);
}
}
virtualvoid print_data_on(outputStream* st, constchar* extra = NULL) const;
};
// RetData // // A RetData is used to access profiling information for a ret bytecode. // It is composed of a count of the number of times that the ret has // been executed, followed by a series of triples of the form // (bci, count, di) which count the number of times that some bci was the // target of the ret and cache a corresponding data displacement. class RetData : public CounterData { protected: enum {
bci0_offset = counter_cell_count,
count0_offset,
displacement0_offset,
ret_row_cell_count = (displacement0_offset + 1) - bci0_offset
};
// Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo);
void print_data_on(outputStream* st, constchar* extra = NULL) const;
};
// BranchData // // A BranchData is used to access profiling data for a two-way branch. // It consists of taken and not_taken counts as well as a data displacement // for the taken case. class BranchData : public JumpData { friendclass VMStructs; friendclass JVMCIVMStructs; protected: enum {
not_taken_off_set = jump_cell_count,
branch_cell_count
};
// Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo);
void print_data_on(outputStream* st, constchar* extra = NULL) const;
};
// ArrayData // // A ArrayData is a base class for accessing profiling data which does // not have a statically known size. It consists of an array length // and an array start. class ArrayData : public ProfileData { friendclass VMStructs; friendclass JVMCIVMStructs; protected: friendclass DataLayout;
enum {
array_len_off_set,
array_start_off_set
};
uint array_uint_at(int index) const { int aindex = index + array_start_off_set; return uint_at(aindex);
} int array_int_at(int index) const { int aindex = index + array_start_off_set; return int_at(aindex);
}
oop array_oop_at(int index) const { int aindex = index + array_start_off_set; return oop_at(aindex);
} void array_set_int_at(int index, int value) { int aindex = index + array_start_off_set;
set_int_at(aindex, value);
}
// Code generation support for subclasses. static ByteSize array_element_offset(int index) { return cell_offset(array_start_off_set + index);
}
// MultiBranchData // // A MultiBranchData is used to access profiling information for // a multi-way branch (*switch bytecodes). It consists of a series // of (count, displacement) pairs, which count the number of times each // case was taken and specify the data displacement for each branch target. class MultiBranchData : public ArrayData { friendclass VMStructs; friendclass JVMCIVMStructs; protected: enum {
default_count_off_set,
default_disaplacement_off_set,
case_array_start
}; enum {
relative_count_off_set,
relative_displacement_off_set,
per_case_cell_count
};
int number_of_cases() const { int alen = array_len() - 2; // get rid of default case here.
assert(alen % per_case_cell_count == 0, "must be even"); return (alen / per_case_cell_count);
}
void print_data_on(outputStream* st, constchar* extra = NULL) const;
};
// ParametersTypeData // // A ParametersTypeData is used to access profiling information about // types of parameters to a method class ParametersTypeData : public ArrayData {
// SpeculativeTrapData // // A SpeculativeTrapData is used to record traps due to type // speculation. It records the root of the compilation: that type // speculation is wrong in the context of one compilation (for // method1) doesn't mean it's wrong in the context of another one (for // method2). Type speculation could have more/different data in the // context of the compilation of method2 and it's worthwhile to try an // optimization that failed for compilation of method1 in the context // of compilation of method2. // Space for SpeculativeTrapData entries is allocated from the extra // data space in the MDO. If we run out of space, the trap data for // the ProfileData at that bci is updated. class SpeculativeTrapData : public ProfileData { protected: enum {
speculative_trap_method, #ifndef _LP64 // The size of the area for traps is a multiple of the header // size, 2 cells on 32 bits. Packed at the end of this area are // argument info entries (with tag // DataLayout::arg_info_data_tag). The logic in // MethodData::bci_to_extra_data() that guarantees traps don't // overflow over argument info entries assumes the size of a // SpeculativeTrapData is twice the header size. On 32 bits, a // SpeculativeTrapData must be 4 cells.
padding, #endif
speculative_trap_cell_count
}; public:
SpeculativeTrapData(DataLayout* layout) : ProfileData(layout) {
assert(layout->tag() == DataLayout::speculative_trap_data_tag, "wrong type");
}
virtualvoid print_data_on(outputStream* st, constchar* extra = NULL) const;
};
// MethodData* // // A MethodData* holds information which has been collected about // a method. Its layout looks like this: // // ----------------------------- // | header | // | klass | // ----------------------------- // | method | // | size of the MethodData* | // ----------------------------- // | Data entries... | // | (variable size) | // | | // . . // . . // . . // | | // ----------------------------- // // The data entry area is a heterogeneous array of DataLayouts. Each // DataLayout in the array corresponds to a specific bytecode in the // method. The entries in the array are sorted by the corresponding // bytecode. Access to the data is via resource-allocated ProfileData, // which point to the underlying blocks of DataLayout structures. // // During interpretation, if profiling in enabled, the interpreter // maintains a method data pointer (mdp), which points at the entry // in the array corresponding to the current bci. In the course of // interpretation, when a bytecode is encountered that has profile data // associated with it, the entry pointed to by mdp is updated, then the // mdp is adjusted to point to the next appropriate DataLayout. If mdp // is NULL to begin with, the interpreter assumes that the current method // is not (yet) being profiled. // // In MethodData* parlance, "dp" is a "data pointer", the actual address // of a DataLayout element. A "di" is a "data index", the offset in bytes // from the base of the data entry array. A "displacement" is the byte offset // in certain ProfileData objects that indicate the amount the mdp must be // adjusted in the event of a change in control flow. //
class CleanExtraDataClosure : public StackObj { public: virtualbool is_live(Method* m) = 0;
};
#if INCLUDE_JVMCI // Encapsulates an encoded speculation reason. These are linked together in // a list that is atomically appended to during deoptimization. Entries are // never removed from the list. // @see jdk.vm.ci.hotspot.HotSpotSpeculationLog.HotSpotSpeculationEncoding class FailedSpeculation: public CHeapObj<mtCompiler> { private: // The length of HotSpotSpeculationEncoding.toByteArray(). The data itself // is an array embedded at the end of this object. int _data_len;
// Next entry in a linked list.
FailedSpeculation* _next;
FailedSpeculation(address data, int data_len);
FailedSpeculation** next_adr() { return &_next; }
// Placement new operator for inlining the speculation data into // the FailedSpeculation object. void* operatornew(size_t size, size_t fs_size) throw();
// Atomically appends a speculation from nm to the list whose head is at (*failed_speculations_address). // Returns false if the FailedSpeculation object could not be allocated. staticbool add_failed_speculation(nmethod* nm, FailedSpeculation** failed_speculations_address, address speculation, int speculation_len);
// Frees all entries in the linked list whose head is at (*failed_speculations_address). staticvoid free_failed_speculations(FailedSpeculation** failed_speculations_address);
}; #endif
class ciMethodData;
class MethodData : public Metadata { friendclass VMStructs; friendclass JVMCIVMStructs; private: friendclass ProfileData; friendclass TypeEntriesAtCall; friendclass ciMethodData;
// If you add a new field that points to any metaspace object, you // must add this field to MethodData::metaspace_pointers_do().
// Back pointer to the Method*
Method* _method;
// Size of this oop in bytes int _size;
// Cached hint for bci_to_dp and bci_to_data int _hint_di;
// Whole-method sticky bits and flags enum {
_trap_hist_limit = Deoptimization::Reason_TRAP_HISTORY_LENGTH,
_trap_hist_mask = max_jubyte,
_extra_data_count = 4 // extra DataLayout headers, for trap history
}; // Public flag values
// Compiler-related counters. class CompilerCounters { friendclass VMStructs; friendclass JVMCIVMStructs;
uint _nof_decompiles; // count of all nmethod removals
uint _nof_overflow_recompiles; // recompile count, excluding recomp. bits
uint _nof_overflow_traps; // trap count, excluding _trap_hist union {
intptr_t _align; // JVMCI separates trap history for OSR compilations from normal compilations
u1 _array[JVMCI_ONLY(2 *) MethodData::_trap_hist_limit];
} _trap_hist;
public:
CompilerCounters() : _nof_decompiles(0), _nof_overflow_recompiles(0), _nof_overflow_traps(0) { #ifndef ZERO // Some Zero platforms do not have expected alignment, and do not use // this code. static_assert would still fire and fail for them.
static_assert(sizeof(_trap_hist) % HeapWordSize == 0, "align"); #endif
uint size_in_words = sizeof(_trap_hist) / HeapWordSize;
Copy::zero_to_words((HeapWord*) &_trap_hist, size_in_words);
}
// Support for code generation static ByteSize trap_history_offset() { return byte_offset_of(CompilerCounters, _trap_hist._array);
}
};
private:
CompilerCounters _compiler_counters;
// Support for interprocedural escape analysis, from Thomas Kotzmann.
intx _eflags; // flags on escape information
intx _arg_local; // bit set of non-escaping arguments
intx _arg_stack; // bit set of stack-allocatable arguments
intx _arg_returned; // bit set of returned arguments
int _creation_mileage; // method mileage at MDO creation
// How many invocations has this MDO seen? // These counters are used to determine the exact age of MDO. // We need those because in tiered a method can be concurrently // executed at different levels.
InvocationCounter _invocation_counter; // Same for backedges.
InvocationCounter _backedge_counter; // Counter values at the time profiling started. int _invocation_counter_start; int _backedge_counter_start;
uint _tenure_traps; int _invoke_mask; // per-method Tier0InvokeNotifyFreqLog int _backedge_mask; // per-method Tier0BackedgeNotifyFreqLog
#if INCLUDE_RTM_OPT // State of RTM code generation during compilation of the method int _rtm_state; #endif
// Number of loops and blocks is computed when compiling the first // time with C1. It is used to determine if method is trivial. short _num_loops; short _num_blocks; // Does this method contain anything worth profiling? enum WouldProfile {unknown, no_profile, profile};
WouldProfile _would_profile;
#if INCLUDE_JVMCI // Support for HotSpotMethodData.setCompiledIRSize(int) int _jvmci_ir_size;
FailedSpeculation* _failed_speculations; #endif
// Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size;
// data index for the area dedicated to parameters. -1 if no // parameter profiling. enum { no_parameters = -2, parameters_uninitialized = -1 }; int _parameters_type_data_di;
// Beginning of the data entries
intptr_t _data[1];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.