--- old/src/hotspot/share/opto/type.cpp 2019-03-11 14:26:59.934354412 +0100 +++ new/src/hotspot/share/opto/type.cpp 2019-03-11 14:26:59.630354416 +0100 @@ -23,8 +23,10 @@ */ #include "precompiled.hpp" +#include "ci/ciField.hpp" #include "ci/ciMethodData.hpp" #include "ci/ciTypeFlow.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "compiler/compileLog.hpp" @@ -46,6 +48,52 @@ // Dictionary of types shared among compilations. Dict* Type::_shared_type_dict = NULL; +const Type::Offset Type::Offset::top(Type::OffsetTop); +const Type::Offset Type::Offset::bottom(Type::OffsetBot); + +const Type::Offset Type::Offset::meet(const Type::Offset other) const { + // Either is 'TOP' offset? Return the other offset! + int offset = other._offset; + if (_offset == OffsetTop) return Offset(offset); + if (offset == OffsetTop) return Offset(_offset); + // If either is different, return 'BOTTOM' offset + if (_offset != offset) return bottom; + return Offset(_offset); +} + +const Type::Offset Type::Offset::dual() const { + if (_offset == OffsetTop) return bottom;// Map 'TOP' into 'BOTTOM' + if (_offset == OffsetBot) return top;// Map 'BOTTOM' into 'TOP' + return Offset(_offset); // Map everything else into self +} + +const Type::Offset Type::Offset::add(intptr_t offset) const { + // Adding to 'TOP' offset? Return 'TOP'! + if (_offset == OffsetTop || offset == OffsetTop) return top; + // Adding to 'BOTTOM' offset? Return 'BOTTOM'! + if (_offset == OffsetBot || offset == OffsetBot) return bottom; + // Addition overflows or "accidentally" equals to OffsetTop? Return 'BOTTOM'! + offset += (intptr_t)_offset; + if (offset != (int)offset || offset == OffsetTop) return bottom; + + // assert( _offset >= 0 && _offset+offset >= 0, "" ); + // It is possible to construct a negative offset during PhaseCCP + + return Offset((int)offset); // Sum valid offsets +} + +void Type::Offset::dump2(outputStream *st) const { + if (_offset == 0) { + return; + } else if (_offset == OffsetTop) { + st->print("+top"); + } + else if (_offset == OffsetBot) { + st->print("+bot"); + } else if (_offset) { + st->print("+%d", _offset); + } +} // Array which maps compiler types to Basic Types const Type::TypeInfo Type::_type_info[Type::lastype] = { @@ -85,6 +133,7 @@ { Bad, T_ILLEGAL, "vectory:", false, Op_VecY, relocInfo::none }, // VectorY { Bad, T_ILLEGAL, "vectorz:", false, Op_VecZ, relocInfo::none }, // VectorZ #endif + { Bad, T_VALUETYPE, "value:", false, Node::NotAMachineReg, relocInfo::none }, // ValueType { Bad, T_ADDRESS, "anyptr:", false, Op_RegP, relocInfo::none }, // AnyPtr { Bad, T_ADDRESS, "rawptr:", false, Op_RegP, relocInfo::none }, // RawPtr { Bad, T_OBJECT, "oop:", true, Op_RegP, relocInfo::oop_type }, // OopPtr @@ -215,6 +264,16 @@ assert(type->is_return_address(), ""); return TypeRawPtr::make((address)(intptr_t)type->as_return_address()->bci()); + case T_VALUETYPE: { + bool is_never_null = type->is_never_null(); + ciValueKlass* vk = type->unwrap()->as_value_klass(); + if (vk->is_scalarizable() && is_never_null) { + return TypeValueType::make(vk); + } else { + return TypeOopPtr::make_from_klass(vk)->join_speculative(is_never_null ? TypePtr::NOTNULL : TypePtr::BOTTOM); + } + } + default: // make sure we did not mix up the cases: assert(type != ciTypeFlow::StateVector::bottom_type(), ""); @@ -243,6 +302,7 @@ case T_FLOAT: return TypeF::make(constant.as_float()); case T_DOUBLE: return TypeD::make(constant.as_double()); case T_ARRAY: + case T_VALUETYPE: case T_OBJECT: { // cases: // can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0) @@ -284,12 +344,14 @@ switch (conbt) { case T_BOOLEAN: conbt = T_BYTE; break; case T_ARRAY: conbt = T_OBJECT; break; + case T_VALUETYPE: conbt = T_OBJECT; break; default: break; } switch (loadbt) { case T_BOOLEAN: loadbt = T_BYTE; break; case T_NARROWOOP: loadbt = T_OBJECT; break; case T_ARRAY: loadbt = T_OBJECT; break; + case T_VALUETYPE: loadbt = T_OBJECT; break; case T_ADDRESS: loadbt = T_OBJECT; break; default: break; } @@ -527,9 +589,9 @@ floop[1] = TypeInt::INT; TypeTuple::LOOPBODY = TypeTuple::make( 2, floop ); - TypePtr::NULL_PTR= TypePtr::make(AnyPtr, TypePtr::Null, 0); - TypePtr::NOTNULL = TypePtr::make(AnyPtr, TypePtr::NotNull, OffsetBot); - TypePtr::BOTTOM = TypePtr::make(AnyPtr, TypePtr::BotPTR, OffsetBot); + TypePtr::NULL_PTR= TypePtr::make(AnyPtr, TypePtr::Null, Offset(0)); + TypePtr::NOTNULL = TypePtr::make(AnyPtr, TypePtr::NotNull, Offset::bottom); + TypePtr::BOTTOM = TypePtr::make(AnyPtr, TypePtr::BotPTR, Offset::bottom); TypeRawPtr::BOTTOM = TypeRawPtr::make( TypePtr::BotPTR ); TypeRawPtr::NOTNULL= TypeRawPtr::make( TypePtr::NotNull ); @@ -546,12 +608,12 @@ TypeInstPtr::BOTTOM = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass()); TypeInstPtr::MIRROR = TypeInstPtr::make(TypePtr::NotNull, current->env()->Class_klass()); TypeInstPtr::MARK = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), - false, 0, oopDesc::mark_offset_in_bytes()); + false, 0, Offset(oopDesc::mark_offset_in_bytes())); TypeInstPtr::KLASS = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), - false, 0, oopDesc::klass_offset_in_bytes()); - TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot); + false, 0, Offset(oopDesc::klass_offset_in_bytes())); + TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, Offset::bottom, TypeOopPtr::InstanceBot); - TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, OffsetBot); + TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, Offset::bottom); TypeNarrowOop::NULL_PTR = TypeNarrowOop::make( TypePtr::NULL_PTR ); TypeNarrowOop::BOTTOM = TypeNarrowOop::make( TypeInstPtr::BOTTOM ); @@ -568,9 +630,9 @@ mreg2type[Op_RegL] = TypeLong::LONG; mreg2type[Op_RegFlags] = TypeInt::CC; - TypeAryPtr::RANGE = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), NULL /* current->env()->Object_klass() */, false, arrayOopDesc::length_offset_in_bytes()); + TypeAryPtr::RANGE = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), NULL /* current->env()->Object_klass() */, false, Offset(arrayOopDesc::length_offset_in_bytes())); - TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot); + TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Offset::bottom); #ifdef _LP64 if (UseCompressedOops) { @@ -580,19 +642,20 @@ #endif { // There is no shared klass for Object[]. See note in TypeAryPtr::klass(). - TypeAryPtr::OOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot); + TypeAryPtr::OOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Offset::bottom); } - TypeAryPtr::BYTES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE ,TypeInt::POS), ciTypeArrayKlass::make(T_BYTE), true, Type::OffsetBot); - TypeAryPtr::SHORTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT ,TypeInt::POS), ciTypeArrayKlass::make(T_SHORT), true, Type::OffsetBot); - TypeAryPtr::CHARS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR ,TypeInt::POS), ciTypeArrayKlass::make(T_CHAR), true, Type::OffsetBot); - TypeAryPtr::INTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::INT ,TypeInt::POS), ciTypeArrayKlass::make(T_INT), true, Type::OffsetBot); - TypeAryPtr::LONGS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeLong::LONG ,TypeInt::POS), ciTypeArrayKlass::make(T_LONG), true, Type::OffsetBot); - TypeAryPtr::FLOATS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT ,TypeInt::POS), ciTypeArrayKlass::make(T_FLOAT), true, Type::OffsetBot); - TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE ,TypeInt::POS), ciTypeArrayKlass::make(T_DOUBLE), true, Type::OffsetBot); + TypeAryPtr::BYTES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE ,TypeInt::POS), ciTypeArrayKlass::make(T_BYTE), true, Offset::bottom); + TypeAryPtr::SHORTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT ,TypeInt::POS), ciTypeArrayKlass::make(T_SHORT), true, Offset::bottom); + TypeAryPtr::CHARS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR ,TypeInt::POS), ciTypeArrayKlass::make(T_CHAR), true, Offset::bottom); + TypeAryPtr::INTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::INT ,TypeInt::POS), ciTypeArrayKlass::make(T_INT), true, Offset::bottom); + TypeAryPtr::LONGS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeLong::LONG ,TypeInt::POS), ciTypeArrayKlass::make(T_LONG), true, Offset::bottom); + TypeAryPtr::FLOATS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT ,TypeInt::POS), ciTypeArrayKlass::make(T_FLOAT), true, Offset::bottom); + TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE ,TypeInt::POS), ciTypeArrayKlass::make(T_DOUBLE), true, Offset::bottom); // Nobody should ask _array_body_type[T_NARROWOOP]. Use NULL as assert. TypeAryPtr::_array_body_type[T_NARROWOOP] = NULL; TypeAryPtr::_array_body_type[T_OBJECT] = TypeAryPtr::OOPS; + TypeAryPtr::_array_body_type[T_VALUETYPE] = TypeAryPtr::OOPS; TypeAryPtr::_array_body_type[T_ARRAY] = TypeAryPtr::OOPS; // arrays are stored in oop arrays TypeAryPtr::_array_body_type[T_BYTE] = TypeAryPtr::BYTES; TypeAryPtr::_array_body_type[T_BOOLEAN] = TypeAryPtr::BYTES; // boolean[] is a byte array @@ -603,8 +666,8 @@ TypeAryPtr::_array_body_type[T_FLOAT] = TypeAryPtr::FLOATS; TypeAryPtr::_array_body_type[T_DOUBLE] = TypeAryPtr::DOUBLES; - TypeKlassPtr::OBJECT = TypeKlassPtr::make( TypePtr::NotNull, current->env()->Object_klass(), 0 ); - TypeKlassPtr::OBJECT_OR_NULL = TypeKlassPtr::make( TypePtr::BotPTR, current->env()->Object_klass(), 0 ); + TypeKlassPtr::OBJECT = TypeKlassPtr::make(TypePtr::NotNull, current->env()->Object_klass(), Offset(0) ); + TypeKlassPtr::OBJECT_OR_NULL = TypeKlassPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), Offset(0) ); const Type **fi2c = TypeTuple::fields(2); fi2c[TypeFunc::Parms+0] = TypeInstPtr::BOTTOM; // Method* @@ -643,6 +706,7 @@ _const_basic_type[T_DOUBLE] = Type::DOUBLE; _const_basic_type[T_OBJECT] = TypeInstPtr::BOTTOM; _const_basic_type[T_ARRAY] = TypeInstPtr::BOTTOM; // there is no separate bottom for arrays + _const_basic_type[T_VALUETYPE] = TypeInstPtr::BOTTOM; _const_basic_type[T_VOID] = TypePtr::NULL_PTR; // reflection represents void this way _const_basic_type[T_ADDRESS] = TypeRawPtr::BOTTOM; // both interpreter return addresses & random raw ptrs _const_basic_type[T_CONFLICT] = Type::BOTTOM; // why not? @@ -659,6 +723,7 @@ _zero_type[T_DOUBLE] = TypeD::ZERO; _zero_type[T_OBJECT] = TypePtr::NULL_PTR; _zero_type[T_ARRAY] = TypePtr::NULL_PTR; // null array is null oop + _zero_type[T_VALUETYPE] = TypePtr::NULL_PTR; _zero_type[T_ADDRESS] = TypePtr::NULL_PTR; // raw pointers use the same null _zero_type[T_VOID] = Type::TOP; // the only void value is no value at all @@ -911,6 +976,9 @@ case NarrowKlass: return t->xmeet(this); + case ValueType: + return t->xmeet(this); + case Bad: // Type check default: // Bogus type not in lattice typerr(t); @@ -978,6 +1046,7 @@ Bad, // VectorX - handled in v-call Bad, // VectorY - handled in v-call Bad, // VectorZ - handled in v-call + Bad, // ValueType - handled in v-call Bad, // AnyPtr - handled in v-call Bad, // RawPtr - handled in v-call @@ -1873,12 +1942,37 @@ const TypeTuple *TypeTuple::INT_CC_PAIR; const TypeTuple *TypeTuple::LONG_CC_PAIR; +static void collect_value_fields(ciValueKlass* vk, const Type** field_array, uint& pos, ExtendedSignature& sig_cc) { + for (int j = 0; j < vk->nof_nonstatic_fields(); j++) { + ciField* field = vk->nonstatic_field_at(j); + BasicType bt = field->type()->basic_type(); + const Type* ft = Type::get_const_type(field->type()); + field_array[pos++] = ft; + if (type2size[bt] == 2) { + field_array[pos++] = Type::HALF; + } + // Skip reserved arguments + while (SigEntry::next_is_reserved(sig_cc, bt)) { + field_array[pos++] = Type::get_const_basic_type(bt); + if (type2size[bt] == 2) { + field_array[pos++] = Type::HALF; + } + } + } +} //------------------------------make------------------------------------------- // Make a TypeTuple from the range of a method signature -const TypeTuple *TypeTuple::make_range(ciSignature* sig) { +const TypeTuple *TypeTuple::make_range(ciSignature* sig, bool ret_vt_fields) { ciType* return_type = sig->return_type(); + bool never_null = sig->returns_never_null(); + uint arg_cnt = return_type->size(); + ret_vt_fields = ret_vt_fields && never_null && return_type->as_value_klass()->can_be_returned_as_fields(); + if (ret_vt_fields) { + arg_cnt = return_type->as_value_klass()->value_arg_slots() + 1; + } + const Type **field_array = fields(arg_cnt); switch (return_type->basic_type()) { case T_LONG: @@ -1899,6 +1993,17 @@ case T_INT: field_array[TypeFunc::Parms] = get_const_type(return_type); break; + case T_VALUETYPE: + if (ret_vt_fields) { + uint pos = TypeFunc::Parms; + field_array[pos] = TypePtr::BOTTOM; + pos++; + ExtendedSignature sig = ExtendedSignature(NULL, SigEntryFilter()); + collect_value_fields(return_type->as_value_klass(), field_array, pos, sig); + } else { + field_array[TypeFunc::Parms] = get_const_type(return_type)->join_speculative(never_null ? TypePtr::NOTNULL : TypePtr::BOTTOM); + } + break; case T_VOID: break; default: @@ -1908,25 +2013,39 @@ } // Make a TypeTuple from the domain of a method signature -const TypeTuple *TypeTuple::make_domain(ciInstanceKlass* recv, ciSignature* sig) { - uint arg_cnt = sig->size(); +const TypeTuple *TypeTuple::make_domain(ciMethod* method, bool vt_fields_as_args) { + ciSignature* sig = method->signature(); + ExtendedSignature sig_cc = ExtendedSignature(vt_fields_as_args ? method->get_sig_cc() : NULL, SigEntryFilter()); + + uint arg_cnt = sig->size() + (method->is_static() ? 0 : 1); + if (vt_fields_as_args) { + for (arg_cnt = 0; !sig_cc.at_end(); ++sig_cc) { + arg_cnt += type2size[(*sig_cc)._bt]; + } + sig_cc = ExtendedSignature(method->get_sig_cc(), SigEntryFilter()); + } uint pos = TypeFunc::Parms; - const Type **field_array; - if (recv != NULL) { - arg_cnt++; - field_array = fields(arg_cnt); - // Use get_const_type here because it respects UseUniqueSubclasses: - field_array[pos++] = get_const_type(recv)->join_speculative(TypePtr::NOTNULL); - } else { - field_array = fields(arg_cnt); + const Type** field_array = fields(arg_cnt); + if (!method->is_static()) { + ciInstanceKlass* recv = method->holder(); + if (vt_fields_as_args && recv->is_valuetype()) { + collect_value_fields(recv->as_value_klass(), field_array, pos, sig_cc); + } else { + field_array[pos++] = get_const_type(recv)->join_speculative(TypePtr::NOTNULL); + if (vt_fields_as_args) { + ++sig_cc; + } + } } int i = 0; while (pos < TypeFunc::Parms + arg_cnt) { ciType* type = sig->type_at(i); + BasicType bt = type->basic_type(); + bool is_flattened = false; - switch (type->basic_type()) { + switch (bt) { case T_LONG: field_array[pos++] = TypeLong::LONG; field_array[pos++] = Type::HALF; @@ -1947,11 +2066,29 @@ case T_SHORT: field_array[pos++] = TypeInt::INT; break; + case T_VALUETYPE: { + bool never_null = sig->is_never_null_at(i); + if (vt_fields_as_args && never_null) { + is_flattened = true; + collect_value_fields(type->as_value_klass(), field_array, pos, sig_cc); + } else { + field_array[pos++] = get_const_type(type)->join_speculative(never_null ? TypePtr::NOTNULL : TypePtr::BOTTOM); + } + break; + } default: ShouldNotReachHere(); } + // Skip reserved arguments + while (!is_flattened && SigEntry::next_is_reserved(sig_cc, bt)) { + field_array[pos++] = Type::get_const_basic_type(bt); + if (type2size[bt] == 2) { + field_array[pos++] = Type::HALF; + } + } i++; } + assert(pos == TypeFunc::Parms + arg_cnt, "wrong number of arguments"); return (TypeTuple*)(new TypeTuple(TypeFunc::Parms + arg_cnt, field_array))->hashcons(); } @@ -2087,6 +2224,10 @@ //------------------------------make------------------------------------------- const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable) { + if (elem->is_valuetypeptr()) { + // Value type array elements cannot be NULL + elem = elem->join_speculative(TypePtr::NOTNULL)->is_oopptr(); + } if (UseCompressedOops && elem->isa_oopptr()) { elem = elem->make_narrowoop(); } @@ -2243,6 +2384,120 @@ return false; } +//==============================TypeValueType======================================= + +//------------------------------make------------------------------------------- +const TypeValueType* TypeValueType::make(ciValueKlass* vk, bool larval) { + return (TypeValueType*)(new TypeValueType(vk, larval))->hashcons(); +} + +//------------------------------meet------------------------------------------- +// Compute the MEET of two types. It returns a new Type object. +const Type* TypeValueType::xmeet(const Type* t) const { + // Perform a fast test for common case; meeting the same types together. + if(this == t) return this; // Meeting same type-rep? + + // Current "this->_base" is ValueType + switch (t->base()) { // switch on original type + + case Int: + case Long: + case FloatTop: + case FloatCon: + case FloatBot: + case DoubleTop: + case DoubleCon: + case DoubleBot: + case NarrowKlass: + case Bottom: + return Type::BOTTOM; + + case OopPtr: + case MetadataPtr: + case KlassPtr: + case RawPtr: + return TypePtr::BOTTOM; + + case Top: + return this; + + case NarrowOop: { + const Type* res = t->make_ptr()->xmeet(this); + if (res->isa_ptr()) { + return res->make_narrowoop(); + } + return res; + } + + case AryPtr: + case InstPtr: { + return t->xmeet(this); + } + + case ValueType: { + // All value types inherit from Object + const TypeValueType* other = t->is_valuetype(); + if (_vk == other->_vk) { + if (_larval == other->_larval || + !_larval) { + return this; + } else { + return t; + } + } + return TypeInstPtr::NOTNULL; + } + + default: // All else is a mistake + typerr(t); + + } + return this; +} + +//------------------------------xdual------------------------------------------ +const Type* TypeValueType::xdual() const { + return this; +} + +//------------------------------eq--------------------------------------------- +// Structural equality check for Type representations +bool TypeValueType::eq(const Type* t) const { + const TypeValueType* vt = t->is_valuetype(); + return (_vk == vt->value_klass() && _larval == vt->larval()); +} + +//------------------------------hash------------------------------------------- +// Type-specific hashing function. +int TypeValueType::hash(void) const { + return (intptr_t)_vk; +} + +//------------------------------singleton-------------------------------------- +// TRUE if Type is a singleton type, FALSE otherwise. Singletons are simple constants. +bool TypeValueType::singleton(void) const { + return false; +} + +//------------------------------empty------------------------------------------ +// TRUE if Type is a type with no values, FALSE otherwise. +bool TypeValueType::empty(void) const { + return false; +} + +//------------------------------dump2------------------------------------------ +#ifndef PRODUCT +void TypeValueType::dump2(Dict &d, uint depth, outputStream* st) const { + int count = _vk->nof_declared_nonstatic_fields(); + st->print("valuetype[%d]:{", count); + st->print("%s", count != 0 ? _vk->declared_nonstatic_field_at(0)->type()->name() : "empty"); + for (int i = 1; i < count; ++i) { + st->print(", %s", _vk->declared_nonstatic_field_at(i)->type()->name()); + } + st->print("}%s", _larval?" : larval":""); +} +#endif + //==============================TypeVect======================================= // Convenience common pre-built types. const TypeVect *TypeVect::VECTS = NULL; // 32-bit vectors @@ -2384,7 +2639,7 @@ }; //------------------------------make------------------------------------------- -const TypePtr *TypePtr::make(TYPES t, enum PTR ptr, int offset, const TypePtr* speculative, int inline_depth) { +const TypePtr* TypePtr::make(TYPES t, enum PTR ptr, Offset offset, const TypePtr* speculative, int inline_depth) { return (TypePtr*)(new TypePtr(t,ptr,offset, speculative, inline_depth))->hashcons(); } @@ -2398,7 +2653,7 @@ //------------------------------get_con---------------------------------------- intptr_t TypePtr::get_con() const { assert( _ptr == Null, "" ); - return _offset; + return offset(); } //------------------------------meet------------------------------------------- @@ -2467,20 +2722,13 @@ } //------------------------------meet_offset------------------------------------ -int TypePtr::meet_offset( int offset ) const { - // Either is 'TOP' offset? Return the other offset! - if( _offset == OffsetTop ) return offset; - if( offset == OffsetTop ) return _offset; - // If either is different, return 'BOTTOM' offset - if( _offset != offset ) return OffsetBot; - return _offset; +Type::Offset TypePtr::meet_offset(int offset) const { + return _offset.meet(Offset(offset)); } //------------------------------dual_offset------------------------------------ -int TypePtr::dual_offset( ) const { - if( _offset == OffsetTop ) return OffsetBot;// Map 'TOP' into 'BOTTOM' - if( _offset == OffsetBot ) return OffsetTop;// Map 'BOTTOM' into 'TOP' - return _offset; // Map everything else into self +Type::Offset TypePtr::dual_offset() const { + return _offset.dual(); } //------------------------------xdual------------------------------------------ @@ -2493,19 +2741,8 @@ } //------------------------------xadd_offset------------------------------------ -int TypePtr::xadd_offset( intptr_t offset ) const { - // Adding to 'TOP' offset? Return 'TOP'! - if( _offset == OffsetTop || offset == OffsetTop ) return OffsetTop; - // Adding to 'BOTTOM' offset? Return 'BOTTOM'! - if( _offset == OffsetBot || offset == OffsetBot ) return OffsetBot; - // Addition overflows or "accidentally" equals to OffsetTop? Return 'BOTTOM'! - offset += (intptr_t)_offset; - if (offset != (int)offset || offset == OffsetTop) return OffsetBot; - - // assert( _offset >= 0 && _offset+offset >= 0, "" ); - // It is possible to construct a negative offset during PhaseCCP - - return (int)offset; // Sum valid offsets +Type::Offset TypePtr::xadd_offset(intptr_t offset) const { + return _offset.add(offset); } //------------------------------add_offset------------------------------------- @@ -2517,13 +2754,13 @@ // Structural equality check for Type representations bool TypePtr::eq( const Type *t ) const { const TypePtr *a = (const TypePtr*)t; - return _ptr == a->ptr() && _offset == a->offset() && eq_speculative(a) && _inline_depth == a->_inline_depth; + return _ptr == a->ptr() && _offset == a->_offset && eq_speculative(a) && _inline_depth == a->_inline_depth; } //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypePtr::hash(void) const { - return java_add(java_add((jint)_ptr, (jint)_offset), java_add((jint)hash_speculative(), (jint)_inline_depth)); + return java_add(java_add((jint)_ptr, (jint)offset()), java_add((jint)hash_speculative(), (jint)_inline_depth)); ; } @@ -2783,9 +3020,7 @@ void TypePtr::dump2( Dict &d, uint depth, outputStream *st ) const { if( _ptr == Null ) st->print("NULL"); else st->print("%s *", ptr_msg[_ptr]); - if( _offset == OffsetTop ) st->print("+top"); - else if( _offset == OffsetBot ) st->print("+bot"); - else if( _offset ) st->print("+%d", _offset); + _offset.dump2(st); dump_inline_depth(st); dump_speculative(st); } @@ -2820,11 +3055,11 @@ // constants bool TypePtr::singleton(void) const { // TopPTR, Null, AnyNull, Constant are all singletons - return (_offset != OffsetBot) && !below_centerline(_ptr); + return (_offset != Offset::bottom) && !below_centerline(_ptr); } bool TypePtr::empty(void) const { - return (_offset == OffsetTop) || above_centerline(_ptr); + return (_offset == Offset::top) || above_centerline(_ptr); } //============================================================================= @@ -2966,7 +3201,7 @@ const TypeOopPtr *TypeOopPtr::BOTTOM; //------------------------------TypeOopPtr------------------------------------- -TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, +TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, Offset offset, Offset field_offset, int instance_id, const TypePtr* speculative, int inline_depth) : TypePtr(t, ptr, offset, speculative, inline_depth), _const_oop(o), _klass(k), @@ -2976,53 +3211,68 @@ _is_ptr_to_boxed_value(false), _instance_id(instance_id) { if (Compile::current()->eliminate_boxing() && (t == InstPtr) && - (offset > 0) && xk && (k != 0) && k->is_instance_klass()) { - _is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset); + (offset.get() > 0) && xk && (k != 0) && k->is_instance_klass()) { + _is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset.get()); } #ifdef _LP64 - if (_offset > 0 || _offset == Type::OffsetTop || _offset == Type::OffsetBot) { - if (_offset == oopDesc::klass_offset_in_bytes()) { + if (this->offset() > 0 || this->offset() == Type::OffsetTop || this->offset() == Type::OffsetBot) { + if (this->offset() == oopDesc::klass_offset_in_bytes()) { _is_ptr_to_narrowklass = UseCompressedClassPointers; } else if (klass() == NULL) { // Array with unknown body type assert(this->isa_aryptr(), "only arrays without klass"); _is_ptr_to_narrowoop = UseCompressedOops; - } else if (this->isa_aryptr()) { - _is_ptr_to_narrowoop = (UseCompressedOops && klass()->is_obj_array_klass() && - _offset != arrayOopDesc::length_offset_in_bytes()); + } else if (UseCompressedOops && this->isa_aryptr() && this->offset() != arrayOopDesc::length_offset_in_bytes()) { + if (klass()->is_obj_array_klass()) { + _is_ptr_to_narrowoop = true; + } else if (klass()->is_value_array_klass() && field_offset != Offset::top && field_offset != Offset::bottom) { + // Check if the field of the value type array element contains oops + ciValueKlass* vk = klass()->as_value_array_klass()->element_klass()->as_value_klass(); + int foffset = field_offset.get() + vk->first_field_offset(); + ciField* field = vk->get_field_by_offset(foffset, false); + assert(field != NULL, "missing field"); + BasicType bt = field->layout_type(); + _is_ptr_to_narrowoop = (bt == T_OBJECT || bt == T_ARRAY || T_VALUETYPE); + } } else if (klass()->is_instance_klass()) { - ciInstanceKlass* ik = klass()->as_instance_klass(); - ciField* field = NULL; if (this->isa_klassptr()) { // Perm objects don't use compressed references - } else if (_offset == OffsetBot || _offset == OffsetTop) { + } else if (_offset == Offset::bottom || _offset == Offset::top) { // unsafe access _is_ptr_to_narrowoop = UseCompressedOops; } else { // exclude unsafe ops assert(this->isa_instptr(), "must be an instance ptr."); - if (klass() == ciEnv::current()->Class_klass() && - (_offset == java_lang_Class::klass_offset_in_bytes() || - _offset == java_lang_Class::array_klass_offset_in_bytes())) { + (this->offset() == java_lang_Class::klass_offset_in_bytes() || + this->offset() == java_lang_Class::array_klass_offset_in_bytes())) { // Special hidden fields from the Class. assert(this->isa_instptr(), "must be an instance ptr."); _is_ptr_to_narrowoop = false; } else if (klass() == ciEnv::current()->Class_klass() && - _offset >= InstanceMirrorKlass::offset_of_static_fields()) { + this->offset() >= InstanceMirrorKlass::offset_of_static_fields()) { // Static fields assert(o != NULL, "must be constant"); - ciInstanceKlass* k = o->as_instance()->java_lang_Class_klass()->as_instance_klass(); - ciField* field = k->get_field_by_offset(_offset, true); - assert(field != NULL, "missing field"); - BasicType basic_elem_type = field->layout_type(); + ciInstanceKlass* ik = o->as_instance()->java_lang_Class_klass()->as_instance_klass(); + BasicType basic_elem_type; + if (ik->is_valuetype() && this->offset() == ik->as_value_klass()->default_value_offset()) { + // Special hidden field that contains the oop of the default value type + basic_elem_type = T_VALUETYPE; + } else { + ciField* field = ik->get_field_by_offset(this->offset(), true); + assert(field != NULL, "missing field"); + basic_elem_type = field->layout_type(); + } _is_ptr_to_narrowoop = UseCompressedOops && (basic_elem_type == T_OBJECT || + basic_elem_type == T_VALUETYPE || basic_elem_type == T_ARRAY); } else { // Instance fields which contains a compressed oop references. - field = ik->get_field_by_offset(_offset, false); + ciInstanceKlass* ik = klass()->as_instance_klass(); + ciField* field = ik->get_field_by_offset(this->offset(), false); if (field != NULL) { BasicType basic_elem_type = field->layout_type(); _is_ptr_to_narrowoop = UseCompressedOops && (basic_elem_type == T_OBJECT || + basic_elem_type == T_VALUETYPE || basic_elem_type == T_ARRAY); } else if (klass()->equals(ciEnv::current()->Object_klass())) { // Compile::find_alias_type() cast exactness on all types to verify @@ -3040,13 +3290,13 @@ } //------------------------------make------------------------------------------- -const TypeOopPtr *TypeOopPtr::make(PTR ptr, int offset, int instance_id, - const TypePtr* speculative, int inline_depth) { +const TypeOopPtr *TypeOopPtr::make(PTR ptr, Offset offset, int instance_id, + const TypePtr* speculative, int inline_depth) { assert(ptr != Constant, "no constant generic pointers"); ciKlass* k = Compile::current()->env()->Object_klass(); bool xk = false; ciObject* o = NULL; - return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, instance_id, speculative, inline_depth))->hashcons(); + return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, Offset::bottom, instance_id, speculative, inline_depth))->hashcons(); } @@ -3085,7 +3335,7 @@ if (k == NULL) return TypeKlassPtr::OBJECT; else - return TypeKlassPtr::make(xk? Constant: NotNull, k, 0); + return TypeKlassPtr::make(xk? Constant: NotNull, k, Offset(0)); } //------------------------------meet------------------------------------------- @@ -3123,7 +3373,7 @@ case AnyPtr: { // Found an AnyPtr type vs self-OopPtr type const TypePtr *tp = t->is_ptr(); - int offset = meet_offset(tp->offset()); + Offset offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); @@ -3165,13 +3415,13 @@ const Type *TypeOopPtr::xdual() const { assert(klass() == Compile::current()->env()->Object_klass(), "no klasses here"); assert(const_oop() == NULL, "no constants here"); - return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth()); + return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), Offset::bottom, dual_instance_id(), dual_speculative(), dual_inline_depth()); } //--------------------------make_from_klass_common----------------------------- // Computes the element-type given a klass. const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_change, bool try_for_exact) { - if (klass->is_instance_klass()) { + if (klass->is_instance_klass() || klass->is_valuetype()) { Compile* C = Compile::current(); Dependencies* deps = C->dependencies(); assert((deps != NULL) == (C->method() != NULL && C->method()->code_size() > 0), "sanity"); @@ -3199,16 +3449,16 @@ } } } - return TypeInstPtr::make(TypePtr::BotPTR, klass, klass_is_exact, NULL, 0); + return TypeInstPtr::make(TypePtr::BotPTR, klass, klass_is_exact, NULL, Offset(0)); } else if (klass->is_obj_array_klass()) { - // Element is an object array. Recursively call ourself. - const TypeOopPtr *etype = TypeOopPtr::make_from_klass_common(klass->as_obj_array_klass()->element_klass(), false, try_for_exact); + // Element is an object or value array. Recursively call ourself. + const TypeOopPtr* etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), false, try_for_exact); bool xk = etype->klass_is_exact(); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS); // We used to pass NotNull in here, asserting that the sub-arrays // are all not-null. This is not true in generally, as code can // slam NULLs down in the subarrays. - const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, xk, 0); + const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, xk, Offset(0)); return arr; } else if (klass->is_type_array_klass()) { // Element is an typeArray @@ -3216,7 +3466,12 @@ const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS); // We used to pass NotNull in here, asserting that the array pointer // is not-null. That was not true in general. - const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, 0); + const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, Offset(0)); + return arr; + } else if (klass->is_value_array_klass()) { + ciValueKlass* vk = klass->as_array_klass()->element_klass()->as_value_klass(); + const TypeAry* arr0 = TypeAry::make(TypeValueType::make(vk), TypeInt::POS); + const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, Offset(0)); return arr; } else { ShouldNotReachHere(); @@ -3229,18 +3484,18 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_constant) { assert(!o->is_null_object(), "null object not yet handled here."); ciKlass* klass = o->klass(); - if (klass->is_instance_klass()) { - // Element is an instance + if (klass->is_instance_klass() || klass->is_valuetype()) { + // Element is an instance or value type if (require_constant) { if (!o->can_be_constant()) return NULL; } else if (!o->should_be_constant()) { - return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, 0); + return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, Offset(0)); } return TypeInstPtr::make(o); } else if (klass->is_obj_array_klass()) { // Element is an object array. Recursively call ourself. const TypeOopPtr *etype = - TypeOopPtr::make_from_klass_raw(klass->as_obj_array_klass()->element_klass()); + TypeOopPtr::make_from_klass_raw(klass->as_array_klass()->element_klass()); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length())); // We used to pass NotNull in here, asserting that the sub-arrays // are all not-null. This is not true in generally, as code can @@ -3248,9 +3503,9 @@ if (require_constant) { if (!o->can_be_constant()) return NULL; } else if (!o->should_be_constant()) { - return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0); + return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0)); } - const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0); + const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, Offset(0)); return arr; } else if (klass->is_type_array_klass()) { // Element is an typeArray @@ -3262,9 +3517,22 @@ if (require_constant) { if (!o->can_be_constant()) return NULL; } else if (!o->should_be_constant()) { - return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0); + return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0)); } - const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0); + const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, Offset(0)); + return arr; + } else if (klass->is_value_array_klass()) { + ciValueKlass* vk = klass->as_array_klass()->element_klass()->as_value_klass(); + const TypeAry* arr0 = TypeAry::make(TypeValueType::make(vk), TypeInt::make(o->as_array()->length())); + // We used to pass NotNull in here, asserting that the sub-arrays + // are all not-null. This is not true in generally, as code can + // slam NULLs down in the subarrays. + if (require_constant) { + if (!o->can_be_constant()) return NULL; + } else if (!o->should_be_constant()) { + return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0)); + } + const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, Offset(0)); return arr; } @@ -3275,9 +3543,9 @@ //------------------------------get_con---------------------------------------- intptr_t TypeOopPtr::get_con() const { assert( _ptr == Null || _ptr == Constant, "" ); - assert( _offset >= 0, "" ); + assert(offset() >= 0, ""); - if (_offset != 0) { + if (offset() != 0) { // After being ported to the compiler interface, the compiler no longer // directly manipulates the addresses of oops. Rather, it only has a pointer // to a handle at compile time. This handle is embedded in the generated @@ -3370,12 +3638,7 @@ st->print("oopptr:%s", ptr_msg[_ptr]); if( _klass_is_exact ) st->print(":exact"); if( const_oop() ) st->print(INTPTR_FORMAT, p2i(const_oop())); - switch( _offset ) { - case OffsetTop: st->print("+top"); break; - case OffsetBot: st->print("+any"); break; - case 0: break; - default: st->print("+%d",_offset); break; - } + _offset.dump2(st); if (_instance_id == InstanceTop) st->print(",iid=top"); else if (_instance_id != InstanceBot) @@ -3392,7 +3655,7 @@ bool TypeOopPtr::singleton(void) const { // detune optimizer to not generate constant oop + constant offset as a constant! // TopPTR, Null, AnyNull, Constant are all singletons - return (_offset == 0) && !below_centerline(_ptr); + return (offset() == 0) && !below_centerline(_ptr); } //------------------------------add_offset------------------------------------- @@ -3484,9 +3747,9 @@ const TypeInstPtr *TypeInstPtr::KLASS; //------------------------------TypeInstPtr------------------------------------- -TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, +TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, Offset off, int instance_id, const TypePtr* speculative, int inline_depth) - : TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative, inline_depth), + : TypeOopPtr(InstPtr, ptr, k, xk, o, off, Offset::bottom, instance_id, speculative, inline_depth), _name(k->name()) { assert(k != NULL && (k->is_loaded() || o == NULL), @@ -3498,7 +3761,7 @@ ciKlass* k, bool xk, ciObject* o, - int offset, + Offset offset, int instance_id, const TypePtr* speculative, int inline_depth) { @@ -3585,7 +3848,7 @@ // Compute the MEET of two InstPtrs when at least one is unloaded. // Assume classes are different since called after check for same name/class-loader const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const { - int off = meet_offset(tinst->offset()); + Offset off = meet_offset(tinst->offset()); PTR ptr = meet_ptr(tinst->ptr()); int instance_id = meet_instance_id(tinst->instance_id()); const TypePtr* speculative = xmeet_speculative(tinst); @@ -3663,7 +3926,7 @@ case AryPtr: { // All arrays inherit from Object class const TypeAryPtr *tp = t->is_aryptr(); - int offset = meet_offset(tp->offset()); + Offset offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(tp->instance_id()); const TypePtr* speculative = xmeet_speculative(tp); @@ -3675,7 +3938,7 @@ // below the centerline when the superclass is exact. We need to // do the same here. if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) { - return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative, depth); + return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, tp->field_offset(), instance_id, speculative, depth); } else { // cannot subclass, so the meet has to fall badly below the centerline ptr = NotNull; @@ -3695,7 +3958,7 @@ if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) { // that is, tp's array type is a subtype of my klass return TypeAryPtr::make(ptr, (ptr == Constant ? tp->const_oop() : NULL), - tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative, depth); + tp->ary(), tp->klass(), tp->klass_is_exact(), offset, tp->field_offset(), instance_id, speculative, depth); } } // The other case cannot happen, since I cannot be a subtype of an array. @@ -3711,7 +3974,7 @@ case OopPtr: { // Meeting to OopPtrs // Found a OopPtr type vs self-InstPtr type const TypeOopPtr *tp = t->is_oopptr(); - int offset = meet_offset(tp->offset()); + Offset offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); switch (tp->ptr()) { case TopPTR: @@ -3736,7 +3999,7 @@ case AnyPtr: { // Meeting to AnyPtrs // Found an AnyPtr type vs self-InstPtr type const TypePtr *tp = t->is_ptr(); - int offset = meet_offset(tp->offset()); + Offset offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(InstanceTop); const TypePtr* speculative = xmeet_speculative(tp); @@ -3776,7 +4039,7 @@ case InstPtr: { // Meeting 2 Oops? // Found an InstPtr sub-type vs self-InstPtr type const TypeInstPtr *tinst = t->is_instptr(); - int off = meet_offset( tinst->offset() ); + Offset off = meet_offset( tinst->offset() ); PTR ptr = meet_ptr( tinst->ptr() ); int instance_id = meet_instance_id(tinst->instance_id()); const TypePtr* speculative = xmeet_speculative(tinst); @@ -3943,6 +4206,24 @@ return make(ptr, k, false, NULL, off, instance_id, speculative, depth); } // End of case InstPtr + case ValueType: { + const TypeValueType *tv = t->is_valuetype(); + + if (above_centerline(ptr())) { + if (tv->value_klass()->is_subtype_of(_klass)) { + return t; + } else { + return TypeInstPtr::make(NotNull, _klass); + } + } else { + if (tv->value_klass()->is_subtype_of(_klass)) { + return TypeInstPtr::make(ptr(), _klass); + } else { + return TypeInstPtr::make(ptr(), ciEnv::current()->Object_klass()); + } + } + } + } // End of switch return this; // Return the double constant } @@ -4011,11 +4292,7 @@ break; } - if( _offset ) { // Dump offset, if any - if( _offset == OffsetBot ) st->print("+any"); - else if( _offset == OffsetTop ) st->print("+unknown"); - else st->print("+%d", _offset); - } + _offset.dump2(st); st->print(" *"); if (_instance_id == InstanceTop) @@ -4069,18 +4346,18 @@ const TypeAryPtr *TypeAryPtr::DOUBLES; //------------------------------make------------------------------------------- -const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, +const TypeAryPtr* TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, Offset offset, Offset field_offset, int instance_id, const TypePtr* speculative, int inline_depth) { assert(!(k == NULL && ary->_elem->isa_int()), "integral arrays must be pre-equipped with a class"); if (!xk) xk = ary->ary_must_be_exact(); assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed"); if (!UseExactTypes) xk = (ptr == Constant); - return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id, false, speculative, inline_depth))->hashcons(); + return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, field_offset, instance_id, false, speculative, inline_depth))->hashcons(); } //------------------------------make------------------------------------------- -const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, +const TypeAryPtr* TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, Offset offset, Offset field_offset, int instance_id, const TypePtr* speculative, int inline_depth, bool is_autobox_cache) { assert(!(k == NULL && ary->_elem->isa_int()), @@ -4089,13 +4366,13 @@ if (!xk) xk = (o != NULL) || ary->ary_must_be_exact(); assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed"); if (!UseExactTypes) xk = (ptr == Constant); - return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache, speculative, inline_depth))->hashcons(); + return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, field_offset, instance_id, is_autobox_cache, speculative, inline_depth))->hashcons(); } //------------------------------cast_to_ptr_type------------------------------- const Type *TypeAryPtr::cast_to_ptr_type(PTR ptr) const { if( ptr == _ptr ) return this; - return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth); + return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); } @@ -4104,18 +4381,18 @@ if( klass_is_exact == _klass_is_exact ) return this; if (!UseExactTypes) return this; if (_ary->ary_must_be_exact()) return this; // cannot clear xk - return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id, _speculative, _inline_depth); + return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); } //-----------------------------cast_to_instance_id---------------------------- const TypeOopPtr *TypeAryPtr::cast_to_instance_id(int instance_id) const { if( instance_id == _instance_id ) return this; - return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id, _speculative, _inline_depth); + return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, _field_offset, instance_id, _speculative, _inline_depth, _is_autobox_cache); } const TypeOopPtr *TypeAryPtr::cast_to_nonconst() const { if (const_oop() == NULL) return this; - return make(NotNull, NULL, _ary, klass(), _klass_is_exact, _offset, _instance_id, _speculative, _inline_depth); + return make(NotNull, NULL, _ary, klass(), _klass_is_exact, _offset, _field_offset, _instance_id, _speculative, _inline_depth); } @@ -4182,7 +4459,7 @@ new_size = narrow_size_type(new_size); if (new_size == size()) return this; const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable()); - return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth); + return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); } //------------------------------cast_to_stable--------------------------------- @@ -4200,7 +4477,7 @@ const TypeAry* new_ary = TypeAry::make(elem, size(), stable); - return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth); + return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); } //-----------------------------stable_dimension-------------------------------- @@ -4222,7 +4499,7 @@ TypePtr::PTR ptr_type = cache ? TypePtr::NotNull : TypePtr::AnyNull; etype = etype->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr(); const TypeAry* new_ary = TypeAry::make(etype, size(), is_stable()); - return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth, cache); + return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, cache); } //------------------------------eq--------------------------------------------- @@ -4231,13 +4508,14 @@ const TypeAryPtr *p = t->is_aryptr(); return _ary == p->_ary && // Check array - TypeOopPtr::eq(p); // Check sub-parts + TypeOopPtr::eq(p) &&// Check sub-parts + _field_offset == p->_field_offset; } //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypeAryPtr::hash(void) const { - return (intptr_t)_ary + TypeOopPtr::hash(); + return (intptr_t)_ary + TypeOopPtr::hash() + _field_offset.get(); } //------------------------------meet------------------------------------------- @@ -4270,7 +4548,7 @@ case OopPtr: { // Meeting to OopPtrs // Found a OopPtr type vs self-AryPtr type const TypeOopPtr *tp = t->is_oopptr(); - int offset = meet_offset(tp->offset()); + Offset offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int depth = meet_inline_depth(tp->inline_depth()); const TypePtr* speculative = xmeet_speculative(tp); @@ -4279,7 +4557,7 @@ case AnyNull: { int instance_id = meet_instance_id(InstanceTop); return make(ptr, (ptr == Constant ? const_oop() : NULL), - _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth); + _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth); } case BotPTR: case NotNull: { @@ -4293,7 +4571,7 @@ case AnyPtr: { // Meeting two AnyPtrs // Found an AnyPtr type vs self-AryPtr type const TypePtr *tp = t->is_ptr(); - int offset = meet_offset(tp->offset()); + Offset offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); @@ -4309,7 +4587,7 @@ case AnyNull: { int instance_id = meet_instance_id(InstanceTop); return make(ptr, (ptr == Constant ? const_oop() : NULL), - _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth); + _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth); } default: ShouldNotReachHere(); } @@ -4321,7 +4599,8 @@ case AryPtr: { // Meeting 2 references? const TypeAryPtr *tap = t->is_aryptr(); - int off = meet_offset(tap->offset()); + Offset off = meet_offset(tap->offset()); + Offset field_off = meet_field_offset(tap->field_offset()); const TypeAry *tary = _ary->meet_speculative(tap->_ary)->is_ary(); PTR ptr = meet_ptr(tap->ptr()); int instance_id = meet_instance_id(tap->instance_id()); @@ -4356,7 +4635,7 @@ if (above_centerline(ptr)) { tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); } - return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot, speculative, depth); + return make(NotNull, NULL, tary, lazy_klass, false, off, field_off, InstanceBot, speculative, depth); } bool xk = false; @@ -4369,7 +4648,7 @@ } else { xk = (tap->_klass_is_exact | this->_klass_is_exact); } - return make(ptr, const_oop(), tary, lazy_klass, xk, off, instance_id, speculative, depth); + return make(ptr, const_oop(), tary, lazy_klass, xk, off, field_off, instance_id, speculative, depth); case Constant: { ciObject* o = const_oop(); if( _ptr == Constant ) { @@ -4388,7 +4667,7 @@ // Only precise for identical arrays xk = this->_klass_is_exact && (klass() == tap->klass()); } - return TypeAryPtr::make(ptr, o, tary, lazy_klass, xk, off, instance_id, speculative, depth); + return TypeAryPtr::make(ptr, o, tary, lazy_klass, xk, off, field_off, instance_id, speculative, depth); } case NotNull: case BotPTR: @@ -4397,7 +4676,7 @@ xk = tap->_klass_is_exact; else xk = (tap->_klass_is_exact & this->_klass_is_exact) && (klass() == tap->klass()); // Only precise for identical arrays - return TypeAryPtr::make(ptr, NULL, tary, lazy_klass, xk, off, instance_id, speculative, depth); + return TypeAryPtr::make(ptr, NULL, tary, lazy_klass, xk, off, field_off, instance_id, speculative, depth); default: ShouldNotReachHere(); } } @@ -4405,7 +4684,7 @@ // All arrays inherit from Object class case InstPtr: { const TypeInstPtr *tp = t->is_instptr(); - int offset = meet_offset(tp->offset()); + Offset offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(tp->instance_id()); const TypePtr* speculative = xmeet_speculative(tp); @@ -4417,12 +4696,12 @@ // below the centerline when the superclass is exact. We need to // do the same here. if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) { - return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth); + return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth); } else { // cannot subclass, so the meet has to fall badly below the centerline ptr = NotNull; instance_id = InstanceBot; - return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative, depth); + return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative, depth); } case Constant: case NotNull: @@ -4437,7 +4716,7 @@ if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) { // that is, my array type is a subtype of 'tp' klass return make(ptr, (ptr == Constant ? const_oop() : NULL), - _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth); + _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth); } } // The other case cannot happen, since t cannot be a subtype of an array. @@ -4449,6 +4728,12 @@ default: typerr(t); } } + + case ValueType: { + // All value types inherit from Object + return TypeInstPtr::make(ptr(), ciEnv::current()->Object_klass()); + } + } return this; // Lint noise } @@ -4456,7 +4741,16 @@ //------------------------------xdual------------------------------------------ // Dual: compute field-by-field dual const Type *TypeAryPtr::xdual() const { - return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative(), dual_inline_depth()); + return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(), _klass, _klass_is_exact, dual_offset(), dual_field_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative(), dual_inline_depth()); +} + +Type::Offset TypeAryPtr::meet_field_offset(const Type::Offset offset) const { + return _field_offset.meet(offset); +} + +//------------------------------dual_offset------------------------------------ +Type::Offset TypeAryPtr::dual_field_offset() const { + return _field_offset.dual(); } //----------------------interface_vs_oop--------------------------------------- @@ -4493,16 +4787,21 @@ break; } - if( _offset != 0 ) { + if (elem()->isa_valuetype()) { + st->print("("); + _field_offset.dump2(st); + st->print(")"); + } + if (offset() != 0) { int header_size = objArrayOopDesc::header_size() * wordSize; - if( _offset == OffsetTop ) st->print("+undefined"); - else if( _offset == OffsetBot ) st->print("+any"); - else if( _offset < header_size ) st->print("+%d", _offset); + if( _offset == Offset::top ) st->print("+undefined"); + else if( _offset == Offset::bottom ) st->print("+any"); + else if( offset() < header_size ) st->print("+%d", offset()); else { BasicType basic_elem_type = elem()->basic_type(); int array_base = arrayOopDesc::base_offset_in_bytes(basic_elem_type); int elem_size = type2aelembytes(basic_elem_type); - st->print("[%d]", (_offset - array_base)/elem_size); + st->print("[%d]", (offset() - array_base)/elem_size); } } st->print(" *"); @@ -4523,7 +4822,7 @@ //------------------------------add_offset------------------------------------- const TypePtr *TypeAryPtr::add_offset(intptr_t offset) const { - return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id, add_offset_speculative(offset), _inline_depth); + return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _field_offset, _instance_id, add_offset_speculative(offset), _inline_depth, _is_autobox_cache); } const Type *TypeAryPtr::remove_speculative() const { @@ -4531,23 +4830,75 @@ return this; } assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth"); - return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, NULL, _inline_depth); + return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _field_offset, _instance_id, NULL, _inline_depth, _is_autobox_cache); } const TypePtr *TypeAryPtr::with_inline_depth(int depth) const { if (!UseInlineDepthForSpeculativeTypes) { return this; } - return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, _speculative, depth); + return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _field_offset, _instance_id, _speculative, depth, _is_autobox_cache); +} + +const TypeAryPtr* TypeAryPtr::with_field_offset(int offset) const { + return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, Offset(offset), _instance_id, _speculative, _inline_depth, _is_autobox_cache); +} + +const TypePtr* TypeAryPtr::add_field_offset_and_offset(intptr_t offset) const { + int adj = 0; + if (offset != Type::OffsetBot && offset != Type::OffsetTop) { + const Type* elemtype = elem(); + if (elemtype->isa_valuetype()) { + if (_offset.get() != OffsetBot && _offset.get() != OffsetTop) { + adj = _offset.get(); + offset += _offset.get(); + } + uint header = arrayOopDesc::base_offset_in_bytes(T_OBJECT); + if (_field_offset.get() != OffsetBot && _field_offset.get() != OffsetTop) { + offset += _field_offset.get(); + if (_offset.get() == OffsetBot || _offset.get() == OffsetTop) { + offset += header; + } + } + if (offset >= (intptr_t)header || offset < 0) { + // Try to get the field of the value type array element we are pointing to + ciKlass* arytype_klass = klass(); + ciValueArrayKlass* vak = arytype_klass->as_value_array_klass(); + ciValueKlass* vk = vak->element_klass()->as_value_klass(); + int shift = vak->log2_element_size(); + int mask = (1 << shift) - 1; + intptr_t field_offset = ((offset - header) & mask); + ciField* field = vk->get_field_by_offset(field_offset + vk->first_field_offset(), false); + if (field == NULL) { + // This may happen with nested AddP(base, AddP(base, base, offset), longcon(16)) + return add_offset(offset); + } else { + return with_field_offset(field_offset)->add_offset(offset - field_offset - adj); + } + } + } + } + return add_offset(offset - adj); +} + +// Return offset incremented by field_offset for flattened value type arrays +const int TypeAryPtr::flattened_offset() const { + int offset = _offset.get(); + if (offset != Type::OffsetBot && offset != Type::OffsetTop && + _field_offset != Offset::bottom && _field_offset != Offset::top) { + offset += _field_offset.get(); + } + return offset; } const TypePtr *TypeAryPtr::with_instance_id(int instance_id) const { assert(is_known_instance(), "should be known"); - return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, instance_id, _speculative, _inline_depth); + return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _field_offset, instance_id, _speculative, _inline_depth); } //============================================================================= + //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypeNarrowPtr::hash(void) const { @@ -4636,12 +4987,14 @@ case KlassPtr: case NarrowOop: case NarrowKlass: - case Bottom: // Ye Olde Default return Type::BOTTOM; case Top: return this; + case ValueType: + return t->xmeet(this); + default: // All else is a mistake typerr(t); @@ -4720,7 +5073,7 @@ bool TypeMetadataPtr::singleton(void) const { // detune optimizer to not generate constant metadata + constant offset as a constant! // TopPTR, Null, AnyNull, Constant are all singletons - return (_offset == 0) && !below_centerline(_ptr); + return (offset() == 0) && !below_centerline(_ptr); } //------------------------------add_offset------------------------------------- @@ -4740,9 +5093,9 @@ //------------------------------get_con---------------------------------------- intptr_t TypeMetadataPtr::get_con() const { assert( _ptr == Null || _ptr == Constant, "" ); - assert( _offset >= 0, "" ); + assert(offset() >= 0, ""); - if (_offset != 0) { + if (offset() != 0) { // After being ported to the compiler interface, the compiler no longer // directly manipulates the addresses of oops. Rather, it only has a pointer // to a handle at compile time. This handle is embedded in the generated @@ -4793,7 +5146,7 @@ case AnyPtr: { // Found an AnyPtr type vs self-OopPtr type const TypePtr *tp = t->is_ptr(); - int offset = meet_offset(tp->offset()); + Offset offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); switch (tp->ptr()) { case Null: @@ -4819,7 +5172,7 @@ case MetadataPtr: { const TypeMetadataPtr *tp = t->is_metadataptr(); - int offset = meet_offset(tp->offset()); + Offset offset = meet_offset(tp->offset()); PTR tptr = tp->ptr(); PTR ptr = meet_ptr(tptr); ciMetadata* md = (tptr == TopPTR) ? metadata() : tp->metadata(); @@ -4852,11 +5205,11 @@ void TypeMetadataPtr::dump2( Dict &d, uint depth, outputStream *st ) const { st->print("metadataptr:%s", ptr_msg[_ptr]); if( metadata() ) st->print(INTPTR_FORMAT, p2i(metadata())); - switch( _offset ) { + switch (offset()) { case OffsetTop: st->print("+top"); break; case OffsetBot: st->print("+any"); break; case 0: break; - default: st->print("+%d",_offset); break; + default: st->print("+%d",offset()); break; } } #endif @@ -4866,20 +5219,20 @@ // Convenience common pre-built type. const TypeMetadataPtr *TypeMetadataPtr::BOTTOM; -TypeMetadataPtr::TypeMetadataPtr(PTR ptr, ciMetadata* metadata, int offset): +TypeMetadataPtr::TypeMetadataPtr(PTR ptr, ciMetadata* metadata, Offset offset): TypePtr(MetadataPtr, ptr, offset), _metadata(metadata) { } const TypeMetadataPtr* TypeMetadataPtr::make(ciMethod* m) { - return make(Constant, m, 0); + return make(Constant, m, Offset(0)); } const TypeMetadataPtr* TypeMetadataPtr::make(ciMethodData* m) { - return make(Constant, m, 0); + return make(Constant, m, Offset(0)); } //------------------------------make------------------------------------------- // Create a meta data constant -const TypeMetadataPtr *TypeMetadataPtr::make(PTR ptr, ciMetadata* m, int offset) { +const TypeMetadataPtr* TypeMetadataPtr::make(PTR ptr, ciMetadata* m, Offset offset) { assert(m == NULL || !m->is_klass(), "wrong type"); return (TypeMetadataPtr*)(new TypeMetadataPtr(ptr, m, offset))->hashcons(); } @@ -4893,34 +5246,28 @@ const TypeKlassPtr *TypeKlassPtr::OBJECT_OR_NULL; //------------------------------TypeKlassPtr----------------------------------- -TypeKlassPtr::TypeKlassPtr( PTR ptr, ciKlass* klass, int offset ) +TypeKlassPtr::TypeKlassPtr( PTR ptr, ciKlass* klass, Offset offset ) : TypePtr(KlassPtr, ptr, offset), _klass(klass), _klass_is_exact(ptr == Constant) { } //------------------------------make------------------------------------------- // ptr to klass 'k', if Constant, or possibly to a sub-klass if not a Constant -const TypeKlassPtr *TypeKlassPtr::make( PTR ptr, ciKlass* k, int offset ) { - assert( k != NULL, "Expect a non-NULL klass"); - assert(k->is_instance_klass() || k->is_array_klass(), "Incorrect type of klass oop"); - TypeKlassPtr *r = - (TypeKlassPtr*)(new TypeKlassPtr(ptr, k, offset))->hashcons(); - - return r; +const TypeKlassPtr* TypeKlassPtr::make(PTR ptr, ciKlass* k, Offset offset) { + assert(k == NULL || k->is_instance_klass() || k->is_array_klass(), "Incorrect type of klass oop"); + return (TypeKlassPtr*)(new TypeKlassPtr(ptr, k, offset))->hashcons(); } //------------------------------eq--------------------------------------------- // Structural equality check for Type representations bool TypeKlassPtr::eq( const Type *t ) const { const TypeKlassPtr *p = t->is_klassptr(); - return - klass()->equals(p->klass()) && - TypePtr::eq(p); + return klass() == p->klass() && TypePtr::eq(p); } //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypeKlassPtr::hash(void) const { - return java_add((jint)klass()->hash(), (jint)TypePtr::hash()); + return java_add(klass() != NULL ? klass()->hash() : (jint)0, (jint)TypePtr::hash()); } //------------------------------singleton-------------------------------------- @@ -4929,7 +5276,7 @@ bool TypeKlassPtr::singleton(void) const { // detune optimizer to not generate constant klass + constant offset as a constant! // TopPTR, Null, AnyNull, Constant are all singletons - return (_offset == 0) && !below_centerline(_ptr); + return (offset() == 0) && !below_centerline(_ptr); } // Do not allow interface-vs.-noninterface joins to collapse to top. @@ -4941,7 +5288,7 @@ const TypeKlassPtr* ktkp = kills->isa_klassptr(); if (ft->empty()) { - if (!empty() && ktkp != NULL && ktkp->klass()->is_loaded() && ktkp->klass()->is_interface()) + if (!empty() && ktkp != NULL && ktkp->is_loaded() && ktkp->klass()->is_interface()) return kills; // Uplift to interface return Type::TOP; // Canonical empty value @@ -4964,7 +5311,6 @@ ciKlass* TypeAryPtr::compute_klass(DEBUG_ONLY(bool verify)) const { // Compute _klass based on element type. ciKlass* k_ary = NULL; - const TypeInstPtr *tinst; const TypeAryPtr *tary; const Type* el = elem(); if (el->isa_narrowoop()) { @@ -4972,9 +5318,11 @@ } // Get element klass - if ((tinst = el->isa_instptr()) != NULL) { - // Compute array klass from element klass - k_ary = ciObjArrayKlass::make(tinst->klass()); + if (el->isa_instptr()) { + // Compute object array klass from element klass + k_ary = ciArrayKlass::make(el->is_oopptr()->klass()); + } else if (el->isa_valuetype()) { + k_ary = ciArrayKlass::make(el->is_valuetype()->value_klass()); } else if ((tary = el->isa_aryptr()) != NULL) { // Compute array klass from element klass ciKlass* k_elem = tary->klass(); @@ -5039,7 +5387,7 @@ // TypeAryPtr::OOPS->klass() are not common enough to matter. ((TypeAryPtr*)this)->_klass = k_ary; if (UseCompressedOops && k_ary != NULL && k_ary->is_obj_array_klass() && - _offset != 0 && _offset != arrayOopDesc::length_offset_in_bytes()) { + offset() != 0 && offset() != arrayOopDesc::length_offset_in_bytes()) { ((TypeAryPtr*)this)->_is_ptr_to_narrowoop = true; } } @@ -5074,6 +5422,7 @@ // It will be NotNull, and exact if and only if the klass type is exact. const TypeOopPtr* TypeKlassPtr::as_instance_type() const { ciKlass* k = klass(); + assert(k != NULL, "klass should not be NULL"); bool xk = klass_is_exact(); //return TypeInstPtr::make(TypePtr::NotNull, k, xk, NULL, 0); const TypeOopPtr* toop = TypeOopPtr::make_from_klass_raw(k); @@ -5113,7 +5462,7 @@ case AnyPtr: { // Meeting to AnyPtrs // Found an AnyPtr type vs self-KlassPtr type const TypePtr *tp = t->is_ptr(); - int offset = meet_offset(tp->offset()); + Offset offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); switch (tp->ptr()) { case TopPTR: @@ -5154,9 +5503,17 @@ case KlassPtr: { // Meet two KlassPtr types const TypeKlassPtr *tkls = t->is_klassptr(); - int off = meet_offset(tkls->offset()); + Offset off = meet_offset(tkls->offset()); PTR ptr = meet_ptr(tkls->ptr()); + if (klass() == NULL || tkls->klass() == NULL) { + ciKlass* k = NULL; + if (ptr == Constant) { + k = (klass() == NULL) ? tkls->klass() : klass(); + } + return make(ptr, k, off); + } + // Check for easy case; klasses are equal (and perhaps not loaded!) // If we have constants, then we created oops so classes are loaded // and we can handle the constants further down. This case handles @@ -5222,9 +5579,9 @@ //------------------------------get_con---------------------------------------- intptr_t TypeKlassPtr::get_con() const { assert( _ptr == Null || _ptr == Constant, "" ); - assert( _offset >= 0, "" ); + assert(offset() >= 0, ""); - if (_offset != 0) { + if (offset() != 0) { // After being ported to the compiler interface, the compiler no longer // directly manipulates the addresses of oops. Rather, it only has a pointer // to a handle at compile time. This handle is embedded in the generated @@ -5247,11 +5604,11 @@ st->print("precise "); case NotNull: { - const char *name = klass()->name()->as_utf8(); - if( name ) { + if (klass() != NULL) { + const char* name = klass()->name()->as_utf8(); st->print("klass %s: " INTPTR_FORMAT, name, p2i(klass())); } else { - ShouldNotReachHere(); + st->print("klass BOTTOM"); } } case BotPTR: @@ -5265,11 +5622,7 @@ break; } - if( _offset ) { // Dump offset, if any - if( _offset == OffsetBot ) { st->print("+any"); } - else if( _offset == OffsetTop ) { st->print("+unknown"); } - else { st->print("+%d", _offset); } - } + _offset.dump2(st); st->print(" *"); } @@ -5281,8 +5634,13 @@ // Convenience common pre-built types. //------------------------------make------------------------------------------- -const TypeFunc *TypeFunc::make( const TypeTuple *domain, const TypeTuple *range ) { - return (TypeFunc*)(new TypeFunc(domain,range))->hashcons(); +const TypeFunc *TypeFunc::make(const TypeTuple *domain_sig, const TypeTuple* domain_cc, + const TypeTuple *range_sig, const TypeTuple *range_cc) { + return (TypeFunc*)(new TypeFunc(domain_sig, domain_cc, range_sig, range_cc))->hashcons(); +} + +const TypeFunc *TypeFunc::make(const TypeTuple *domain, const TypeTuple *range) { + return make(domain, domain, range, range); } //------------------------------make------------------------------------------- @@ -5290,14 +5648,16 @@ Compile* C = Compile::current(); const TypeFunc* tf = C->last_tf(method); // check cache if (tf != NULL) return tf; // The hit rate here is almost 50%. - const TypeTuple *domain; - if (method->is_static()) { - domain = TypeTuple::make_domain(NULL, method->signature()); - } else { - domain = TypeTuple::make_domain(method->holder(), method->signature()); - } - const TypeTuple *range = TypeTuple::make_range(method->signature()); - tf = TypeFunc::make(domain, range); + // Value types are not passed/returned by reference, instead each field of + // the value type is passed/returned as an argument. We maintain two views of + // the argument/return list here: one based on the signature (with a value + // type argument/return as a single slot), one based on the actual calling + // convention (with a value type argument/return as a list of its fields). + const TypeTuple* domain_sig = TypeTuple::make_domain(method, false); + const TypeTuple* domain_cc = TypeTuple::make_domain(method, method->has_scalarized_args()); + const TypeTuple* range_sig = TypeTuple::make_range(method->signature(), false); + const TypeTuple* range_cc = TypeTuple::make_range(method->signature(), ValueTypeReturnedAsFields); + tf = TypeFunc::make(domain_sig, domain_cc, range_sig, range_cc); C->set_last_tf(method, tf); // fill cache return tf; } @@ -5333,29 +5693,31 @@ // Structural equality check for Type representations bool TypeFunc::eq( const Type *t ) const { const TypeFunc *a = (const TypeFunc*)t; - return _domain == a->_domain && - _range == a->_range; + return _domain_sig == a->_domain_sig && + _domain_cc == a->_domain_cc && + _range_sig == a->_range_sig && + _range_cc == a->_range_cc; } //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypeFunc::hash(void) const { - return (intptr_t)_domain + (intptr_t)_range; + return (intptr_t)_domain_sig + (intptr_t)_domain_cc + (intptr_t)_range_sig + (intptr_t)_range_cc; } //------------------------------dump2------------------------------------------ // Dump Function Type #ifndef PRODUCT void TypeFunc::dump2( Dict &d, uint depth, outputStream *st ) const { - if( _range->cnt() <= Parms ) + if( _range_sig->cnt() <= Parms ) st->print("void"); else { uint i; - for (i = Parms; i < _range->cnt()-1; i++) { - _range->field_at(i)->dump2(d,depth,st); + for (i = Parms; i < _range_sig->cnt()-1; i++) { + _range_sig->field_at(i)->dump2(d,depth,st); st->print("/"); } - _range->field_at(i)->dump2(d,depth,st); + _range_sig->field_at(i)->dump2(d,depth,st); } st->print(" "); st->print("( "); @@ -5364,11 +5726,11 @@ return; } d.Insert((void*)this,(void*)this); // Stop recursion - if (Parms < _domain->cnt()) - _domain->field_at(Parms)->dump2(d,depth-1,st); - for (uint i = Parms+1; i < _domain->cnt(); i++) { + if (Parms < _domain_sig->cnt()) + _domain_sig->field_at(Parms)->dump2(d,depth-1,st); + for (uint i = Parms+1; i < _domain_sig->cnt(); i++) { st->print(", "); - _domain->field_at(i)->dump2(d,depth-1,st); + _domain_sig->field_at(i)->dump2(d,depth-1,st); } st->print(" )"); } @@ -5388,8 +5750,8 @@ BasicType TypeFunc::return_type() const{ - if (range()->cnt() == TypeFunc::Parms) { + if (range_sig()->cnt() == TypeFunc::Parms) { return T_VOID; } - return range()->field_at(TypeFunc::Parms)->basic_type(); + return range_sig()->field_at(TypeFunc::Parms)->basic_type(); }