< prev index next > src/hotspot/share/ci/ciTypeFlow.cpp
Print this page
*/
#include "precompiled.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciField.hpp"
+ #include "ci/ciInlineKlass.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciMethodData.hpp"
#include "ci/ciObjArrayKlass.hpp"
#include "ci/ciStreams.hpp"
#include "ci/ciTypeArrayKlass.hpp"
assert(t1 != t2, "checked in caller");
if (t1->equals(top_type())) {
return t2;
} else if (t2->equals(top_type())) {
return t1;
- } else if (t1->is_primitive_type() || t2->is_primitive_type()) {
+ }
+ // Unwrap after saving nullness information and handling top meets
+ bool null_free1 = t1->is_null_free();
+ bool null_free2 = t2->is_null_free();
+ if (t1->unwrap() == t2->unwrap() && null_free1 == null_free2) {
+ return t1;
+ }
+ t1 = t1->unwrap();
+ t2 = t2->unwrap();
+
+ if (t1->is_primitive_type() || t2->is_primitive_type()) {
// Special case null_type. null_type meet any reference type T
- // is T. null_type meet null_type is null_type.
+ // is T. null_type meet null_type is null_type.
if (t1->equals(null_type())) {
if (!t2->is_primitive_type() || t2->equals(null_type())) {
return t2;
}
} else if (t2->equals(null_type())) {
}
// At least one of the two types is a non-top primitive type.
// The other type is not equal to it. Fall to bottom.
return bottom_type();
- } else {
- // Both types are non-top non-primitive types. That is,
- // both types are either instanceKlasses or arrayKlasses.
- ciKlass* object_klass = analyzer->env()->Object_klass();
- ciKlass* k1 = t1->as_klass();
- ciKlass* k2 = t2->as_klass();
- if (k1->equals(object_klass) || k2->equals(object_klass)) {
- return object_klass;
- } else if (!k1->is_loaded() || !k2->is_loaded()) {
- // Unloaded classes fall to java.lang.Object at a merge.
- return object_klass;
- } else if (k1->is_interface() != k2->is_interface()) {
- // When an interface meets a non-interface, we get Object;
- // This is what the verifier does.
- return object_klass;
- } else if (k1->is_array_klass() || k2->is_array_klass()) {
- // When an array meets a non-array, we get Object.
- // When objArray meets typeArray, we also get Object.
- // And when typeArray meets different typeArray, we again get Object.
- // But when objArray meets objArray, we look carefully at element types.
- if (k1->is_obj_array_klass() && k2->is_obj_array_klass()) {
- // Meet the element types, then construct the corresponding array type.
- ciKlass* elem1 = k1->as_obj_array_klass()->element_klass();
- ciKlass* elem2 = k2->as_obj_array_klass()->element_klass();
- ciKlass* elem = type_meet_internal(elem1, elem2, analyzer)->as_klass();
- // Do an easy shortcut if one type is a super of the other.
- if (elem == elem1) {
- assert(k1 == ciObjArrayKlass::make(elem), "shortcut is OK");
- return k1;
- } else if (elem == elem2) {
- assert(k2 == ciObjArrayKlass::make(elem), "shortcut is OK");
- return k2;
- } else {
- return ciObjArrayKlass::make(elem);
- }
+ }
+
+ // Both types are non-top non-primitive types. That is,
+ // both types are either instanceKlasses or arrayKlasses.
+ ciKlass* object_klass = analyzer->env()->Object_klass();
+ ciKlass* k1 = t1->as_klass();
+ ciKlass* k2 = t2->as_klass();
+ if (k1->equals(object_klass) || k2->equals(object_klass)) {
+ return object_klass;
+ } else if (!k1->is_loaded() || !k2->is_loaded()) {
+ // Unloaded classes fall to java.lang.Object at a merge.
+ return object_klass;
+ } else if (k1->is_interface() != k2->is_interface()) {
+ // When an interface meets a non-interface, we get Object;
+ // This is what the verifier does.
+ return object_klass;
+ } else if (k1->is_array_klass() || k2->is_array_klass()) {
+ // When an array meets a non-array, we get Object.
+ // When (obj/flat)Array meets typeArray, we also get Object.
+ // And when typeArray meets different typeArray, we again get Object.
+ // But when (obj/flat)Array meets (obj/flat)Array, we look carefully at element types.
+ if ((k1->is_obj_array_klass() || k1->is_flat_array_klass()) &&
+ (k2->is_obj_array_klass() || k2->is_flat_array_klass())) {
+ ciType* elem1 = k1->as_array_klass()->element_klass();
+ ciType* elem2 = k2->as_array_klass()->element_klass();
+ ciType* elem = elem1;
+ if (elem1 != elem2) {
+ elem = type_meet_internal(elem1, elem2, analyzer)->as_klass();
+ }
+ // Do an easy shortcut if one type is a super of the other.
+ if (elem == elem1 && !elem->is_inlinetype()) {
+ assert(k1 == ciArrayKlass::make(elem), "shortcut is OK");
+ return k1;
+ } else if (elem == elem2 && !elem->is_inlinetype()) {
+ assert(k2 == ciArrayKlass::make(elem), "shortcut is OK");
+ return k2;
} else {
- return object_klass;
+ return ciArrayKlass::make(elem);
}
} else {
- // Must be two plain old instance klasses.
- assert(k1->is_instance_klass(), "previous cases handle non-instances");
- assert(k2->is_instance_klass(), "previous cases handle non-instances");
- return k1->least_common_ancestor(k2);
+ return object_klass;
+ }
+ } else {
+ // Must be two plain old instance klasses.
+ assert(k1->is_instance_klass(), "previous cases handle non-instances");
+ assert(k2->is_instance_klass(), "previous cases handle non-instances");
+ ciType* result = k1->least_common_ancestor(k2);
+ if (null_free1 && null_free2 && result->is_inlinetype()) {
+ result = analyzer->mark_as_null_free(result);
}
+ return result;
}
}
// ------------------------------------------------------------------
// even if it were possible for an OSR entry point to be at bci zero.
}
// "Push" the method signature into the first few locals.
state->set_stack_size(-max_locals());
if (!method()->is_static()) {
- state->push(method()->holder());
+ ciType* holder = method()->holder();
+ if (holder->is_inlinetype()) {
+ // The receiver is null-free
+ holder = mark_as_null_free(holder);
+ }
+ state->push(holder);
assert(state->tos() == state->local(0), "");
}
for (ciSignatureStream str(method()->signature());
!str.at_return_type();
str.next()) {
}
}
}
// ------------------------------------------------------------------
- // ciTypeFlow::StateVector::do_aaload
- void ciTypeFlow::StateVector::do_aaload(ciBytecodeStream* str) {
+ // ciTypeFlow::StateVector::do_aload
+ void ciTypeFlow::StateVector::do_aload(ciBytecodeStream* str) {
pop_int();
- ciObjArrayKlass* array_klass = pop_objArray();
+ ciArrayKlass* array_klass = pop_objOrFlatArray();
if (array_klass == nullptr) {
- // Did aaload on a null reference; push a null and ignore the exception.
+ // Did aload on a null reference; push a null and ignore the exception.
// This instruction will never continue normally. All we have to do
// is report a value that will meet correctly with any downstream
// reference types on paths that will truly be executed. This null type
// meets with any reference type to yield that same reference type.
// (The compiler will generate an unconditional exception here.)
// ciTypeFlow::StateVector::do_checkcast
void ciTypeFlow::StateVector::do_checkcast(ciBytecodeStream* str) {
bool will_link;
ciKlass* klass = str->get_klass(will_link);
if (!will_link) {
- // VM's interpreter will not load 'klass' if object is null.
+ // VM's interpreter will not load 'klass' if object is nullptr.
// Type flow after this block may still be needed in two situations:
// 1) C2 uses do_null_assert() and continues compilation for later blocks
// 2) C2 does an OSR compile in a later block (see bug 4778368).
pop_object();
do_null_assert(klass);
} else {
- pop_object();
+ ciType* type = pop_value();
+ type = type->unwrap();
+ if (type->is_loaded() && klass->is_loaded() &&
+ type != klass && type->is_subtype_of(klass)) {
+ // Useless cast, propagate more precise type of object
+ klass = type->as_klass();
+ }
push_object(klass);
}
}
// ------------------------------------------------------------------
ciField* field = str->get_field(will_link);
if (!will_link) {
trap(str, field->holder(), str->get_field_holder_index());
} else {
ciType* field_type = field->type();
- if (!field_type->is_loaded()) {
+ if (field->is_static() && field->is_null_free() &&
+ !field_type->as_instance_klass()->is_initialized()) {
+ // Deoptimize if we load from a static field with an uninitialized inline type
+ // because we need to throw an exception if initialization of the type failed.
+ trap(str, field_type->as_klass(),
+ Deoptimization::make_trap_request
+ (Deoptimization::Reason_unloaded,
+ Deoptimization::Action_reinterpret));
+ return;
+ } else if (!field_type->is_loaded()) {
// Normally, we need the field's type to be loaded if we are to
// do anything interesting with its value.
// We used to do this: trap(str, str->get_field_signature_index());
//
// There is one good reason not to trap here. Execution can
// here can make an OSR entry point unreachable, triggering the
// assert on non_osr_block in ciTypeFlow::get_start_state.
// (See bug 4379915.)
do_null_assert(field_type->as_klass());
} else {
+ if (field->is_null_free()) {
+ field_type = outer()->mark_as_null_free(field_type);
+ }
push_translate(field_type);
}
}
}
// does not need to be loaded! The compiler must assume that
// the value of the unloaded class reference is null; if the code
// ever sees a non-null value, loading has occurred.
//
// See do_getstatic() for similar explanation, as well as bug 4684993.
- do_null_assert(return_type->as_klass());
+ if (InlineTypeReturnedAsFields) {
+ // Return might be in scalarized form but we can't handle it because we
+ // don't know the type. This can happen due to a missing preload attribute.
+ // TODO 8284443 Use PhaseMacroExpand::expand_mh_intrinsic_return for this
+ trap(str, nullptr,
+ Deoptimization::make_trap_request
+ (Deoptimization::Reason_uninitialized,
+ Deoptimization::Action_reinterpret));
+ } else {
+ do_null_assert(return_type->as_klass());
+ }
} else {
push_translate(return_type);
}
}
}
ciObject* obj = con.as_object();
if (obj->is_null_object()) {
push_null();
} else {
assert(obj->is_instance() || obj->is_array(), "must be java_mirror of klass");
- push_object(obj->klass());
+ ciType* type = obj->klass();
+ if (type->is_inlinetype()) {
+ type = outer()->mark_as_null_free(type);
+ }
+ push(type);
}
} else {
assert(basic_type == con.basic_type() || con.basic_type() == T_OBJECT,
"not a boxed form: %s vs %s", type2name(basic_type), type2name(con.basic_type()));
push_translate(ciType::make(basic_type));
tty->print_cr(">> Interpreting bytecode %d:%s", str->cur_bci(),
Bytecodes::name(str->cur_bc()));
}
switch(str->cur_bc()) {
- case Bytecodes::_aaload: do_aaload(str); break;
+ case Bytecodes::_aaload: do_aload(str); break;
case Bytecodes::_aastore:
{
pop_object();
pop_int();
- pop_objArray();
+ pop_objOrFlatArray();
break;
}
case Bytecodes::_aconst_null:
{
push_null();
bool will_link;
ciKlass* element_klass = str->get_klass(will_link);
if (!will_link) {
trap(str, element_klass, str->get_klass_index());
} else {
- push_object(ciObjArrayKlass::make(element_klass));
+ push_object(ciArrayKlass::make(element_klass));
}
break;
}
case Bytecodes::_areturn:
case Bytecodes::_ifnonnull:
ciType* value2 = pop_value();
push(value1);
push(value2);
break;
}
+
case Bytecodes::_wide:
default:
{
// The iterator should skip this.
ShouldNotReachHere();
#ifndef PRODUCT
// ------------------------------------------------------------------
// ciTypeFlow::StateVector::print_cell_on
void ciTypeFlow::StateVector::print_cell_on(outputStream* st, Cell c) const {
- ciType* type = type_at(c);
+ ciType* type = type_at(c)->unwrap();
if (type == top_type()) {
st->print("top");
} else if (type == bottom_type()) {
st->print("bottom");
} else if (type == null_type()) {
_successors->append_if_missing(block);
}
break;
}
- case Bytecodes::_athrow: case Bytecodes::_ireturn:
- case Bytecodes::_lreturn: case Bytecodes::_freturn:
- case Bytecodes::_dreturn: case Bytecodes::_areturn:
+ case Bytecodes::_athrow:
+ case Bytecodes::_ireturn:
+ case Bytecodes::_lreturn:
+ case Bytecodes::_freturn:
+ case Bytecodes::_dreturn:
+ case Bytecodes::_areturn:
case Bytecodes::_return:
_successors =
new (arena) GrowableArray<Block*>(arena, 1, 0, nullptr);
// No successors
break;
// Record the first failure reason.
_failure_reason = reason;
}
}
+ ciType* ciTypeFlow::mark_as_null_free(ciType* type) {
+ // Wrap the type to carry the information that it is null-free
+ return env()->make_null_free_wrapper(type);
+ }
+
#ifndef PRODUCT
void ciTypeFlow::print() const { print_on(tty); }
// ------------------------------------------------------------------
// ciTypeFlow::print_on
< prev index next >