--- old/src/hotspot/share/opto/type.cpp 2019-09-11 16:33:04.000000000 +0200 +++ new/src/hotspot/share/opto/type.cpp 2019-09-11 16:32:58.000000000 +0200 @@ -604,9 +604,9 @@ 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, Offset(oopDesc::mark_offset_in_bytes())); + false, 0, Offset(oopDesc::mark_offset_in_bytes()), false); TypeInstPtr::KLASS = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), - false, 0, Offset(oopDesc::klass_offset_in_bytes())); + false, 0, Offset(oopDesc::klass_offset_in_bytes()), false); TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, Offset::bottom, TypeOopPtr::InstanceBot); TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, Offset::bottom); @@ -665,8 +665,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(), Offset(0) ); - TypeKlassPtr::OBJECT_OR_NULL = TypeKlassPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), Offset(0) ); + TypeKlassPtr::OBJECT = TypeKlassPtr::make(TypePtr::NotNull, current->env()->Object_klass(), Offset(0), false); + TypeKlassPtr::OBJECT_OR_NULL = TypeKlassPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), Offset(0), false ); const Type **fi2c = TypeTuple::fields(2); fi2c[TypeFunc::Parms+0] = TypeInstPtr::BOTTOM; // Method* @@ -3355,7 +3355,7 @@ if (k == NULL) return TypeKlassPtr::OBJECT; else - return TypeKlassPtr::make(xk? Constant: NotNull, k, Offset(0)); + return TypeKlassPtr::make(xk? Constant: NotNull, k, Offset(0), isa_instptr() && is_instptr()->flatten_array()); } //------------------------------meet------------------------------------------- @@ -3469,7 +3469,7 @@ } } } - return TypeInstPtr::make(TypePtr::BotPTR, klass, klass_is_exact, NULL, Offset(0)); + return TypeInstPtr::make(TypePtr::BotPTR, klass, klass_is_exact, NULL, Offset(0), klass->flatten_array()); } else if (klass->is_obj_array_klass()) { // 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); @@ -3521,7 +3521,7 @@ if (make_constant) { return TypeInstPtr::make(o); } else { - return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, Offset(0)); + return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, Offset(0), klass->flatten_array()); } } else if (klass->is_obj_array_klass()) { // Element is an object array. Recursively call ourself. @@ -3778,12 +3778,15 @@ //------------------------------TypeInstPtr------------------------------------- TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, Offset off, - int instance_id, const TypePtr* speculative, int inline_depth) + bool flatten_array, int instance_id, const TypePtr* speculative, + int inline_depth) : TypeOopPtr(InstPtr, ptr, k, xk, o, off, Offset::bottom, instance_id, speculative, inline_depth), - _name(k->name()) { + _name(k->name()), _flatten_array(flatten_array) { assert(k != NULL && (k->is_loaded() || o == NULL), "cannot have constants with non-loaded klass"); + assert(!klass()->is_valuetype() || !klass()->flatten_array() || flatten_array, "incorrect flatten array bit"); + assert(!flatten_array || can_be_value_type(), "incorrect flatten array bit"); }; //------------------------------make------------------------------------------- @@ -3792,6 +3795,7 @@ bool xk, ciObject* o, Offset offset, + bool flatten_array, int instance_id, const TypePtr* speculative, int inline_depth) { @@ -3815,7 +3819,7 @@ // Now hash this baby TypeInstPtr *result = - (TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o ,offset, instance_id, speculative, inline_depth))->hashcons(); + (TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o ,offset, flatten_array, instance_id, speculative, inline_depth))->hashcons(); return result; } @@ -3848,7 +3852,7 @@ if( ptr == _ptr ) return this; // Reconstruct _sig info here since not a problem with later lazy // construction, _sig will show up on demand. - return make(ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative, _inline_depth); + return make(ptr, klass(), klass_is_exact(), const_oop(), _offset, _flatten_array, _instance_id, _speculative, _inline_depth); } @@ -3860,18 +3864,18 @@ ciInstanceKlass* ik = _klass->as_instance_klass(); if( (ik->is_final() || _const_oop) ) return this; // cannot clear xk if( ik->is_interface() ) return this; // cannot set xk - return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id, _speculative, _inline_depth); + return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _flatten_array, _instance_id, _speculative, _inline_depth); } //-----------------------------cast_to_instance_id---------------------------- const TypeOopPtr *TypeInstPtr::cast_to_instance_id(int instance_id) const { if( instance_id == _instance_id ) return this; - return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id, _speculative, _inline_depth); + return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, _flatten_array, instance_id, _speculative, _inline_depth); } const TypeOopPtr *TypeInstPtr::cast_to_nonconst() const { if (const_oop() == NULL) return this; - return make(NotNull, klass(), _klass_is_exact, NULL, _offset, _instance_id, _speculative, _inline_depth); + return make(NotNull, klass(), _klass_is_exact, NULL, _offset, _flatten_array, _instance_id, _speculative, _inline_depth); } //------------------------------xmeet_unloaded--------------------------------- @@ -3903,7 +3907,7 @@ assert(loaded->ptr() != TypePtr::Null, "insanity check"); // if( loaded->ptr() == TypePtr::TopPTR ) { return unloaded; } - else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make(ptr, unloaded->klass(), false, NULL, off, instance_id, speculative, depth); } + else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make(ptr, unloaded->klass(), false, NULL, off, false, instance_id, speculative, depth); } else if (loaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; } else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) { if (unloaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; } @@ -3973,7 +3977,7 @@ // 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, false, instance_id, speculative, depth); } case Constant: case NotNull: @@ -3996,7 +4000,7 @@ if( ptr == Constant ) ptr = NotNull; instance_id = InstanceBot; - return make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative, depth); + return make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, false, instance_id, speculative, depth); default: typerr(t); } } @@ -4013,7 +4017,7 @@ const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); return make(ptr, klass(), klass_is_exact(), - (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth); + (ptr == Constant ? const_oop() : NULL), offset, flatten_array(), instance_id, speculative, depth); } case NotNull: case BotPTR: { @@ -4041,7 +4045,7 @@ case TopPTR: case AnyNull: { return make(ptr, klass(), klass_is_exact(), - (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth); + (ptr == Constant ? const_oop() : NULL), offset, flatten_array(), instance_id, speculative, depth); } case NotNull: case BotPTR: @@ -4079,8 +4083,9 @@ // If we have constants, then we created oops so classes are loaded // and we can handle the constants further down. This case handles // both-not-loaded or both-loaded classes - if (ptr != Constant && klass()->equals(tinst->klass()) && klass_is_exact() == tinst->klass_is_exact()) { - return make(ptr, klass(), klass_is_exact(), NULL, off, instance_id, speculative, depth); + if (ptr != Constant && klass()->equals(tinst->klass()) && klass_is_exact() == tinst->klass_is_exact() && + flatten_array() == tinst->flatten_array()) { + return make(ptr, klass(), klass_is_exact(), NULL, off, flatten_array(), instance_id, speculative, depth); } // Classes require inspection in the Java klass hierarchy. Must be loaded. @@ -4088,6 +4093,8 @@ ciKlass* this_klass = this->klass(); bool tinst_xk = tinst->klass_is_exact(); bool this_xk = this->klass_is_exact(); + bool tinst_flatten_array = tinst->flatten_array(); + bool this_flatten_array = this->flatten_array(); if (!tinst_klass->is_loaded() || !this_klass->is_loaded() ) { // One of these classes has not been loaded const TypeInstPtr *unloaded_meet = xmeet_unloaded(tinst); @@ -4110,6 +4117,9 @@ bool tmp2 = tinst_xk; tinst_xk = this_xk; this_xk = tmp2; + tmp2 = tinst_flatten_array; + tinst_flatten_array = this_flatten_array; + this_flatten_array = tmp2; } if (tinst_klass->is_interface() && !(this_klass->is_interface() || @@ -4121,6 +4131,7 @@ // See if the oop subtypes (implements) interface. ciKlass *k; bool xk; + bool value; if( this_klass->is_subtype_of( tinst_klass ) ) { // Oop indeed subtypes. Now keep oop or interface depending // on whether we are both above the centerline or either is @@ -4129,12 +4140,14 @@ k = below_centerline(ptr) ? tinst_klass : this_klass; // If we are keeping this_klass, keep its exactness too. xk = below_centerline(ptr) ? tinst_xk : this_xk; + value = below_centerline(ptr) ? tinst_flatten_array : this_flatten_array; } else { // Does not implement, fall to Object // Oop does not implement interface, so mixing falls to Object // just like the verifier does (if both are above the // centerline fall to interface) k = above_centerline(ptr) ? tinst_klass : ciEnv::current()->Object_klass(); xk = above_centerline(ptr) ? tinst_xk : false; + value = above_centerline(ptr) ? tinst_flatten_array : false; // Watch out for Constant vs. AnyNull interface. if (ptr == Constant) ptr = NotNull; // forget it was a constant instance_id = InstanceBot; @@ -4144,7 +4157,7 @@ // Find out which constant. o = (this_klass == klass()) ? const_oop() : tinst->const_oop(); } - return make(ptr, k, xk, o, off, instance_id, speculative, depth); + return make(ptr, k, xk, o, off, value, instance_id, speculative, depth); } // Either oop vs oop or interface vs interface or interface vs Object @@ -4176,29 +4189,37 @@ // Check for subtyping: ciKlass *subtype = NULL; bool subtype_exact = false; + bool flatten_array = false; if( tinst_klass->equals(this_klass) ) { subtype = this_klass; subtype_exact = below_centerline(ptr) ? (this_xk && tinst_xk) : (this_xk || tinst_xk); + flatten_array = below_centerline(ptr) ? (this_flatten_array && tinst_flatten_array) : (this_flatten_array || tinst_flatten_array); } else if( !tinst_xk && this_klass->is_subtype_of( tinst_klass ) ) { subtype = this_klass; // Pick subtyping class subtype_exact = this_xk; + flatten_array = this_flatten_array; } else if( !this_xk && tinst_klass->is_subtype_of( this_klass ) ) { subtype = tinst_klass; // Pick subtyping class subtype_exact = tinst_xk; + flatten_array = tinst_flatten_array; } if( subtype ) { if( above_centerline(ptr) ) { // both are up? this_klass = tinst_klass = subtype; this_xk = tinst_xk = subtype_exact; + this_flatten_array = tinst_flatten_array = flatten_array; } else if( above_centerline(this ->_ptr) && !above_centerline(tinst->_ptr) ) { this_klass = tinst_klass; // tinst is down; keep down man this_xk = tinst_xk; + this_flatten_array = tinst_flatten_array; } else if( above_centerline(tinst->_ptr) && !above_centerline(this ->_ptr) ) { tinst_klass = this_klass; // this is down; keep down man tinst_xk = this_xk; + tinst_flatten_array = this_flatten_array; } else { this_xk = subtype_exact; // either they are equal, or we'll do an LCA + this_flatten_array = flatten_array; } } @@ -4221,7 +4242,7 @@ else ptr = NotNull; } - return make(ptr, this_klass, this_xk, o, off, instance_id, speculative, depth); + return make(ptr, this_klass, this_xk, o, off, this_flatten_array, instance_id, speculative, depth); } // Else classes are not equal // Since klasses are different, we require a LCA in the Java @@ -4233,7 +4254,7 @@ // Now we find the LCA of Java classes ciKlass* k = this_klass->least_common_ancestor(tinst_klass); - return make(ptr, k, false, NULL, off, instance_id, speculative, depth); + return make(ptr, k, false, NULL, off, false, instance_id, speculative, depth); } // End of case InstPtr case ValueType: { @@ -4278,7 +4299,7 @@ // Dual: do NOT dual on klasses. This means I do NOT understand the Java // inheritance mechanism. const Type *TypeInstPtr::xdual() const { - return new TypeInstPtr(dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth()); + return new TypeInstPtr(dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), flatten_array(), dual_instance_id(), dual_speculative(), dual_inline_depth()); } //------------------------------eq--------------------------------------------- @@ -4287,13 +4308,14 @@ const TypeInstPtr *p = t->is_instptr(); return klass()->equals(p->klass()) && + flatten_array() == p->flatten_array() && TypeOopPtr::eq(p); // Check sub-type stuff } //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypeInstPtr::hash(void) const { - int hash = java_add((jint)klass()->hash(), (jint)TypeOopPtr::hash()); + int hash = java_add(java_add((jint)klass()->hash(), (jint)TypeOopPtr::hash()), (jint)flatten_array()); return hash; } @@ -4328,6 +4350,11 @@ _offset.dump2(st); st->print(" *"); + + if (flatten_array() && !klass()->is_valuetype()) { + st->print(" (flatten array)"); + } + if (_instance_id == InstanceTop) st->print(",iid=top"); else if (_instance_id != InstanceBot) @@ -4340,7 +4367,7 @@ //------------------------------add_offset------------------------------------- const TypePtr *TypeInstPtr::add_offset(intptr_t offset) const { - return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), + return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), flatten_array(), _instance_id, add_offset_speculative(offset), _inline_depth); } @@ -4349,7 +4376,7 @@ return this; } assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth"); - return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, + return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, flatten_array(), _instance_id, NULL, _inline_depth); } @@ -4357,14 +4384,19 @@ if (!UseInlineDepthForSpeculativeTypes) { return this; } - return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative, depth); + return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, flatten_array(), _instance_id, _speculative, depth); } const TypePtr *TypeInstPtr::with_instance_id(int instance_id) const { assert(is_known_instance(), "should be known"); - return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, instance_id, _speculative, _inline_depth); + return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, flatten_array(), instance_id, _speculative, _inline_depth); +} + +const TypeInstPtr *TypeInstPtr::cast_to_flatten_array() const { + return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, true, _instance_id, _speculative, _inline_depth); } + //============================================================================= // Convenience common pre-built types. const TypeAryPtr *TypeAryPtr::RANGE; @@ -4772,7 +4804,7 @@ // 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, false, instance_id, speculative, depth); } case Constant: case NotNull: @@ -4795,7 +4827,7 @@ if( ptr == Constant ) 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, false, instance_id, speculative, depth); default: typerr(t); } } @@ -5333,28 +5365,30 @@ const TypeKlassPtr *TypeKlassPtr::OBJECT_OR_NULL; //------------------------------TypeKlassPtr----------------------------------- -TypeKlassPtr::TypeKlassPtr( PTR ptr, ciKlass* klass, Offset offset ) - : TypePtr(KlassPtr, ptr, offset), _klass(klass), _klass_is_exact(ptr == Constant) { +TypeKlassPtr::TypeKlassPtr(PTR ptr, ciKlass* klass, Offset offset, bool flatten_array) + : TypePtr(KlassPtr, ptr, offset), _klass(klass), _klass_is_exact(ptr == Constant), _flatten_array(flatten_array) { + assert(!klass->is_valuetype() || !klass->flatten_array() || flatten_array, "incorrect flatten array bit"); + assert(!flatten_array || can_be_value_type(), "incorrect flatten array bit"); } //------------------------------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, Offset offset) { +const TypeKlassPtr* TypeKlassPtr::make(PTR ptr, ciKlass* k, Offset offset, bool value) { assert(k == NULL || k->is_instance_klass() || k->is_array_klass(), "Incorrect type of klass oop"); - return (TypeKlassPtr*)(new TypeKlassPtr(ptr, k, offset))->hashcons(); + return (TypeKlassPtr*)(new TypeKlassPtr(ptr, k, offset, value))->hashcons(); } //------------------------------eq--------------------------------------------- // Structural equality check for Type representations bool TypeKlassPtr::eq( const Type *t ) const { const TypeKlassPtr *p = t->is_klassptr(); - return klass() == p->klass() && TypePtr::eq(p); + return klass() == p->klass() && TypePtr::eq(p) && flatten_array() == p->flatten_array(); } //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypeKlassPtr::hash(void) const { - return java_add(klass() != NULL ? klass()->hash() : (jint)0, (jint)TypePtr::hash()); + return java_add(java_add(klass() != NULL ? klass()->hash() : (jint)0, (jint)TypePtr::hash()), (jint)flatten_array()); } //------------------------------singleton-------------------------------------- @@ -5488,14 +5522,14 @@ //------------------------------add_offset------------------------------------- // Access internals of klass object const TypePtr *TypeKlassPtr::add_offset( intptr_t offset ) const { - return make( _ptr, klass(), xadd_offset(offset) ); + return make(_ptr, klass(), xadd_offset(offset), flatten_array()); } //------------------------------cast_to_ptr_type------------------------------- const Type *TypeKlassPtr::cast_to_ptr_type(PTR ptr) const { assert(_base == KlassPtr, "subclass must override cast_to_ptr_type"); if( ptr == _ptr ) return this; - return make(ptr, _klass, _offset); + return make(ptr, _klass, _offset, _flatten_array); } @@ -5503,7 +5537,7 @@ const Type *TypeKlassPtr::cast_to_exactness(bool klass_is_exact) const { if( klass_is_exact == _klass_is_exact ) return this; if (!UseExactTypes) return this; - return make(klass_is_exact ? Constant : NotNull, _klass, _offset); + return make(klass_is_exact ? Constant : NotNull, _klass, _offset, _flatten_array); } @@ -5518,6 +5552,9 @@ const TypeOopPtr* toop = TypeOopPtr::make_from_klass_raw(k); guarantee(toop != NULL, "need type for given klass"); toop = toop->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr(); + if (flatten_array() && !klass()->is_valuetype()) { + toop = toop->is_instptr()->cast_to_flatten_array(); + } return toop->cast_to_exactness(xk)->is_oopptr(); } @@ -5560,7 +5597,7 @@ case Null: if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); case AnyNull: - return make( ptr, klass(), offset ); + return make(ptr, klass(), offset, klass()->flatten_array()); case BotPTR: case NotNull: return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); @@ -5601,15 +5638,15 @@ if (ptr == Constant) { k = (klass() == NULL) ? tkls->klass() : klass(); } - return make(ptr, k, off); + return make(ptr, k, off, false); } // 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 // not-loaded classes - if( ptr != Constant && tkls->klass()->equals(klass()) ) { - return make( ptr, klass(), off ); + if (ptr != Constant && tkls->klass()->equals(klass()) && flatten_array() == tkls->flatten_array()) { + return make(ptr, klass(), off, flatten_array()); } // Classes require inspection in the Java klass hierarchy. Must be loaded. @@ -5617,6 +5654,9 @@ ciKlass* this_klass = this->klass(); assert( tkls_klass->is_loaded(), "This class should have been loaded."); assert( this_klass->is_loaded(), "This class should have been loaded."); + bool tkls_flatten_array = tkls->flatten_array(); + bool this_flatten_array = this->flatten_array(); + bool flatten_array = below_centerline(ptr) ? (this_flatten_array && tkls_flatten_array) : (this_flatten_array || tkls_flatten_array); // If 'this' type is above the centerline and is a superclass of the // other, we can treat 'this' as having the same type as the other. @@ -5644,7 +5684,7 @@ else ptr = NotNull; } - return make( ptr, this_klass, off ); + return make(ptr, this_klass, off, flatten_array); } // Else classes are not equal // Since klasses are different, we require the LCA in the Java @@ -5653,7 +5693,7 @@ ptr = NotNull; // Now we find the LCA of Java classes ciKlass* k = this_klass->least_common_ancestor(tkls_klass); - return make( ptr, k, off ); + return make(ptr, k, off, k->is_valuetype() && k->flatten_array()); } // End of case KlassPtr } // End of switch @@ -5663,7 +5703,7 @@ //------------------------------xdual------------------------------------------ // Dual: compute field-by-field dual const Type *TypeKlassPtr::xdual() const { - return new TypeKlassPtr( dual_ptr(), klass(), dual_offset() ); + return new TypeKlassPtr(dual_ptr(), klass(), dual_offset(), flatten_array()); } //------------------------------get_con----------------------------------------