--- old/src/hotspot/share/opto/type.hpp 2019-03-11 14:27:00.518354403 +0100 +++ new/src/hotspot/share/opto/type.hpp 2019-03-11 14:27:00.246354407 +0100 @@ -25,8 +25,10 @@ #ifndef SHARE_OPTO_TYPE_HPP #define SHARE_OPTO_TYPE_HPP +#include "ci/ciValueKlass.hpp" #include "opto/adlcVMDeps.hpp" #include "runtime/handles.hpp" +#include "runtime/sharedRuntime.hpp" // Portions of code courtesy of Clifford Click @@ -52,6 +54,7 @@ class TypeNarrowKlass; class TypeAry; class TypeTuple; +class TypeValueType; class TypeVect; class TypeVectS; class TypeVectD; @@ -92,6 +95,7 @@ VectorX, // 128bit Vector types VectorY, // 256bit Vector types VectorZ, // 512bit Vector types + ValueType, // Value type AnyPtr, // Any old raw, klass, inst, or array pointer RawPtr, // Raw (non-oop) pointers @@ -123,6 +127,30 @@ OffsetBot = -2000000001 // any possible offset }; + class Offset { + private: + const int _offset; + + public: + explicit Offset(int offset) : _offset(offset) {} + + const Offset meet(const Offset other) const; + const Offset dual() const; + const Offset add(intptr_t offset) const; + bool operator==(const Offset& other) const { + return _offset == other._offset; + } + bool operator!=(const Offset& other) const { + return _offset != other._offset; + } + int get() const { return _offset; } + + void dump2(outputStream *st) const; + + static const Offset top; + static const Offset bottom; + }; + // Min and max WIDEN values. enum WIDEN { WidenMin = 0, @@ -273,9 +301,6 @@ bool is_ptr_to_narrowoop() const; bool is_ptr_to_narrowklass() const; - bool is_ptr_to_boxing_obj() const; - - // Convenience access float getf() const; double getd() const; @@ -308,6 +333,8 @@ const TypeInstPtr *is_instptr() const; // Instance const TypeAryPtr *isa_aryptr() const; // Returns NULL if not AryPtr const TypeAryPtr *is_aryptr() const; // Array oop + const TypeValueType* isa_valuetype() const; // Returns NULL if not Value Type + const TypeValueType* is_valuetype() const; // Value Type const TypeMetadataPtr *isa_metadataptr() const; // Returns NULL if not oop ptr type const TypeMetadataPtr *is_metadataptr() const; // Java-style GC'd pointer @@ -317,6 +344,9 @@ virtual bool is_finite() const; // Has a finite value virtual bool is_nan() const; // Is not a number (NaN) + bool is_valuetypeptr() const; + ciValueKlass* value_klass() const; + // Returns this ptr type or the equivalent ptr type for this compressed pointer. const TypePtr* make_ptr() const; @@ -663,8 +693,8 @@ } static const TypeTuple *make( uint cnt, const Type **fields ); - static const TypeTuple *make_range(ciSignature *sig); - static const TypeTuple *make_domain(ciInstanceKlass* recv, ciSignature *sig); + static const TypeTuple *make_range(ciSignature* sig, bool ret_vt_fields = false); + static const TypeTuple *make_domain(ciMethod* method, bool vt_fields_as_args = false); // Subroutine call type with space allocated for argument types // Memory for Control, I_O, Memory, FramePtr, and ReturnAdr is allocated implicitly @@ -715,6 +745,9 @@ bool ary_must_be_exact() const; // true if arrays of such are never generic virtual const Type* remove_speculative() const; virtual const Type* cleanup_speculative() const; + + bool is_value_type_array() const { return _elem->isa_valuetype() != NULL; } + #ifdef ASSERT // One type is interface, the other is oop virtual bool interface_vs_oop(const Type *t) const; @@ -724,6 +757,41 @@ #endif }; + +//------------------------------TypeValue--------------------------------------- +// Class of Value Type Types +class TypeValueType : public Type { +private: + ciValueKlass* _vk; + bool _larval; + +protected: + TypeValueType(ciValueKlass* vk, bool larval) + : Type(ValueType), + _vk(vk), _larval(larval) { + } + +public: + static const TypeValueType* make(ciValueKlass* vk, bool larval = false); + ciValueKlass* value_klass() const { return _vk; } + bool larval() const { return _larval; } + + virtual bool eq(const Type* t) const; + virtual int hash() const; // Type specific hashing + virtual bool singleton(void) const; // TRUE if type is a singleton + virtual bool empty(void) const; // TRUE if type is vacuous + + virtual const Type* xmeet(const Type* t) const; + virtual const Type* xdual() const; // Compute dual right now. + + virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const { return false; } + virtual bool would_improve_ptr(ProfilePtrKind ptr_kind) const { return false; } + +#ifndef PRODUCT + virtual void dump2(Dict &d, uint, outputStream* st) const; // Specialized per-Type dumping +#endif +}; + //------------------------------TypeVect--------------------------------------- // Class of Vector Types class TypeVect : public Type { @@ -803,7 +871,7 @@ public: enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR }; protected: - TypePtr(TYPES t, PTR ptr, int offset, + TypePtr(TYPES t, PTR ptr, Offset offset, const TypePtr* speculative = NULL, int inline_depth = InlineDepthBottom) : Type(t), _speculative(speculative), _inline_depth(inline_depth), _offset(offset), @@ -846,13 +914,13 @@ #endif public: - const int _offset; // Offset into oop, with TOP & BOT + const Offset _offset; // Offset into oop, with TOP & BOT const PTR _ptr; // Pointer equivalence class - const int offset() const { return _offset; } + const int offset() const { return _offset.get(); } const PTR ptr() const { return _ptr; } - static const TypePtr *make(TYPES t, PTR ptr, int offset, + static const TypePtr* make(TYPES t, PTR ptr, Offset offset, const TypePtr* speculative = NULL, int inline_depth = InlineDepthBottom); @@ -861,8 +929,10 @@ virtual intptr_t get_con() const; - int xadd_offset( intptr_t offset ) const; + Offset xadd_offset(intptr_t offset) const; virtual const TypePtr *add_offset( intptr_t offset ) const; + virtual const int flattened_offset() const { return offset(); } + virtual bool eq(const Type *t) const; virtual int hash() const; // Type specific hashing @@ -870,8 +940,8 @@ virtual bool empty(void) const; // TRUE if type is vacuous virtual const Type *xmeet( const Type *t ) const; virtual const Type *xmeet_helper( const Type *t ) const; - int meet_offset( int offset ) const; - int dual_offset( ) const; + Offset meet_offset(int offset) const; + Offset dual_offset() const; virtual const Type *xdual() const; // Compute dual right now. // meet, dual and join over pointer equivalence sets @@ -916,7 +986,7 @@ // include the stack pointer, top of heap, card-marking area, handles, etc. class TypeRawPtr : public TypePtr { protected: - TypeRawPtr( PTR ptr, address bits ) : TypePtr(RawPtr,ptr,0), _bits(bits){} + TypeRawPtr(PTR ptr, address bits) : TypePtr(RawPtr,ptr,Offset(0)), _bits(bits){} public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -947,8 +1017,8 @@ // Some kind of oop (Java pointer), either instance or array. class TypeOopPtr : public TypePtr { protected: - TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, - const TypePtr* speculative, int inline_depth); + 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); public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -1007,7 +1077,7 @@ bool require_constant = false); // Make a generic (unclassed) pointer to an oop. - static const TypeOopPtr* make(PTR ptr, int offset, int instance_id, + static const TypeOopPtr* make(PTR ptr, Offset offset, int instance_id, const TypePtr* speculative = NULL, int inline_depth = InlineDepthBottom); @@ -1022,7 +1092,10 @@ bool is_ptr_to_boxed_value() const { return _is_ptr_to_boxed_value; } bool is_known_instance() const { return _instance_id > 0; } int instance_id() const { return _instance_id; } - bool is_known_instance_field() const { return is_known_instance() && _offset >= 0; } + bool is_known_instance_field() const { return is_known_instance() && _offset.get() >= 0; } + + virtual bool can_be_value_type() const { return EnableValhalla && can_be_value_type_raw(); } + virtual bool can_be_value_type_raw() const { return _klass == NULL || _klass->is_valuetype() || ((_klass->is_java_lang_Object() || _klass->is_interface()) && !klass_is_exact()); } virtual intptr_t get_con() const; @@ -1062,7 +1135,7 @@ // Class of Java object pointers, pointing either to non-array Java instances // or to a Klass* (including array klasses). class TypeInstPtr : public TypeOopPtr { - TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, + TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, Offset offset, int instance_id, const TypePtr* speculative, int inline_depth); virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -1076,30 +1149,30 @@ // Make a pointer to a constant oop. static const TypeInstPtr *make(ciObject* o) { - return make(TypePtr::Constant, o->klass(), true, o, 0, InstanceBot); + return make(TypePtr::Constant, o->klass(), true, o, Offset(0), InstanceBot); } // Make a pointer to a constant oop with offset. - static const TypeInstPtr *make(ciObject* o, int offset) { + static const TypeInstPtr* make(ciObject* o, Offset offset) { return make(TypePtr::Constant, o->klass(), true, o, offset, InstanceBot); } // Make a pointer to some value of type klass. static const TypeInstPtr *make(PTR ptr, ciKlass* klass) { - return make(ptr, klass, false, NULL, 0, InstanceBot); + return make(ptr, klass, false, NULL, Offset(0), InstanceBot); } // Make a pointer to some non-polymorphic value of exactly type klass. static const TypeInstPtr *make_exact(PTR ptr, ciKlass* klass) { - return make(ptr, klass, true, NULL, 0, InstanceBot); + return make(ptr, klass, true, NULL, Offset(0), InstanceBot); } // Make a pointer to some value of type klass with offset. - static const TypeInstPtr *make(PTR ptr, ciKlass* klass, int offset) { + static const TypeInstPtr *make(PTR ptr, ciKlass* klass, Offset offset) { return make(ptr, klass, false, NULL, offset, InstanceBot); } // Make a pointer to an oop. - static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, + static const TypeInstPtr* make(PTR ptr, ciKlass* k, bool xk, ciObject* o, Offset offset, int instance_id = InstanceBot, const TypePtr* speculative = NULL, int inline_depth = InlineDepthBottom); @@ -1146,12 +1219,13 @@ //------------------------------TypeAryPtr------------------------------------- // Class of Java array pointers class TypeAryPtr : public TypeOopPtr { - TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, - int offset, int instance_id, bool is_autobox_cache, - const TypePtr* speculative, int inline_depth) - : TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative, inline_depth), + TypeAryPtr(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, + Offset offset, Offset field_offset, int instance_id, bool is_autobox_cache, + const TypePtr* speculative, int inline_depth) + : TypeOopPtr(AryPtr, ptr, k, xk, o, offset, field_offset, instance_id, speculative, inline_depth), _ary(ary), - _is_autobox_cache(is_autobox_cache) + _is_autobox_cache(is_autobox_cache), + _field_offset(field_offset) { #ifdef ASSERT if (k != NULL) { @@ -1174,6 +1248,12 @@ virtual int hash() const; // Type specific hashing const TypeAry *_ary; // Array we point into const bool _is_autobox_cache; + // For flattened value type arrays, each field of the value type in + // the array has its own memory slice so we need to keep track of + // which field is accessed + const Offset _field_offset; + Offset meet_field_offset(const Type::Offset offset) const; + Offset dual_field_offset() const; ciKlass* compute_klass(DEBUG_ONLY(bool verify = false)) const; @@ -1187,15 +1267,18 @@ bool is_autobox_cache() const { return _is_autobox_cache; } - static const TypeAryPtr *make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, + static const TypeAryPtr* make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, Offset offset, + Offset field_offset = Offset::bottom, int instance_id = InstanceBot, const TypePtr* speculative = NULL, int inline_depth = InlineDepthBottom); // Constant pointer to array - static const TypeAryPtr *make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, + static const TypeAryPtr* make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, Offset offset, + Offset field_offset = Offset::bottom, int instance_id = InstanceBot, const TypePtr* speculative = NULL, - int inline_depth = InlineDepthBottom, bool is_autobox_cache = false); + int inline_depth = InlineDepthBottom, + bool is_autobox_cache = false); // Return a 'ptr' version of this type virtual const Type *cast_to_ptr_type(PTR ptr) const; @@ -1226,6 +1309,13 @@ const TypeAryPtr* cast_to_autobox_cache(bool cache) const; + const int flattened_offset() const; + const Offset field_offset() const { return _field_offset; } + const TypeAryPtr* with_field_offset(int offset) const; + const TypePtr* add_field_offset_and_offset(intptr_t offset) const; + + virtual bool can_be_value_type() const { return false; } + // Convenience common pre-built types. static const TypeAryPtr *RANGE; static const TypeAryPtr *OOPS; @@ -1257,7 +1347,7 @@ // Some kind of metadata, either Method*, MethodData* or CPCacheOop class TypeMetadataPtr : public TypePtr { protected: - TypeMetadataPtr(PTR ptr, ciMetadata* metadata, int offset); + TypeMetadataPtr(PTR ptr, ciMetadata* metadata, Offset offset); // Do not allow interface-vs.-noninterface joins to collapse to top. virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; public: @@ -1269,7 +1359,7 @@ ciMetadata* _metadata; public: - static const TypeMetadataPtr* make(PTR ptr, ciMetadata* m, int offset); + static const TypeMetadataPtr* make(PTR ptr, ciMetadata* m, Offset offset); static const TypeMetadataPtr* make(ciMethod* m); static const TypeMetadataPtr* make(ciMethodData* m); @@ -1296,7 +1386,7 @@ //------------------------------TypeKlassPtr----------------------------------- // Class of Java Klass pointers class TypeKlassPtr : public TypePtr { - TypeKlassPtr( PTR ptr, ciKlass* klass, int offset ); + TypeKlassPtr(PTR ptr, ciKlass* klass, Offset offset); protected: virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; @@ -1306,47 +1396,23 @@ virtual bool singleton(void) const; // TRUE if type is a singleton private: - static const TypeKlassPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact); - ciKlass* _klass; // Does the type exclude subclasses of the klass? (Inexact == polymorphic.) bool _klass_is_exact; public: - ciSymbol* name() const { return klass()->name(); } - ciKlass* klass() const { return _klass; } bool klass_is_exact() const { return _klass_is_exact; } - bool is_loaded() const { return klass()->is_loaded(); } - - // Creates a type given a klass. Correctly handles multi-dimensional arrays - // Respects UseUniqueSubclasses. - // If the klass is final, the resulting type will be exact. - static const TypeKlassPtr* make_from_klass(ciKlass* klass) { - return make_from_klass_common(klass, true, false); - } - // Same as before, but will produce an exact type, even if - // the klass is not final, as long as it has exactly one implementation. - static const TypeKlassPtr* make_from_klass_unique(ciKlass* klass) { - return make_from_klass_common(klass, true, true); - } - // Same as before, but does not respects UseUniqueSubclasses. - // Use this only for creating array element types. - static const TypeKlassPtr* make_from_klass_raw(ciKlass* klass) { - return make_from_klass_common(klass, false, false); - } - - // Make a generic (unclassed) pointer to metadata. - static const TypeKlassPtr* make(PTR ptr, int offset); + bool is_loaded() const { return klass() != NULL && klass()->is_loaded(); } // ptr to klass 'k' - static const TypeKlassPtr *make( ciKlass* k ) { return make( TypePtr::Constant, k, 0); } + static const TypeKlassPtr* make(ciKlass* k) { return make( TypePtr::Constant, k, Offset(0)); } // ptr to klass 'k' with offset - static const TypeKlassPtr *make( ciKlass* k, int offset ) { return make( TypePtr::Constant, k, offset); } + static const TypeKlassPtr* make(ciKlass* k, Offset offset) { return make( TypePtr::Constant, k, offset); } // ptr to klass 'k' or sub-klass - static const TypeKlassPtr *make( PTR ptr, ciKlass* k, int offset); + static const TypeKlassPtr* make(PTR ptr, ciKlass* k, Offset offset); virtual const Type *cast_to_ptr_type(PTR ptr) const; @@ -1493,14 +1559,26 @@ //------------------------------TypeFunc--------------------------------------- // Class of Array Types class TypeFunc : public Type { - TypeFunc( const TypeTuple *domain, const TypeTuple *range ) : Type(Function), _domain(domain), _range(range) {} + TypeFunc(const TypeTuple *domain_sig, const TypeTuple *domain_cc, const TypeTuple *range_sig, const TypeTuple *range_cc) + : Type(Function), _domain_sig(domain_sig), _domain_cc(domain_cc), _range_sig(range_sig), _range_cc(range_cc) {} virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing virtual bool singleton(void) const; // TRUE if type is a singleton virtual bool empty(void) const; // TRUE if type is vacuous - const TypeTuple* const _domain; // Domain of inputs - const TypeTuple* const _range; // Range of results + // Domains of inputs: value type arguments are not passed by + // reference, instead each field of the value type is passed as an + // argument. We maintain 2 views of the argument list here: one + // based on the signature (with a value type argument as a single + // slot), one based on the actual calling convention (with a value + // type argument as a list of its fields). + const TypeTuple* const _domain_sig; + const TypeTuple* const _domain_cc; + // Range of results. Similar to domains: a value type result can be + // returned in registers in which case range_cc lists all fields and + // is the actual calling convention. + const TypeTuple* const _range_sig; + const TypeTuple* const _range_cc; public: // Constants are shared among ADLC and VM @@ -1514,11 +1592,15 @@ // Accessors: - const TypeTuple* domain() const { return _domain; } - const TypeTuple* range() const { return _range; } + const TypeTuple* domain_sig() const { return _domain_sig; } + const TypeTuple* domain_cc() const { return _domain_cc; } + const TypeTuple* range_sig() const { return _range_sig; } + const TypeTuple* range_cc() const { return _range_cc; } static const TypeFunc *make(ciMethod* method); static const TypeFunc *make(ciSignature signature, const Type* extra); + static const TypeFunc *make(const TypeTuple* domain_sig, const TypeTuple* domain_cc, + const TypeTuple* range_sig, const TypeTuple* range_cc); static const TypeFunc *make(const TypeTuple* domain, const TypeTuple* range); virtual const Type *xmeet( const Type *t ) const; @@ -1526,6 +1608,8 @@ BasicType return_type() const; + bool returns_value_type_as_fields() const { return range_sig() != range_cc(); } + #ifndef PRODUCT virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping #endif @@ -1675,6 +1759,15 @@ return (TypeAryPtr*)this; } +inline const TypeValueType* Type::isa_valuetype() const { + return (_base == ValueType) ? (TypeValueType*)this : NULL; +} + +inline const TypeValueType* Type::is_valuetype() const { + assert(_base == ValueType, "Not a value type"); + return (TypeValueType*)this; +} + inline const TypeNarrowOop *Type::is_narrowoop() const { // OopPtr is the first and KlassPtr the last, with no non-oops between. assert(_base == NarrowOop, "Not a narrow oop" ) ; @@ -1741,11 +1834,14 @@ return false; } -inline bool Type::is_ptr_to_boxing_obj() const { - const TypeInstPtr* tp = isa_instptr(); - return (tp != NULL) && (tp->offset() == 0) && - tp->klass()->is_instance_klass() && - tp->klass()->as_instance_klass()->is_box_klass(); +inline bool Type::is_valuetypeptr() const { + return isa_instptr() != NULL && is_instptr()->klass()->is_valuetype(); +} + + +inline ciValueKlass* Type::value_klass() const { + assert(is_valuetypeptr(), "must be a value type ptr"); + return is_instptr()->klass()->as_value_klass(); } @@ -1774,6 +1870,7 @@ #define AndXNode AndLNode #define OrXNode OrLNode #define CmpXNode CmpLNode +#define CmpUXNode CmpULNode #define SubXNode SubLNode #define LShiftXNode LShiftLNode // For object size computation: @@ -1793,6 +1890,8 @@ #define Op_SubX Op_SubL #define Op_XorX Op_XorL #define Op_URShiftX Op_URShiftL +#define Op_LoadX Op_LoadL +#define Op_StoreX Op_StoreL // conversions #define ConvI2X(x) ConvI2L(x) #define ConvL2X(x) (x) @@ -1821,6 +1920,7 @@ #define AndXNode AndINode #define OrXNode OrINode #define CmpXNode CmpINode +#define CmpUXNode CmpUNode #define SubXNode SubINode #define LShiftXNode LShiftINode // For object size computation: @@ -1840,6 +1940,8 @@ #define Op_SubX Op_SubI #define Op_XorX Op_XorI #define Op_URShiftX Op_URShiftI +#define Op_LoadX Op_LoadI +#define Op_StoreX Op_StoreI // conversions #define ConvI2X(x) (x) #define ConvL2X(x) ConvL2I(x)