Tue, 10 Sep 2013 14:51:48 -0700
8001107: @Stable annotation for constant folding of lazily evaluated variables
Reviewed-by: rbackman, twisti, kvn
Contributed-by: john.r.rose@oracle.com, vladimir.x.ivanov@oracle.com
1.1 --- a/src/share/vm/ci/ciArray.cpp Mon Sep 09 19:53:28 2013 +0200 1.2 +++ b/src/share/vm/ci/ciArray.cpp Tue Sep 10 14:51:48 2013 -0700 1.3 @@ -24,13 +24,92 @@ 1.4 1.5 #include "precompiled.hpp" 1.6 #include "ci/ciArray.hpp" 1.7 +#include "ci/ciArrayKlass.hpp" 1.8 +#include "ci/ciConstant.hpp" 1.9 #include "ci/ciKlass.hpp" 1.10 #include "ci/ciUtilities.hpp" 1.11 +#include "oops/objArrayOop.hpp" 1.12 +#include "oops/typeArrayOop.hpp" 1.13 1.14 // ciArray 1.15 // 1.16 // This class represents an arrayOop in the HotSpot virtual 1.17 // machine. 1.18 +static BasicType fixup_element_type(BasicType bt) { 1.19 + if (bt == T_ARRAY) return T_OBJECT; 1.20 + if (bt == T_BOOLEAN) return T_BYTE; 1.21 + return bt; 1.22 +} 1.23 + 1.24 +ciConstant ciArray::element_value_impl(BasicType elembt, 1.25 + arrayOop ary, 1.26 + int index) { 1.27 + if (ary == NULL) 1.28 + return ciConstant(); 1.29 + assert(ary->is_array(), ""); 1.30 + if (index < 0 || index >= ary->length()) 1.31 + return ciConstant(); 1.32 + ArrayKlass* ak = (ArrayKlass*) ary->klass(); 1.33 + BasicType abt = ak->element_type(); 1.34 + if (fixup_element_type(elembt) != 1.35 + fixup_element_type(abt)) 1.36 + return ciConstant(); 1.37 + switch (elembt) { 1.38 + case T_ARRAY: 1.39 + case T_OBJECT: 1.40 + { 1.41 + assert(ary->is_objArray(), ""); 1.42 + objArrayOop objary = (objArrayOop) ary; 1.43 + oop elem = objary->obj_at(index); 1.44 + ciEnv* env = CURRENT_ENV; 1.45 + ciObject* box = env->get_object(elem); 1.46 + return ciConstant(T_OBJECT, box); 1.47 + } 1.48 + } 1.49 + assert(ary->is_typeArray(), ""); 1.50 + typeArrayOop tary = (typeArrayOop) ary; 1.51 + jint value = 0; 1.52 + switch (elembt) { 1.53 + case T_LONG: return ciConstant(tary->long_at(index)); 1.54 + case T_FLOAT: return ciConstant(tary->float_at(index)); 1.55 + case T_DOUBLE: return ciConstant(tary->double_at(index)); 1.56 + default: return ciConstant(); 1.57 + case T_BYTE: value = tary->byte_at(index); break; 1.58 + case T_BOOLEAN: value = tary->byte_at(index) & 1; break; 1.59 + case T_SHORT: value = tary->short_at(index); break; 1.60 + case T_CHAR: value = tary->char_at(index); break; 1.61 + case T_INT: value = tary->int_at(index); break; 1.62 + } 1.63 + return ciConstant(elembt, value); 1.64 +} 1.65 + 1.66 +// ------------------------------------------------------------------ 1.67 +// ciArray::element_value 1.68 +// 1.69 +// Current value of an element. 1.70 +// Returns T_ILLEGAL if there is no element at the given index. 1.71 +ciConstant ciArray::element_value(int index) { 1.72 + BasicType elembt = element_basic_type(); 1.73 + GUARDED_VM_ENTRY( 1.74 + return element_value_impl(elembt, get_arrayOop(), index); 1.75 + ) 1.76 +} 1.77 + 1.78 +// ------------------------------------------------------------------ 1.79 +// ciArray::element_value_by_offset 1.80 +// 1.81 +// Current value of an element at the specified offset. 1.82 +// Returns T_ILLEGAL if there is no element at the given offset. 1.83 +ciConstant ciArray::element_value_by_offset(intptr_t element_offset) { 1.84 + BasicType elembt = element_basic_type(); 1.85 + intptr_t shift = exact_log2(type2aelembytes(elembt)); 1.86 + intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt); 1.87 + intptr_t index = (element_offset - header) >> shift; 1.88 + intptr_t offset = header + ((intptr_t)index << shift); 1.89 + if (offset != element_offset || index != (jint)index) 1.90 + return ciConstant(); 1.91 + return element_value((jint) index); 1.92 +} 1.93 1.94 // ------------------------------------------------------------------ 1.95 // ciArray::print_impl
2.1 --- a/src/share/vm/ci/ciArray.hpp Mon Sep 09 19:53:28 2013 +0200 2.2 +++ b/src/share/vm/ci/ciArray.hpp Tue Sep 10 14:51:48 2013 -0700 2.3 @@ -25,6 +25,8 @@ 2.4 #ifndef SHARE_VM_CI_CIARRAY_HPP 2.5 #define SHARE_VM_CI_CIARRAY_HPP 2.6 2.7 +#include "ci/ciArrayKlass.hpp" 2.8 +#include "ci/ciConstant.hpp" 2.9 #include "ci/ciObject.hpp" 2.10 #include "oops/arrayOop.hpp" 2.11 #include "oops/objArrayOop.hpp" 2.12 @@ -45,15 +47,30 @@ 2.13 2.14 ciArray(ciKlass* klass, int len) : ciObject(klass), _length(len) {} 2.15 2.16 - arrayOop get_arrayOop() { return (arrayOop)get_oop(); } 2.17 + arrayOop get_arrayOop() const { return (arrayOop)get_oop(); } 2.18 2.19 const char* type_string() { return "ciArray"; } 2.20 2.21 void print_impl(outputStream* st); 2.22 2.23 + ciConstant element_value_impl(BasicType elembt, arrayOop ary, int index); 2.24 + 2.25 public: 2.26 int length() { return _length; } 2.27 2.28 + // Convenience routines. 2.29 + ciArrayKlass* array_type() { return klass()->as_array_klass(); } 2.30 + ciType* element_type() { return array_type()->element_type(); } 2.31 + BasicType element_basic_type() { return element_type()->basic_type(); } 2.32 + 2.33 + // Current value of an element. 2.34 + // Returns T_ILLEGAL if there is no element at the given index. 2.35 + ciConstant element_value(int index); 2.36 + 2.37 + // Current value of an element at the specified offset. 2.38 + // Returns T_ILLEGAL if there is no element at the given offset. 2.39 + ciConstant element_value_by_offset(intptr_t element_offset); 2.40 + 2.41 // What kind of ciObject is this? 2.42 bool is_array() { return true; } 2.43 bool is_java_object() { return true; }
3.1 --- a/src/share/vm/ci/ciConstant.hpp Mon Sep 09 19:53:28 2013 +0200 3.2 +++ b/src/share/vm/ci/ciConstant.hpp Tue Sep 10 14:51:48 2013 -0700 3.3 @@ -41,7 +41,6 @@ 3.4 union { 3.5 jint _int; 3.6 jlong _long; 3.7 - jint _long_half[2]; 3.8 jfloat _float; 3.9 jdouble _double; 3.10 ciObject* _object; 3.11 @@ -111,6 +110,20 @@ 3.12 return _value._object; 3.13 } 3.14 3.15 + bool is_null_or_zero() const { 3.16 + if (!is_java_primitive(basic_type())) { 3.17 + return as_object()->is_null_object(); 3.18 + } else if (type2size[basic_type()] == 1) { 3.19 + // treat float bits as int, to avoid comparison with -0 and NaN 3.20 + return (_value._int == 0); 3.21 + } else if (type2size[basic_type()] == 2) { 3.22 + // treat double bits as long, to avoid comparison with -0 and NaN 3.23 + return (_value._long == 0); 3.24 + } else { 3.25 + return false; 3.26 + } 3.27 + } 3.28 + 3.29 // Debugging output 3.30 void print(); 3.31 };
4.1 --- a/src/share/vm/ci/ciField.cpp Mon Sep 09 19:53:28 2013 +0200 4.2 +++ b/src/share/vm/ci/ciField.cpp Tue Sep 10 14:51:48 2013 -0700 4.3 @@ -189,12 +189,14 @@ 4.4 _holder = CURRENT_ENV->get_instance_klass(fd->field_holder()); 4.5 4.6 // Check to see if the field is constant. 4.7 - if (_holder->is_initialized() && this->is_final()) { 4.8 + bool is_final = this->is_final(); 4.9 + bool is_stable = FoldStableValues && this->is_stable(); 4.10 + if (_holder->is_initialized() && (is_final || is_stable)) { 4.11 if (!this->is_static()) { 4.12 // A field can be constant if it's a final static field or if 4.13 // it's a final non-static field of a trusted class (classes in 4.14 // java.lang.invoke and sun.invoke packages and subpackages). 4.15 - if (trust_final_non_static_fields(_holder)) { 4.16 + if (is_stable || trust_final_non_static_fields(_holder)) { 4.17 _is_constant = true; 4.18 return; 4.19 } 4.20 @@ -227,7 +229,6 @@ 4.21 4.22 Handle mirror = k->java_mirror(); 4.23 4.24 - _is_constant = true; 4.25 switch(type()->basic_type()) { 4.26 case T_BYTE: 4.27 _constant_value = ciConstant(type()->basic_type(), mirror->byte_field(_offset)); 4.28 @@ -273,6 +274,12 @@ 4.29 } 4.30 } 4.31 } 4.32 + if (is_stable && _constant_value.is_null_or_zero()) { 4.33 + // It is not a constant after all; treat it as uninitialized. 4.34 + _is_constant = false; 4.35 + } else { 4.36 + _is_constant = true; 4.37 + } 4.38 } else { 4.39 _is_constant = false; 4.40 } 4.41 @@ -373,8 +380,11 @@ 4.42 tty->print(" signature="); 4.43 _signature->print_symbol(); 4.44 tty->print(" offset=%d type=", _offset); 4.45 - if (_type != NULL) _type->print_name(); 4.46 - else tty->print("(reference)"); 4.47 + if (_type != NULL) 4.48 + _type->print_name(); 4.49 + else 4.50 + tty->print("(reference)"); 4.51 + tty->print(" flags=%04x", flags().as_int()); 4.52 tty->print(" is_constant=%s", bool_to_str(_is_constant)); 4.53 if (_is_constant && is_static()) { 4.54 tty->print(" constant_value=");
5.1 --- a/src/share/vm/ci/ciField.hpp Mon Sep 09 19:53:28 2013 +0200 5.2 +++ b/src/share/vm/ci/ciField.hpp Tue Sep 10 14:51:48 2013 -0700 5.3 @@ -139,7 +139,10 @@ 5.4 // non-constant fields. These are java.lang.System.in 5.5 // and java.lang.System.out. Abomination. 5.6 // 5.7 - // Note: the check for case 4 is not yet implemented. 5.8 + // A field is also considered constant if it is marked @Stable 5.9 + // and is non-null (or non-zero, if a primitive). 5.10 + // For non-static fields, the null/zero check must be 5.11 + // arranged by the user, as constant_value().is_null_or_zero(). 5.12 bool is_constant() { return _is_constant; } 5.13 5.14 // Get the constant value of this field. 5.15 @@ -173,6 +176,7 @@ 5.16 bool is_protected () { return flags().is_protected(); } 5.17 bool is_static () { return flags().is_static(); } 5.18 bool is_final () { return flags().is_final(); } 5.19 + bool is_stable () { return flags().is_stable(); } 5.20 bool is_volatile () { return flags().is_volatile(); } 5.21 bool is_transient () { return flags().is_transient(); } 5.22
6.1 --- a/src/share/vm/ci/ciFlags.hpp Mon Sep 09 19:53:28 2013 +0200 6.2 +++ b/src/share/vm/ci/ciFlags.hpp Tue Sep 10 14:51:48 2013 -0700 6.3 @@ -59,6 +59,7 @@ 6.4 bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; } 6.5 bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; } 6.6 bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; } 6.7 + bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; } 6.8 6.9 // Conversion 6.10 jint as_int() { return _flags; }
7.1 --- a/src/share/vm/ci/ciInstance.cpp Mon Sep 09 19:53:28 2013 +0200 7.2 +++ b/src/share/vm/ci/ciInstance.cpp Tue Sep 10 14:51:48 2013 -0700 7.3 @@ -127,6 +127,8 @@ 7.4 ciConstant ciInstance::field_value_by_offset(int field_offset) { 7.5 ciInstanceKlass* ik = klass()->as_instance_klass(); 7.6 ciField* field = ik->get_field_by_offset(field_offset, false); 7.7 + if (field == NULL) 7.8 + return ciConstant(); // T_ILLEGAL 7.9 return field_value(field); 7.10 } 7.11
8.1 --- a/src/share/vm/ci/ciTypeArray.cpp Mon Sep 09 19:53:28 2013 +0200 8.2 +++ b/src/share/vm/ci/ciTypeArray.cpp Tue Sep 10 14:51:48 2013 -0700 8.3 @@ -39,5 +39,10 @@ 8.4 jchar ciTypeArray::char_at(int index) { 8.5 VM_ENTRY_MARK; 8.6 assert(index >= 0 && index < length(), "out of range"); 8.7 - return get_typeArrayOop()->char_at(index); 8.8 + jchar c = get_typeArrayOop()->char_at(index); 8.9 +#ifdef ASSERT 8.10 + jchar d = element_value(index).as_char(); 8.11 + assert(c == d, ""); 8.12 +#endif //ASSERT 8.13 + return c; 8.14 }
9.1 --- a/src/share/vm/classfile/classFileParser.cpp Mon Sep 09 19:53:28 2013 +0200 9.2 +++ b/src/share/vm/classfile/classFileParser.cpp Tue Sep 10 14:51:48 2013 -0700 9.3 @@ -1774,6 +1774,10 @@ 9.4 if (_location != _in_method) break; // only allow for methods 9.5 if (!privileged) break; // only allow in privileged code 9.6 return _method_LambdaForm_Hidden; 9.7 + case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_invoke_Stable_signature): 9.8 + if (_location != _in_field) break; // only allow for fields 9.9 + if (!privileged) break; // only allow in privileged code 9.10 + return _field_Stable; 9.11 case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_misc_Contended_signature): 9.12 if (_location != _in_field && _location != _in_class) break; // only allow for fields and classes 9.13 if (!EnableContended || (RestrictContended && !privileged)) break; // honor privileges 9.14 @@ -1786,6 +1790,8 @@ 9.15 void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) { 9.16 if (is_contended()) 9.17 f->set_contended_group(contended_group()); 9.18 + if (is_stable()) 9.19 + f->set_stable(true); 9.20 } 9.21 9.22 ClassFileParser::FieldAnnotationCollector::~FieldAnnotationCollector() {
10.1 --- a/src/share/vm/classfile/classFileParser.hpp Mon Sep 09 19:53:28 2013 +0200 10.2 +++ b/src/share/vm/classfile/classFileParser.hpp Tue Sep 10 14:51:48 2013 -0700 10.3 @@ -125,6 +125,7 @@ 10.4 _method_LambdaForm_Compiled, 10.5 _method_LambdaForm_Hidden, 10.6 _sun_misc_Contended, 10.7 + _field_Stable, 10.8 _annotation_LIMIT 10.9 }; 10.10 const Location _location; 10.11 @@ -143,14 +144,23 @@ 10.12 assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob"); 10.13 _annotations_present |= nth_bit((int)id); 10.14 } 10.15 + 10.16 + void remove_annotation(ID id) { 10.17 + assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob"); 10.18 + _annotations_present &= ~nth_bit((int)id); 10.19 + } 10.20 + 10.21 // Report if the annotation is present. 10.22 - bool has_any_annotations() { return _annotations_present != 0; } 10.23 - bool has_annotation(ID id) { return (nth_bit((int)id) & _annotations_present) != 0; } 10.24 + bool has_any_annotations() const { return _annotations_present != 0; } 10.25 + bool has_annotation(ID id) const { return (nth_bit((int)id) & _annotations_present) != 0; } 10.26 10.27 void set_contended_group(u2 group) { _contended_group = group; } 10.28 - u2 contended_group() { return _contended_group; } 10.29 + u2 contended_group() const { return _contended_group; } 10.30 10.31 - bool is_contended() { return has_annotation(_sun_misc_Contended); } 10.32 + bool is_contended() const { return has_annotation(_sun_misc_Contended); } 10.33 + 10.34 + void set_stable(bool stable) { set_annotation(_field_Stable); } 10.35 + bool is_stable() const { return has_annotation(_field_Stable); } 10.36 }; 10.37 10.38 // This class also doubles as a holder for metadata cleanup.
11.1 --- a/src/share/vm/classfile/vmSymbols.hpp Mon Sep 09 19:53:28 2013 +0200 11.2 +++ b/src/share/vm/classfile/vmSymbols.hpp Tue Sep 10 14:51:48 2013 -0700 11.3 @@ -270,6 +270,7 @@ 11.4 template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ 11.5 template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \ 11.6 template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \ 11.7 + template(sun_invoke_Stable_signature, "Lsun/invoke/Stable;") \ 11.8 template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \ 11.9 template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \ 11.10 template(java_lang_invoke_MagicLambdaImpl, "java/lang/invoke/MagicLambdaImpl") \
12.1 --- a/src/share/vm/oops/fieldInfo.hpp Mon Sep 09 19:53:28 2013 +0200 12.2 +++ b/src/share/vm/oops/fieldInfo.hpp Tue Sep 10 14:51:48 2013 -0700 12.3 @@ -240,6 +240,14 @@ 12.4 return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0; 12.5 } 12.6 12.7 + bool is_stable() const { 12.8 + return (access_flags() & JVM_ACC_FIELD_STABLE) != 0; 12.9 + } 12.10 + void set_stable(bool z) { 12.11 + if (z) _shorts[access_flags_offset] |= JVM_ACC_FIELD_STABLE; 12.12 + else _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE; 12.13 + } 12.14 + 12.15 Symbol* lookup_symbol(int symbol_index) const { 12.16 assert(is_internal(), "only internal fields"); 12.17 return vmSymbols::symbol_at((vmSymbols::SID)symbol_index);
13.1 --- a/src/share/vm/opto/c2_globals.hpp Mon Sep 09 19:53:28 2013 +0200 13.2 +++ b/src/share/vm/opto/c2_globals.hpp Tue Sep 10 14:51:48 2013 -0700 13.3 @@ -448,6 +448,9 @@ 13.4 product(bool, EliminateAutoBox, true, \ 13.5 "Control optimizations for autobox elimination") \ 13.6 \ 13.7 + experimental(bool, UseImplicitStableValues, false, \ 13.8 + "Mark well-known stable fields as such (e.g. String.value)") \ 13.9 + \ 13.10 product(intx, AutoBoxCacheMax, 128, \ 13.11 "Sets max value cached by the java.lang.Integer autobox cache") \ 13.12 \
14.1 --- a/src/share/vm/opto/compile.cpp Mon Sep 09 19:53:28 2013 +0200 14.2 +++ b/src/share/vm/opto/compile.cpp Tue Sep 10 14:51:48 2013 -0700 14.3 @@ -1297,6 +1297,10 @@ 14.4 14.5 // Array pointers need some flattening 14.6 const TypeAryPtr *ta = tj->isa_aryptr(); 14.7 + if (ta && ta->is_stable()) { 14.8 + // Erase stability property for alias analysis. 14.9 + tj = ta = ta->cast_to_stable(false); 14.10 + } 14.11 if( ta && is_known_inst ) { 14.12 if ( offset != Type::OffsetBot && 14.13 offset > arrayOopDesc::length_offset_in_bytes() ) { 14.14 @@ -1497,6 +1501,7 @@ 14.15 _index = i; 14.16 _adr_type = at; 14.17 _field = NULL; 14.18 + _element = NULL; 14.19 _is_rewritable = true; // default 14.20 const TypeOopPtr *atoop = (at != NULL) ? at->isa_oopptr() : NULL; 14.21 if (atoop != NULL && atoop->is_known_instance()) { 14.22 @@ -1615,6 +1620,16 @@ 14.23 && flat->is_instptr()->klass() == env()->Class_klass()) 14.24 alias_type(idx)->set_rewritable(false); 14.25 } 14.26 + if (flat->isa_aryptr()) { 14.27 +#ifdef ASSERT 14.28 + const int header_size_min = arrayOopDesc::base_offset_in_bytes(T_BYTE); 14.29 + // (T_BYTE has the weakest alignment and size restrictions...) 14.30 + assert(flat->offset() < header_size_min, "array body reference must be OffsetBot"); 14.31 +#endif 14.32 + if (flat->offset() == TypePtr::OffsetBot) { 14.33 + alias_type(idx)->set_element(flat->is_aryptr()->elem()); 14.34 + } 14.35 + } 14.36 if (flat->isa_klassptr()) { 14.37 if (flat->offset() == in_bytes(Klass::super_check_offset_offset())) 14.38 alias_type(idx)->set_rewritable(false); 14.39 @@ -1677,7 +1692,7 @@ 14.40 else 14.41 t = TypeOopPtr::make_from_klass_raw(field->holder()); 14.42 AliasType* atp = alias_type(t->add_offset(field->offset_in_bytes()), field); 14.43 - assert(field->is_final() == !atp->is_rewritable(), "must get the rewritable bits correct"); 14.44 + assert((field->is_final() || field->is_stable()) == !atp->is_rewritable(), "must get the rewritable bits correct"); 14.45 return atp; 14.46 } 14.47
15.1 --- a/src/share/vm/opto/compile.hpp Mon Sep 09 19:53:28 2013 +0200 15.2 +++ b/src/share/vm/opto/compile.hpp Tue Sep 10 14:51:48 2013 -0700 15.3 @@ -72,6 +72,7 @@ 15.4 class StartNode; 15.5 class SafePointNode; 15.6 class JVMState; 15.7 +class Type; 15.8 class TypeData; 15.9 class TypePtr; 15.10 class TypeOopPtr; 15.11 @@ -119,6 +120,7 @@ 15.12 int _index; // unique index, used with MergeMemNode 15.13 const TypePtr* _adr_type; // normalized address type 15.14 ciField* _field; // relevant instance field, or null if none 15.15 + const Type* _element; // relevant array element type, or null if none 15.16 bool _is_rewritable; // false if the memory is write-once only 15.17 int _general_index; // if this is type is an instance, the general 15.18 // type that this is an instance of 15.19 @@ -129,6 +131,7 @@ 15.20 int index() const { return _index; } 15.21 const TypePtr* adr_type() const { return _adr_type; } 15.22 ciField* field() const { return _field; } 15.23 + const Type* element() const { return _element; } 15.24 bool is_rewritable() const { return _is_rewritable; } 15.25 bool is_volatile() const { return (_field ? _field->is_volatile() : false); } 15.26 int general_index() const { return (_general_index != 0) ? _general_index : _index; } 15.27 @@ -137,7 +140,14 @@ 15.28 void set_field(ciField* f) { 15.29 assert(!_field,""); 15.30 _field = f; 15.31 - if (f->is_final()) _is_rewritable = false; 15.32 + if (f->is_final() || f->is_stable()) { 15.33 + // In the case of @Stable, multiple writes are possible but may be assumed to be no-ops. 15.34 + _is_rewritable = false; 15.35 + } 15.36 + } 15.37 + void set_element(const Type* e) { 15.38 + assert(_element == NULL, ""); 15.39 + _element = e; 15.40 } 15.41 15.42 void print_on(outputStream* st) PRODUCT_RETURN;
16.1 --- a/src/share/vm/opto/graphKit.cpp Mon Sep 09 19:53:28 2013 +0200 16.2 +++ b/src/share/vm/opto/graphKit.cpp Tue Sep 10 14:51:48 2013 -0700 16.3 @@ -3825,8 +3825,13 @@ 16.4 TypeAry::make(TypeInt::CHAR,TypeInt::POS), 16.5 ciTypeArrayKlass::make(T_CHAR), true, 0); 16.6 int value_field_idx = C->get_alias_index(value_field_type); 16.7 - return make_load(ctrl, basic_plus_adr(str, str, value_offset), 16.8 - value_type, T_OBJECT, value_field_idx); 16.9 + Node* load = make_load(ctrl, basic_plus_adr(str, str, value_offset), 16.10 + value_type, T_OBJECT, value_field_idx); 16.11 + // String.value field is known to be @Stable. 16.12 + if (UseImplicitStableValues) { 16.13 + load = cast_array_to_stable(load, value_type); 16.14 + } 16.15 + return load; 16.16 } 16.17 16.18 void GraphKit::store_String_offset(Node* ctrl, Node* str, Node* value) { 16.19 @@ -3844,9 +3849,6 @@ 16.20 const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), 16.21 false, NULL, 0); 16.22 const TypePtr* value_field_type = string_type->add_offset(value_offset); 16.23 - const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull, 16.24 - TypeAry::make(TypeInt::CHAR,TypeInt::POS), 16.25 - ciTypeArrayKlass::make(T_CHAR), true, 0); 16.26 int value_field_idx = C->get_alias_index(value_field_type); 16.27 store_to_memory(ctrl, basic_plus_adr(str, value_offset), 16.28 value, T_OBJECT, value_field_idx); 16.29 @@ -3861,3 +3863,9 @@ 16.30 store_to_memory(ctrl, basic_plus_adr(str, count_offset), 16.31 value, T_INT, count_field_idx); 16.32 } 16.33 + 16.34 +Node* GraphKit::cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type) { 16.35 + // Reify the property as a CastPP node in Ideal graph to comply with monotonicity 16.36 + // assumption of CCP analysis. 16.37 + return _gvn.transform(new(C) CastPPNode(ary, ary_type->cast_to_stable(true))); 16.38 +}
17.1 --- a/src/share/vm/opto/graphKit.hpp Mon Sep 09 19:53:28 2013 +0200 17.2 +++ b/src/share/vm/opto/graphKit.hpp Tue Sep 10 14:51:48 2013 -0700 17.3 @@ -836,6 +836,9 @@ 17.4 // Insert a loop predicate into the graph 17.5 void add_predicate(int nargs = 0); 17.6 void add_predicate_impl(Deoptimization::DeoptReason reason, int nargs); 17.7 + 17.8 + // Produce new array node of stable type 17.9 + Node* cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type); 17.10 }; 17.11 17.12 // Helper class to support building of control flow branches. Upon
18.1 --- a/src/share/vm/opto/library_call.cpp Mon Sep 09 19:53:28 2013 +0200 18.2 +++ b/src/share/vm/opto/library_call.cpp Tue Sep 10 14:51:48 2013 -0700 18.3 @@ -1280,6 +1280,11 @@ 18.4 const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin)); 18.5 const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot); 18.6 18.7 + // String.value field is known to be @Stable. 18.8 + if (UseImplicitStableValues) { 18.9 + target = cast_array_to_stable(target, target_type); 18.10 + } 18.11 + 18.12 IdealKit kit(this, false, true); 18.13 #define __ kit. 18.14 Node* zero = __ ConI(0);
19.1 --- a/src/share/vm/opto/memnode.cpp Mon Sep 09 19:53:28 2013 +0200 19.2 +++ b/src/share/vm/opto/memnode.cpp Tue Sep 10 14:51:48 2013 -0700 19.3 @@ -962,6 +962,19 @@ 19.4 return (uintptr_t)in(Control) + (uintptr_t)in(Memory) + (uintptr_t)in(Address); 19.5 } 19.6 19.7 +static bool skip_through_membars(Compile::AliasType* atp, const TypeInstPtr* tp, bool eliminate_boxing) { 19.8 + if ((atp != NULL) && (atp->index() >= Compile::AliasIdxRaw)) { 19.9 + bool non_volatile = (atp->field() != NULL) && !atp->field()->is_volatile(); 19.10 + bool is_stable_ary = FoldStableValues && 19.11 + (tp != NULL) && (tp->isa_aryptr() != NULL) && 19.12 + tp->isa_aryptr()->is_stable(); 19.13 + 19.14 + return (eliminate_boxing && non_volatile) || is_stable_ary; 19.15 + } 19.16 + 19.17 + return false; 19.18 +} 19.19 + 19.20 //---------------------------can_see_stored_value------------------------------ 19.21 // This routine exists to make sure this set of tests is done the same 19.22 // everywhere. We need to make a coordinated change: first LoadNode::Ideal 19.23 @@ -976,11 +989,9 @@ 19.24 const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr(); 19.25 Compile::AliasType* atp = (tp != NULL) ? phase->C->alias_type(tp) : NULL; 19.26 // This is more general than load from boxing objects. 19.27 - if (phase->C->eliminate_boxing() && (atp != NULL) && 19.28 - (atp->index() >= Compile::AliasIdxRaw) && 19.29 - (atp->field() != NULL) && !atp->field()->is_volatile()) { 19.30 + if (skip_through_membars(atp, tp, phase->C->eliminate_boxing())) { 19.31 uint alias_idx = atp->index(); 19.32 - bool final = atp->field()->is_final(); 19.33 + bool final = !atp->is_rewritable(); 19.34 Node* result = NULL; 19.35 Node* current = st; 19.36 // Skip through chains of MemBarNodes checking the MergeMems for 19.37 @@ -1015,7 +1026,6 @@ 19.38 } 19.39 } 19.40 19.41 - 19.42 // Loop around twice in the case Load -> Initialize -> Store. 19.43 // (See PhaseIterGVN::add_users_to_worklist, which knows about this case.) 19.44 for (int trip = 0; trip <= 1; trip++) { 19.45 @@ -1577,6 +1587,40 @@ 19.46 return NULL; 19.47 } 19.48 19.49 +// Try to constant-fold a stable array element. 19.50 +static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) { 19.51 + assert(ary->is_stable(), "array should be stable"); 19.52 + 19.53 + if (ary->const_oop() != NULL) { 19.54 + // Decode the results of GraphKit::array_element_address. 19.55 + ciArray* aobj = ary->const_oop()->as_array(); 19.56 + ciConstant con = aobj->element_value_by_offset(off); 19.57 + 19.58 + if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) { 19.59 + const Type* con_type = Type::make_from_constant(con); 19.60 + if (con_type != NULL) { 19.61 + if (con_type->isa_aryptr()) { 19.62 + // Join with the array element type, in case it is also stable. 19.63 + int dim = ary->stable_dimension(); 19.64 + con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1); 19.65 + } 19.66 + if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) { 19.67 + con_type = con_type->make_narrowoop(); 19.68 + } 19.69 +#ifndef PRODUCT 19.70 + if (TraceIterativeGVN) { 19.71 + tty->print("FoldStableValues: array element [off=%d]: con_type=", off); 19.72 + con_type->dump(); tty->cr(); 19.73 + } 19.74 +#endif //PRODUCT 19.75 + return con_type; 19.76 + } 19.77 + } 19.78 + } 19.79 + 19.80 + return NULL; 19.81 +} 19.82 + 19.83 //------------------------------Value----------------------------------------- 19.84 const Type *LoadNode::Value( PhaseTransform *phase ) const { 19.85 // Either input is TOP ==> the result is TOP 19.86 @@ -1591,8 +1635,31 @@ 19.87 Compile* C = phase->C; 19.88 19.89 // Try to guess loaded type from pointer type 19.90 - if (tp->base() == Type::AryPtr) { 19.91 - const Type *t = tp->is_aryptr()->elem(); 19.92 + if (tp->isa_aryptr()) { 19.93 + const TypeAryPtr* ary = tp->is_aryptr(); 19.94 + const Type *t = ary->elem(); 19.95 + 19.96 + // Determine whether the reference is beyond the header or not, by comparing 19.97 + // the offset against the offset of the start of the array's data. 19.98 + // Different array types begin at slightly different offsets (12 vs. 16). 19.99 + // We choose T_BYTE as an example base type that is least restrictive 19.100 + // as to alignment, which will therefore produce the smallest 19.101 + // possible base offset. 19.102 + const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE); 19.103 + const bool off_beyond_header = ((uint)off >= (uint)min_base_off); 19.104 + 19.105 + // Try to constant-fold a stable array element. 19.106 + if (FoldStableValues && ary->is_stable()) { 19.107 + // Make sure the reference is not into the header 19.108 + if (off_beyond_header && off != Type::OffsetBot) { 19.109 + assert(adr->is_AddP() && adr->in(AddPNode::Offset)->is_Con(), "offset is a constant"); 19.110 + const Type* con_type = fold_stable_ary_elem(ary, off, memory_type()); 19.111 + if (con_type != NULL) { 19.112 + return con_type; 19.113 + } 19.114 + } 19.115 + } 19.116 + 19.117 // Don't do this for integer types. There is only potential profit if 19.118 // the element type t is lower than _type; that is, for int types, if _type is 19.119 // more restrictive than t. This only happens here if one is short and the other 19.120 @@ -1613,14 +1680,7 @@ 19.121 && Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) { 19.122 // t might actually be lower than _type, if _type is a unique 19.123 // concrete subclass of abstract class t. 19.124 - // Make sure the reference is not into the header, by comparing 19.125 - // the offset against the offset of the start of the array's data. 19.126 - // Different array types begin at slightly different offsets (12 vs. 16). 19.127 - // We choose T_BYTE as an example base type that is least restrictive 19.128 - // as to alignment, which will therefore produce the smallest 19.129 - // possible base offset. 19.130 - const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE); 19.131 - if ((uint)off >= (uint)min_base_off) { // is the offset beyond the header? 19.132 + if (off_beyond_header) { // is the offset beyond the header? 19.133 const Type* jt = t->join(_type); 19.134 // In any case, do not allow the join, per se, to empty out the type. 19.135 if (jt->empty() && !t->empty()) {
20.1 --- a/src/share/vm/opto/parse.hpp Mon Sep 09 19:53:28 2013 +0200 20.2 +++ b/src/share/vm/opto/parse.hpp Tue Sep 10 14:51:48 2013 -0700 20.3 @@ -518,7 +518,7 @@ 20.4 20.5 // loading from a constant field or the constant pool 20.6 // returns false if push failed (non-perm field constants only, not ldcs) 20.7 - bool push_constant(ciConstant con, bool require_constant = false, bool is_autobox_cache = false); 20.8 + bool push_constant(ciConstant con, bool require_constant = false, bool is_autobox_cache = false, const Type* basic_type = NULL); 20.9 20.10 // implementation of object creation bytecodes 20.11 void emit_guard_for_new(ciInstanceKlass* klass);
21.1 --- a/src/share/vm/opto/parse3.cpp Mon Sep 09 19:53:28 2013 +0200 21.2 +++ b/src/share/vm/opto/parse3.cpp Tue Sep 10 14:51:48 2013 -0700 21.3 @@ -147,7 +147,15 @@ 21.4 void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) { 21.5 // Does this field have a constant value? If so, just push the value. 21.6 if (field->is_constant()) { 21.7 - // final field 21.8 + // final or stable field 21.9 + const Type* stable_type = NULL; 21.10 + if (FoldStableValues && field->is_stable()) { 21.11 + stable_type = Type::get_const_type(field->type()); 21.12 + if (field->type()->is_array_klass()) { 21.13 + int stable_dimension = field->type()->as_array_klass()->dimension(); 21.14 + stable_type = stable_type->is_aryptr()->cast_to_stable(true, stable_dimension); 21.15 + } 21.16 + } 21.17 if (field->is_static()) { 21.18 // final static field 21.19 if (C->eliminate_boxing()) { 21.20 @@ -167,11 +175,10 @@ 21.21 } 21.22 } 21.23 } 21.24 - if (push_constant(field->constant_value())) 21.25 + if (push_constant(field->constant_value(), false, false, stable_type)) 21.26 return; 21.27 - } 21.28 - else { 21.29 - // final non-static field 21.30 + } else { 21.31 + // final or stable non-static field 21.32 // Treat final non-static fields of trusted classes (classes in 21.33 // java.lang.invoke and sun.invoke packages and subpackages) as 21.34 // compile time constants. 21.35 @@ -179,8 +186,12 @@ 21.36 const TypeOopPtr* oop_ptr = obj->bottom_type()->isa_oopptr(); 21.37 ciObject* constant_oop = oop_ptr->const_oop(); 21.38 ciConstant constant = field->constant_value_of(constant_oop); 21.39 - if (push_constant(constant, true)) 21.40 - return; 21.41 + if (FoldStableValues && field->is_stable() && constant.is_null_or_zero()) { 21.42 + // fall through to field load; the field is not yet initialized 21.43 + } else { 21.44 + if (push_constant(constant, true, false, stable_type)) 21.45 + return; 21.46 + } 21.47 } 21.48 } 21.49 } 21.50 @@ -301,7 +312,8 @@ 21.51 // Note the presence of writes to final non-static fields, so that we 21.52 // can insert a memory barrier later on to keep the writes from floating 21.53 // out of the constructor. 21.54 - if (is_field && field->is_final()) { 21.55 + // Any method can write a @Stable field; insert memory barriers after those also. 21.56 + if (is_field && (field->is_final() || field->is_stable())) { 21.57 set_wrote_final(true); 21.58 // Preserve allocation ptr to create precedent edge to it in membar 21.59 // generated on exit from constructor. 21.60 @@ -314,35 +326,21 @@ 21.61 } 21.62 21.63 21.64 -bool Parse::push_constant(ciConstant constant, bool require_constant, bool is_autobox_cache) { 21.65 + 21.66 +bool Parse::push_constant(ciConstant constant, bool require_constant, bool is_autobox_cache, const Type* stable_type) { 21.67 + const Type* con_type = Type::make_from_constant(constant, require_constant, is_autobox_cache); 21.68 switch (constant.basic_type()) { 21.69 - case T_BOOLEAN: push( intcon(constant.as_boolean()) ); break; 21.70 - case T_INT: push( intcon(constant.as_int()) ); break; 21.71 - case T_CHAR: push( intcon(constant.as_char()) ); break; 21.72 - case T_BYTE: push( intcon(constant.as_byte()) ); break; 21.73 - case T_SHORT: push( intcon(constant.as_short()) ); break; 21.74 - case T_FLOAT: push( makecon(TypeF::make(constant.as_float())) ); break; 21.75 - case T_DOUBLE: push_pair( makecon(TypeD::make(constant.as_double())) ); break; 21.76 - case T_LONG: push_pair( longcon(constant.as_long()) ); break; 21.77 case T_ARRAY: 21.78 - case T_OBJECT: { 21.79 + case T_OBJECT: 21.80 // cases: 21.81 // can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0) 21.82 // should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2) 21.83 // An oop is not scavengable if it is in the perm gen. 21.84 - ciObject* oop_constant = constant.as_object(); 21.85 - if (oop_constant->is_null_object()) { 21.86 - push( zerocon(T_OBJECT) ); 21.87 - break; 21.88 - } else if (require_constant || oop_constant->should_be_constant()) { 21.89 - push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant, is_autobox_cache)) ); 21.90 - break; 21.91 - } else { 21.92 - // we cannot inline the oop, but we can use it later to narrow a type 21.93 - return false; 21.94 - } 21.95 - } 21.96 - case T_ILLEGAL: { 21.97 + if (stable_type != NULL && con_type != NULL && con_type->isa_oopptr()) 21.98 + con_type = con_type->join(stable_type); 21.99 + break; 21.100 + 21.101 + case T_ILLEGAL: 21.102 // Invalid ciConstant returned due to OutOfMemoryError in the CI 21.103 assert(C->env()->failing(), "otherwise should not see this"); 21.104 // These always occur because of object types; we are going to 21.105 @@ -350,17 +348,16 @@ 21.106 push( zerocon(T_OBJECT) ); 21.107 return false; 21.108 } 21.109 - default: 21.110 - ShouldNotReachHere(); 21.111 + 21.112 + if (con_type == NULL) 21.113 + // we cannot inline the oop, but we can use it later to narrow a type 21.114 return false; 21.115 - } 21.116 21.117 - // success 21.118 + push_node(constant.basic_type(), makecon(con_type)); 21.119 return true; 21.120 } 21.121 21.122 21.123 - 21.124 //============================================================================= 21.125 void Parse::do_anewarray() { 21.126 bool will_link;
22.1 --- a/src/share/vm/opto/type.cpp Mon Sep 09 19:53:28 2013 +0200 22.2 +++ b/src/share/vm/opto/type.cpp Tue Sep 10 14:51:48 2013 -0700 22.3 @@ -189,6 +189,38 @@ 22.4 } 22.5 22.6 22.7 +//-----------------------make_from_constant------------------------------------ 22.8 +const Type* Type::make_from_constant(ciConstant constant, 22.9 + bool require_constant, bool is_autobox_cache) { 22.10 + switch (constant.basic_type()) { 22.11 + case T_BOOLEAN: return TypeInt::make(constant.as_boolean()); 22.12 + case T_CHAR: return TypeInt::make(constant.as_char()); 22.13 + case T_BYTE: return TypeInt::make(constant.as_byte()); 22.14 + case T_SHORT: return TypeInt::make(constant.as_short()); 22.15 + case T_INT: return TypeInt::make(constant.as_int()); 22.16 + case T_LONG: return TypeLong::make(constant.as_long()); 22.17 + case T_FLOAT: return TypeF::make(constant.as_float()); 22.18 + case T_DOUBLE: return TypeD::make(constant.as_double()); 22.19 + case T_ARRAY: 22.20 + case T_OBJECT: 22.21 + { 22.22 + // cases: 22.23 + // can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0) 22.24 + // should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2) 22.25 + // An oop is not scavengable if it is in the perm gen. 22.26 + ciObject* oop_constant = constant.as_object(); 22.27 + if (oop_constant->is_null_object()) { 22.28 + return Type::get_zero_type(T_OBJECT); 22.29 + } else if (require_constant || oop_constant->should_be_constant()) { 22.30 + return TypeOopPtr::make_from_constant(oop_constant, require_constant, is_autobox_cache); 22.31 + } 22.32 + } 22.33 + } 22.34 + // Fall through to failure 22.35 + return NULL; 22.36 +} 22.37 + 22.38 + 22.39 //------------------------------make------------------------------------------- 22.40 // Create a simple Type, with default empty symbol sets. Then hashcons it 22.41 // and look for an existing copy in the type dictionary. 22.42 @@ -1824,12 +1856,12 @@ 22.43 } 22.44 22.45 //------------------------------make------------------------------------------- 22.46 -const TypeAry *TypeAry::make( const Type *elem, const TypeInt *size) { 22.47 +const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable) { 22.48 if (UseCompressedOops && elem->isa_oopptr()) { 22.49 elem = elem->make_narrowoop(); 22.50 } 22.51 size = normalize_array_size(size); 22.52 - return (TypeAry*)(new TypeAry(elem,size))->hashcons(); 22.53 + return (TypeAry*)(new TypeAry(elem,size,stable))->hashcons(); 22.54 } 22.55 22.56 //------------------------------meet------------------------------------------- 22.57 @@ -1850,7 +1882,8 @@ 22.58 case Array: { // Meeting 2 arrays? 22.59 const TypeAry *a = t->is_ary(); 22.60 return TypeAry::make(_elem->meet(a->_elem), 22.61 - _size->xmeet(a->_size)->is_int()); 22.62 + _size->xmeet(a->_size)->is_int(), 22.63 + _stable & a->_stable); 22.64 } 22.65 case Top: 22.66 break; 22.67 @@ -1863,7 +1896,7 @@ 22.68 const Type *TypeAry::xdual() const { 22.69 const TypeInt* size_dual = _size->dual()->is_int(); 22.70 size_dual = normalize_array_size(size_dual); 22.71 - return new TypeAry( _elem->dual(), size_dual); 22.72 + return new TypeAry(_elem->dual(), size_dual, !_stable); 22.73 } 22.74 22.75 //------------------------------eq--------------------------------------------- 22.76 @@ -1871,13 +1904,14 @@ 22.77 bool TypeAry::eq( const Type *t ) const { 22.78 const TypeAry *a = (const TypeAry*)t; 22.79 return _elem == a->_elem && 22.80 + _stable == a->_stable && 22.81 _size == a->_size; 22.82 } 22.83 22.84 //------------------------------hash------------------------------------------- 22.85 // Type-specific hashing function. 22.86 int TypeAry::hash(void) const { 22.87 - return (intptr_t)_elem + (intptr_t)_size; 22.88 + return (intptr_t)_elem + (intptr_t)_size + (_stable ? 43 : 0); 22.89 } 22.90 22.91 //----------------------interface_vs_oop--------------------------------------- 22.92 @@ -1894,6 +1928,7 @@ 22.93 //------------------------------dump2------------------------------------------ 22.94 #ifndef PRODUCT 22.95 void TypeAry::dump2( Dict &d, uint depth, outputStream *st ) const { 22.96 + if (_stable) st->print("stable:"); 22.97 _elem->dump2(d, depth, st); 22.98 st->print("["); 22.99 _size->dump2(d, depth, st); 22.100 @@ -3457,11 +3492,39 @@ 22.101 assert(new_size != NULL, ""); 22.102 new_size = narrow_size_type(new_size); 22.103 if (new_size == size()) return this; 22.104 - const TypeAry* new_ary = TypeAry::make(elem(), new_size); 22.105 + const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable()); 22.106 return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id); 22.107 } 22.108 22.109 22.110 +//------------------------------cast_to_stable--------------------------------- 22.111 +const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const { 22.112 + if (stable_dimension <= 0 || (stable_dimension == 1 && stable == this->is_stable())) 22.113 + return this; 22.114 + 22.115 + const Type* elem = this->elem(); 22.116 + const TypePtr* elem_ptr = elem->make_ptr(); 22.117 + 22.118 + if (stable_dimension > 1 && elem_ptr != NULL && elem_ptr->isa_aryptr()) { 22.119 + // If this is widened from a narrow oop, TypeAry::make will re-narrow it. 22.120 + elem = elem_ptr = elem_ptr->is_aryptr()->cast_to_stable(stable, stable_dimension - 1); 22.121 + } 22.122 + 22.123 + const TypeAry* new_ary = TypeAry::make(elem, size(), stable); 22.124 + 22.125 + return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id); 22.126 +} 22.127 + 22.128 +//-----------------------------stable_dimension-------------------------------- 22.129 +int TypeAryPtr::stable_dimension() const { 22.130 + if (!is_stable()) return 0; 22.131 + int dim = 1; 22.132 + const TypePtr* elem_ptr = elem()->make_ptr(); 22.133 + if (elem_ptr != NULL && elem_ptr->isa_aryptr()) 22.134 + dim += elem_ptr->is_aryptr()->stable_dimension(); 22.135 + return dim; 22.136 +} 22.137 + 22.138 //------------------------------eq--------------------------------------------- 22.139 // Structural equality check for Type representations 22.140 bool TypeAryPtr::eq( const Type *t ) const { 22.141 @@ -3570,7 +3633,7 @@ 22.142 // Something like byte[int+] meets char[int+]. 22.143 // This must fall to bottom, not (int[-128..65535])[int+]. 22.144 instance_id = InstanceBot; 22.145 - tary = TypeAry::make(Type::BOTTOM, tary->_size); 22.146 + tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); 22.147 } 22.148 } else // Non integral arrays. 22.149 // Must fall to bottom if exact klasses in upper lattice 22.150 @@ -3584,7 +3647,7 @@ 22.151 (tap ->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) || 22.152 // 'this' is exact and super or unrelated: 22.153 (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { 22.154 - tary = TypeAry::make(Type::BOTTOM, tary->_size); 22.155 + tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); 22.156 return make( NotNull, NULL, tary, lazy_klass, false, off, InstanceBot ); 22.157 } 22.158
23.1 --- a/src/share/vm/opto/type.hpp Mon Sep 09 19:53:28 2013 +0200 23.2 +++ b/src/share/vm/opto/type.hpp Tue Sep 10 14:51:48 2013 -0700 23.3 @@ -372,6 +372,10 @@ 23.4 // Mapping from CI type system to compiler type: 23.5 static const Type* get_typeflow_type(ciType* type); 23.6 23.7 + static const Type* make_from_constant(ciConstant constant, 23.8 + bool require_constant = false, 23.9 + bool is_autobox_cache = false); 23.10 + 23.11 private: 23.12 // support arrays 23.13 static const BasicType _basic_type[]; 23.14 @@ -588,8 +592,8 @@ 23.15 //------------------------------TypeAry---------------------------------------- 23.16 // Class of Array Types 23.17 class TypeAry : public Type { 23.18 - TypeAry( const Type *elem, const TypeInt *size) : Type(Array), 23.19 - _elem(elem), _size(size) {} 23.20 + TypeAry(const Type* elem, const TypeInt* size, bool stable) : Type(Array), 23.21 + _elem(elem), _size(size), _stable(stable) {} 23.22 public: 23.23 virtual bool eq( const Type *t ) const; 23.24 virtual int hash() const; // Type specific hashing 23.25 @@ -599,10 +603,11 @@ 23.26 private: 23.27 const Type *_elem; // Element type of array 23.28 const TypeInt *_size; // Elements in array 23.29 + const bool _stable; // Are elements @Stable? 23.30 friend class TypeAryPtr; 23.31 23.32 public: 23.33 - static const TypeAry *make( const Type *elem, const TypeInt *size); 23.34 + static const TypeAry* make(const Type* elem, const TypeInt* size, bool stable = false); 23.35 23.36 virtual const Type *xmeet( const Type *t ) const; 23.37 virtual const Type *xdual() const; // Compute dual right now. 23.38 @@ -988,6 +993,7 @@ 23.39 const TypeAry* ary() const { return _ary; } 23.40 const Type* elem() const { return _ary->_elem; } 23.41 const TypeInt* size() const { return _ary->_size; } 23.42 + bool is_stable() const { return _ary->_stable; } 23.43 23.44 bool is_autobox_cache() const { return _is_autobox_cache; } 23.45 23.46 @@ -1011,6 +1017,9 @@ 23.47 virtual const Type *xmeet( const Type *t ) const; 23.48 virtual const Type *xdual() const; // Compute dual right now. 23.49 23.50 + const TypeAryPtr* cast_to_stable(bool stable, int stable_dimension = 1) const; 23.51 + int stable_dimension() const; 23.52 + 23.53 // Convenience common pre-built types. 23.54 static const TypeAryPtr *RANGE; 23.55 static const TypeAryPtr *OOPS;
24.1 --- a/src/share/vm/runtime/globals.hpp Mon Sep 09 19:53:28 2013 +0200 24.2 +++ b/src/share/vm/runtime/globals.hpp Tue Sep 10 14:51:48 2013 -0700 24.3 @@ -3649,6 +3649,9 @@ 24.4 experimental(bool, TrustFinalNonStaticFields, false, \ 24.5 "trust final non-static declarations for constant folding") \ 24.6 \ 24.7 + experimental(bool, FoldStableValues, false, \ 24.8 + "Private flag to control optimizations for stable variables") \ 24.9 + \ 24.10 develop(bool, TraceInvokeDynamic, false, \ 24.11 "trace internal invoke dynamic operations") \ 24.12 \
25.1 --- a/src/share/vm/utilities/accessFlags.hpp Mon Sep 09 19:53:28 2013 +0200 25.2 +++ b/src/share/vm/utilities/accessFlags.hpp Tue Sep 10 14:51:48 2013 -0700 25.3 @@ -78,11 +78,13 @@ 25.4 JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI 25.5 JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI 25.6 JVM_ACC_FIELD_INTERNAL = 0x00000400, // internal field, same as JVM_ACC_ABSTRACT 25.7 + JVM_ACC_FIELD_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED 25.8 JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature 25.9 25.10 JVM_ACC_FIELD_INTERNAL_FLAGS = JVM_ACC_FIELD_ACCESS_WATCHED | 25.11 JVM_ACC_FIELD_MODIFICATION_WATCHED | 25.12 JVM_ACC_FIELD_INTERNAL | 25.13 + JVM_ACC_FIELD_STABLE | 25.14 JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE, 25.15 25.16 // flags accepted by set_field_flags() 25.17 @@ -148,6 +150,7 @@ 25.18 { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; } 25.19 bool on_stack() const { return (_flags & JVM_ACC_ON_STACK) != 0; } 25.20 bool is_internal() const { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; } 25.21 + bool is_stable() const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; } 25.22 bool field_has_generic_signature() const 25.23 { return (_flags & JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) != 0; } 25.24