aoqi@0: /* aoqi@0: * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "ci/ciConstant.hpp" aoqi@0: #include "ci/ciField.hpp" aoqi@0: #include "ci/ciMethod.hpp" aoqi@0: #include "ci/ciMethodData.hpp" aoqi@0: #include "ci/ciObjArrayKlass.hpp" aoqi@0: #include "ci/ciStreams.hpp" aoqi@0: #include "ci/ciTypeArrayKlass.hpp" aoqi@0: #include "ci/ciTypeFlow.hpp" aoqi@0: #include "compiler/compileLog.hpp" aoqi@0: #include "interpreter/bytecode.hpp" aoqi@0: #include "interpreter/bytecodes.hpp" aoqi@0: #include "memory/allocation.inline.hpp" vlivanov@7385: #include "opto/compile.hpp" goetz@7546: #include "opto/node.hpp" aoqi@0: #include "runtime/deoptimization.hpp" aoqi@0: #include "utilities/growableArray.hpp" aoqi@0: aoqi@0: // ciTypeFlow::JsrSet aoqi@0: // aoqi@0: // A JsrSet represents some set of JsrRecords. This class aoqi@0: // is used to record a set of all jsr routines which we permit aoqi@0: // execution to return (ret) from. aoqi@0: // aoqi@0: // During abstract interpretation, JsrSets are used to determine aoqi@0: // whether two paths which reach a given block are unique, and aoqi@0: // should be cloned apart, or are compatible, and should merge aoqi@0: // together. aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::JsrSet::JsrSet aoqi@0: ciTypeFlow::JsrSet::JsrSet(Arena* arena, int default_len) { aoqi@0: if (arena != NULL) { aoqi@0: // Allocate growable array in Arena. aoqi@0: _set = new (arena) GrowableArray(arena, default_len, 0, NULL); aoqi@0: } else { aoqi@0: // Allocate growable array in current ResourceArea. aoqi@0: _set = new GrowableArray(4, 0, NULL, false); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::JsrSet::copy_into aoqi@0: void ciTypeFlow::JsrSet::copy_into(JsrSet* jsrs) { aoqi@0: int len = size(); aoqi@0: jsrs->_set->clear(); aoqi@0: for (int i = 0; i < len; i++) { aoqi@0: jsrs->_set->append(_set->at(i)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::JsrSet::is_compatible_with aoqi@0: // aoqi@0: // !!!! MISGIVINGS ABOUT THIS... disregard aoqi@0: // aoqi@0: // Is this JsrSet compatible with some other JsrSet? aoqi@0: // aoqi@0: // In set-theoretic terms, a JsrSet can be viewed as a partial function aoqi@0: // from entry addresses to return addresses. Two JsrSets A and B are aoqi@0: // compatible iff aoqi@0: // aoqi@0: // For any x, aoqi@0: // A(x) defined and B(x) defined implies A(x) == B(x) aoqi@0: // aoqi@0: // Less formally, two JsrSets are compatible when they have identical aoqi@0: // return addresses for any entry addresses they share in common. aoqi@0: bool ciTypeFlow::JsrSet::is_compatible_with(JsrSet* other) { aoqi@0: // Walk through both sets in parallel. If the same entry address aoqi@0: // appears in both sets, then the return address must match for aoqi@0: // the sets to be compatible. aoqi@0: int size1 = size(); aoqi@0: int size2 = other->size(); aoqi@0: aoqi@0: // Special case. If nothing is on the jsr stack, then there can aoqi@0: // be no ret. aoqi@0: if (size2 == 0) { aoqi@0: return true; aoqi@0: } else if (size1 != size2) { aoqi@0: return false; aoqi@0: } else { aoqi@0: for (int i = 0; i < size1; i++) { aoqi@0: JsrRecord* record1 = record_at(i); aoqi@0: JsrRecord* record2 = other->record_at(i); aoqi@0: if (record1->entry_address() != record2->entry_address() || aoqi@0: record1->return_address() != record2->return_address()) { aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: #if 0 aoqi@0: int pos1 = 0; aoqi@0: int pos2 = 0; aoqi@0: int size1 = size(); aoqi@0: int size2 = other->size(); aoqi@0: while (pos1 < size1 && pos2 < size2) { aoqi@0: JsrRecord* record1 = record_at(pos1); aoqi@0: JsrRecord* record2 = other->record_at(pos2); aoqi@0: int entry1 = record1->entry_address(); aoqi@0: int entry2 = record2->entry_address(); aoqi@0: if (entry1 < entry2) { aoqi@0: pos1++; aoqi@0: } else if (entry1 > entry2) { aoqi@0: pos2++; aoqi@0: } else { aoqi@0: if (record1->return_address() == record2->return_address()) { aoqi@0: pos1++; aoqi@0: pos2++; aoqi@0: } else { aoqi@0: // These two JsrSets are incompatible. aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: // The two JsrSets agree. aoqi@0: return true; aoqi@0: #endif aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::JsrSet::insert_jsr_record aoqi@0: // aoqi@0: // Insert the given JsrRecord into the JsrSet, maintaining the order aoqi@0: // of the set and replacing any element with the same entry address. aoqi@0: void ciTypeFlow::JsrSet::insert_jsr_record(JsrRecord* record) { aoqi@0: int len = size(); aoqi@0: int entry = record->entry_address(); aoqi@0: int pos = 0; aoqi@0: for ( ; pos < len; pos++) { aoqi@0: JsrRecord* current = record_at(pos); aoqi@0: if (entry == current->entry_address()) { aoqi@0: // Stomp over this entry. aoqi@0: _set->at_put(pos, record); aoqi@0: assert(size() == len, "must be same size"); aoqi@0: return; aoqi@0: } else if (entry < current->entry_address()) { aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Insert the record into the list. aoqi@0: JsrRecord* swap = record; aoqi@0: JsrRecord* temp = NULL; aoqi@0: for ( ; pos < len; pos++) { aoqi@0: temp = _set->at(pos); aoqi@0: _set->at_put(pos, swap); aoqi@0: swap = temp; aoqi@0: } aoqi@0: _set->append(swap); aoqi@0: assert(size() == len+1, "must be larger"); aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::JsrSet::remove_jsr_record aoqi@0: // aoqi@0: // Remove the JsrRecord with the given return address from the JsrSet. aoqi@0: void ciTypeFlow::JsrSet::remove_jsr_record(int return_address) { aoqi@0: int len = size(); aoqi@0: for (int i = 0; i < len; i++) { aoqi@0: if (record_at(i)->return_address() == return_address) { aoqi@0: // We have found the proper entry. Remove it from the aoqi@0: // JsrSet and exit. aoqi@0: for (int j = i+1; j < len ; j++) { aoqi@0: _set->at_put(j-1, _set->at(j)); aoqi@0: } aoqi@0: _set->trunc_to(len-1); aoqi@0: assert(size() == len-1, "must be smaller"); aoqi@0: return; aoqi@0: } aoqi@0: } aoqi@0: assert(false, "verify: returning from invalid subroutine"); aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::JsrSet::apply_control aoqi@0: // aoqi@0: // Apply the effect of a control-flow bytecode on the JsrSet. The aoqi@0: // only bytecodes that modify the JsrSet are jsr and ret. aoqi@0: void ciTypeFlow::JsrSet::apply_control(ciTypeFlow* analyzer, aoqi@0: ciBytecodeStream* str, aoqi@0: ciTypeFlow::StateVector* state) { aoqi@0: Bytecodes::Code code = str->cur_bc(); aoqi@0: if (code == Bytecodes::_jsr) { aoqi@0: JsrRecord* record = aoqi@0: analyzer->make_jsr_record(str->get_dest(), str->next_bci()); aoqi@0: insert_jsr_record(record); aoqi@0: } else if (code == Bytecodes::_jsr_w) { aoqi@0: JsrRecord* record = aoqi@0: analyzer->make_jsr_record(str->get_far_dest(), str->next_bci()); aoqi@0: insert_jsr_record(record); aoqi@0: } else if (code == Bytecodes::_ret) { aoqi@0: Cell local = state->local(str->get_index()); aoqi@0: ciType* return_address = state->type_at(local); aoqi@0: assert(return_address->is_return_address(), "verify: wrong type"); aoqi@0: if (size() == 0) { aoqi@0: // Ret-state underflow: Hit a ret w/o any previous jsrs. Bail out. aoqi@0: // This can happen when a loop is inside a finally clause (4614060). aoqi@0: analyzer->record_failure("OSR in finally clause"); aoqi@0: return; aoqi@0: } aoqi@0: remove_jsr_record(return_address->as_return_address()->bci()); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::JsrSet::print_on aoqi@0: void ciTypeFlow::JsrSet::print_on(outputStream* st) const { aoqi@0: st->print("{ "); aoqi@0: int num_elements = size(); aoqi@0: if (num_elements > 0) { aoqi@0: int i = 0; aoqi@0: for( ; i < num_elements - 1; i++) { aoqi@0: _set->at(i)->print_on(st); aoqi@0: st->print(", "); aoqi@0: } aoqi@0: _set->at(i)->print_on(st); aoqi@0: st->print(" "); aoqi@0: } aoqi@0: st->print("}"); aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: // ciTypeFlow::StateVector aoqi@0: // aoqi@0: // A StateVector summarizes the type information at some point in aoqi@0: // the program. aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::type_meet aoqi@0: // aoqi@0: // Meet two types. aoqi@0: // aoqi@0: // The semi-lattice of types use by this analysis are modeled on those aoqi@0: // of the verifier. The lattice is as follows: aoqi@0: // aoqi@0: // top_type() >= all non-extremal types >= bottom_type aoqi@0: // and aoqi@0: // Every primitive type is comparable only with itself. The meet of aoqi@0: // reference types is determined by their kind: instance class, aoqi@0: // interface, or array class. The meet of two types of the same aoqi@0: // kind is their least common ancestor. The meet of two types of aoqi@0: // different kinds is always java.lang.Object. aoqi@0: ciType* ciTypeFlow::StateVector::type_meet_internal(ciType* t1, ciType* t2, ciTypeFlow* analyzer) { aoqi@0: assert(t1 != t2, "checked in caller"); aoqi@0: if (t1->equals(top_type())) { aoqi@0: return t2; aoqi@0: } else if (t2->equals(top_type())) { aoqi@0: return t1; aoqi@0: } else if (t1->is_primitive_type() || t2->is_primitive_type()) { aoqi@0: // Special case null_type. null_type meet any reference type T aoqi@0: // is T. null_type meet null_type is null_type. aoqi@0: if (t1->equals(null_type())) { aoqi@0: if (!t2->is_primitive_type() || t2->equals(null_type())) { aoqi@0: return t2; aoqi@0: } aoqi@0: } else if (t2->equals(null_type())) { aoqi@0: if (!t1->is_primitive_type()) { aoqi@0: return t1; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // At least one of the two types is a non-top primitive type. aoqi@0: // The other type is not equal to it. Fall to bottom. aoqi@0: return bottom_type(); aoqi@0: } else { aoqi@0: // Both types are non-top non-primitive types. That is, aoqi@0: // both types are either instanceKlasses or arrayKlasses. aoqi@0: ciKlass* object_klass = analyzer->env()->Object_klass(); aoqi@0: ciKlass* k1 = t1->as_klass(); aoqi@0: ciKlass* k2 = t2->as_klass(); aoqi@0: if (k1->equals(object_klass) || k2->equals(object_klass)) { aoqi@0: return object_klass; aoqi@0: } else if (!k1->is_loaded() || !k2->is_loaded()) { aoqi@0: // Unloaded classes fall to java.lang.Object at a merge. aoqi@0: return object_klass; aoqi@0: } else if (k1->is_interface() != k2->is_interface()) { aoqi@0: // When an interface meets a non-interface, we get Object; aoqi@0: // This is what the verifier does. aoqi@0: return object_klass; aoqi@0: } else if (k1->is_array_klass() || k2->is_array_klass()) { aoqi@0: // When an array meets a non-array, we get Object. aoqi@0: // When objArray meets typeArray, we also get Object. aoqi@0: // And when typeArray meets different typeArray, we again get Object. aoqi@0: // But when objArray meets objArray, we look carefully at element types. aoqi@0: if (k1->is_obj_array_klass() && k2->is_obj_array_klass()) { aoqi@0: // Meet the element types, then construct the corresponding array type. aoqi@0: ciKlass* elem1 = k1->as_obj_array_klass()->element_klass(); aoqi@0: ciKlass* elem2 = k2->as_obj_array_klass()->element_klass(); aoqi@0: ciKlass* elem = type_meet_internal(elem1, elem2, analyzer)->as_klass(); aoqi@0: // Do an easy shortcut if one type is a super of the other. aoqi@0: if (elem == elem1) { aoqi@0: assert(k1 == ciObjArrayKlass::make(elem), "shortcut is OK"); aoqi@0: return k1; aoqi@0: } else if (elem == elem2) { aoqi@0: assert(k2 == ciObjArrayKlass::make(elem), "shortcut is OK"); aoqi@0: return k2; aoqi@0: } else { aoqi@0: return ciObjArrayKlass::make(elem); aoqi@0: } aoqi@0: } else { aoqi@0: return object_klass; aoqi@0: } aoqi@0: } else { aoqi@0: // Must be two plain old instance klasses. aoqi@0: assert(k1->is_instance_klass(), "previous cases handle non-instances"); aoqi@0: assert(k2->is_instance_klass(), "previous cases handle non-instances"); aoqi@0: return k1->least_common_ancestor(k2); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::StateVector aoqi@0: // aoqi@0: // Build a new state vector aoqi@0: ciTypeFlow::StateVector::StateVector(ciTypeFlow* analyzer) { aoqi@0: _outer = analyzer; aoqi@0: _stack_size = -1; aoqi@0: _monitor_count = -1; aoqi@0: // Allocate the _types array aoqi@0: int max_cells = analyzer->max_cells(); aoqi@0: _types = (ciType**)analyzer->arena()->Amalloc(sizeof(ciType*) * max_cells); aoqi@0: for (int i=0; iget_flow_analysis(); aoqi@0: if (non_osr_flow->failing()) { aoqi@0: record_failure(non_osr_flow->failure_reason()); aoqi@0: return NULL; aoqi@0: } aoqi@0: JsrSet* jsrs = new JsrSet(NULL, 16); aoqi@0: Block* non_osr_block = non_osr_flow->existing_block_at(start_bci(), jsrs); aoqi@0: if (non_osr_block == NULL) { aoqi@0: record_failure("cannot reach OSR point"); aoqi@0: return NULL; aoqi@0: } aoqi@0: // load up the non-OSR state at this point aoqi@0: non_osr_block->copy_state_into(state); aoqi@0: int non_osr_start = non_osr_block->start(); aoqi@0: if (non_osr_start != start_bci()) { aoqi@0: // must flow forward from it aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print_cr(">> Interpreting pre-OSR block %d:", non_osr_start); aoqi@0: } aoqi@0: Block* block = block_at(non_osr_start, jsrs); aoqi@0: assert(block->limit() == start_bci(), "must flow forward to start"); aoqi@0: flow_block(block, state, jsrs); aoqi@0: } aoqi@0: return state; aoqi@0: // Note: The code below would be an incorrect for an OSR flow, aoqi@0: // even if it were possible for an OSR entry point to be at bci zero. aoqi@0: } aoqi@0: // "Push" the method signature into the first few locals. aoqi@0: state->set_stack_size(-max_locals()); aoqi@0: if (!method()->is_static()) { aoqi@0: state->push(method()->holder()); aoqi@0: assert(state->tos() == state->local(0), ""); aoqi@0: } aoqi@0: for (ciSignatureStream str(method()->signature()); aoqi@0: !str.at_return_type(); aoqi@0: str.next()) { aoqi@0: state->push_translate(str.type()); aoqi@0: } aoqi@0: // Set the rest of the locals to bottom. aoqi@0: Cell cell = state->next_cell(state->tos()); aoqi@0: state->set_stack_size(0); aoqi@0: int limit = state->limit_cell(); aoqi@0: for (; cell < limit; cell = state->next_cell(cell)) { aoqi@0: state->set_type_at(cell, state->bottom_type()); aoqi@0: } aoqi@0: // Lock an object, if necessary. aoqi@0: state->set_monitor_count(method()->is_synchronized() ? 1 : 0); aoqi@0: return state; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::copy_into aoqi@0: // aoqi@0: // Copy our value into some other StateVector aoqi@0: void ciTypeFlow::StateVector::copy_into(ciTypeFlow::StateVector* copy) aoqi@0: const { aoqi@0: copy->set_stack_size(stack_size()); aoqi@0: copy->set_monitor_count(monitor_count()); aoqi@0: Cell limit = limit_cell(); aoqi@0: for (Cell c = start_cell(); c < limit; c = next_cell(c)) { aoqi@0: copy->set_type_at(c, type_at(c)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::meet aoqi@0: // aoqi@0: // Meets this StateVector with another, destructively modifying this aoqi@0: // one. Returns true if any modification takes place. aoqi@0: bool ciTypeFlow::StateVector::meet(const ciTypeFlow::StateVector* incoming) { aoqi@0: if (monitor_count() == -1) { aoqi@0: set_monitor_count(incoming->monitor_count()); aoqi@0: } aoqi@0: assert(monitor_count() == incoming->monitor_count(), "monitors must match"); aoqi@0: aoqi@0: if (stack_size() == -1) { aoqi@0: set_stack_size(incoming->stack_size()); aoqi@0: Cell limit = limit_cell(); aoqi@0: #ifdef ASSERT aoqi@0: { for (Cell c = start_cell(); c < limit; c = next_cell(c)) { aoqi@0: assert(type_at(c) == top_type(), ""); aoqi@0: } } aoqi@0: #endif aoqi@0: // Make a simple copy of the incoming state. aoqi@0: for (Cell c = start_cell(); c < limit; c = next_cell(c)) { aoqi@0: set_type_at(c, incoming->type_at(c)); aoqi@0: } aoqi@0: return true; // it is always different the first time aoqi@0: } aoqi@0: #ifdef ASSERT aoqi@0: if (stack_size() != incoming->stack_size()) { aoqi@0: _outer->method()->print_codes(); aoqi@0: tty->print_cr("!!!! Stack size conflict"); aoqi@0: tty->print_cr("Current state:"); aoqi@0: print_on(tty); aoqi@0: tty->print_cr("Incoming state:"); aoqi@0: ((StateVector*)incoming)->print_on(tty); aoqi@0: } aoqi@0: #endif aoqi@0: assert(stack_size() == incoming->stack_size(), "sanity"); aoqi@0: aoqi@0: bool different = false; aoqi@0: Cell limit = limit_cell(); aoqi@0: for (Cell c = start_cell(); c < limit; c = next_cell(c)) { aoqi@0: ciType* t1 = type_at(c); aoqi@0: ciType* t2 = incoming->type_at(c); aoqi@0: if (!t1->equals(t2)) { aoqi@0: ciType* new_type = type_meet(t1, t2); aoqi@0: if (!t1->equals(new_type)) { aoqi@0: set_type_at(c, new_type); aoqi@0: different = true; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: return different; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::meet_exception aoqi@0: // aoqi@0: // Meets this StateVector with another, destructively modifying this aoqi@0: // one. The incoming state is coming via an exception. Returns true aoqi@0: // if any modification takes place. aoqi@0: bool ciTypeFlow::StateVector::meet_exception(ciInstanceKlass* exc, aoqi@0: const ciTypeFlow::StateVector* incoming) { aoqi@0: if (monitor_count() == -1) { aoqi@0: set_monitor_count(incoming->monitor_count()); aoqi@0: } aoqi@0: assert(monitor_count() == incoming->monitor_count(), "monitors must match"); aoqi@0: aoqi@0: if (stack_size() == -1) { aoqi@0: set_stack_size(1); aoqi@0: } aoqi@0: aoqi@0: assert(stack_size() == 1, "must have one-element stack"); aoqi@0: aoqi@0: bool different = false; aoqi@0: aoqi@0: // Meet locals from incoming array. aoqi@0: Cell limit = local(_outer->max_locals()-1); aoqi@0: for (Cell c = start_cell(); c <= limit; c = next_cell(c)) { aoqi@0: ciType* t1 = type_at(c); aoqi@0: ciType* t2 = incoming->type_at(c); aoqi@0: if (!t1->equals(t2)) { aoqi@0: ciType* new_type = type_meet(t1, t2); aoqi@0: if (!t1->equals(new_type)) { aoqi@0: set_type_at(c, new_type); aoqi@0: different = true; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Handle stack separately. When an exception occurs, the aoqi@0: // only stack entry is the exception instance. aoqi@0: ciType* tos_type = type_at_tos(); aoqi@0: if (!tos_type->equals(exc)) { aoqi@0: ciType* new_type = type_meet(tos_type, exc); aoqi@0: if (!tos_type->equals(new_type)) { aoqi@0: set_type_at_tos(new_type); aoqi@0: different = true; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return different; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::push_translate aoqi@0: void ciTypeFlow::StateVector::push_translate(ciType* type) { aoqi@0: BasicType basic_type = type->basic_type(); aoqi@0: if (basic_type == T_BOOLEAN || basic_type == T_CHAR || aoqi@0: basic_type == T_BYTE || basic_type == T_SHORT) { aoqi@0: push_int(); aoqi@0: } else { aoqi@0: push(type); aoqi@0: if (type->is_two_word()) { aoqi@0: push(half_type(type)); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_aaload aoqi@0: void ciTypeFlow::StateVector::do_aaload(ciBytecodeStream* str) { aoqi@0: pop_int(); aoqi@0: ciObjArrayKlass* array_klass = pop_objArray(); aoqi@0: if (array_klass == NULL) { aoqi@0: // Did aaload on a null reference; push a null and ignore the exception. aoqi@0: // This instruction will never continue normally. All we have to do aoqi@0: // is report a value that will meet correctly with any downstream aoqi@0: // reference types on paths that will truly be executed. This null type aoqi@0: // meets with any reference type to yield that same reference type. aoqi@0: // (The compiler will generate an unconditional exception here.) aoqi@0: push(null_type()); aoqi@0: return; aoqi@0: } aoqi@0: if (!array_klass->is_loaded()) { aoqi@0: // Only fails for some -Xcomp runs aoqi@0: trap(str, array_klass, aoqi@0: Deoptimization::make_trap_request aoqi@0: (Deoptimization::Reason_unloaded, aoqi@0: Deoptimization::Action_reinterpret)); aoqi@0: return; aoqi@0: } aoqi@0: ciKlass* element_klass = array_klass->element_klass(); aoqi@0: if (!element_klass->is_loaded() && element_klass->is_instance_klass()) { aoqi@0: Untested("unloaded array element class in ciTypeFlow"); aoqi@0: trap(str, element_klass, aoqi@0: Deoptimization::make_trap_request aoqi@0: (Deoptimization::Reason_unloaded, aoqi@0: Deoptimization::Action_reinterpret)); aoqi@0: } else { aoqi@0: push_object(element_klass); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_checkcast aoqi@0: void ciTypeFlow::StateVector::do_checkcast(ciBytecodeStream* str) { aoqi@0: bool will_link; aoqi@0: ciKlass* klass = str->get_klass(will_link); aoqi@0: if (!will_link) { aoqi@0: // VM's interpreter will not load 'klass' if object is NULL. aoqi@0: // Type flow after this block may still be needed in two situations: aoqi@0: // 1) C2 uses do_null_assert() and continues compilation for later blocks aoqi@0: // 2) C2 does an OSR compile in a later block (see bug 4778368). aoqi@0: pop_object(); aoqi@0: do_null_assert(klass); aoqi@0: } else { aoqi@0: pop_object(); aoqi@0: push_object(klass); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_getfield aoqi@0: void ciTypeFlow::StateVector::do_getfield(ciBytecodeStream* str) { aoqi@0: // could add assert here for type of object. aoqi@0: pop_object(); aoqi@0: do_getstatic(str); aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_getstatic aoqi@0: void ciTypeFlow::StateVector::do_getstatic(ciBytecodeStream* str) { aoqi@0: bool will_link; aoqi@0: ciField* field = str->get_field(will_link); aoqi@0: if (!will_link) { aoqi@0: trap(str, field->holder(), str->get_field_holder_index()); aoqi@0: } else { aoqi@0: ciType* field_type = field->type(); aoqi@0: if (!field_type->is_loaded()) { aoqi@0: // Normally, we need the field's type to be loaded if we are to aoqi@0: // do anything interesting with its value. aoqi@0: // We used to do this: trap(str, str->get_field_signature_index()); aoqi@0: // aoqi@0: // There is one good reason not to trap here. Execution can aoqi@0: // get past this "getfield" or "getstatic" if the value of aoqi@0: // the field is null. As long as the value is null, the class aoqi@0: // does not need to be loaded! The compiler must assume that aoqi@0: // the value of the unloaded class reference is null; if the code aoqi@0: // ever sees a non-null value, loading has occurred. aoqi@0: // aoqi@0: // This actually happens often enough to be annoying. If the aoqi@0: // compiler throws an uncommon trap at this bytecode, you can aoqi@0: // get an endless loop of recompilations, when all the code aoqi@0: // needs to do is load a series of null values. Also, a trap aoqi@0: // here can make an OSR entry point unreachable, triggering the aoqi@0: // assert on non_osr_block in ciTypeFlow::get_start_state. aoqi@0: // (See bug 4379915.) aoqi@0: do_null_assert(field_type->as_klass()); aoqi@0: } else { aoqi@0: push_translate(field_type); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_invoke aoqi@0: void ciTypeFlow::StateVector::do_invoke(ciBytecodeStream* str, aoqi@0: bool has_receiver) { aoqi@0: bool will_link; aoqi@0: ciSignature* declared_signature = NULL; aoqi@0: ciMethod* callee = str->get_method(will_link, &declared_signature); aoqi@0: assert(declared_signature != NULL, "cannot be null"); aoqi@0: if (!will_link) { aoqi@0: // We weren't able to find the method. aoqi@0: if (str->cur_bc() == Bytecodes::_invokedynamic) { aoqi@0: trap(str, NULL, aoqi@0: Deoptimization::make_trap_request aoqi@0: (Deoptimization::Reason_uninitialized, aoqi@0: Deoptimization::Action_reinterpret)); aoqi@0: } else { aoqi@0: ciKlass* unloaded_holder = callee->holder(); aoqi@0: trap(str, unloaded_holder, str->get_method_holder_index()); aoqi@0: } aoqi@0: } else { aoqi@0: // We are using the declared signature here because it might be aoqi@0: // different from the callee signature (Cf. invokedynamic and aoqi@0: // invokehandle). aoqi@0: ciSignatureStream sigstr(declared_signature); aoqi@0: const int arg_size = declared_signature->size(); aoqi@0: const int stack_base = stack_size() - arg_size; aoqi@0: int i = 0; aoqi@0: for( ; !sigstr.at_return_type(); sigstr.next()) { aoqi@0: ciType* type = sigstr.type(); aoqi@0: ciType* stack_type = type_at(stack(stack_base + i++)); aoqi@0: // Do I want to check this type? aoqi@0: // assert(stack_type->is_subtype_of(type), "bad type for field value"); aoqi@0: if (type->is_two_word()) { aoqi@0: ciType* stack_type2 = type_at(stack(stack_base + i++)); aoqi@0: assert(stack_type2->equals(half_type(type)), "must be 2nd half"); aoqi@0: } aoqi@0: } aoqi@0: assert(arg_size == i, "must match"); aoqi@0: for (int j = 0; j < arg_size; j++) { aoqi@0: pop(); aoqi@0: } aoqi@0: if (has_receiver) { aoqi@0: // Check this? aoqi@0: pop_object(); aoqi@0: } aoqi@0: assert(!sigstr.is_done(), "must have return type"); aoqi@0: ciType* return_type = sigstr.type(); aoqi@0: if (!return_type->is_void()) { aoqi@0: if (!return_type->is_loaded()) { aoqi@0: // As in do_getstatic(), generally speaking, we need the return type to aoqi@0: // be loaded if we are to do anything interesting with its value. aoqi@0: // We used to do this: trap(str, str->get_method_signature_index()); aoqi@0: // aoqi@0: // We do not trap here since execution can get past this invoke if aoqi@0: // the return value is null. As long as the value is null, the class aoqi@0: // does not need to be loaded! The compiler must assume that aoqi@0: // the value of the unloaded class reference is null; if the code aoqi@0: // ever sees a non-null value, loading has occurred. aoqi@0: // aoqi@0: // See do_getstatic() for similar explanation, as well as bug 4684993. aoqi@0: do_null_assert(return_type->as_klass()); aoqi@0: } else { aoqi@0: push_translate(return_type); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_jsr aoqi@0: void ciTypeFlow::StateVector::do_jsr(ciBytecodeStream* str) { aoqi@0: push(ciReturnAddress::make(str->next_bci())); aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_ldc aoqi@0: void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) { aoqi@0: ciConstant con = str->get_constant(); aoqi@0: BasicType basic_type = con.basic_type(); aoqi@0: if (basic_type == T_ILLEGAL) { aoqi@0: // OutOfMemoryError in the CI while loading constant aoqi@0: push_null(); aoqi@0: outer()->record_failure("ldc did not link"); aoqi@0: return; aoqi@0: } aoqi@0: if (basic_type == T_OBJECT || basic_type == T_ARRAY) { aoqi@0: ciObject* obj = con.as_object(); aoqi@0: if (obj->is_null_object()) { aoqi@0: push_null(); aoqi@0: } else { vlivanov@7288: assert(obj->is_instance() || obj->is_array(), "must be java_mirror of klass"); aoqi@0: push_object(obj->klass()); aoqi@0: } aoqi@0: } else { aoqi@0: push_translate(ciType::make(basic_type)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_multianewarray aoqi@0: void ciTypeFlow::StateVector::do_multianewarray(ciBytecodeStream* str) { aoqi@0: int dimensions = str->get_dimensions(); aoqi@0: bool will_link; aoqi@0: ciArrayKlass* array_klass = str->get_klass(will_link)->as_array_klass(); aoqi@0: if (!will_link) { aoqi@0: trap(str, array_klass, str->get_klass_index()); aoqi@0: } else { aoqi@0: for (int i = 0; i < dimensions; i++) { aoqi@0: pop_int(); aoqi@0: } aoqi@0: push_object(array_klass); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_new aoqi@0: void ciTypeFlow::StateVector::do_new(ciBytecodeStream* str) { aoqi@0: bool will_link; aoqi@0: ciKlass* klass = str->get_klass(will_link); aoqi@0: if (!will_link || str->is_unresolved_klass()) { aoqi@0: trap(str, klass, str->get_klass_index()); aoqi@0: } else { aoqi@0: push_object(klass); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_newarray aoqi@0: void ciTypeFlow::StateVector::do_newarray(ciBytecodeStream* str) { aoqi@0: pop_int(); aoqi@0: ciKlass* klass = ciTypeArrayKlass::make((BasicType)str->get_index()); aoqi@0: push_object(klass); aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_putfield aoqi@0: void ciTypeFlow::StateVector::do_putfield(ciBytecodeStream* str) { aoqi@0: do_putstatic(str); aoqi@0: if (_trap_bci != -1) return; // unloaded field holder, etc. aoqi@0: // could add assert here for type of object. aoqi@0: pop_object(); aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_putstatic aoqi@0: void ciTypeFlow::StateVector::do_putstatic(ciBytecodeStream* str) { aoqi@0: bool will_link; aoqi@0: ciField* field = str->get_field(will_link); aoqi@0: if (!will_link) { aoqi@0: trap(str, field->holder(), str->get_field_holder_index()); aoqi@0: } else { aoqi@0: ciType* field_type = field->type(); aoqi@0: ciType* type = pop_value(); aoqi@0: // Do I want to check this type? aoqi@0: // assert(type->is_subtype_of(field_type), "bad type for field value"); aoqi@0: if (field_type->is_two_word()) { aoqi@0: ciType* type2 = pop_value(); aoqi@0: assert(type2->is_two_word(), "must be 2nd half"); aoqi@0: assert(type == half_type(type2), "must be 2nd half"); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_ret aoqi@0: void ciTypeFlow::StateVector::do_ret(ciBytecodeStream* str) { aoqi@0: Cell index = local(str->get_index()); aoqi@0: aoqi@0: ciType* address = type_at(index); aoqi@0: assert(address->is_return_address(), "bad return address"); aoqi@0: set_type_at(index, bottom_type()); aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::trap aoqi@0: // aoqi@0: // Stop interpretation of this path with a trap. aoqi@0: void ciTypeFlow::StateVector::trap(ciBytecodeStream* str, ciKlass* klass, int index) { aoqi@0: _trap_bci = str->cur_bci(); aoqi@0: _trap_index = index; aoqi@0: aoqi@0: // Log information about this trap: aoqi@0: CompileLog* log = outer()->env()->log(); aoqi@0: if (log != NULL) { aoqi@0: int mid = log->identify(outer()->method()); aoqi@0: int kid = (klass == NULL)? -1: log->identify(klass); aoqi@0: log->begin_elem("uncommon_trap method='%d' bci='%d'", mid, str->cur_bci()); aoqi@0: char buf[100]; aoqi@0: log->print(" %s", Deoptimization::format_trap_request(buf, sizeof(buf), aoqi@0: index)); aoqi@0: if (kid >= 0) aoqi@0: log->print(" klass='%d'", kid); aoqi@0: log->end_elem(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::do_null_assert aoqi@0: // Corresponds to graphKit::do_null_assert. aoqi@0: void ciTypeFlow::StateVector::do_null_assert(ciKlass* unloaded_klass) { aoqi@0: if (unloaded_klass->is_loaded()) { aoqi@0: // We failed to link, but we can still compute with this class, aoqi@0: // since it is loaded somewhere. The compiler will uncommon_trap aoqi@0: // if the object is not null, but the typeflow pass can not assume aoqi@0: // that the object will be null, otherwise it may incorrectly tell aoqi@0: // the parser that an object is known to be null. 4761344, 4807707 aoqi@0: push_object(unloaded_klass); aoqi@0: } else { aoqi@0: // The class is not loaded anywhere. It is safe to model the aoqi@0: // null in the typestates, because we can compile in a null check aoqi@0: // which will deoptimize us if someone manages to load the aoqi@0: // class later. aoqi@0: push_null(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::apply_one_bytecode aoqi@0: // aoqi@0: // Apply the effect of one bytecode to this StateVector aoqi@0: bool ciTypeFlow::StateVector::apply_one_bytecode(ciBytecodeStream* str) { aoqi@0: _trap_bci = -1; aoqi@0: _trap_index = 0; aoqi@0: aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print_cr(">> Interpreting bytecode %d:%s", str->cur_bci(), aoqi@0: Bytecodes::name(str->cur_bc())); aoqi@0: } aoqi@0: aoqi@0: switch(str->cur_bc()) { aoqi@0: case Bytecodes::_aaload: do_aaload(str); break; aoqi@0: aoqi@0: case Bytecodes::_aastore: aoqi@0: { aoqi@0: pop_object(); aoqi@0: pop_int(); aoqi@0: pop_objArray(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_aconst_null: aoqi@0: { aoqi@0: push_null(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_aload: load_local_object(str->get_index()); break; aoqi@0: case Bytecodes::_aload_0: load_local_object(0); break; aoqi@0: case Bytecodes::_aload_1: load_local_object(1); break; aoqi@0: case Bytecodes::_aload_2: load_local_object(2); break; aoqi@0: case Bytecodes::_aload_3: load_local_object(3); break; aoqi@0: aoqi@0: case Bytecodes::_anewarray: aoqi@0: { aoqi@0: pop_int(); aoqi@0: bool will_link; aoqi@0: ciKlass* element_klass = str->get_klass(will_link); aoqi@0: if (!will_link) { aoqi@0: trap(str, element_klass, str->get_klass_index()); aoqi@0: } else { aoqi@0: push_object(ciObjArrayKlass::make(element_klass)); aoqi@0: } aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_areturn: aoqi@0: case Bytecodes::_ifnonnull: aoqi@0: case Bytecodes::_ifnull: aoqi@0: { aoqi@0: pop_object(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_monitorenter: aoqi@0: { aoqi@0: pop_object(); aoqi@0: set_monitor_count(monitor_count() + 1); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_monitorexit: aoqi@0: { aoqi@0: pop_object(); aoqi@0: assert(monitor_count() > 0, "must be a monitor to exit from"); aoqi@0: set_monitor_count(monitor_count() - 1); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_arraylength: aoqi@0: { aoqi@0: pop_array(); aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_astore: store_local_object(str->get_index()); break; aoqi@0: case Bytecodes::_astore_0: store_local_object(0); break; aoqi@0: case Bytecodes::_astore_1: store_local_object(1); break; aoqi@0: case Bytecodes::_astore_2: store_local_object(2); break; aoqi@0: case Bytecodes::_astore_3: store_local_object(3); break; aoqi@0: aoqi@0: case Bytecodes::_athrow: aoqi@0: { aoqi@0: NEEDS_CLEANUP; aoqi@0: pop_object(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_baload: aoqi@0: case Bytecodes::_caload: aoqi@0: case Bytecodes::_iaload: aoqi@0: case Bytecodes::_saload: aoqi@0: { aoqi@0: pop_int(); aoqi@0: ciTypeArrayKlass* array_klass = pop_typeArray(); aoqi@0: // Put assert here for right type? aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_bastore: aoqi@0: case Bytecodes::_castore: aoqi@0: case Bytecodes::_iastore: aoqi@0: case Bytecodes::_sastore: aoqi@0: { aoqi@0: pop_int(); aoqi@0: pop_int(); aoqi@0: pop_typeArray(); aoqi@0: // assert here? aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_bipush: aoqi@0: case Bytecodes::_iconst_m1: aoqi@0: case Bytecodes::_iconst_0: aoqi@0: case Bytecodes::_iconst_1: aoqi@0: case Bytecodes::_iconst_2: aoqi@0: case Bytecodes::_iconst_3: aoqi@0: case Bytecodes::_iconst_4: aoqi@0: case Bytecodes::_iconst_5: aoqi@0: case Bytecodes::_sipush: aoqi@0: { aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_checkcast: do_checkcast(str); break; aoqi@0: aoqi@0: case Bytecodes::_d2f: aoqi@0: { aoqi@0: pop_double(); aoqi@0: push_float(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_d2i: aoqi@0: { aoqi@0: pop_double(); aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_d2l: aoqi@0: { aoqi@0: pop_double(); aoqi@0: push_long(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dadd: aoqi@0: case Bytecodes::_ddiv: aoqi@0: case Bytecodes::_dmul: aoqi@0: case Bytecodes::_drem: aoqi@0: case Bytecodes::_dsub: aoqi@0: { aoqi@0: pop_double(); aoqi@0: pop_double(); aoqi@0: push_double(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_daload: aoqi@0: { aoqi@0: pop_int(); aoqi@0: ciTypeArrayKlass* array_klass = pop_typeArray(); aoqi@0: // Put assert here for right type? aoqi@0: push_double(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dastore: aoqi@0: { aoqi@0: pop_double(); aoqi@0: pop_int(); aoqi@0: pop_typeArray(); aoqi@0: // assert here? aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dcmpg: aoqi@0: case Bytecodes::_dcmpl: aoqi@0: { aoqi@0: pop_double(); aoqi@0: pop_double(); aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dconst_0: aoqi@0: case Bytecodes::_dconst_1: aoqi@0: { aoqi@0: push_double(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dload: load_local_double(str->get_index()); break; aoqi@0: case Bytecodes::_dload_0: load_local_double(0); break; aoqi@0: case Bytecodes::_dload_1: load_local_double(1); break; aoqi@0: case Bytecodes::_dload_2: load_local_double(2); break; aoqi@0: case Bytecodes::_dload_3: load_local_double(3); break; aoqi@0: aoqi@0: case Bytecodes::_dneg: aoqi@0: { aoqi@0: pop_double(); aoqi@0: push_double(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dreturn: aoqi@0: { aoqi@0: pop_double(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dstore: store_local_double(str->get_index()); break; aoqi@0: case Bytecodes::_dstore_0: store_local_double(0); break; aoqi@0: case Bytecodes::_dstore_1: store_local_double(1); break; aoqi@0: case Bytecodes::_dstore_2: store_local_double(2); break; aoqi@0: case Bytecodes::_dstore_3: store_local_double(3); break; aoqi@0: aoqi@0: case Bytecodes::_dup: aoqi@0: { aoqi@0: push(type_at_tos()); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dup_x1: aoqi@0: { aoqi@0: ciType* value1 = pop_value(); aoqi@0: ciType* value2 = pop_value(); aoqi@0: push(value1); aoqi@0: push(value2); aoqi@0: push(value1); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dup_x2: aoqi@0: { aoqi@0: ciType* value1 = pop_value(); aoqi@0: ciType* value2 = pop_value(); aoqi@0: ciType* value3 = pop_value(); aoqi@0: push(value1); aoqi@0: push(value3); aoqi@0: push(value2); aoqi@0: push(value1); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dup2: aoqi@0: { aoqi@0: ciType* value1 = pop_value(); aoqi@0: ciType* value2 = pop_value(); aoqi@0: push(value2); aoqi@0: push(value1); aoqi@0: push(value2); aoqi@0: push(value1); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dup2_x1: aoqi@0: { aoqi@0: ciType* value1 = pop_value(); aoqi@0: ciType* value2 = pop_value(); aoqi@0: ciType* value3 = pop_value(); aoqi@0: push(value2); aoqi@0: push(value1); aoqi@0: push(value3); aoqi@0: push(value2); aoqi@0: push(value1); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_dup2_x2: aoqi@0: { aoqi@0: ciType* value1 = pop_value(); aoqi@0: ciType* value2 = pop_value(); aoqi@0: ciType* value3 = pop_value(); aoqi@0: ciType* value4 = pop_value(); aoqi@0: push(value2); aoqi@0: push(value1); aoqi@0: push(value4); aoqi@0: push(value3); aoqi@0: push(value2); aoqi@0: push(value1); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_f2d: aoqi@0: { aoqi@0: pop_float(); aoqi@0: push_double(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_f2i: aoqi@0: { aoqi@0: pop_float(); aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_f2l: aoqi@0: { aoqi@0: pop_float(); aoqi@0: push_long(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_fadd: aoqi@0: case Bytecodes::_fdiv: aoqi@0: case Bytecodes::_fmul: aoqi@0: case Bytecodes::_frem: aoqi@0: case Bytecodes::_fsub: aoqi@0: { aoqi@0: pop_float(); aoqi@0: pop_float(); aoqi@0: push_float(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_faload: aoqi@0: { aoqi@0: pop_int(); aoqi@0: ciTypeArrayKlass* array_klass = pop_typeArray(); aoqi@0: // Put assert here. aoqi@0: push_float(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_fastore: aoqi@0: { aoqi@0: pop_float(); aoqi@0: pop_int(); aoqi@0: ciTypeArrayKlass* array_klass = pop_typeArray(); aoqi@0: // Put assert here. aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_fcmpg: aoqi@0: case Bytecodes::_fcmpl: aoqi@0: { aoqi@0: pop_float(); aoqi@0: pop_float(); aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_fconst_0: aoqi@0: case Bytecodes::_fconst_1: aoqi@0: case Bytecodes::_fconst_2: aoqi@0: { aoqi@0: push_float(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_fload: load_local_float(str->get_index()); break; aoqi@0: case Bytecodes::_fload_0: load_local_float(0); break; aoqi@0: case Bytecodes::_fload_1: load_local_float(1); break; aoqi@0: case Bytecodes::_fload_2: load_local_float(2); break; aoqi@0: case Bytecodes::_fload_3: load_local_float(3); break; aoqi@0: aoqi@0: case Bytecodes::_fneg: aoqi@0: { aoqi@0: pop_float(); aoqi@0: push_float(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_freturn: aoqi@0: { aoqi@0: pop_float(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_fstore: store_local_float(str->get_index()); break; aoqi@0: case Bytecodes::_fstore_0: store_local_float(0); break; aoqi@0: case Bytecodes::_fstore_1: store_local_float(1); break; aoqi@0: case Bytecodes::_fstore_2: store_local_float(2); break; aoqi@0: case Bytecodes::_fstore_3: store_local_float(3); break; aoqi@0: aoqi@0: case Bytecodes::_getfield: do_getfield(str); break; aoqi@0: case Bytecodes::_getstatic: do_getstatic(str); break; aoqi@0: aoqi@0: case Bytecodes::_goto: aoqi@0: case Bytecodes::_goto_w: aoqi@0: case Bytecodes::_nop: aoqi@0: case Bytecodes::_return: aoqi@0: { aoqi@0: // do nothing. aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_i2b: aoqi@0: case Bytecodes::_i2c: aoqi@0: case Bytecodes::_i2s: aoqi@0: case Bytecodes::_ineg: aoqi@0: { aoqi@0: pop_int(); aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_i2d: aoqi@0: { aoqi@0: pop_int(); aoqi@0: push_double(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_i2f: aoqi@0: { aoqi@0: pop_int(); aoqi@0: push_float(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_i2l: aoqi@0: { aoqi@0: pop_int(); aoqi@0: push_long(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_iadd: aoqi@0: case Bytecodes::_iand: aoqi@0: case Bytecodes::_idiv: aoqi@0: case Bytecodes::_imul: aoqi@0: case Bytecodes::_ior: aoqi@0: case Bytecodes::_irem: aoqi@0: case Bytecodes::_ishl: aoqi@0: case Bytecodes::_ishr: aoqi@0: case Bytecodes::_isub: aoqi@0: case Bytecodes::_iushr: aoqi@0: case Bytecodes::_ixor: aoqi@0: { aoqi@0: pop_int(); aoqi@0: pop_int(); aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_if_acmpeq: aoqi@0: case Bytecodes::_if_acmpne: aoqi@0: { aoqi@0: pop_object(); aoqi@0: pop_object(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_if_icmpeq: aoqi@0: case Bytecodes::_if_icmpge: aoqi@0: case Bytecodes::_if_icmpgt: aoqi@0: case Bytecodes::_if_icmple: aoqi@0: case Bytecodes::_if_icmplt: aoqi@0: case Bytecodes::_if_icmpne: aoqi@0: { aoqi@0: pop_int(); aoqi@0: pop_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_ifeq: aoqi@0: case Bytecodes::_ifle: aoqi@0: case Bytecodes::_iflt: aoqi@0: case Bytecodes::_ifge: aoqi@0: case Bytecodes::_ifgt: aoqi@0: case Bytecodes::_ifne: aoqi@0: case Bytecodes::_ireturn: aoqi@0: case Bytecodes::_lookupswitch: aoqi@0: case Bytecodes::_tableswitch: aoqi@0: { aoqi@0: pop_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_iinc: aoqi@0: { aoqi@0: int lnum = str->get_index(); aoqi@0: check_int(local(lnum)); aoqi@0: store_to_local(lnum); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_iload: load_local_int(str->get_index()); break; aoqi@0: case Bytecodes::_iload_0: load_local_int(0); break; aoqi@0: case Bytecodes::_iload_1: load_local_int(1); break; aoqi@0: case Bytecodes::_iload_2: load_local_int(2); break; aoqi@0: case Bytecodes::_iload_3: load_local_int(3); break; aoqi@0: aoqi@0: case Bytecodes::_instanceof: aoqi@0: { aoqi@0: // Check for uncommon trap: aoqi@0: do_checkcast(str); aoqi@0: pop_object(); aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_invokeinterface: do_invoke(str, true); break; aoqi@0: case Bytecodes::_invokespecial: do_invoke(str, true); break; aoqi@0: case Bytecodes::_invokestatic: do_invoke(str, false); break; aoqi@0: case Bytecodes::_invokevirtual: do_invoke(str, true); break; aoqi@0: case Bytecodes::_invokedynamic: do_invoke(str, false); break; aoqi@0: aoqi@0: case Bytecodes::_istore: store_local_int(str->get_index()); break; aoqi@0: case Bytecodes::_istore_0: store_local_int(0); break; aoqi@0: case Bytecodes::_istore_1: store_local_int(1); break; aoqi@0: case Bytecodes::_istore_2: store_local_int(2); break; aoqi@0: case Bytecodes::_istore_3: store_local_int(3); break; aoqi@0: aoqi@0: case Bytecodes::_jsr: aoqi@0: case Bytecodes::_jsr_w: do_jsr(str); break; aoqi@0: aoqi@0: case Bytecodes::_l2d: aoqi@0: { aoqi@0: pop_long(); aoqi@0: push_double(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_l2f: aoqi@0: { aoqi@0: pop_long(); aoqi@0: push_float(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_l2i: aoqi@0: { aoqi@0: pop_long(); aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_ladd: aoqi@0: case Bytecodes::_land: aoqi@0: case Bytecodes::_ldiv: aoqi@0: case Bytecodes::_lmul: aoqi@0: case Bytecodes::_lor: aoqi@0: case Bytecodes::_lrem: aoqi@0: case Bytecodes::_lsub: aoqi@0: case Bytecodes::_lxor: aoqi@0: { aoqi@0: pop_long(); aoqi@0: pop_long(); aoqi@0: push_long(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_laload: aoqi@0: { aoqi@0: pop_int(); aoqi@0: ciTypeArrayKlass* array_klass = pop_typeArray(); aoqi@0: // Put assert here for right type? aoqi@0: push_long(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_lastore: aoqi@0: { aoqi@0: pop_long(); aoqi@0: pop_int(); aoqi@0: pop_typeArray(); aoqi@0: // assert here? aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_lcmp: aoqi@0: { aoqi@0: pop_long(); aoqi@0: pop_long(); aoqi@0: push_int(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_lconst_0: aoqi@0: case Bytecodes::_lconst_1: aoqi@0: { aoqi@0: push_long(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_ldc: aoqi@0: case Bytecodes::_ldc_w: aoqi@0: case Bytecodes::_ldc2_w: aoqi@0: { aoqi@0: do_ldc(str); aoqi@0: break; aoqi@0: } aoqi@0: aoqi@0: case Bytecodes::_lload: load_local_long(str->get_index()); break; aoqi@0: case Bytecodes::_lload_0: load_local_long(0); break; aoqi@0: case Bytecodes::_lload_1: load_local_long(1); break; aoqi@0: case Bytecodes::_lload_2: load_local_long(2); break; aoqi@0: case Bytecodes::_lload_3: load_local_long(3); break; aoqi@0: aoqi@0: case Bytecodes::_lneg: aoqi@0: { aoqi@0: pop_long(); aoqi@0: push_long(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_lreturn: aoqi@0: { aoqi@0: pop_long(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_lshl: aoqi@0: case Bytecodes::_lshr: aoqi@0: case Bytecodes::_lushr: aoqi@0: { aoqi@0: pop_int(); aoqi@0: pop_long(); aoqi@0: push_long(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_lstore: store_local_long(str->get_index()); break; aoqi@0: case Bytecodes::_lstore_0: store_local_long(0); break; aoqi@0: case Bytecodes::_lstore_1: store_local_long(1); break; aoqi@0: case Bytecodes::_lstore_2: store_local_long(2); break; aoqi@0: case Bytecodes::_lstore_3: store_local_long(3); break; aoqi@0: aoqi@0: case Bytecodes::_multianewarray: do_multianewarray(str); break; aoqi@0: aoqi@0: case Bytecodes::_new: do_new(str); break; aoqi@0: aoqi@0: case Bytecodes::_newarray: do_newarray(str); break; aoqi@0: aoqi@0: case Bytecodes::_pop: aoqi@0: { aoqi@0: pop(); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_pop2: aoqi@0: { aoqi@0: pop(); aoqi@0: pop(); aoqi@0: break; aoqi@0: } aoqi@0: aoqi@0: case Bytecodes::_putfield: do_putfield(str); break; aoqi@0: case Bytecodes::_putstatic: do_putstatic(str); break; aoqi@0: aoqi@0: case Bytecodes::_ret: do_ret(str); break; aoqi@0: aoqi@0: case Bytecodes::_swap: aoqi@0: { aoqi@0: ciType* value1 = pop_value(); aoqi@0: ciType* value2 = pop_value(); aoqi@0: push(value1); aoqi@0: push(value2); aoqi@0: break; aoqi@0: } aoqi@0: case Bytecodes::_wide: aoqi@0: default: aoqi@0: { aoqi@0: // The iterator should skip this. aoqi@0: ShouldNotReachHere(); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (CITraceTypeFlow) { aoqi@0: print_on(tty); aoqi@0: } aoqi@0: aoqi@0: return (_trap_bci != -1); aoqi@0: } aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::print_cell_on aoqi@0: void ciTypeFlow::StateVector::print_cell_on(outputStream* st, Cell c) const { aoqi@0: ciType* type = type_at(c); aoqi@0: if (type == top_type()) { aoqi@0: st->print("top"); aoqi@0: } else if (type == bottom_type()) { aoqi@0: st->print("bottom"); aoqi@0: } else if (type == null_type()) { aoqi@0: st->print("null"); aoqi@0: } else if (type == long2_type()) { aoqi@0: st->print("long2"); aoqi@0: } else if (type == double2_type()) { aoqi@0: st->print("double2"); aoqi@0: } else if (is_int(type)) { aoqi@0: st->print("int"); aoqi@0: } else if (is_long(type)) { aoqi@0: st->print("long"); aoqi@0: } else if (is_float(type)) { aoqi@0: st->print("float"); aoqi@0: } else if (is_double(type)) { aoqi@0: st->print("double"); aoqi@0: } else if (type->is_return_address()) { aoqi@0: st->print("address(%d)", type->as_return_address()->bci()); aoqi@0: } else { aoqi@0: if (type->is_klass()) { aoqi@0: type->as_klass()->name()->print_symbol_on(st); aoqi@0: } else { aoqi@0: st->print("UNEXPECTED TYPE"); aoqi@0: type->print(); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::StateVector::print_on aoqi@0: void ciTypeFlow::StateVector::print_on(outputStream* st) const { aoqi@0: int num_locals = _outer->max_locals(); aoqi@0: int num_stack = stack_size(); aoqi@0: int num_monitors = monitor_count(); aoqi@0: st->print_cr(" State : locals %d, stack %d, monitors %d", num_locals, num_stack, num_monitors); aoqi@0: if (num_stack >= 0) { aoqi@0: int i; aoqi@0: for (i = 0; i < num_locals; i++) { aoqi@0: st->print(" local %2d : ", i); aoqi@0: print_cell_on(st, local(i)); aoqi@0: st->cr(); aoqi@0: } aoqi@0: for (i = 0; i < num_stack; i++) { aoqi@0: st->print(" stack %2d : ", i); aoqi@0: print_cell_on(st, stack(i)); aoqi@0: st->cr(); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::SuccIter::next aoqi@0: // aoqi@0: void ciTypeFlow::SuccIter::next() { aoqi@0: int succ_ct = _pred->successors()->length(); aoqi@0: int next = _index + 1; aoqi@0: if (next < succ_ct) { aoqi@0: _index = next; aoqi@0: _succ = _pred->successors()->at(next); aoqi@0: return; aoqi@0: } aoqi@0: for (int i = next - succ_ct; i < _pred->exceptions()->length(); i++) { aoqi@0: // Do not compile any code for unloaded exception types. aoqi@0: // Following compiler passes are responsible for doing this also. aoqi@0: ciInstanceKlass* exception_klass = _pred->exc_klasses()->at(i); aoqi@0: if (exception_klass->is_loaded()) { aoqi@0: _index = next; aoqi@0: _succ = _pred->exceptions()->at(i); aoqi@0: return; aoqi@0: } aoqi@0: next++; aoqi@0: } aoqi@0: _index = -1; aoqi@0: _succ = NULL; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::SuccIter::set_succ aoqi@0: // aoqi@0: void ciTypeFlow::SuccIter::set_succ(Block* succ) { aoqi@0: int succ_ct = _pred->successors()->length(); aoqi@0: if (_index < succ_ct) { aoqi@0: _pred->successors()->at_put(_index, succ); aoqi@0: } else { aoqi@0: int idx = _index - succ_ct; aoqi@0: _pred->exceptions()->at_put(idx, succ); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ciTypeFlow::Block aoqi@0: // aoqi@0: // A basic block. aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Block::Block aoqi@0: ciTypeFlow::Block::Block(ciTypeFlow* outer, aoqi@0: ciBlock *ciblk, aoqi@0: ciTypeFlow::JsrSet* jsrs) { aoqi@0: _ciblock = ciblk; aoqi@0: _exceptions = NULL; aoqi@0: _exc_klasses = NULL; aoqi@0: _successors = NULL; aoqi@0: _state = new (outer->arena()) StateVector(outer); aoqi@0: JsrSet* new_jsrs = aoqi@0: new (outer->arena()) JsrSet(outer->arena(), jsrs->size()); aoqi@0: jsrs->copy_into(new_jsrs); aoqi@0: _jsrs = new_jsrs; aoqi@0: _next = NULL; aoqi@0: _on_work_list = false; aoqi@0: _backedge_copy = false; aoqi@0: _has_monitorenter = false; aoqi@0: _trap_bci = -1; aoqi@0: _trap_index = 0; aoqi@0: df_init(); aoqi@0: aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print_cr(">> Created new block"); aoqi@0: print_on(tty); aoqi@0: } aoqi@0: aoqi@0: assert(this->outer() == outer, "outer link set up"); aoqi@0: assert(!outer->have_block_count(), "must not have mapped blocks yet"); aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Block::df_init aoqi@0: void ciTypeFlow::Block::df_init() { aoqi@0: _pre_order = -1; assert(!has_pre_order(), ""); aoqi@0: _post_order = -1; assert(!has_post_order(), ""); aoqi@0: _loop = NULL; aoqi@0: _irreducible_entry = false; aoqi@0: _rpo_next = NULL; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Block::successors aoqi@0: // aoqi@0: // Get the successors for this Block. aoqi@0: GrowableArray* aoqi@0: ciTypeFlow::Block::successors(ciBytecodeStream* str, aoqi@0: ciTypeFlow::StateVector* state, aoqi@0: ciTypeFlow::JsrSet* jsrs) { aoqi@0: if (_successors == NULL) { aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print(">> Computing successors for block "); aoqi@0: print_value_on(tty); aoqi@0: tty->cr(); aoqi@0: } aoqi@0: aoqi@0: ciTypeFlow* analyzer = outer(); aoqi@0: Arena* arena = analyzer->arena(); aoqi@0: Block* block = NULL; aoqi@0: bool has_successor = !has_trap() && aoqi@0: (control() != ciBlock::fall_through_bci || limit() < analyzer->code_size()); aoqi@0: if (!has_successor) { aoqi@0: _successors = aoqi@0: new (arena) GrowableArray(arena, 1, 0, NULL); aoqi@0: // No successors aoqi@0: } else if (control() == ciBlock::fall_through_bci) { aoqi@0: assert(str->cur_bci() == limit(), "bad block end"); aoqi@0: // This block simply falls through to the next. aoqi@0: _successors = aoqi@0: new (arena) GrowableArray(arena, 1, 0, NULL); aoqi@0: aoqi@0: Block* block = analyzer->block_at(limit(), _jsrs); aoqi@0: assert(_successors->length() == FALL_THROUGH, ""); aoqi@0: _successors->append(block); aoqi@0: } else { aoqi@0: int current_bci = str->cur_bci(); aoqi@0: int next_bci = str->next_bci(); aoqi@0: int branch_bci = -1; aoqi@0: Block* target = NULL; aoqi@0: assert(str->next_bci() == limit(), "bad block end"); aoqi@0: // This block is not a simple fall-though. Interpret aoqi@0: // the current bytecode to find our successors. aoqi@0: switch (str->cur_bc()) { aoqi@0: case Bytecodes::_ifeq: case Bytecodes::_ifne: aoqi@0: case Bytecodes::_iflt: case Bytecodes::_ifge: aoqi@0: case Bytecodes::_ifgt: case Bytecodes::_ifle: aoqi@0: case Bytecodes::_if_icmpeq: case Bytecodes::_if_icmpne: aoqi@0: case Bytecodes::_if_icmplt: case Bytecodes::_if_icmpge: aoqi@0: case Bytecodes::_if_icmpgt: case Bytecodes::_if_icmple: aoqi@0: case Bytecodes::_if_acmpeq: case Bytecodes::_if_acmpne: aoqi@0: case Bytecodes::_ifnull: case Bytecodes::_ifnonnull: aoqi@0: // Our successors are the branch target and the next bci. aoqi@0: branch_bci = str->get_dest(); aoqi@0: _successors = aoqi@0: new (arena) GrowableArray(arena, 2, 0, NULL); aoqi@0: assert(_successors->length() == IF_NOT_TAKEN, ""); aoqi@0: _successors->append(analyzer->block_at(next_bci, jsrs)); aoqi@0: assert(_successors->length() == IF_TAKEN, ""); aoqi@0: _successors->append(analyzer->block_at(branch_bci, jsrs)); aoqi@0: break; aoqi@0: aoqi@0: case Bytecodes::_goto: aoqi@0: branch_bci = str->get_dest(); aoqi@0: _successors = aoqi@0: new (arena) GrowableArray(arena, 1, 0, NULL); aoqi@0: assert(_successors->length() == GOTO_TARGET, ""); aoqi@0: _successors->append(analyzer->block_at(branch_bci, jsrs)); aoqi@0: break; aoqi@0: aoqi@0: case Bytecodes::_jsr: aoqi@0: branch_bci = str->get_dest(); aoqi@0: _successors = aoqi@0: new (arena) GrowableArray(arena, 1, 0, NULL); aoqi@0: assert(_successors->length() == GOTO_TARGET, ""); aoqi@0: _successors->append(analyzer->block_at(branch_bci, jsrs)); aoqi@0: break; aoqi@0: aoqi@0: case Bytecodes::_goto_w: aoqi@0: case Bytecodes::_jsr_w: aoqi@0: _successors = aoqi@0: new (arena) GrowableArray(arena, 1, 0, NULL); aoqi@0: assert(_successors->length() == GOTO_TARGET, ""); aoqi@0: _successors->append(analyzer->block_at(str->get_far_dest(), jsrs)); aoqi@0: break; aoqi@0: aoqi@0: case Bytecodes::_tableswitch: { aoqi@0: Bytecode_tableswitch tableswitch(str); aoqi@0: aoqi@0: int len = tableswitch.length(); aoqi@0: _successors = aoqi@0: new (arena) GrowableArray(arena, len+1, 0, NULL); aoqi@0: int bci = current_bci + tableswitch.default_offset(); aoqi@0: Block* block = analyzer->block_at(bci, jsrs); aoqi@0: assert(_successors->length() == SWITCH_DEFAULT, ""); aoqi@0: _successors->append(block); aoqi@0: while (--len >= 0) { aoqi@0: int bci = current_bci + tableswitch.dest_offset_at(len); aoqi@0: block = analyzer->block_at(bci, jsrs); aoqi@0: assert(_successors->length() >= SWITCH_CASES, ""); aoqi@0: _successors->append_if_missing(block); aoqi@0: } aoqi@0: break; aoqi@0: } aoqi@0: aoqi@0: case Bytecodes::_lookupswitch: { aoqi@0: Bytecode_lookupswitch lookupswitch(str); aoqi@0: aoqi@0: int npairs = lookupswitch.number_of_pairs(); aoqi@0: _successors = aoqi@0: new (arena) GrowableArray(arena, npairs+1, 0, NULL); aoqi@0: int bci = current_bci + lookupswitch.default_offset(); aoqi@0: Block* block = analyzer->block_at(bci, jsrs); aoqi@0: assert(_successors->length() == SWITCH_DEFAULT, ""); aoqi@0: _successors->append(block); aoqi@0: while(--npairs >= 0) { aoqi@0: LookupswitchPair pair = lookupswitch.pair_at(npairs); aoqi@0: int bci = current_bci + pair.offset(); aoqi@0: Block* block = analyzer->block_at(bci, jsrs); aoqi@0: assert(_successors->length() >= SWITCH_CASES, ""); aoqi@0: _successors->append_if_missing(block); aoqi@0: } aoqi@0: break; aoqi@0: } aoqi@0: aoqi@0: case Bytecodes::_athrow: case Bytecodes::_ireturn: aoqi@0: case Bytecodes::_lreturn: case Bytecodes::_freturn: aoqi@0: case Bytecodes::_dreturn: case Bytecodes::_areturn: aoqi@0: case Bytecodes::_return: aoqi@0: _successors = aoqi@0: new (arena) GrowableArray(arena, 1, 0, NULL); aoqi@0: // No successors aoqi@0: break; aoqi@0: aoqi@0: case Bytecodes::_ret: { aoqi@0: _successors = aoqi@0: new (arena) GrowableArray(arena, 1, 0, NULL); aoqi@0: aoqi@0: Cell local = state->local(str->get_index()); aoqi@0: ciType* return_address = state->type_at(local); aoqi@0: assert(return_address->is_return_address(), "verify: wrong type"); aoqi@0: int bci = return_address->as_return_address()->bci(); aoqi@0: assert(_successors->length() == GOTO_TARGET, ""); aoqi@0: _successors->append(analyzer->block_at(bci, jsrs)); aoqi@0: break; aoqi@0: } aoqi@0: aoqi@0: case Bytecodes::_wide: aoqi@0: default: aoqi@0: ShouldNotReachHere(); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: return _successors; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Block:compute_exceptions aoqi@0: // aoqi@0: // Compute the exceptional successors and types for this Block. aoqi@0: void ciTypeFlow::Block::compute_exceptions() { aoqi@0: assert(_exceptions == NULL && _exc_klasses == NULL, "repeat"); aoqi@0: aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print(">> Computing exceptions for block "); aoqi@0: print_value_on(tty); aoqi@0: tty->cr(); aoqi@0: } aoqi@0: aoqi@0: ciTypeFlow* analyzer = outer(); aoqi@0: Arena* arena = analyzer->arena(); aoqi@0: aoqi@0: // Any bci in the block will do. aoqi@0: ciExceptionHandlerStream str(analyzer->method(), start()); aoqi@0: aoqi@0: // Allocate our growable arrays. aoqi@0: int exc_count = str.count(); aoqi@0: _exceptions = new (arena) GrowableArray(arena, exc_count, 0, NULL); aoqi@0: _exc_klasses = new (arena) GrowableArray(arena, exc_count, aoqi@0: 0, NULL); aoqi@0: aoqi@0: for ( ; !str.is_done(); str.next()) { aoqi@0: ciExceptionHandler* handler = str.handler(); aoqi@0: int bci = handler->handler_bci(); aoqi@0: ciInstanceKlass* klass = NULL; aoqi@0: if (bci == -1) { aoqi@0: // There is no catch all. It is possible to exit the method. aoqi@0: break; aoqi@0: } aoqi@0: if (handler->is_catch_all()) { aoqi@0: klass = analyzer->env()->Throwable_klass(); aoqi@0: } else { aoqi@0: klass = handler->catch_klass(); aoqi@0: } aoqi@0: _exceptions->append(analyzer->block_at(bci, _jsrs)); aoqi@0: _exc_klasses->append(klass); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Block::set_backedge_copy aoqi@0: // Use this only to make a pre-existing public block into a backedge copy. aoqi@0: void ciTypeFlow::Block::set_backedge_copy(bool z) { aoqi@0: assert(z || (z == is_backedge_copy()), "cannot make a backedge copy public"); aoqi@0: _backedge_copy = z; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Block::is_clonable_exit aoqi@0: // aoqi@0: // At most 2 normal successors, one of which continues looping, aoqi@0: // and all exceptional successors must exit. aoqi@0: bool ciTypeFlow::Block::is_clonable_exit(ciTypeFlow::Loop* lp) { aoqi@0: int normal_cnt = 0; aoqi@0: int in_loop_cnt = 0; aoqi@0: for (SuccIter iter(this); !iter.done(); iter.next()) { aoqi@0: Block* succ = iter.succ(); aoqi@0: if (iter.is_normal_ctrl()) { aoqi@0: if (++normal_cnt > 2) return false; aoqi@0: if (lp->contains(succ->loop())) { aoqi@0: if (++in_loop_cnt > 1) return false; aoqi@0: } aoqi@0: } else { aoqi@0: if (lp->contains(succ->loop())) return false; aoqi@0: } aoqi@0: } aoqi@0: return in_loop_cnt == 1; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Block::looping_succ aoqi@0: // aoqi@0: ciTypeFlow::Block* ciTypeFlow::Block::looping_succ(ciTypeFlow::Loop* lp) { aoqi@0: assert(successors()->length() <= 2, "at most 2 normal successors"); aoqi@0: for (SuccIter iter(this); !iter.done(); iter.next()) { aoqi@0: Block* succ = iter.succ(); aoqi@0: if (lp->contains(succ->loop())) { aoqi@0: return succ; aoqi@0: } aoqi@0: } aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Block::print_value_on aoqi@0: void ciTypeFlow::Block::print_value_on(outputStream* st) const { aoqi@0: if (has_pre_order()) st->print("#%-2d ", pre_order()); aoqi@0: if (has_rpo()) st->print("rpo#%-2d ", rpo()); aoqi@0: st->print("[%d - %d)", start(), limit()); aoqi@0: if (is_loop_head()) st->print(" lphd"); aoqi@0: if (is_irreducible_entry()) st->print(" irred"); aoqi@0: if (_jsrs->size() > 0) { st->print("/"); _jsrs->print_on(st); } aoqi@0: if (is_backedge_copy()) st->print("/backedge_copy"); aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Block::print_on aoqi@0: void ciTypeFlow::Block::print_on(outputStream* st) const { aoqi@0: if ((Verbose || WizardMode) && (limit() >= 0)) { aoqi@0: // Don't print 'dummy' blocks (i.e. blocks with limit() '-1') aoqi@0: outer()->method()->print_codes_on(start(), limit(), st); aoqi@0: } aoqi@0: st->print_cr(" ==================================================== "); aoqi@0: st->print (" "); aoqi@0: print_value_on(st); aoqi@0: st->print(" Stored locals: "); def_locals()->print_on(st, outer()->method()->max_locals()); tty->cr(); aoqi@0: if (loop() && loop()->parent() != NULL) { aoqi@0: st->print(" loops:"); aoqi@0: Loop* lp = loop(); aoqi@0: do { aoqi@0: st->print(" %d<-%d", lp->head()->pre_order(),lp->tail()->pre_order()); aoqi@0: if (lp->is_irreducible()) st->print("(ir)"); aoqi@0: lp = lp->parent(); aoqi@0: } while (lp->parent() != NULL); aoqi@0: } aoqi@0: st->cr(); aoqi@0: _state->print_on(st); aoqi@0: if (_successors == NULL) { aoqi@0: st->print_cr(" No successor information"); aoqi@0: } else { aoqi@0: int num_successors = _successors->length(); aoqi@0: st->print_cr(" Successors : %d", num_successors); aoqi@0: for (int i = 0; i < num_successors; i++) { aoqi@0: Block* successor = _successors->at(i); aoqi@0: st->print(" "); aoqi@0: successor->print_value_on(st); aoqi@0: st->cr(); aoqi@0: } aoqi@0: } aoqi@0: if (_exceptions == NULL) { aoqi@0: st->print_cr(" No exception information"); aoqi@0: } else { aoqi@0: int num_exceptions = _exceptions->length(); aoqi@0: st->print_cr(" Exceptions : %d", num_exceptions); aoqi@0: for (int i = 0; i < num_exceptions; i++) { aoqi@0: Block* exc_succ = _exceptions->at(i); aoqi@0: ciInstanceKlass* exc_klass = _exc_klasses->at(i); aoqi@0: st->print(" "); aoqi@0: exc_succ->print_value_on(st); aoqi@0: st->print(" -- "); aoqi@0: exc_klass->name()->print_symbol_on(st); aoqi@0: st->cr(); aoqi@0: } aoqi@0: } aoqi@0: if (has_trap()) { aoqi@0: st->print_cr(" Traps on %d with trap index %d", trap_bci(), trap_index()); aoqi@0: } aoqi@0: st->print_cr(" ==================================================== "); aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::LocalSet::print_on aoqi@0: void ciTypeFlow::LocalSet::print_on(outputStream* st, int limit) const { aoqi@0: st->print("{"); aoqi@0: for (int i = 0; i < max; i++) { aoqi@0: if (test(i)) st->print(" %d", i); aoqi@0: } aoqi@0: if (limit > max) { aoqi@0: st->print(" %d..%d ", max, limit); aoqi@0: } aoqi@0: st->print(" }"); aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: // ciTypeFlow aoqi@0: // aoqi@0: // This is a pass over the bytecodes which computes the following: aoqi@0: // basic block structure aoqi@0: // interpreter type-states (a la the verifier) aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::ciTypeFlow aoqi@0: ciTypeFlow::ciTypeFlow(ciEnv* env, ciMethod* method, int osr_bci) { aoqi@0: _env = env; aoqi@0: _method = method; aoqi@0: _methodBlocks = method->get_method_blocks(); aoqi@0: _max_locals = method->max_locals(); aoqi@0: _max_stack = method->max_stack(); aoqi@0: _code_size = method->code_size(); aoqi@0: _has_irreducible_entry = false; aoqi@0: _osr_bci = osr_bci; aoqi@0: _failure_reason = NULL; aoqi@0: assert(0 <= start_bci() && start_bci() < code_size() , err_msg("correct osr_bci argument: 0 <= %d < %d", start_bci(), code_size())); aoqi@0: _work_list = NULL; aoqi@0: aoqi@0: _ciblock_count = _methodBlocks->num_blocks(); aoqi@0: _idx_to_blocklist = NEW_ARENA_ARRAY(arena(), GrowableArray*, _ciblock_count); aoqi@0: for (int i = 0; i < _ciblock_count; i++) { aoqi@0: _idx_to_blocklist[i] = NULL; aoqi@0: } aoqi@0: _block_map = NULL; // until all blocks are seen aoqi@0: _jsr_count = 0; aoqi@0: _jsr_records = NULL; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::work_list_next aoqi@0: // aoqi@0: // Get the next basic block from our work list. aoqi@0: ciTypeFlow::Block* ciTypeFlow::work_list_next() { aoqi@0: assert(!work_list_empty(), "work list must not be empty"); aoqi@0: Block* next_block = _work_list; aoqi@0: _work_list = next_block->next(); aoqi@0: next_block->set_next(NULL); aoqi@0: next_block->set_on_work_list(false); aoqi@0: return next_block; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::add_to_work_list aoqi@0: // aoqi@0: // Add a basic block to our work list. aoqi@0: // List is sorted by decreasing postorder sort (same as increasing RPO) aoqi@0: void ciTypeFlow::add_to_work_list(ciTypeFlow::Block* block) { aoqi@0: assert(!block->is_on_work_list(), "must not already be on work list"); aoqi@0: aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print(">> Adding block "); aoqi@0: block->print_value_on(tty); aoqi@0: tty->print_cr(" to the work list : "); aoqi@0: } aoqi@0: aoqi@0: block->set_on_work_list(true); aoqi@0: aoqi@0: // decreasing post order sort aoqi@0: aoqi@0: Block* prev = NULL; aoqi@0: Block* current = _work_list; aoqi@0: int po = block->post_order(); aoqi@0: while (current != NULL) { aoqi@0: if (!current->has_post_order() || po > current->post_order()) aoqi@0: break; aoqi@0: prev = current; aoqi@0: current = current->next(); aoqi@0: } aoqi@0: if (prev == NULL) { aoqi@0: block->set_next(_work_list); aoqi@0: _work_list = block; aoqi@0: } else { aoqi@0: block->set_next(current); aoqi@0: prev->set_next(block); aoqi@0: } aoqi@0: aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->cr(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::block_at aoqi@0: // aoqi@0: // Return the block beginning at bci which has a JsrSet compatible aoqi@0: // with jsrs. aoqi@0: ciTypeFlow::Block* ciTypeFlow::block_at(int bci, ciTypeFlow::JsrSet* jsrs, CreateOption option) { aoqi@0: // First find the right ciBlock. aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print(">> Requesting block for %d/", bci); aoqi@0: jsrs->print_on(tty); aoqi@0: tty->cr(); aoqi@0: } aoqi@0: aoqi@0: ciBlock* ciblk = _methodBlocks->block_containing(bci); aoqi@0: assert(ciblk->start_bci() == bci, "bad ciBlock boundaries"); aoqi@0: Block* block = get_block_for(ciblk->index(), jsrs, option); aoqi@0: aoqi@0: assert(block == NULL? (option == no_create): block->is_backedge_copy() == (option == create_backedge_copy), "create option consistent with result"); aoqi@0: aoqi@0: if (CITraceTypeFlow) { aoqi@0: if (block != NULL) { aoqi@0: tty->print(">> Found block "); aoqi@0: block->print_value_on(tty); aoqi@0: tty->cr(); aoqi@0: } else { aoqi@0: tty->print_cr(">> No such block."); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return block; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::make_jsr_record aoqi@0: // aoqi@0: // Make a JsrRecord for a given (entry, return) pair, if such a record aoqi@0: // does not already exist. aoqi@0: ciTypeFlow::JsrRecord* ciTypeFlow::make_jsr_record(int entry_address, aoqi@0: int return_address) { aoqi@0: if (_jsr_records == NULL) { aoqi@0: _jsr_records = new (arena()) GrowableArray(arena(), aoqi@0: _jsr_count, aoqi@0: 0, aoqi@0: NULL); aoqi@0: } aoqi@0: JsrRecord* record = NULL; aoqi@0: int len = _jsr_records->length(); aoqi@0: for (int i = 0; i < len; i++) { aoqi@0: JsrRecord* record = _jsr_records->at(i); aoqi@0: if (record->entry_address() == entry_address && aoqi@0: record->return_address() == return_address) { aoqi@0: return record; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: record = new (arena()) JsrRecord(entry_address, return_address); aoqi@0: _jsr_records->append(record); aoqi@0: return record; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::flow_exceptions aoqi@0: // aoqi@0: // Merge the current state into all exceptional successors at the aoqi@0: // current point in the code. aoqi@0: void ciTypeFlow::flow_exceptions(GrowableArray* exceptions, aoqi@0: GrowableArray* exc_klasses, aoqi@0: ciTypeFlow::StateVector* state) { aoqi@0: int len = exceptions->length(); aoqi@0: assert(exc_klasses->length() == len, "must have same length"); aoqi@0: for (int i = 0; i < len; i++) { aoqi@0: Block* block = exceptions->at(i); aoqi@0: ciInstanceKlass* exception_klass = exc_klasses->at(i); aoqi@0: aoqi@0: if (!exception_klass->is_loaded()) { aoqi@0: // Do not compile any code for unloaded exception types. aoqi@0: // Following compiler passes are responsible for doing this also. aoqi@0: continue; aoqi@0: } aoqi@0: aoqi@0: if (block->meet_exception(exception_klass, state)) { aoqi@0: // Block was modified and has PO. Add it to the work list. aoqi@0: if (block->has_post_order() && aoqi@0: !block->is_on_work_list()) { aoqi@0: add_to_work_list(block); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::flow_successors aoqi@0: // aoqi@0: // Merge the current state into all successors at the current point aoqi@0: // in the code. aoqi@0: void ciTypeFlow::flow_successors(GrowableArray* successors, aoqi@0: ciTypeFlow::StateVector* state) { aoqi@0: int len = successors->length(); aoqi@0: for (int i = 0; i < len; i++) { aoqi@0: Block* block = successors->at(i); aoqi@0: if (block->meet(state)) { aoqi@0: // Block was modified and has PO. Add it to the work list. aoqi@0: if (block->has_post_order() && aoqi@0: !block->is_on_work_list()) { aoqi@0: add_to_work_list(block); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::can_trap aoqi@0: // aoqi@0: // Tells if a given instruction is able to generate an exception edge. aoqi@0: bool ciTypeFlow::can_trap(ciBytecodeStream& str) { aoqi@0: // Cf. GenerateOopMap::do_exception_edge. aoqi@0: if (!Bytecodes::can_trap(str.cur_bc())) return false; aoqi@0: aoqi@0: switch (str.cur_bc()) { aoqi@0: // %%% FIXME: ldc of Class can generate an exception aoqi@0: case Bytecodes::_ldc: aoqi@0: case Bytecodes::_ldc_w: aoqi@0: case Bytecodes::_ldc2_w: aoqi@0: case Bytecodes::_aload_0: aoqi@0: // These bytecodes can trap for rewriting. We need to assume that aoqi@0: // they do not throw exceptions to make the monitor analysis work. aoqi@0: return false; aoqi@0: aoqi@0: case Bytecodes::_ireturn: aoqi@0: case Bytecodes::_lreturn: aoqi@0: case Bytecodes::_freturn: aoqi@0: case Bytecodes::_dreturn: aoqi@0: case Bytecodes::_areturn: aoqi@0: case Bytecodes::_return: aoqi@0: // We can assume the monitor stack is empty in this analysis. aoqi@0: return false; aoqi@0: aoqi@0: case Bytecodes::_monitorexit: aoqi@0: // We can assume monitors are matched in this analysis. aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::clone_loop_heads aoqi@0: // aoqi@0: // Clone the loop heads aoqi@0: bool ciTypeFlow::clone_loop_heads(Loop* lp, StateVector* temp_vector, JsrSet* temp_set) { aoqi@0: bool rslt = false; aoqi@0: for (PreorderLoops iter(loop_tree_root()); !iter.done(); iter.next()) { aoqi@0: lp = iter.current(); aoqi@0: Block* head = lp->head(); aoqi@0: if (lp == loop_tree_root() || aoqi@0: lp->is_irreducible() || aoqi@0: !head->is_clonable_exit(lp)) aoqi@0: continue; aoqi@0: aoqi@0: // Avoid BoxLock merge. aoqi@0: if (EliminateNestedLocks && head->has_monitorenter()) aoqi@0: continue; aoqi@0: aoqi@0: // check not already cloned aoqi@0: if (head->backedge_copy_count() != 0) aoqi@0: continue; aoqi@0: aoqi@0: // Don't clone head of OSR loop to get correct types in start block. aoqi@0: if (is_osr_flow() && head->start() == start_bci()) aoqi@0: continue; aoqi@0: aoqi@0: // check _no_ shared head below us aoqi@0: Loop* ch; aoqi@0: for (ch = lp->child(); ch != NULL && ch->head() != head; ch = ch->sibling()); aoqi@0: if (ch != NULL) aoqi@0: continue; aoqi@0: aoqi@0: // Clone head aoqi@0: Block* new_head = head->looping_succ(lp); aoqi@0: Block* clone = clone_loop_head(lp, temp_vector, temp_set); aoqi@0: // Update lp's info aoqi@0: clone->set_loop(lp); aoqi@0: lp->set_head(new_head); aoqi@0: lp->set_tail(clone); aoqi@0: // And move original head into outer loop aoqi@0: head->set_loop(lp->parent()); aoqi@0: aoqi@0: rslt = true; aoqi@0: } aoqi@0: return rslt; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::clone_loop_head aoqi@0: // aoqi@0: // Clone lp's head and replace tail's successors with clone. aoqi@0: // aoqi@0: // | aoqi@0: // v aoqi@0: // head <-> body aoqi@0: // | aoqi@0: // v aoqi@0: // exit aoqi@0: // aoqi@0: // new_head aoqi@0: // aoqi@0: // | aoqi@0: // v aoqi@0: // head ----------\ aoqi@0: // | | aoqi@0: // | v aoqi@0: // | clone <-> body aoqi@0: // | | aoqi@0: // | /--/ aoqi@0: // | | aoqi@0: // v v aoqi@0: // exit aoqi@0: // aoqi@0: ciTypeFlow::Block* ciTypeFlow::clone_loop_head(Loop* lp, StateVector* temp_vector, JsrSet* temp_set) { aoqi@0: Block* head = lp->head(); aoqi@0: Block* tail = lp->tail(); aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print(">> Requesting clone of loop head "); head->print_value_on(tty); aoqi@0: tty->print(" for predecessor "); tail->print_value_on(tty); aoqi@0: tty->cr(); aoqi@0: } aoqi@0: Block* clone = block_at(head->start(), head->jsrs(), create_backedge_copy); aoqi@0: assert(clone->backedge_copy_count() == 1, "one backedge copy for all back edges"); aoqi@0: aoqi@0: assert(!clone->has_pre_order(), "just created"); aoqi@0: clone->set_next_pre_order(); aoqi@0: aoqi@0: // Insert clone after (orig) tail in reverse post order aoqi@0: clone->set_rpo_next(tail->rpo_next()); aoqi@0: tail->set_rpo_next(clone); aoqi@0: aoqi@0: // tail->head becomes tail->clone aoqi@0: for (SuccIter iter(tail); !iter.done(); iter.next()) { aoqi@0: if (iter.succ() == head) { aoqi@0: iter.set_succ(clone); aoqi@0: } aoqi@0: } aoqi@0: flow_block(tail, temp_vector, temp_set); aoqi@0: if (head == tail) { aoqi@0: // For self-loops, clone->head becomes clone->clone aoqi@0: flow_block(clone, temp_vector, temp_set); aoqi@0: for (SuccIter iter(clone); !iter.done(); iter.next()) { aoqi@0: if (iter.succ() == head) { aoqi@0: iter.set_succ(clone); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: flow_block(clone, temp_vector, temp_set); aoqi@0: aoqi@0: return clone; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::flow_block aoqi@0: // aoqi@0: // Interpret the effects of the bytecodes on the incoming state aoqi@0: // vector of a basic block. Push the changed state to succeeding aoqi@0: // basic blocks. aoqi@0: void ciTypeFlow::flow_block(ciTypeFlow::Block* block, aoqi@0: ciTypeFlow::StateVector* state, aoqi@0: ciTypeFlow::JsrSet* jsrs) { aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print("\n>> ANALYZING BLOCK : "); aoqi@0: tty->cr(); aoqi@0: block->print_on(tty); aoqi@0: } aoqi@0: assert(block->has_pre_order(), "pre-order is assigned before 1st flow"); aoqi@0: aoqi@0: int start = block->start(); aoqi@0: int limit = block->limit(); aoqi@0: int control = block->control(); aoqi@0: if (control != ciBlock::fall_through_bci) { aoqi@0: limit = control; aoqi@0: } aoqi@0: aoqi@0: // Grab the state from the current block. aoqi@0: block->copy_state_into(state); aoqi@0: state->def_locals()->clear(); aoqi@0: aoqi@0: GrowableArray* exceptions = block->exceptions(); aoqi@0: GrowableArray* exc_klasses = block->exc_klasses(); aoqi@0: bool has_exceptions = exceptions->length() > 0; aoqi@0: aoqi@0: bool exceptions_used = false; aoqi@0: aoqi@0: ciBytecodeStream str(method()); aoqi@0: str.reset_to_bci(start); aoqi@0: Bytecodes::Code code; aoqi@0: while ((code = str.next()) != ciBytecodeStream::EOBC() && aoqi@0: str.cur_bci() < limit) { aoqi@0: // Check for exceptional control flow from this point. aoqi@0: if (has_exceptions && can_trap(str)) { aoqi@0: flow_exceptions(exceptions, exc_klasses, state); aoqi@0: exceptions_used = true; aoqi@0: } aoqi@0: // Apply the effects of the current bytecode to our state. aoqi@0: bool res = state->apply_one_bytecode(&str); aoqi@0: aoqi@0: // Watch for bailouts. aoqi@0: if (failing()) return; aoqi@0: aoqi@0: if (str.cur_bc() == Bytecodes::_monitorenter) { aoqi@0: block->set_has_monitorenter(); aoqi@0: } aoqi@0: aoqi@0: if (res) { aoqi@0: aoqi@0: // We have encountered a trap. Record it in this block. aoqi@0: block->set_trap(state->trap_bci(), state->trap_index()); aoqi@0: aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print_cr(">> Found trap"); aoqi@0: block->print_on(tty); aoqi@0: } aoqi@0: aoqi@0: // Save set of locals defined in this block aoqi@0: block->def_locals()->add(state->def_locals()); aoqi@0: aoqi@0: // Record (no) successors. aoqi@0: block->successors(&str, state, jsrs); aoqi@0: aoqi@0: assert(!has_exceptions || exceptions_used, "Not removing exceptions"); aoqi@0: aoqi@0: // Discontinue interpretation of this Block. aoqi@0: return; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: GrowableArray* successors = NULL; aoqi@0: if (control != ciBlock::fall_through_bci) { aoqi@0: // Check for exceptional control flow from this point. aoqi@0: if (has_exceptions && can_trap(str)) { aoqi@0: flow_exceptions(exceptions, exc_klasses, state); aoqi@0: exceptions_used = true; aoqi@0: } aoqi@0: aoqi@0: // Fix the JsrSet to reflect effect of the bytecode. aoqi@0: block->copy_jsrs_into(jsrs); aoqi@0: jsrs->apply_control(this, &str, state); aoqi@0: aoqi@0: // Find successor edges based on old state and new JsrSet. aoqi@0: successors = block->successors(&str, state, jsrs); aoqi@0: aoqi@0: // Apply the control changes to the state. aoqi@0: state->apply_one_bytecode(&str); aoqi@0: } else { aoqi@0: // Fall through control aoqi@0: successors = block->successors(&str, NULL, NULL); aoqi@0: } aoqi@0: aoqi@0: // Save set of locals defined in this block aoqi@0: block->def_locals()->add(state->def_locals()); aoqi@0: aoqi@0: // Remove untaken exception paths aoqi@0: if (!exceptions_used) aoqi@0: exceptions->clear(); aoqi@0: aoqi@0: // Pass our state to successors. aoqi@0: flow_successors(successors, state); aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::PostOrderLoops::next aoqi@0: // aoqi@0: // Advance to next loop tree using a postorder, left-to-right traversal. aoqi@0: void ciTypeFlow::PostorderLoops::next() { aoqi@0: assert(!done(), "must not be done."); aoqi@0: if (_current->sibling() != NULL) { aoqi@0: _current = _current->sibling(); aoqi@0: while (_current->child() != NULL) { aoqi@0: _current = _current->child(); aoqi@0: } aoqi@0: } else { aoqi@0: _current = _current->parent(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::PreOrderLoops::next aoqi@0: // aoqi@0: // Advance to next loop tree using a preorder, left-to-right traversal. aoqi@0: void ciTypeFlow::PreorderLoops::next() { aoqi@0: assert(!done(), "must not be done."); aoqi@0: if (_current->child() != NULL) { aoqi@0: _current = _current->child(); aoqi@0: } else if (_current->sibling() != NULL) { aoqi@0: _current = _current->sibling(); aoqi@0: } else { aoqi@0: while (_current != _root && _current->sibling() == NULL) { aoqi@0: _current = _current->parent(); aoqi@0: } aoqi@0: if (_current == _root) { aoqi@0: _current = NULL; aoqi@0: assert(done(), "must be done."); aoqi@0: } else { aoqi@0: assert(_current->sibling() != NULL, "must be more to do"); aoqi@0: _current = _current->sibling(); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Loop::sorted_merge aoqi@0: // aoqi@0: // Merge the branch lp into this branch, sorting on the loop head aoqi@0: // pre_orders. Returns the leaf of the merged branch. aoqi@0: // Child and sibling pointers will be setup later. aoqi@0: // Sort is (looking from leaf towards the root) aoqi@0: // descending on primary key: loop head's pre_order, and aoqi@0: // ascending on secondary key: loop tail's pre_order. aoqi@0: ciTypeFlow::Loop* ciTypeFlow::Loop::sorted_merge(Loop* lp) { aoqi@0: Loop* leaf = this; aoqi@0: Loop* prev = NULL; aoqi@0: Loop* current = leaf; aoqi@0: while (lp != NULL) { aoqi@0: int lp_pre_order = lp->head()->pre_order(); aoqi@0: // Find insertion point for "lp" aoqi@0: while (current != NULL) { aoqi@0: if (current == lp) aoqi@0: return leaf; // Already in list aoqi@0: if (current->head()->pre_order() < lp_pre_order) aoqi@0: break; aoqi@0: if (current->head()->pre_order() == lp_pre_order && aoqi@0: current->tail()->pre_order() > lp->tail()->pre_order()) { aoqi@0: break; aoqi@0: } aoqi@0: prev = current; aoqi@0: current = current->parent(); aoqi@0: } aoqi@0: Loop* next_lp = lp->parent(); // Save future list of items to insert aoqi@0: // Insert lp before current aoqi@0: lp->set_parent(current); aoqi@0: if (prev != NULL) { aoqi@0: prev->set_parent(lp); aoqi@0: } else { aoqi@0: leaf = lp; aoqi@0: } aoqi@0: prev = lp; // Inserted item is new prev[ious] aoqi@0: lp = next_lp; // Next item to insert aoqi@0: } aoqi@0: return leaf; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::build_loop_tree aoqi@0: // aoqi@0: // Incrementally build loop tree. aoqi@0: void ciTypeFlow::build_loop_tree(Block* blk) { aoqi@0: assert(!blk->is_post_visited(), "precondition"); aoqi@0: Loop* innermost = NULL; // merge of loop tree branches over all successors aoqi@0: aoqi@0: for (SuccIter iter(blk); !iter.done(); iter.next()) { aoqi@0: Loop* lp = NULL; aoqi@0: Block* succ = iter.succ(); aoqi@0: if (!succ->is_post_visited()) { aoqi@0: // Found backedge since predecessor post visited, but successor is not aoqi@0: assert(succ->pre_order() <= blk->pre_order(), "should be backedge"); aoqi@0: aoqi@0: // Create a LoopNode to mark this loop. aoqi@0: lp = new (arena()) Loop(succ, blk); aoqi@0: if (succ->loop() == NULL) aoqi@0: succ->set_loop(lp); aoqi@0: // succ->loop will be updated to innermost loop on a later call, when blk==succ aoqi@0: aoqi@0: } else { // Nested loop aoqi@0: lp = succ->loop(); aoqi@0: aoqi@0: // If succ is loop head, find outer loop. aoqi@0: while (lp != NULL && lp->head() == succ) { aoqi@0: lp = lp->parent(); aoqi@0: } aoqi@0: if (lp == NULL) { aoqi@0: // Infinite loop, it's parent is the root aoqi@0: lp = loop_tree_root(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Check for irreducible loop. aoqi@0: // Successor has already been visited. If the successor's loop head aoqi@0: // has already been post-visited, then this is another entry into the loop. aoqi@0: while (lp->head()->is_post_visited() && lp != loop_tree_root()) { aoqi@0: _has_irreducible_entry = true; aoqi@0: lp->set_irreducible(succ); aoqi@0: if (!succ->is_on_work_list()) { aoqi@0: // Assume irreducible entries need more data flow aoqi@0: add_to_work_list(succ); aoqi@0: } aoqi@0: Loop* plp = lp->parent(); aoqi@0: if (plp == NULL) { aoqi@0: // This only happens for some irreducible cases. The parent aoqi@0: // will be updated during a later pass. aoqi@0: break; aoqi@0: } aoqi@0: lp = plp; aoqi@0: } aoqi@0: aoqi@0: // Merge loop tree branch for all successors. aoqi@0: innermost = innermost == NULL ? lp : innermost->sorted_merge(lp); aoqi@0: aoqi@0: } // end loop aoqi@0: aoqi@0: if (innermost == NULL) { aoqi@0: assert(blk->successors()->length() == 0, "CFG exit"); aoqi@0: blk->set_loop(loop_tree_root()); aoqi@0: } else if (innermost->head() == blk) { aoqi@0: // If loop header, complete the tree pointers aoqi@0: if (blk->loop() != innermost) { aoqi@0: #ifdef ASSERT aoqi@0: assert(blk->loop()->head() == innermost->head(), "same head"); aoqi@0: Loop* dl; aoqi@0: for (dl = innermost; dl != NULL && dl != blk->loop(); dl = dl->parent()); aoqi@0: assert(dl == blk->loop(), "blk->loop() already in innermost list"); aoqi@0: #endif aoqi@0: blk->set_loop(innermost); aoqi@0: } aoqi@0: innermost->def_locals()->add(blk->def_locals()); aoqi@0: Loop* l = innermost; aoqi@0: Loop* p = l->parent(); aoqi@0: while (p && l->head() == blk) { aoqi@0: l->set_sibling(p->child()); // Put self on parents 'next child' aoqi@0: p->set_child(l); // Make self the first child of parent aoqi@0: p->def_locals()->add(l->def_locals()); aoqi@0: l = p; // Walk up the parent chain aoqi@0: p = l->parent(); aoqi@0: } aoqi@0: } else { aoqi@0: blk->set_loop(innermost); aoqi@0: innermost->def_locals()->add(blk->def_locals()); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Loop::contains aoqi@0: // aoqi@0: // Returns true if lp is nested loop. aoqi@0: bool ciTypeFlow::Loop::contains(ciTypeFlow::Loop* lp) const { aoqi@0: assert(lp != NULL, ""); aoqi@0: if (this == lp || head() == lp->head()) return true; aoqi@0: int depth1 = depth(); aoqi@0: int depth2 = lp->depth(); aoqi@0: if (depth1 > depth2) aoqi@0: return false; aoqi@0: while (depth1 < depth2) { aoqi@0: depth2--; aoqi@0: lp = lp->parent(); aoqi@0: } aoqi@0: return this == lp; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Loop::depth aoqi@0: // aoqi@0: // Loop depth aoqi@0: int ciTypeFlow::Loop::depth() const { aoqi@0: int dp = 0; aoqi@0: for (Loop* lp = this->parent(); lp != NULL; lp = lp->parent()) aoqi@0: dp++; aoqi@0: return dp; aoqi@0: } aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::Loop::print aoqi@0: void ciTypeFlow::Loop::print(outputStream* st, int indent) const { aoqi@0: for (int i = 0; i < indent; i++) st->print(" "); aoqi@0: st->print("%d<-%d %s", aoqi@0: is_root() ? 0 : this->head()->pre_order(), aoqi@0: is_root() ? 0 : this->tail()->pre_order(), aoqi@0: is_irreducible()?" irr":""); aoqi@0: st->print(" defs: "); aoqi@0: def_locals()->print_on(st, _head->outer()->method()->max_locals()); aoqi@0: st->cr(); aoqi@0: for (Loop* ch = child(); ch != NULL; ch = ch->sibling()) aoqi@0: ch->print(st, indent+2); aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::df_flow_types aoqi@0: // aoqi@0: // Perform the depth first type flow analysis. Helper for flow_types. aoqi@0: void ciTypeFlow::df_flow_types(Block* start, aoqi@0: bool do_flow, aoqi@0: StateVector* temp_vector, aoqi@0: JsrSet* temp_set) { aoqi@0: int dft_len = 100; aoqi@0: GrowableArray stk(dft_len); aoqi@0: aoqi@0: ciBlock* dummy = _methodBlocks->make_dummy_block(); aoqi@0: JsrSet* root_set = new JsrSet(NULL, 0); aoqi@0: Block* root_head = new (arena()) Block(this, dummy, root_set); aoqi@0: Block* root_tail = new (arena()) Block(this, dummy, root_set); aoqi@0: root_head->set_pre_order(0); aoqi@0: root_head->set_post_order(0); aoqi@0: root_tail->set_pre_order(max_jint); aoqi@0: root_tail->set_post_order(max_jint); aoqi@0: set_loop_tree_root(new (arena()) Loop(root_head, root_tail)); aoqi@0: aoqi@0: stk.push(start); aoqi@0: aoqi@0: _next_pre_order = 0; // initialize pre_order counter aoqi@0: _rpo_list = NULL; aoqi@0: int next_po = 0; // initialize post_order counter aoqi@0: aoqi@0: // Compute RPO and the control flow graph aoqi@0: int size; aoqi@0: while ((size = stk.length()) > 0) { aoqi@0: Block* blk = stk.top(); // Leave node on stack aoqi@0: if (!blk->is_visited()) { aoqi@0: // forward arc in graph aoqi@0: assert (!blk->has_pre_order(), ""); aoqi@0: blk->set_next_pre_order(); aoqi@0: vlivanov@7385: if (_next_pre_order >= (int)Compile::current()->max_node_limit() / 2) { aoqi@0: // Too many basic blocks. Bail out. aoqi@0: // This can happen when try/finally constructs are nested to depth N, aoqi@0: // and there is O(2**N) cloning of jsr bodies. See bug 4697245! aoqi@0: // "MaxNodeLimit / 2" is used because probably the parser will aoqi@0: // generate at least twice that many nodes and bail out. aoqi@0: record_failure("too many basic blocks"); aoqi@0: return; aoqi@0: } aoqi@0: if (do_flow) { aoqi@0: flow_block(blk, temp_vector, temp_set); aoqi@0: if (failing()) return; // Watch for bailouts. aoqi@0: } aoqi@0: } else if (!blk->is_post_visited()) { aoqi@0: // cross or back arc aoqi@0: for (SuccIter iter(blk); !iter.done(); iter.next()) { aoqi@0: Block* succ = iter.succ(); aoqi@0: if (!succ->is_visited()) { aoqi@0: stk.push(succ); aoqi@0: } aoqi@0: } aoqi@0: if (stk.length() == size) { aoqi@0: // There were no additional children, post visit node now aoqi@0: stk.pop(); // Remove node from stack aoqi@0: aoqi@0: build_loop_tree(blk); aoqi@0: blk->set_post_order(next_po++); // Assign post order aoqi@0: prepend_to_rpo_list(blk); aoqi@0: assert(blk->is_post_visited(), ""); aoqi@0: aoqi@0: if (blk->is_loop_head() && !blk->is_on_work_list()) { aoqi@0: // Assume loop heads need more data flow aoqi@0: add_to_work_list(blk); aoqi@0: } aoqi@0: } aoqi@0: } else { aoqi@0: stk.pop(); // Remove post-visited node from stack aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::flow_types aoqi@0: // aoqi@0: // Perform the type flow analysis, creating and cloning Blocks as aoqi@0: // necessary. aoqi@0: void ciTypeFlow::flow_types() { aoqi@0: ResourceMark rm; aoqi@0: StateVector* temp_vector = new StateVector(this); aoqi@0: JsrSet* temp_set = new JsrSet(NULL, 16); aoqi@0: aoqi@0: // Create the method entry block. aoqi@0: Block* start = block_at(start_bci(), temp_set); aoqi@0: aoqi@0: // Load the initial state into it. aoqi@0: const StateVector* start_state = get_start_state(); aoqi@0: if (failing()) return; aoqi@0: start->meet(start_state); aoqi@0: aoqi@0: // Depth first visit aoqi@0: df_flow_types(start, true /*do flow*/, temp_vector, temp_set); aoqi@0: aoqi@0: if (failing()) return; aoqi@0: assert(_rpo_list == start, "must be start"); aoqi@0: aoqi@0: // Any loops found? aoqi@0: if (loop_tree_root()->child() != NULL && aoqi@0: env()->comp_level() >= CompLevel_full_optimization) { aoqi@0: // Loop optimizations are not performed on Tier1 compiles. aoqi@0: aoqi@0: bool changed = clone_loop_heads(loop_tree_root(), temp_vector, temp_set); aoqi@0: aoqi@0: // If some loop heads were cloned, recompute postorder and loop tree aoqi@0: if (changed) { aoqi@0: loop_tree_root()->set_child(NULL); aoqi@0: for (Block* blk = _rpo_list; blk != NULL;) { aoqi@0: Block* next = blk->rpo_next(); aoqi@0: blk->df_init(); aoqi@0: blk = next; aoqi@0: } aoqi@0: df_flow_types(start, false /*no flow*/, temp_vector, temp_set); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print_cr("\nLoop tree"); aoqi@0: loop_tree_root()->print(); aoqi@0: } aoqi@0: aoqi@0: // Continue flow analysis until fixed point reached aoqi@0: aoqi@0: debug_only(int max_block = _next_pre_order;) aoqi@0: aoqi@0: while (!work_list_empty()) { aoqi@0: Block* blk = work_list_next(); aoqi@0: assert (blk->has_post_order(), "post order assigned above"); aoqi@0: aoqi@0: flow_block(blk, temp_vector, temp_set); aoqi@0: aoqi@0: assert (max_block == _next_pre_order, "no new blocks"); aoqi@0: assert (!failing(), "no more bailouts"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::map_blocks aoqi@0: // aoqi@0: // Create the block map, which indexes blocks in reverse post-order. aoqi@0: void ciTypeFlow::map_blocks() { aoqi@0: assert(_block_map == NULL, "single initialization"); aoqi@0: int block_ct = _next_pre_order; aoqi@0: _block_map = NEW_ARENA_ARRAY(arena(), Block*, block_ct); aoqi@0: assert(block_ct == block_count(), ""); aoqi@0: aoqi@0: Block* blk = _rpo_list; aoqi@0: for (int m = 0; m < block_ct; m++) { aoqi@0: int rpo = blk->rpo(); aoqi@0: assert(rpo == m, "should be sequential"); aoqi@0: _block_map[rpo] = blk; aoqi@0: blk = blk->rpo_next(); aoqi@0: } aoqi@0: assert(blk == NULL, "should be done"); aoqi@0: aoqi@0: for (int j = 0; j < block_ct; j++) { aoqi@0: assert(_block_map[j] != NULL, "must not drop any blocks"); aoqi@0: Block* block = _block_map[j]; aoqi@0: // Remove dead blocks from successor lists: aoqi@0: for (int e = 0; e <= 1; e++) { aoqi@0: GrowableArray* l = e? block->exceptions(): block->successors(); aoqi@0: for (int k = 0; k < l->length(); k++) { aoqi@0: Block* s = l->at(k); aoqi@0: if (!s->has_post_order()) { aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print("Removing dead %s successor of #%d: ", (e? "exceptional": "normal"), block->pre_order()); aoqi@0: s->print_value_on(tty); aoqi@0: tty->cr(); aoqi@0: } aoqi@0: l->remove(s); aoqi@0: --k; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::get_block_for aoqi@0: // aoqi@0: // Find a block with this ciBlock which has a compatible JsrSet. aoqi@0: // If no such block exists, create it, unless the option is no_create. aoqi@0: // If the option is create_backedge_copy, always create a fresh backedge copy. aoqi@0: ciTypeFlow::Block* ciTypeFlow::get_block_for(int ciBlockIndex, ciTypeFlow::JsrSet* jsrs, CreateOption option) { aoqi@0: Arena* a = arena(); aoqi@0: GrowableArray* blocks = _idx_to_blocklist[ciBlockIndex]; aoqi@0: if (blocks == NULL) { aoqi@0: // Query only? aoqi@0: if (option == no_create) return NULL; aoqi@0: aoqi@0: // Allocate the growable array. aoqi@0: blocks = new (a) GrowableArray(a, 4, 0, NULL); aoqi@0: _idx_to_blocklist[ciBlockIndex] = blocks; aoqi@0: } aoqi@0: aoqi@0: if (option != create_backedge_copy) { aoqi@0: int len = blocks->length(); aoqi@0: for (int i = 0; i < len; i++) { aoqi@0: Block* block = blocks->at(i); aoqi@0: if (!block->is_backedge_copy() && block->is_compatible_with(jsrs)) { aoqi@0: return block; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Query only? aoqi@0: if (option == no_create) return NULL; aoqi@0: aoqi@0: // We did not find a compatible block. Create one. aoqi@0: Block* new_block = new (a) Block(this, _methodBlocks->block(ciBlockIndex), jsrs); aoqi@0: if (option == create_backedge_copy) new_block->set_backedge_copy(true); aoqi@0: blocks->append(new_block); aoqi@0: return new_block; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::backedge_copy_count aoqi@0: // aoqi@0: int ciTypeFlow::backedge_copy_count(int ciBlockIndex, ciTypeFlow::JsrSet* jsrs) const { aoqi@0: GrowableArray* blocks = _idx_to_blocklist[ciBlockIndex]; aoqi@0: aoqi@0: if (blocks == NULL) { aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: int count = 0; aoqi@0: int len = blocks->length(); aoqi@0: for (int i = 0; i < len; i++) { aoqi@0: Block* block = blocks->at(i); aoqi@0: if (block->is_backedge_copy() && block->is_compatible_with(jsrs)) { aoqi@0: count++; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return count; aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::do_flow aoqi@0: // aoqi@0: // Perform type inference flow analysis. aoqi@0: void ciTypeFlow::do_flow() { aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print_cr("\nPerforming flow analysis on method"); aoqi@0: method()->print(); aoqi@0: if (is_osr_flow()) tty->print(" at OSR bci %d", start_bci()); aoqi@0: tty->cr(); aoqi@0: method()->print_codes(); aoqi@0: } aoqi@0: if (CITraceTypeFlow) { aoqi@0: tty->print_cr("Initial CI Blocks"); aoqi@0: print_on(tty); aoqi@0: } aoqi@0: flow_types(); aoqi@0: // Watch for bailouts. aoqi@0: if (failing()) { aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: map_blocks(); aoqi@0: aoqi@0: if (CIPrintTypeFlow || CITraceTypeFlow) { aoqi@0: rpo_print_on(tty); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::record_failure() aoqi@0: // The ciTypeFlow object keeps track of failure reasons separately from the ciEnv. aoqi@0: // This is required because there is not a 1-1 relation between the ciEnv and aoqi@0: // the TypeFlow passes within a compilation task. For example, if the compiler aoqi@0: // is considering inlining a method, it will request a TypeFlow. If that fails, aoqi@0: // the compilation as a whole may continue without the inlining. Some TypeFlow aoqi@0: // requests are not optional; if they fail the requestor is responsible for aoqi@0: // copying the failure reason up to the ciEnv. (See Parse::Parse.) aoqi@0: void ciTypeFlow::record_failure(const char* reason) { aoqi@0: if (env()->log() != NULL) { aoqi@0: env()->log()->elem("failure reason='%s' phase='typeflow'", reason); aoqi@0: } aoqi@0: if (_failure_reason == NULL) { aoqi@0: // Record the first failure reason. aoqi@0: _failure_reason = reason; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: // ------------------------------------------------------------------ aoqi@0: // ciTypeFlow::print_on aoqi@0: void ciTypeFlow::print_on(outputStream* st) const { aoqi@0: // Walk through CI blocks aoqi@0: st->print_cr("********************************************************"); aoqi@0: st->print ("TypeFlow for "); aoqi@0: method()->name()->print_symbol_on(st); aoqi@0: int limit_bci = code_size(); aoqi@0: st->print_cr(" %d bytes", limit_bci); aoqi@0: ciMethodBlocks *mblks = _methodBlocks; aoqi@0: ciBlock* current = NULL; aoqi@0: for (int bci = 0; bci < limit_bci; bci++) { aoqi@0: ciBlock* blk = mblks->block_containing(bci); aoqi@0: if (blk != NULL && blk != current) { aoqi@0: current = blk; aoqi@0: current->print_on(st); aoqi@0: aoqi@0: GrowableArray* blocks = _idx_to_blocklist[blk->index()]; aoqi@0: int num_blocks = (blocks == NULL) ? 0 : blocks->length(); aoqi@0: aoqi@0: if (num_blocks == 0) { aoqi@0: st->print_cr(" No Blocks"); aoqi@0: } else { aoqi@0: for (int i = 0; i < num_blocks; i++) { aoqi@0: Block* block = blocks->at(i); aoqi@0: block->print_on(st); aoqi@0: } aoqi@0: } aoqi@0: st->print_cr("--------------------------------------------------------"); aoqi@0: st->cr(); aoqi@0: } aoqi@0: } aoqi@0: st->print_cr("********************************************************"); aoqi@0: st->cr(); aoqi@0: } aoqi@0: aoqi@0: void ciTypeFlow::rpo_print_on(outputStream* st) const { aoqi@0: st->print_cr("********************************************************"); aoqi@0: st->print ("TypeFlow for "); aoqi@0: method()->name()->print_symbol_on(st); aoqi@0: int limit_bci = code_size(); aoqi@0: st->print_cr(" %d bytes", limit_bci); aoqi@0: for (Block* blk = _rpo_list; blk != NULL; blk = blk->rpo_next()) { aoqi@0: blk->print_on(st); aoqi@0: st->print_cr("--------------------------------------------------------"); aoqi@0: st->cr(); aoqi@0: } aoqi@0: st->print_cr("********************************************************"); aoqi@0: st->cr(); aoqi@0: } aoqi@0: #endif