void ciMethodData::print_data_on(outputStream* st) { ResourceMark rm; ciProfileData* data; for (data = first_data(); is_valid(data); data = next_data(data)) { st->print("%d", dp_to_di(data->dp())); st->fill_to(6); data->print_data_on(st); } st->print_cr("--- Extra data:"); DataLayout* dp = data_layout_at(data_size()); DataLayout* end = data_layout_at(data_size() + extra_data_size()); for (; dp < end; dp = methodDataOopDesc::next_extra(dp)) { if (dp->tag() == DataLayout::no_tag) continue; if (dp->tag() == DataLayout::bit_data_tag) { data = new BitData(dp); } else { assert(dp->tag() == DataLayout::arg_info_data_tag, "must be BitData or ArgInfo"); data = new ciArgInfoData(dp); dp = end; // ArgInfoData is at the end of extra data section. } st->print("%d", dp_to_di(data->dp())); st->fill_to(6); data->print_data_on(st); } }
// Translate a bci to its corresponding data, or NULL. ciProfileData* ciMethodData::bci_to_data(int bci) { ciProfileData* data = data_before(bci); for ( ; is_valid(data); data = next_data(data)) { if (data->bci() == bci) { set_hint_di(dp_to_di(data->dp())); return data; } else if (data->bci() > bci) { break; } } // bci_to_extra_data(bci) ... DataLayout* dp = data_layout_at(data_size()); DataLayout* end = data_layout_at(data_size() + extra_data_size()); for (; dp < end; dp = methodDataOopDesc::next_extra(dp)) { if (dp->tag() == DataLayout::no_tag) { _saw_free_extra_data = true; // observed an empty slot (common case) return NULL; } if (dp->tag() == DataLayout::arg_info_data_tag) { break; // ArgInfoData is at the end of extra data section. } if (dp->bci() == bci) { assert(dp->tag() == DataLayout::bit_data_tag, "sane"); return new ciBitData(dp); } } return NULL; }
ciArgInfoData *ciMethodData::arg_info() const { // Should be last, have to skip all traps. DataLayout* dp = data_layout_at(data_size()); DataLayout* end = data_layout_at(data_size() + extra_data_size()); for (; dp < end; dp = methodDataOopDesc::next_extra(dp)) { if (dp->tag() == DataLayout::arg_info_data_tag) return new ciArgInfoData(dp); } return NULL; }
// Get the data at an arbitrary (sort of) data index. ProfileData* methodDataOopDesc::data_at(int data_index) { if (out_of_bounds(data_index)) { return NULL; } DataLayout* data_layout = data_layout_at(data_index); return data_layout->data_in(); }
// Get the data at an arbitrary (sort of) data index. ProfileData* MethodData::data_at(int data_index) const { if (out_of_bounds(data_index)) { return NULL; } DataLayout* data_layout = data_layout_at(data_index); return data_layout->data_in(); }
// Get the data at an arbitrary (sort of) data index. ciProfileData* ciMethodData::data_at(int data_index) { if (out_of_bounds(data_index)) { return NULL; } DataLayout* data_layout = data_layout_at(data_index); switch (data_layout->tag()) { case DataLayout::no_tag: default: ShouldNotReachHere(); return NULL; case DataLayout::bit_data_tag: return new ciBitData(data_layout); case DataLayout::counter_data_tag: return new ciCounterData(data_layout); case DataLayout::jump_data_tag: return new ciJumpData(data_layout); case DataLayout::receiver_type_data_tag: return new ciReceiverTypeData(data_layout); case DataLayout::virtual_call_data_tag: return new ciVirtualCallData(data_layout); case DataLayout::ret_data_tag: return new ciRetData(data_layout); case DataLayout::branch_data_tag: return new ciBranchData(data_layout); case DataLayout::multi_branch_data_tag: return new ciMultiBranchData(data_layout); case DataLayout::arg_info_data_tag: return new ciArgInfoData(data_layout); }; }
// Get the data at an arbitrary (sort of) data index. ProfileData* methodDataOopDesc::data_at(int data_index) { if (out_of_bounds(data_index)) { return NULL; } DataLayout* data_layout = data_layout_at(data_index); switch (data_layout->tag()) { case DataLayout::no_tag: default: ShouldNotReachHere(); return NULL; case DataLayout::bit_data_tag: return new BitData(data_layout); case DataLayout::counter_data_tag: return new CounterData(data_layout); case DataLayout::jump_data_tag: return new JumpData(data_layout); case DataLayout::virtual_call_data_tag: return new VirtualCallData(data_layout); case DataLayout::ret_data_tag: return new RetData(data_layout); case DataLayout::branch_data_tag: return new BranchData(data_layout); case DataLayout::multi_branch_data_tag: return new MultiBranchData(data_layout); }; }
ciProfileData* data_before(int bci) { // avoid SEGV on this edge case if (data_size() == 0) return NULL; int hint = hint_di(); if (data_layout_at(hint)->bci() <= bci) return data_at(hint); return first_data(); }
void ciMethodData::load_data() { MethodData* mdo = get_MethodData(); if (mdo == NULL) { return; } // To do: don't copy the data if it is not "ripe" -- require a minimum # // of invocations. // Snapshot the data -- actually, take an approximate snapshot of // the data. Any concurrently executing threads may be changing the // data as we copy it. Copy::disjoint_words((HeapWord*) mdo, (HeapWord*) &_orig, sizeof(_orig) / HeapWordSize); Arena* arena = CURRENT_ENV->arena(); _data_size = mdo->data_size(); _extra_data_size = mdo->extra_data_size(); int total_size = _data_size + _extra_data_size; _data = (intptr_t *) arena->Amalloc(total_size); Copy::disjoint_words((HeapWord*) mdo->data_base(), (HeapWord*) _data, total_size / HeapWordSize); // Traverse the profile data, translating any oops into their // ci equivalents. ResourceMark rm; ciProfileData* ci_data = first_data(); ProfileData* data = mdo->first_data(); while (is_valid(ci_data)) { ci_data->translate_from(data); ci_data = next_data(ci_data); data = mdo->next_data(data); } if (mdo->parameters_type_data() != NULL) { _parameters = data_layout_at(mdo->parameters_type_data_di()); ciParametersTypeData* parameters = new ciParametersTypeData(_parameters); parameters->translate_from(mdo->parameters_type_data()); } load_extra_data(); // Note: Extra data are all BitData, and do not need translation. _current_mileage = MethodData::mileage_of(mdo->method()); _invocation_counter = mdo->invocation_count(); _backedge_counter = mdo->backedge_count(); _state = mdo->is_mature()? mature_state: immature_state; _eflags = mdo->eflags(); _arg_local = mdo->arg_local(); _arg_stack = mdo->arg_stack(); _arg_returned = mdo->arg_returned(); #ifndef PRODUCT if (ReplayCompiles) { ciReplay::initialize(this); } #endif }
// Initialize the methodDataOop corresponding to a given method. void methodDataOopDesc::initialize(methodHandle method) { ResourceMark rm; // Set the method back-pointer. _method = method(); set_creation_mileage(mileage_of(method())); // Initialize flags and trap history. _nof_decompiles = 0; _nof_overflow_recompiles = 0; _nof_overflow_traps = 0; assert(sizeof(_trap_hist) % sizeof(HeapWord) == 0, "align"); Copy::zero_to_words((HeapWord*) &_trap_hist, sizeof(_trap_hist) / sizeof(HeapWord)); // Go through the bytecodes and allocate and initialize the // corresponding data cells. int data_size = 0; int empty_bc_count = 0; // number of bytecodes lacking data BytecodeStream stream(method); Bytecodes::Code c; while ((c = stream.next()) >= 0) { int size_in_bytes = initialize_data(&stream, data_size); data_size += size_in_bytes; if (size_in_bytes == 0) empty_bc_count += 1; } _data_size = data_size; int object_size = in_bytes(data_offset()) + data_size; // Add some extra DataLayout cells (at least one) to track stray traps. int extra_data_count = compute_extra_data_count(data_size, empty_bc_count); int extra_size = extra_data_count * DataLayout::compute_size_in_bytes(0); // Add a cell to record information about modified arguments. // Set up _args_modified array after traps cells so that // the code for traps cells works. DataLayout *dp = data_layout_at(data_size + extra_size); int arg_size = method->size_of_parameters(); dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1); object_size += extra_size + DataLayout::compute_size_in_bytes(arg_size+1); // Set an initial hint. Don't use set_hint_di() because // first_di() may be out of bounds if data_size is 0. // In that situation, _hint_di is never used, but at // least well-defined. _hint_di = first_di(); post_initialize(&stream); set_object_is_parsable(object_size); }
void MethodData::initialize() { No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC ResourceMark rm; init(); set_creation_mileage(mileage_of(method())); // Go through the bytecodes and allocate and initialize the // corresponding data cells. int data_size = 0; int empty_bc_count = 0; // number of bytecodes lacking data _data[0] = 0; // apparently not set below. BytecodeStream stream(method()); Bytecodes::Code c; while ((c = stream.next()) >= 0) { int size_in_bytes = initialize_data(&stream, data_size); data_size += size_in_bytes; if (is_empty_data(size_in_bytes, c)) empty_bc_count++; } _data_size = data_size; int object_size = in_bytes(data_offset()) + data_size; // Add some extra DataLayout cells (at least one) to track stray traps. int extra_data_count = compute_extra_data_count(data_size, empty_bc_count); int extra_size = extra_data_count * DataLayout::compute_size_in_bytes(0); object_size += extra_size; Copy::zero_to_bytes((HeapWord*) extra_data_base(), extra_size); #ifndef GRAALVM // Add a cell to record information about modified arguments. // Set up _args_modified array after traps cells so that // the code for traps cells works. DataLayout *dp = data_layout_at(data_size + extra_size); int arg_size = method()->size_of_parameters(); dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1); object_size += DataLayout::compute_size_in_bytes(arg_size+1); #endif // Set an initial hint. Don't use set_hint_di() because // first_di() may be out of bounds if data_size is 0. // In that situation, _hint_di is never used, but at // least well-defined. _hint_di = first_di(); post_initialize(&stream); set_size(object_size); }
// Initialize an individual data segment. Returns the size of // the segment in bytes. int methodDataOopDesc::initialize_data(BytecodeStream* stream, int data_index) { int cell_count = -1; int tag = DataLayout::no_tag; DataLayout* data_layout = data_layout_at(data_index); Bytecodes::Code c = stream->code(); switch (c) { case Bytecodes::_checkcast: case Bytecodes::_instanceof: case Bytecodes::_aastore: if (TypeProfileCasts) { cell_count = ReceiverTypeData::static_cell_count(); tag = DataLayout::receiver_type_data_tag; } else { cell_count = BitData::static_cell_count(); tag = DataLayout::bit_data_tag; } break; case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: cell_count = CounterData::static_cell_count(); tag = DataLayout::counter_data_tag; break; case Bytecodes::_goto: case Bytecodes::_goto_w: case Bytecodes::_jsr: case Bytecodes::_jsr_w: cell_count = JumpData::static_cell_count(); tag = DataLayout::jump_data_tag; break; case Bytecodes::_invokevirtual: case Bytecodes::_invokeinterface: cell_count = VirtualCallData::static_cell_count(); tag = DataLayout::virtual_call_data_tag; break; case Bytecodes::_invokedynamic: // %%% should make a type profile for any invokedynamic that takes a ref argument cell_count = CounterData::static_cell_count(); tag = DataLayout::counter_data_tag; break; case Bytecodes::_ret: cell_count = RetData::static_cell_count(); tag = DataLayout::ret_data_tag; break; case Bytecodes::_ifeq: case Bytecodes::_ifne: case Bytecodes::_iflt: case Bytecodes::_ifge: case Bytecodes::_ifgt: case Bytecodes::_ifle: case Bytecodes::_if_icmpeq: case Bytecodes::_if_icmpne: case Bytecodes::_if_icmplt: case Bytecodes::_if_icmpge: case Bytecodes::_if_icmpgt: case Bytecodes::_if_icmple: case Bytecodes::_if_acmpeq: case Bytecodes::_if_acmpne: case Bytecodes::_ifnull: case Bytecodes::_ifnonnull: cell_count = BranchData::static_cell_count(); tag = DataLayout::branch_data_tag; break; case Bytecodes::_lookupswitch: case Bytecodes::_tableswitch: cell_count = MultiBranchData::compute_cell_count(stream); tag = DataLayout::multi_branch_data_tag; break; } assert(tag == DataLayout::multi_branch_data_tag || cell_count == bytecode_cell_count(c), "cell counts must agree"); if (cell_count >= 0) { assert(tag != DataLayout::no_tag, "bad tag"); assert(bytecode_has_profile(c), "agree w/ BHP"); data_layout->initialize(tag, stream->bci(), cell_count); return DataLayout::compute_size_in_bytes(cell_count); } else { assert(!bytecode_has_profile(c), "agree w/ !BHP"); return 0; } }