duke@435: /* xdono@631: * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: #include "incls/_precompiled.incl" duke@435: #include "incls/_ciMethodData.cpp.incl" duke@435: duke@435: // ciMethodData duke@435: duke@435: // ------------------------------------------------------------------ duke@435: // ciMethodData::ciMethodData duke@435: // duke@435: ciMethodData::ciMethodData(methodDataHandle h_md) : ciObject(h_md) { duke@435: assert(h_md() != NULL, "no null method data"); duke@435: Copy::zero_to_words((HeapWord*) &_orig, sizeof(_orig) / sizeof(HeapWord)); duke@435: _data = NULL; duke@435: _data_size = 0; duke@435: _extra_data_size = 0; duke@435: _current_mileage = 0; duke@435: _state = empty_state; duke@435: _saw_free_extra_data = false; duke@435: // Set an initial hint. Don't use set_hint_di() because duke@435: // first_di() may be out of bounds if data_size is 0. duke@435: _hint_di = first_di(); kvn@480: // Initialize the escape information (to "don't know."); kvn@480: _eflags = _arg_local = _arg_stack = _arg_returned = 0; duke@435: } duke@435: duke@435: // ------------------------------------------------------------------ duke@435: // ciMethodData::ciMethodData duke@435: // duke@435: // No methodDataOop. duke@435: ciMethodData::ciMethodData() : ciObject() { duke@435: Copy::zero_to_words((HeapWord*) &_orig, sizeof(_orig) / sizeof(HeapWord)); duke@435: _data = NULL; duke@435: _data_size = 0; duke@435: _extra_data_size = 0; duke@435: _current_mileage = 0; duke@435: _state = empty_state; duke@435: _saw_free_extra_data = false; duke@435: // Set an initial hint. Don't use set_hint_di() because duke@435: // first_di() may be out of bounds if data_size is 0. duke@435: _hint_di = first_di(); kvn@480: // Initialize the escape information (to "don't know."); kvn@480: _eflags = _arg_local = _arg_stack = _arg_returned = 0; duke@435: } duke@435: duke@435: void ciMethodData::load_data() { duke@435: methodDataOop mdo = get_methodDataOop(); duke@435: if (mdo == NULL) return; duke@435: duke@435: // To do: don't copy the data if it is not "ripe" -- require a minimum # duke@435: // of invocations. duke@435: duke@435: // Snapshot the data -- actually, take an approximate snapshot of duke@435: // the data. Any concurrently executing threads may be changing the duke@435: // data as we copy it. duke@435: int skip_header = oopDesc::header_size(); duke@435: Copy::disjoint_words((HeapWord*) mdo + skip_header, duke@435: (HeapWord*) &_orig + skip_header, duke@435: sizeof(_orig) / HeapWordSize - skip_header); duke@435: DEBUG_ONLY(*_orig.adr_method() = NULL); // no dangling oops, please duke@435: Arena* arena = CURRENT_ENV->arena(); duke@435: _data_size = mdo->data_size(); duke@435: _extra_data_size = mdo->extra_data_size(); duke@435: int total_size = _data_size + _extra_data_size; duke@435: _data = (intptr_t *) arena->Amalloc(total_size); duke@435: Copy::disjoint_words((HeapWord*) mdo->data_base(), (HeapWord*) _data, total_size / HeapWordSize); duke@435: duke@435: // Traverse the profile data, translating any oops into their duke@435: // ci equivalents. duke@435: ResourceMark rm; duke@435: ciProfileData* ci_data = first_data(); duke@435: ProfileData* data = mdo->first_data(); duke@435: while (is_valid(ci_data)) { duke@435: ci_data->translate_from(data); duke@435: ci_data = next_data(ci_data); duke@435: data = mdo->next_data(data); duke@435: } duke@435: // Note: Extra data are all BitData, and do not need translation. duke@435: _current_mileage = methodDataOopDesc::mileage_of(mdo->method()); duke@435: _state = mdo->is_mature()? mature_state: immature_state; duke@435: duke@435: _eflags = mdo->eflags(); duke@435: _arg_local = mdo->arg_local(); duke@435: _arg_stack = mdo->arg_stack(); duke@435: _arg_returned = mdo->arg_returned(); duke@435: } duke@435: duke@435: void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) { duke@435: for (uint row = 0; row < row_limit(); row++) { duke@435: klassOop k = data->as_ReceiverTypeData()->receiver(row); duke@435: if (k != NULL) { duke@435: ciKlass* klass = CURRENT_ENV->get_object(k)->as_klass(); duke@435: set_receiver(row, klass); duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: // Get the data at an arbitrary (sort of) data index. duke@435: ciProfileData* ciMethodData::data_at(int data_index) { duke@435: if (out_of_bounds(data_index)) { duke@435: return NULL; duke@435: } duke@435: DataLayout* data_layout = data_layout_at(data_index); duke@435: duke@435: switch (data_layout->tag()) { duke@435: case DataLayout::no_tag: duke@435: default: duke@435: ShouldNotReachHere(); duke@435: return NULL; duke@435: case DataLayout::bit_data_tag: duke@435: return new ciBitData(data_layout); duke@435: case DataLayout::counter_data_tag: duke@435: return new ciCounterData(data_layout); duke@435: case DataLayout::jump_data_tag: duke@435: return new ciJumpData(data_layout); duke@435: case DataLayout::receiver_type_data_tag: duke@435: return new ciReceiverTypeData(data_layout); duke@435: case DataLayout::virtual_call_data_tag: duke@435: return new ciVirtualCallData(data_layout); duke@435: case DataLayout::ret_data_tag: duke@435: return new ciRetData(data_layout); duke@435: case DataLayout::branch_data_tag: duke@435: return new ciBranchData(data_layout); duke@435: case DataLayout::multi_branch_data_tag: duke@435: return new ciMultiBranchData(data_layout); kvn@480: case DataLayout::arg_info_data_tag: kvn@480: return new ciArgInfoData(data_layout); duke@435: }; duke@435: } duke@435: duke@435: // Iteration over data. duke@435: ciProfileData* ciMethodData::next_data(ciProfileData* current) { duke@435: int current_index = dp_to_di(current->dp()); duke@435: int next_index = current_index + current->size_in_bytes(); duke@435: ciProfileData* next = data_at(next_index); duke@435: return next; duke@435: } duke@435: duke@435: // Translate a bci to its corresponding data, or NULL. duke@435: ciProfileData* ciMethodData::bci_to_data(int bci) { duke@435: ciProfileData* data = data_before(bci); duke@435: for ( ; is_valid(data); data = next_data(data)) { duke@435: if (data->bci() == bci) { duke@435: set_hint_di(dp_to_di(data->dp())); duke@435: return data; duke@435: } else if (data->bci() > bci) { duke@435: break; duke@435: } duke@435: } duke@435: // bci_to_extra_data(bci) ... duke@435: DataLayout* dp = data_layout_at(data_size()); duke@435: DataLayout* end = data_layout_at(data_size() + extra_data_size()); duke@435: for (; dp < end; dp = methodDataOopDesc::next_extra(dp)) { duke@435: if (dp->tag() == DataLayout::no_tag) { duke@435: _saw_free_extra_data = true; // observed an empty slot (common case) duke@435: return NULL; duke@435: } kvn@480: if (dp->tag() == DataLayout::arg_info_data_tag) { kvn@480: break; // ArgInfoData is at the end of extra data section. kvn@480: } duke@435: if (dp->bci() == bci) { duke@435: assert(dp->tag() == DataLayout::bit_data_tag, "sane"); duke@435: return new ciBitData(dp); duke@435: } duke@435: } duke@435: return NULL; duke@435: } duke@435: duke@435: // Conservatively decode the trap_state of a ciProfileData. duke@435: int ciMethodData::has_trap_at(ciProfileData* data, int reason) { duke@435: typedef Deoptimization::DeoptReason DR_t; duke@435: int per_bc_reason duke@435: = Deoptimization::reason_recorded_per_bytecode_if_any((DR_t) reason); duke@435: if (trap_count(reason) == 0) { duke@435: // Impossible for this trap to have occurred, regardless of trap_state. duke@435: // Note: This happens if the MDO is empty. duke@435: return 0; duke@435: } else if (per_bc_reason == Deoptimization::Reason_none) { duke@435: // We cannot conclude anything; a trap happened somewhere, maybe here. duke@435: return -1; duke@435: } else if (data == NULL) { duke@435: // No profile here, not even an extra_data record allocated on the fly. duke@435: // If there are empty extra_data records, and there had been a trap, duke@435: // there would have been a non-null data pointer. If there are no duke@435: // free extra_data records, we must return a conservative -1. duke@435: if (_saw_free_extra_data) duke@435: return 0; // Q.E.D. duke@435: else duke@435: return -1; // bail with a conservative answer duke@435: } else { duke@435: return Deoptimization::trap_state_has_reason(data->trap_state(), per_bc_reason); duke@435: } duke@435: } duke@435: duke@435: int ciMethodData::trap_recompiled_at(ciProfileData* data) { duke@435: if (data == NULL) { duke@435: return (_saw_free_extra_data? 0: -1); // (see previous method) duke@435: } else { duke@435: return Deoptimization::trap_state_is_recompiled(data->trap_state())? 1: 0; duke@435: } duke@435: } duke@435: duke@435: void ciMethodData::clear_escape_info() { duke@435: VM_ENTRY_MARK; duke@435: methodDataOop mdo = get_methodDataOop(); kvn@480: if (mdo != NULL) { duke@435: mdo->clear_escape_info(); kvn@480: ArgInfoData *aid = arg_info(); kvn@480: int arg_count = (aid == NULL) ? 0 : aid->number_of_args(); kvn@480: for (int i = 0; i < arg_count; i++) { kvn@480: set_arg_modified(i, 0); kvn@480: } kvn@480: } duke@435: _eflags = _arg_local = _arg_stack = _arg_returned = 0; duke@435: } duke@435: duke@435: // copy our escape info to the methodDataOop if it exists duke@435: void ciMethodData::update_escape_info() { duke@435: VM_ENTRY_MARK; duke@435: methodDataOop mdo = get_methodDataOop(); duke@435: if ( mdo != NULL) { duke@435: mdo->set_eflags(_eflags); duke@435: mdo->set_arg_local(_arg_local); duke@435: mdo->set_arg_stack(_arg_stack); duke@435: mdo->set_arg_returned(_arg_returned); kvn@480: int arg_count = mdo->method()->size_of_parameters(); kvn@480: for (int i = 0; i < arg_count; i++) { kvn@480: mdo->set_arg_modified(i, arg_modified(i)); kvn@480: } duke@435: } duke@435: } duke@435: duke@435: bool ciMethodData::has_escape_info() { duke@435: return eflag_set(methodDataOopDesc::estimated); duke@435: } duke@435: duke@435: void ciMethodData::set_eflag(methodDataOopDesc::EscapeFlag f) { duke@435: set_bits(_eflags, f); duke@435: } duke@435: duke@435: void ciMethodData::clear_eflag(methodDataOopDesc::EscapeFlag f) { duke@435: clear_bits(_eflags, f); duke@435: } duke@435: duke@435: bool ciMethodData::eflag_set(methodDataOopDesc::EscapeFlag f) const { duke@435: return mask_bits(_eflags, f) != 0; duke@435: } duke@435: duke@435: void ciMethodData::set_arg_local(int i) { duke@435: set_nth_bit(_arg_local, i); duke@435: } duke@435: duke@435: void ciMethodData::set_arg_stack(int i) { duke@435: set_nth_bit(_arg_stack, i); duke@435: } duke@435: duke@435: void ciMethodData::set_arg_returned(int i) { duke@435: set_nth_bit(_arg_returned, i); duke@435: } duke@435: kvn@480: void ciMethodData::set_arg_modified(int arg, uint val) { kvn@480: ArgInfoData *aid = arg_info(); kvn@480: if (aid == NULL) kvn@480: return; kvn@480: assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number"); kvn@480: aid->set_arg_modified(arg, val); kvn@480: } kvn@480: duke@435: bool ciMethodData::is_arg_local(int i) const { duke@435: return is_set_nth_bit(_arg_local, i); duke@435: } duke@435: duke@435: bool ciMethodData::is_arg_stack(int i) const { duke@435: return is_set_nth_bit(_arg_stack, i); duke@435: } duke@435: duke@435: bool ciMethodData::is_arg_returned(int i) const { duke@435: return is_set_nth_bit(_arg_returned, i); duke@435: } duke@435: kvn@480: uint ciMethodData::arg_modified(int arg) const { kvn@480: ArgInfoData *aid = arg_info(); kvn@480: if (aid == NULL) kvn@480: return 0; kvn@480: assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number"); kvn@480: return aid->arg_modified(arg); kvn@480: } kvn@480: duke@435: ByteSize ciMethodData::offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) { duke@435: // Get offset within methodDataOop of the data array duke@435: ByteSize data_offset = methodDataOopDesc::data_offset(); duke@435: duke@435: // Get cell offset of the ProfileData within data array duke@435: int cell_offset = dp_to_di(data->dp()); duke@435: duke@435: // Add in counter_offset, the # of bytes into the ProfileData of counter or flag duke@435: int offset = in_bytes(data_offset) + cell_offset + in_bytes(slot_offset_in_data); duke@435: duke@435: return in_ByteSize(offset); duke@435: } duke@435: kvn@480: ciArgInfoData *ciMethodData::arg_info() const { kvn@480: // Should be last, have to skip all traps. kvn@480: DataLayout* dp = data_layout_at(data_size()); kvn@480: DataLayout* end = data_layout_at(data_size() + extra_data_size()); kvn@480: for (; dp < end; dp = methodDataOopDesc::next_extra(dp)) { kvn@480: if (dp->tag() == DataLayout::arg_info_data_tag) kvn@480: return new ciArgInfoData(dp); kvn@480: } kvn@480: return NULL; kvn@480: } kvn@480: kvn@480: duke@435: // Implementation of the print method. duke@435: void ciMethodData::print_impl(outputStream* st) { duke@435: ciObject::print_impl(st); duke@435: } duke@435: duke@435: #ifndef PRODUCT duke@435: void ciMethodData::print() { duke@435: print_data_on(tty); duke@435: } duke@435: duke@435: void ciMethodData::print_data_on(outputStream* st) { duke@435: ResourceMark rm; duke@435: ciProfileData* data; duke@435: for (data = first_data(); is_valid(data); data = next_data(data)) { duke@435: st->print("%d", dp_to_di(data->dp())); duke@435: st->fill_to(6); duke@435: data->print_data_on(st); duke@435: } kvn@480: st->print_cr("--- Extra data:"); kvn@480: DataLayout* dp = data_layout_at(data_size()); kvn@480: DataLayout* end = data_layout_at(data_size() + extra_data_size()); kvn@480: for (; dp < end; dp = methodDataOopDesc::next_extra(dp)) { kvn@480: if (dp->tag() == DataLayout::no_tag) continue; kvn@480: if (dp->tag() == DataLayout::bit_data_tag) { kvn@480: data = new BitData(dp); kvn@480: } else { kvn@480: assert(dp->tag() == DataLayout::arg_info_data_tag, "must be BitData or ArgInfo"); kvn@480: data = new ciArgInfoData(dp); kvn@480: dp = end; // ArgInfoData is at the end of extra data section. kvn@480: } kvn@480: st->print("%d", dp_to_di(data->dp())); kvn@480: st->fill_to(6); kvn@480: data->print_data_on(st); kvn@480: } duke@435: } duke@435: duke@435: void ciReceiverTypeData::print_receiver_data_on(outputStream* st) { duke@435: uint row; duke@435: int entries = 0; duke@435: for (row = 0; row < row_limit(); row++) { duke@435: if (receiver(row) != NULL) entries++; duke@435: } duke@435: st->print_cr("count(%u) entries(%u)", count(), entries); duke@435: for (row = 0; row < row_limit(); row++) { duke@435: if (receiver(row) != NULL) { duke@435: tab(st); duke@435: receiver(row)->print_name_on(st); duke@435: st->print_cr("(%u)", receiver_count(row)); duke@435: } duke@435: } duke@435: } duke@435: duke@435: void ciReceiverTypeData::print_data_on(outputStream* st) { duke@435: print_shared(st, "ciReceiverTypeData"); duke@435: print_receiver_data_on(st); duke@435: } duke@435: duke@435: void ciVirtualCallData::print_data_on(outputStream* st) { duke@435: print_shared(st, "ciVirtualCallData"); duke@435: rtd_super()->print_receiver_data_on(st); duke@435: } duke@435: #endif