view anno-stable-8001107.patch @ 509:37735140b62a

rebase to current hsx/hotspot-comp
author jrose
date Sat, 03 Nov 2012 19:00:15 -0700
parents b6f0babd7cf1
children c4e42349c4b6
line wrap: on
line source
8001107: @Stable annotation for constant folding of lazily evaluated variables

diff --git a/src/share/vm/ci/ciArray.cpp b/src/share/vm/ci/ciArray.cpp
--- a/src/share/vm/ci/ciArray.cpp
+++ b/src/share/vm/ci/ciArray.cpp
@@ -26,12 +26,102 @@
 #include "ci/ciArray.hpp"
 #include "ci/ciKlass.hpp"
 #include "ci/ciUtilities.hpp"
+#include "oops/objArrayOop.hpp"
+#include "oops/typeArrayOop.hpp"
 
 // ciArray
 //
 // This class represents an arrayOop in the HotSpot virtual
 // machine.
 
+ciArrayKlass* ciArray::array_type() {
+  return klass()->as_array_klass();
+}
+
+ciType* ciArray::element_type() {
+  return array_type()->element_type();
+}
+
+BasicType ciArray::element_basic_type() {
+  return element_type()->basic_type();
+}
+
+static BasicType fixup_element_type(BasicType bt) {
+  if (bt == T_ARRAY)    return T_OBJECT;
+  if (bt == T_BOOLEAN)  return T_BYTE;
+  return bt;
+}
+
+ciConstant ciArray::element_value_impl(BasicType elembt,
+                                       arrayOop ary,
+                                       int index) {
+  if (ary == NULL)
+    return ciConstant();
+  assert(ary->is_array(), "");
+  if (index < 0 || index >= ary->length())
+    return ciConstant();
+  ArrayKlass* ak = (ArrayKlass*) ary->klass();
+  BasicType abt = ak->element_type();
+  if (fixup_element_type(elembt) !=
+      fixup_element_type(abt))
+    return ciConstant();
+  switch (elembt) {
+  case T_ARRAY:
+  case T_OBJECT:
+    {
+      assert(ary->is_objArray(), "");
+      objArrayOop objary = (objArrayOop) ary;
+      oop elem = objary->obj_at(index);
+      ciEnv* env = CURRENT_ENV;
+      ciObject* box = env->get_object(elem);
+      return ciConstant(T_OBJECT, box);
+    }
+  }
+  assert(ary->is_typeArray(), "");
+  typeArrayOop tary = (typeArrayOop) ary;
+  jint value = 0;
+  switch (elembt) {
+  case T_LONG:          return ciConstant(tary->long_at(index));
+  case T_FLOAT:         return ciConstant(tary->float_at(index));
+  case T_DOUBLE:        return ciConstant(tary->double_at(index));
+  default:              return ciConstant();
+  case T_BYTE:          value = tary->byte_at(index);           break;
+  case T_BOOLEAN:       value = tary->byte_at(index) & 1;       break;
+  case T_SHORT:         value = tary->short_at(index);          break;
+  case T_CHAR:          value = tary->char_at(index);           break;
+  case T_INT:           value = tary->int_at(index);            break;
+  }
+  return ciConstant(elembt, value);
+}
+
+// ------------------------------------------------------------------
+// ciArray::element_value
+//
+// Current value of an element.
+// Returns T_ILLEGAL if there is no element at the given index.
+ciConstant ciArray::element_value(int index) {
+  BasicType elembt = element_basic_type();
+  GUARDED_VM_ENTRY(
+    return element_value_impl(elembt, get_arrayOop(), index);
+  )
+}
+
+// ------------------------------------------------------------------
+// ciArray::element_value_by_offset
+//
+// Current value of an element at the specified offset.
+// Returns T_ILLEGAL if there is no element at the given offset.
+ciConstant ciArray::element_value_by_offset(intptr_t element_offset) {
+  BasicType elembt = element_basic_type();
+  intptr_t shift  = exact_log2(type2aelembytes(elembt));
+  intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt);
+  intptr_t index = (element_offset - header) >> shift;
+  intptr_t offset = header + ((intptr_t)index << shift);
+  if (offset != element_offset || index != (jint)index)
+    return ciConstant();
+  return element_value((jint) index);
+}
+
 // ------------------------------------------------------------------
 // ciArray::print_impl
 //
diff --git a/src/share/vm/ci/ciArray.hpp b/src/share/vm/ci/ciArray.hpp
--- a/src/share/vm/ci/ciArray.hpp
+++ b/src/share/vm/ci/ciArray.hpp
@@ -51,9 +51,24 @@
 
   void print_impl(outputStream* st);
 
+  ciConstant element_value_impl(BasicType elembt, arrayOop ary, int index);
+
 public:
   int length() { return _length; }
 
+  // Convenience routines.
+  ciArrayKlass* array_type();       // klass()->as_array_klass()
+  ciType* element_type();           // array_type()->element_type()
+  BasicType element_basic_type();   // element_type()->basic_type()
+
+  // Current value of an element.
+  // Returns T_ILLEGAL if there is no element at the given index.
+  ciConstant element_value(int index);
+
+  // Current value of an element at the specified offset.
+  // Returns T_ILLEGAL if there is no element at the given offset.
+  ciConstant element_value_by_offset(intptr_t element_offset);
+
   // What kind of ciObject is this?
   bool is_array()        { return true; }
   bool is_java_object()  { return true; }
diff --git a/src/share/vm/ci/ciConstant.hpp b/src/share/vm/ci/ciConstant.hpp
--- a/src/share/vm/ci/ciConstant.hpp
+++ b/src/share/vm/ci/ciConstant.hpp
@@ -41,7 +41,6 @@
   union {
     jint      _int;
     jlong     _long;
-    jint      _long_half[2];
     jfloat    _float;
     jdouble   _double;
     ciObject* _object;
@@ -111,6 +110,19 @@
     return _value._object;
   }
 
+  bool     is_null_or_zero() const {
+    if (!is_java_primitive(basic_type()))
+      return as_object()->is_null_object();
+    else if (type2size[basic_type()] == 1)
+      // treat float bits as int, to avoid comparison with -0 and NaN
+      return (_value._int == 0);
+    else if (type2size[basic_type()] == 2)
+      // treat double bits as long, to avoid comparison with -0 and NaN
+      return (_value._long == 0);
+    else
+      return false;
+  }
+
   // Debugging output
   void print();
 };
diff --git a/src/share/vm/ci/ciField.cpp b/src/share/vm/ci/ciField.cpp
--- a/src/share/vm/ci/ciField.cpp
+++ b/src/share/vm/ci/ciField.cpp
@@ -189,12 +189,14 @@
   _holder = CURRENT_ENV->get_instance_klass(fd->field_holder());
 
   // Check to see if the field is constant.
-  if (_holder->is_initialized() && this->is_final()) {
+  bool is_final = this->is_final();
+  bool is_stable = this->is_stable();
+  if (_holder->is_initialized() && (is_final || is_stable)) {
     if (!this->is_static()) {
       // A field can be constant if it's a final static field or if
       // it's a final non-static field of a trusted class (classes in
       // java.lang.invoke and sun.invoke packages and subpackages).
-      if (trust_final_non_static_fields(_holder)) {
+      if (is_stable || trust_final_non_static_fields(_holder)) {
         _is_constant = true;
         return;
       }
@@ -227,7 +229,6 @@
 
     Handle mirror = k->java_mirror();
 
-    _is_constant = true;
     switch(type()->basic_type()) {
     case T_BYTE:
       _constant_value = ciConstant(type()->basic_type(), mirror->byte_field(_offset));
@@ -273,6 +274,12 @@
         }
       }
     }
+    if (is_stable && _constant_value.is_null_or_zero()) {
+      // It is not a constant after all; treat it as uninitialized.
+      _is_constant = false;
+    } else {
+      _is_constant = true;
+    }
   } else {
     _is_constant = false;
   }
@@ -373,6 +380,7 @@
   tty->print(" offset=%d type=", _offset);
   if (_type != NULL) _type->print_name();
   else               tty->print("(reference)");
+  tty->print(" flags=%04x", flags().as_int());
   tty->print(" is_constant=%s", bool_to_str(_is_constant));
   if (_is_constant && is_static()) {
     tty->print(" constant_value=");
diff --git a/src/share/vm/ci/ciField.hpp b/src/share/vm/ci/ciField.hpp
--- a/src/share/vm/ci/ciField.hpp
+++ b/src/share/vm/ci/ciField.hpp
@@ -139,7 +139,10 @@
   //      non-constant fields.  These are java.lang.System.in
   //      and java.lang.System.out.  Abomination.
   //
-  // Note: the check for case 4 is not yet implemented.
+  // A field is also considered constant if it is marked @Stable
+  // and is non-null (or non-zero, if a primitive).
+  // For non-static fields, the null/zero check must be
+  // arranged by the user, as constant_value().is_null_or_zero().
   bool is_constant() { return _is_constant; }
 
   // Get the constant value of this field.
@@ -173,6 +176,7 @@
   bool is_protected   () { return flags().is_protected(); }
   bool is_static      () { return flags().is_static(); }
   bool is_final       () { return flags().is_final(); }
+  bool is_stable      () { return flags().is_stable(); }
   bool is_volatile    () { return flags().is_volatile(); }
   bool is_transient   () { return flags().is_transient(); }
 
diff --git a/src/share/vm/ci/ciFlags.hpp b/src/share/vm/ci/ciFlags.hpp
--- a/src/share/vm/ci/ciFlags.hpp
+++ b/src/share/vm/ci/ciFlags.hpp
@@ -59,6 +59,7 @@
   bool is_interface   () const         { return (_flags & JVM_ACC_INTERFACE   ) != 0; }
   bool is_abstract    () const         { return (_flags & JVM_ACC_ABSTRACT    ) != 0; }
   bool is_strict      () const         { return (_flags & JVM_ACC_STRICT      ) != 0; }
+  bool is_stable      () const         { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
 
   // Conversion
   jint   as_int()                      { return _flags; }
diff --git a/src/share/vm/ci/ciInstance.cpp b/src/share/vm/ci/ciInstance.cpp
--- a/src/share/vm/ci/ciInstance.cpp
+++ b/src/share/vm/ci/ciInstance.cpp
@@ -127,6 +127,7 @@
 ciConstant ciInstance::field_value_by_offset(int field_offset) {
   ciInstanceKlass* ik = klass()->as_instance_klass();
   ciField* field = ik->get_field_by_offset(field_offset, false);
+  if (field == NULL)  return ciConstant();  // T_ILLEGAL
   return field_value(field);
 }
 
diff --git a/src/share/vm/ci/ciTypeArray.cpp b/src/share/vm/ci/ciTypeArray.cpp
--- a/src/share/vm/ci/ciTypeArray.cpp
+++ b/src/share/vm/ci/ciTypeArray.cpp
@@ -39,5 +39,10 @@
 jchar ciTypeArray::char_at(int index) {
   VM_ENTRY_MARK;
   assert(index >= 0 && index < length(), "out of range");
-  return get_typeArrayOop()->char_at(index);
+  jchar c = element_value(index).as_char();
+#ifdef ASSERT
+  jchar d = get_typeArrayOop()->char_at(index);
+  assert(c == d, "");
+#endif //ASSERT
+  return c;
 }
diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp
--- a/src/share/vm/classfile/classFileParser.cpp
+++ b/src/share/vm/classfile/classFileParser.cpp
@@ -959,6 +959,7 @@
         runtime_visible_annotations_length = attribute_length;
         runtime_visible_annotations = cfs->get_u1_buffer();
         assert(runtime_visible_annotations != NULL, "null visible annotations");
+        parse_annotations(loader_data, runtime_visible_annotations, runtime_visible_annotations_length, cp, parsed_annotations, CHECK);
         cfs->skip_u1(runtime_visible_annotations_length, CHECK);
       } else if (PreserveAllAnnotations && attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
         runtime_invisible_annotations_length = attribute_length;
@@ -1695,7 +1696,8 @@
 }
 
 // Sift through annotations, looking for those significant to the VM:
-void ClassFileParser::parse_annotations(u1* buffer, int limit,
+void ClassFileParser::parse_annotations(ClassLoaderData* loader_data,
+                                        u1* buffer, int limit,
                                         constantPoolHandle cp,
                                         ClassFileParser::AnnotationCollector* coll,
                                         TRAPS) {
@@ -1733,7 +1735,7 @@
     }
 
     // Here is where parsing particular annotations will take place.
-    AnnotationCollector::ID id = coll->annotation_index(aname);
+    AnnotationCollector::ID id = coll->annotation_index(loader_data, aname);
     if (id == AnnotationCollector::_unknown)  continue;
     coll->set_annotation(id);
     // If there are no values, just set the bit and move on:
@@ -1762,28 +1764,44 @@
   }
 }
 
-ClassFileParser::AnnotationCollector::ID ClassFileParser::AnnotationCollector::annotation_index(Symbol* name) {
+ClassFileParser::AnnotationCollector::ID
+ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_data,
+                                                       Symbol* name) {
   vmSymbols::SID sid = vmSymbols::find_sid(name);
+  bool privileged = false;
+  if (loader_data->is_the_null_class_loader_data()) {
+    // Privileged code can use all annotations.  Other code silently drops some.
+    privileged = true;
+  }
   switch (sid) {
   case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature):
     if (_location != _in_method)  break;  // only allow for methods
+    if (!privileged)              break;  // only allow in privileged code
     return _method_ForceInline;
   case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature):
     if (_location != _in_method)  break;  // only allow for methods
+    if (!privileged)              break;  // only allow in privileged code
     return _method_DontInline;
   case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature):
     if (_location != _in_method)  break;  // only allow for methods
+    if (!privileged)              break;  // only allow in privileged code
     return _method_LambdaForm_Compiled;
   case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Hidden_signature):
     if (_location != _in_method)  break;  // only allow for methods
+    if (!privileged)              break;  // only allow in privileged code
     return _method_LambdaForm_Hidden;
+  case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_invoke_Stable_signature):
+    if (_location != _in_field)   break;  // only allow for fields
+    if (!privileged)              break;  // only allow in privileged code
+    return _field_Stable;
   default: break;
   }
   return AnnotationCollector::_unknown;
 }
 
 void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) {
-  fatal("no field annotations yet");
+  if (has_annotation(_field_Stable))
+    f->set_stable(true);
 }
 
 void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) {
@@ -2125,7 +2143,7 @@
         runtime_visible_annotations_length = method_attribute_length;
         runtime_visible_annotations = cfs->get_u1_buffer();
         assert(runtime_visible_annotations != NULL, "null visible annotations");
-        parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, cp, &parsed_annotations, CHECK_(nullHandle));
+        parse_annotations(loader_data, runtime_visible_annotations, runtime_visible_annotations_length, cp, &parsed_annotations, CHECK_(nullHandle));
         cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle));
       } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
         runtime_invisible_annotations_length = method_attribute_length;
@@ -2785,7 +2803,8 @@
         runtime_visible_annotations_length = attribute_length;
         runtime_visible_annotations = cfs->get_u1_buffer();
         assert(runtime_visible_annotations != NULL, "null visible annotations");
-        parse_annotations(runtime_visible_annotations,
+        parse_annotations(loader_data,
+                          runtime_visible_annotations,
                           runtime_visible_annotations_length,
                           cp,
                           parsed_annotations,
diff --git a/src/share/vm/classfile/classFileParser.hpp b/src/share/vm/classfile/classFileParser.hpp
--- a/src/share/vm/classfile/classFileParser.hpp
+++ b/src/share/vm/classfile/classFileParser.hpp
@@ -92,6 +92,7 @@
       _method_DontInline,
       _method_LambdaForm_Compiled,
       _method_LambdaForm_Hidden,
+      _field_Stable,
       _annotation_LIMIT
     };
     const Location _location;
@@ -102,7 +103,7 @@
       assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
     }
     // If this annotation name has an ID, report it (or _none).
-    ID annotation_index(Symbol* name);
+    ID annotation_index(ClassLoaderData* loader_data, Symbol* name);
     // Set the annotation name:
     void set_annotation(ID id) {
       assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
@@ -237,7 +238,8 @@
                                         int runtime_invisible_annotations_length, TRAPS);
   int skip_annotation(u1* buffer, int limit, int index);
   int skip_annotation_value(u1* buffer, int limit, int index);
-  void parse_annotations(u1* buffer, int limit, constantPoolHandle cp,
+  void parse_annotations(ClassLoaderData* loader_data,
+                         u1* buffer, int limit, constantPoolHandle cp,
                          /* Results (currently, only one result is supported): */
                          AnnotationCollector* result,
                          TRAPS);
diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
--- a/src/share/vm/classfile/vmSymbols.hpp
+++ b/src/share/vm/classfile/vmSymbols.hpp
@@ -255,6 +255,7 @@
   template(java_lang_invoke_LambdaForm,               "java/lang/invoke/LambdaForm")              \
   template(java_lang_invoke_ForceInline_signature,    "Ljava/lang/invoke/ForceInline;")           \
   template(java_lang_invoke_DontInline_signature,     "Ljava/lang/invoke/DontInline;")            \
+  template(sun_invoke_Stable_signature,               "Lsun/invoke/Stable;")                      \
   template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \
   template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;")  \
   /* internal up-calls made only by the JVM, via class sun.invoke.MethodHandleNatives: */         \
diff --git a/src/share/vm/oops/fieldInfo.hpp b/src/share/vm/oops/fieldInfo.hpp
--- a/src/share/vm/oops/fieldInfo.hpp
+++ b/src/share/vm/oops/fieldInfo.hpp
@@ -114,6 +114,14 @@
     return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0;
   }
 
+  bool is_stable() const {
+    return (access_flags() & JVM_ACC_FIELD_STABLE) != 0;
+  }
+  void set_stable(bool z) {
+    if (z) _shorts[access_flags_offset] |=  JVM_ACC_FIELD_STABLE;
+    else   _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE;
+  }
+
   Symbol* lookup_symbol(int symbol_index) const {
     assert(is_internal(), "only internal fields");
     return vmSymbols::symbol_at((vmSymbols::SID)symbol_index);
diff --git a/src/share/vm/opto/c2_globals.hpp b/src/share/vm/opto/c2_globals.hpp
--- a/src/share/vm/opto/c2_globals.hpp
+++ b/src/share/vm/opto/c2_globals.hpp
@@ -433,6 +433,9 @@
   diagnostic(bool, EliminateAutoBox, false,                                 \
           "Private flag to control optimizations for autobox elimination")  \
                                                                             \
+  diagnostic(bool, FoldStableValues, false,                                 \
+          "Private flag to control optimizations for stable variables")     \
+                                                                            \
   product(intx, AutoBoxCacheMax, 128,                                       \
           "Sets max value cached by the java.lang.Integer autobox cache")   \
                                                                             \
diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp
--- a/src/share/vm/opto/compile.cpp
+++ b/src/share/vm/opto/compile.cpp
@@ -1162,6 +1162,10 @@
 
   // Array pointers need some flattening
   const TypeAryPtr *ta = tj->isa_aryptr();
+  if (ta && ta->stable()) {
+    // Erase stability property for alias analysis.
+    tj = ta = ta->cast_to_stable(false);
+  }
   if( ta && is_known_inst ) {
     if ( offset != Type::OffsetBot &&
          offset > arrayOopDesc::length_offset_in_bytes() ) {
@@ -1362,6 +1366,7 @@
   _index = i;
   _adr_type = at;
   _field = NULL;
+  _element = NULL;
   _is_rewritable = true; // default
   const TypeOopPtr *atoop = (at != NULL) ? at->isa_oopptr() : NULL;
   if (atoop != NULL && atoop->is_known_instance()) {
@@ -1480,6 +1485,15 @@
           && flat->is_instptr()->klass() == env()->Class_klass())
         alias_type(idx)->set_rewritable(false);
     }
+    if (flat->isa_aryptr()) {
+#ifdef ASSERT
+      const int header_size_min  = arrayOopDesc::base_offset_in_bytes(T_BYTE);
+      // (T_BYTE has the weakest alignment and size restrictions...)
+      assert(flat->offset() < header_size_min, "array body reference must be OffsetBot");
+#endif
+      if (flat->offset() == TypePtr::OffsetBot)
+        alias_type(idx)->set_element(flat->is_aryptr()->elem());
+    }
     if (flat->isa_klassptr()) {
       if (flat->offset() == in_bytes(Klass::super_check_offset_offset()))
         alias_type(idx)->set_rewritable(false);
@@ -1542,7 +1556,7 @@
   else
     t = TypeOopPtr::make_from_klass_raw(field->holder());
   AliasType* atp = alias_type(t->add_offset(field->offset_in_bytes()), field);
-  assert(field->is_final() == !atp->is_rewritable(), "must get the rewritable bits correct");
+  assert((field->is_final() || field->is_stable()) == !atp->is_rewritable(), "must get the rewritable bits correct");
   return atp;
 }
 
diff --git a/src/share/vm/opto/compile.hpp b/src/share/vm/opto/compile.hpp
--- a/src/share/vm/opto/compile.hpp
+++ b/src/share/vm/opto/compile.hpp
@@ -69,6 +69,7 @@
 class StartNode;
 class SafePointNode;
 class JVMState;
+class Type;
 class TypeData;
 class TypePtr;
 class TypeFunc;
@@ -111,6 +112,7 @@
     int             _index;         // unique index, used with MergeMemNode
     const TypePtr*  _adr_type;      // normalized address type
     ciField*        _field;         // relevant instance field, or null if none
+    const Type*     _element;       // relevant array element type, or null if none
     bool            _is_rewritable; // false if the memory is write-once only
     int             _general_index; // if this is type is an instance, the general
                                     // type that this is an instance of
@@ -121,6 +123,7 @@
     int             index()         const { return _index; }
     const TypePtr*  adr_type()      const { return _adr_type; }
     ciField*        field()         const { return _field; }
+    const Type*     element()       const { return _element; }
     bool            is_rewritable() const { return _is_rewritable; }
     bool            is_volatile()   const { return (_field ? _field->is_volatile() : false); }
     int             general_index() const { return (_general_index != 0) ? _general_index : _index; }
@@ -129,7 +132,12 @@
     void set_field(ciField* f) {
       assert(!_field,"");
       _field = f;
-      if (f->is_final())  _is_rewritable = false;
+      if (f->is_final() || f->is_stable())  _is_rewritable = false;
+      // In the case of @Stable, multiple writes are possible but may be assumed to be no-ops.
+    }
+    void set_element(const Type* e) {
+      assert(!_element,"");
+      _element = e;
     }
 
     void print_on(outputStream* st) PRODUCT_RETURN;
diff --git a/src/share/vm/opto/graphKit.cpp b/src/share/vm/opto/graphKit.cpp
--- a/src/share/vm/opto/graphKit.cpp
+++ b/src/share/vm/opto/graphKit.cpp
@@ -3788,7 +3788,7 @@
                                                      false, NULL, 0);
   const TypePtr* value_field_type = string_type->add_offset(value_offset);
   const TypeAryPtr*  value_type = TypeAryPtr::make(TypePtr::NotNull,
-                                                   TypeAry::make(TypeInt::CHAR,TypeInt::POS),
+                                                   TypeAry::make(TypeInt::CHAR,TypeInt::POS,/*stable=*/true),
                                                    ciTypeArrayKlass::make(T_CHAR), true, 0);
   int value_field_idx = C->get_alias_index(value_field_type);
   return make_load(ctrl, basic_plus_adr(str, str, value_offset),
@@ -3811,7 +3811,7 @@
                                                      false, NULL, 0);
   const TypePtr* value_field_type = string_type->add_offset(value_offset);
   const TypeAryPtr*  value_type = TypeAryPtr::make(TypePtr::NotNull,
-                                                   TypeAry::make(TypeInt::CHAR,TypeInt::POS),
+                                                   TypeAry::make(TypeInt::CHAR,TypeInt::POS,/*stable=*/true),
                                                    ciTypeArrayKlass::make(T_CHAR), true, 0);
   int value_field_idx = C->get_alias_index(value_field_type);
   store_to_memory(ctrl, basic_plus_adr(str, value_offset),
diff --git a/src/share/vm/opto/library_call.cpp b/src/share/vm/opto/library_call.cpp
--- a/src/share/vm/opto/library_call.cpp
+++ b/src/share/vm/opto/library_call.cpp
@@ -1230,7 +1230,7 @@
 
   Node* target = _gvn.transform( makecon(TypeOopPtr::make_from_constant(target_array, true)) );
   jint target_length = target_array->length();
-  const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin));
+  const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin), /*stable=*/true);
   const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot);
 
   IdealKit kit(this, false, true);
diff --git a/src/share/vm/opto/memnode.cpp b/src/share/vm/opto/memnode.cpp
--- a/src/share/vm/opto/memnode.cpp
+++ b/src/share/vm/opto/memnode.cpp
@@ -932,12 +932,13 @@
 Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
   Node* ld_adr = in(MemNode::Address);
 
-  const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr();
+  const TypeOopPtr* tp = phase->type(ld_adr)->isa_oopptr();
   Compile::AliasType* atp = tp != NULL ? phase->C->alias_type(tp) : NULL;
-  if (EliminateAutoBox && atp != NULL && atp->index() >= Compile::AliasIdxRaw &&
-      atp->field() != NULL && !atp->field()->is_volatile()) {
+  if (atp != NULL && atp->index() >= Compile::AliasIdxRaw &&
+      ((EliminateAutoBox && atp->field() != NULL && !atp->field()->is_volatile())
+       || (FoldStableValues && tp->isa_aryptr() && (tp->is_aryptr()->stable())))) {
     uint alias_idx = atp->index();
-    bool final = atp->field()->is_final();
+    bool final = !atp->is_rewritable();
     Node* result = NULL;
     Node* current = st;
     // Skip through chains of MemBarNodes checking the MergeMems for
@@ -972,7 +973,6 @@
     }
   }
 
-
   // Loop around twice in the case Load -> Initialize -> Store.
   // (See PhaseIterGVN::add_users_to_worklist, which knows about this case.)
   for (int trip = 0; trip <= 1; trip++) {
@@ -1527,6 +1527,48 @@
   // Try to guess loaded type from pointer type
   if (tp->base() == Type::AryPtr) {
     const Type *t = tp->is_aryptr()->elem();
+
+    // Make sure the reference is not into the header, by comparing
+    // the offset against the offset of the start of the array's data.
+    // Different array types begin at slightly different offsets (12 vs. 16).
+    // We choose T_BYTE as an example base type that is least restrictive
+    // as to alignment, which will therefore produce the smallest
+    // possible base offset.
+    const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE);
+    const bool off_in_header = ((uint)off < (uint)min_base_off);
+
+    // Try to constant-fold a stable array element.
+    if (FoldStableValues && !off_in_header && off != Type::OffsetBot &&
+        adr->is_AddP() && adr->in(AddPNode::Base)->is_Con() &&
+        tp->is_aryptr()->stable()) {
+      // Decode the results of GraphKit::array_element_address.
+      BasicType loadbt = memory_type();
+      BasicType elembt = t->array_element_basic_type();
+      if (elembt == T_BOOLEAN)  elembt = T_BYTE;  // oddity about boolean[]
+      ciArray* aobj = tp->is_aryptr()->const_oop()->as_array();
+      ciConstant con = aobj->element_value_by_offset(off);
+      if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) {
+        const Type* con_type = Type::make_from_constant(con);
+        if (con_type != NULL) {
+          if (con_type->isa_aryptr()) {
+            // Join with the array element type, in case it is also stable.
+            int dim = tp->is_aryptr()->stable_dimension();
+            con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1);
+          }
+          if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) {
+            con_type = con_type->make_narrowoop();
+          }
+#ifndef PRODUCT
+          if (TraceIterativeGVN) {
+            tty->print("FoldStableValues: array element [off=%d]: con_type=", off);
+            con_type->dump(); tty->cr();
+          }
+#endif //PRODUCT
+          return con_type;
+        }
+      }
+    }
+
     // Don't do this for integer types. There is only potential profit if
     // the element type t is lower than _type; that is, for int types, if _type is
     // more restrictive than t.  This only happens here if one is short and the other
@@ -1547,14 +1589,7 @@
         && Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) {
       // t might actually be lower than _type, if _type is a unique
       // concrete subclass of abstract class t.
-      // Make sure the reference is not into the header, by comparing
-      // the offset against the offset of the start of the array's data.
-      // Different array types begin at slightly different offsets (12 vs. 16).
-      // We choose T_BYTE as an example base type that is least restrictive
-      // as to alignment, which will therefore produce the smallest
-      // possible base offset.
-      const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE);
-      if ((uint)off >= (uint)min_base_off) {  // is the offset beyond the header?
+      if (!off_in_header) {
         const Type* jt = t->join(_type);
         // In any case, do not allow the join, per se, to empty out the type.
         if (jt->empty() && !t->empty()) {
diff --git a/src/share/vm/opto/parse.hpp b/src/share/vm/opto/parse.hpp
--- a/src/share/vm/opto/parse.hpp
+++ b/src/share/vm/opto/parse.hpp
@@ -503,7 +503,7 @@
 
   // loading from a constant field or the constant pool
   // returns false if push failed (non-perm field constants only, not ldcs)
-  bool push_constant(ciConstant con, bool require_constant = false);
+  bool push_constant(ciConstant con, bool require_constant = false, const Type* basic_type = NULL);
 
   // implementation of object creation bytecodes
   void emit_guard_for_new(ciInstanceKlass* klass);
diff --git a/src/share/vm/opto/parse1.cpp b/src/share/vm/opto/parse1.cpp
--- a/src/share/vm/opto/parse1.cpp
+++ b/src/share/vm/opto/parse1.cpp
@@ -917,6 +917,7 @@
     // such unusual early publications.  But no barrier is needed on
     // exceptional returns, since they cannot publish normally.
     //
+    // Any method can write a @Stable field, and we give those the same treatment.
     _exits.insert_mem_bar(Op_MemBarRelease);
 #ifndef PRODUCT
     if (PrintOpto && (Verbose || WizardMode)) {
diff --git a/src/share/vm/opto/parse3.cpp b/src/share/vm/opto/parse3.cpp
--- a/src/share/vm/opto/parse3.cpp
+++ b/src/share/vm/opto/parse3.cpp
@@ -147,14 +147,21 @@
 void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
   // Does this field have a constant value?  If so, just push the value.
   if (field->is_constant()) {
-    // final field
+    // final or stable field
+    const Type* stable_type = NULL;
+    if (FoldStableValues && field->is_stable()) {
+      stable_type = Type::get_const_type(field->type());
+      if (field->type()->is_array_klass()) {
+        int stable_dimension = field->type()->as_array_klass()->dimension();
+        stable_type = stable_type->is_aryptr()->cast_to_stable(true, stable_dimension);
+      }
+    }
     if (field->is_static()) {
       // final static field
-      if (push_constant(field->constant_value()))
+      if (push_constant(field->constant_value(), false, stable_type))
         return;
-    }
-    else {
-      // final non-static field
+    } else {
+      // final or stable non-static field
       // Treat final non-static fields of trusted classes (classes in
       // java.lang.invoke and sun.invoke packages and subpackages) as
       // compile time constants.
@@ -162,8 +169,12 @@
         const TypeOopPtr* oop_ptr = obj->bottom_type()->isa_oopptr();
         ciObject* constant_oop = oop_ptr->const_oop();
         ciConstant constant = field->constant_value_of(constant_oop);
-        if (push_constant(constant, true))
-          return;
+        if (FoldStableValues && field->is_stable() && constant.is_null_or_zero()) {
+          // fall through to field load; the field is not yet initialized
+        } else {
+          if (push_constant(constant, true, stable_type))
+            return;
+        }
       }
     }
   }
@@ -302,41 +313,28 @@
   // Note the presence of writes to final non-static fields, so that we
   // can insert a memory barrier later on to keep the writes from floating
   // out of the constructor.
-  if (is_field && field->is_final()) {
+  // Any method can write a @Stable field; insert memory barriers after those also.
+  if (is_field && field->is_final()
+      || field->is_stable()) {
     set_wrote_final(true);
   }
 }
 
 
-bool Parse::push_constant(ciConstant constant, bool require_constant) {
+bool Parse::push_constant(ciConstant constant, bool require_constant, const Type* stable_type) {
+  const Type* con_type = Type::make_from_constant(constant, require_constant);
   switch (constant.basic_type()) {
-  case T_BOOLEAN:  push( intcon(constant.as_boolean()) ); break;
-  case T_INT:      push( intcon(constant.as_int())     ); break;
-  case T_CHAR:     push( intcon(constant.as_char())    ); break;
-  case T_BYTE:     push( intcon(constant.as_byte())    ); break;
-  case T_SHORT:    push( intcon(constant.as_short())   ); break;
-  case T_FLOAT:    push( makecon(TypeF::make(constant.as_float())) );  break;
-  case T_DOUBLE:   push_pair( makecon(TypeD::make(constant.as_double())) );  break;
-  case T_LONG:     push_pair( longcon(constant.as_long()) ); break;
   case T_ARRAY:
-  case T_OBJECT: {
+  case T_OBJECT:
     // cases:
     //   can_be_constant    = (oop not scavengable || ScavengeRootsInCode != 0)
     //   should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
     // An oop is not scavengable if it is in the perm gen.
-    ciObject* oop_constant = constant.as_object();
-    if (oop_constant->is_null_object()) {
-      push( zerocon(T_OBJECT) );
-      break;
-    } else if (require_constant || oop_constant->should_be_constant()) {
-      push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant)) );
-      break;
-    } else {
-      // we cannot inline the oop, but we can use it later to narrow a type
-      return false;
-    }
-  }
-  case T_ILLEGAL: {
+    if (stable_type != NULL && con_type != NULL && con_type->isa_oopptr())
+      con_type = con_type->join(stable_type);
+    break;
+
+  case T_ILLEGAL:
     // Invalid ciConstant returned due to OutOfMemoryError in the CI
     assert(C->env()->failing(), "otherwise should not see this");
     // These always occur because of object types; we are going to
@@ -344,17 +342,16 @@
     push( zerocon(T_OBJECT) );
     return false;
   }
-  default:
-    ShouldNotReachHere();
+
+  if (con_type == NULL)
+    // we cannot inline the oop, but we can use it later to narrow a type
     return false;
-  }
 
-  // success
+  push_node(constant.basic_type(), makecon(con_type));
   return true;
 }
 
 
-
 //=============================================================================
 void Parse::do_anewarray() {
   bool will_link;
diff --git a/src/share/vm/opto/type.cpp b/src/share/vm/opto/type.cpp
--- a/src/share/vm/opto/type.cpp
+++ b/src/share/vm/opto/type.cpp
@@ -188,6 +188,38 @@
 }
 
 
+//-----------------------make_from_constant------------------------------------
+const Type* Type::make_from_constant(ciConstant constant,
+                                     bool require_constant) {
+  switch (constant.basic_type()) {
+  case T_BOOLEAN:  return TypeInt::make(constant.as_boolean());
+  case T_CHAR:     return TypeInt::make(constant.as_char());
+  case T_BYTE:     return TypeInt::make(constant.as_byte());
+  case T_SHORT:    return TypeInt::make(constant.as_short());
+  case T_INT:      return TypeInt::make(constant.as_int());
+  case T_LONG:     return TypeLong::make(constant.as_long());
+  case T_FLOAT:    return TypeF::make(constant.as_float());
+  case T_DOUBLE:   return TypeD::make(constant.as_double());
+  case T_ARRAY:
+  case T_OBJECT:
+    {
+      // cases:
+      //   can_be_constant    = (oop not scavengable || ScavengeRootsInCode != 0)
+      //   should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
+      // An oop is not scavengable if it is in the perm gen.
+      ciObject* oop_constant = constant.as_object();
+      if (oop_constant->is_null_object()) {
+        return Type::get_zero_type(T_OBJECT);
+      } else if (require_constant || oop_constant->should_be_constant()) {
+        return TypeOopPtr::make_from_constant(oop_constant, require_constant);
+      }
+    }
+  }
+  // Fall through to failure
+  return NULL;
+}
+
+
 //------------------------------make-------------------------------------------
 // Create a simple Type, with default empty symbol sets.  Then hashcons it
 // and look for an existing copy in the type dictionary.
@@ -1804,12 +1836,13 @@
 }
 
 //------------------------------make-------------------------------------------
-const TypeAry *TypeAry::make( const Type *elem, const TypeInt *size) {
+const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable) {
   if (UseCompressedOops && elem->isa_oopptr()) {
     elem = elem->make_narrowoop();
   }
+  assert(stable == true || stable == false, "");
   size = normalize_array_size(size);
-  return (TypeAry*)(new TypeAry(elem,size))->hashcons();
+  return (TypeAry*)(new TypeAry(elem,size,stable))->hashcons();
 }
 
 //------------------------------meet-------------------------------------------
@@ -1830,7 +1863,8 @@
   case Array: {                 // Meeting 2 arrays?
     const TypeAry *a = t->is_ary();
     return TypeAry::make(_elem->meet(a->_elem),
-                         _size->xmeet(a->_size)->is_int());
+                         _size->xmeet(a->_size)->is_int(),
+                         _stable & a->_stable);
   }
   case Top:
     break;
@@ -1843,7 +1877,7 @@
 const Type *TypeAry::xdual() const {
   const TypeInt* size_dual = _size->dual()->is_int();
   size_dual = normalize_array_size(size_dual);
-  return new TypeAry( _elem->dual(), size_dual);
+  return new TypeAry(_elem->dual(), size_dual, !_stable);
 }
 
 //------------------------------eq---------------------------------------------
@@ -1851,13 +1885,14 @@
 bool TypeAry::eq( const Type *t ) const {
   const TypeAry *a = (const TypeAry*)t;
   return _elem == a->_elem &&
+    _stable == a->_stable &&
     _size == a->_size;
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeAry::hash(void) const {
-  return (intptr_t)_elem + (intptr_t)_size;
+  return (intptr_t)_elem + (intptr_t)_size + (_stable ? 42 : 0);
 }
 
 //----------------------interface_vs_oop---------------------------------------
@@ -1874,6 +1909,7 @@
 //------------------------------dump2------------------------------------------
 #ifndef PRODUCT
 void TypeAry::dump2( Dict &d, uint depth, outputStream *st ) const {
+  if (_stable)  st->print("stable:");
   _elem->dump2(d, depth, st);
   st->print("[");
   _size->dump2(d, depth, st);
@@ -3387,11 +3423,34 @@
   assert(new_size != NULL, "");
   new_size = narrow_size_type(new_size);
   if (new_size == size())  return this;
-  const TypeAry* new_ary = TypeAry::make(elem(), new_size);
+  const TypeAry* new_ary = TypeAry::make(elem(), new_size, stable());
   return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
 }
 
 
+//------------------------------cast_to_stable---------------------------------
+const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const {
+  assert(stable == true || stable == false, "");
+  if (stable_dimension <= 0 || stable_dimension == 1 && stable == this->stable())  return this;
+  const Type* elem = this->elem();
+  const TypePtr* elem_ptr = elem->make_ptr();
+  if (stable_dimension > 1 && elem_ptr != NULL && elem_ptr->base() == Type::AryPtr)
+    // If this is widened from a narrow oop, TypeAry::make will re-narrow it.
+    elem = elem_ptr = elem_ptr->is_aryptr()->cast_to_stable(stable, stable_dimension - 1);
+  const TypeAry* new_ary = TypeAry::make(elem, size(), stable);
+  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
+}
+
+//-----------------------------stable_dimension--------------------------------
+int TypeAryPtr::stable_dimension() const {
+  if (!stable())  return 0;
+  int dim = 1;
+  const TypePtr* elem_ptr = elem()->make_ptr();
+  if (elem_ptr != NULL && elem_ptr->isa_aryptr())
+    dim += elem_ptr->is_aryptr()->stable_dimension();
+  return dim;
+}
+
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
 bool TypeAryPtr::eq( const Type *t ) const {
@@ -3499,7 +3558,7 @@
         // Something like byte[int+] meets char[int+].
         // This must fall to bottom, not (int[-128..65535])[int+].
         instance_id = InstanceBot;
-        tary = TypeAry::make(Type::BOTTOM, tary->_size);
+        tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
       }
     } else // Non integral arrays.
     // Must fall to bottom if exact klasses in upper lattice
@@ -3513,7 +3572,7 @@
          (tap ->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) ||
          // 'this' is exact and super or unrelated:
          (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) {
-      tary = TypeAry::make(Type::BOTTOM, tary->_size);
+      tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
       return make( NotNull, NULL, tary, lazy_klass, false, off, InstanceBot );
     }
 
diff --git a/src/share/vm/opto/type.hpp b/src/share/vm/opto/type.hpp
--- a/src/share/vm/opto/type.hpp
+++ b/src/share/vm/opto/type.hpp
@@ -357,6 +357,9 @@
   // Mapping from CI type system to compiler type:
   static const Type* get_typeflow_type(ciType* type);
 
+  static const Type* make_from_constant(ciConstant constant,
+                                        bool require_constant = false);
+
 private:
   // support arrays
   static const BasicType _basic_type[];
@@ -573,8 +576,8 @@
 //------------------------------TypeAry----------------------------------------
 // Class of Array Types
 class TypeAry : public Type {
-  TypeAry( const Type *elem, const TypeInt *size) : Type(Array),
-    _elem(elem), _size(size) {}
+  TypeAry(const Type* elem, const TypeInt* size, bool stable) : Type(Array),
+      _elem(elem), _size(size), _stable(stable) {}
 public:
   virtual bool eq( const Type *t ) const;
   virtual int  hash() const;             // Type specific hashing
@@ -584,10 +587,11 @@
 private:
   const Type *_elem;            // Element type of array
   const TypeInt *_size;         // Elements in array
+  const bool _stable;           // Are elements @Stable?
   friend class TypeAryPtr;
 
 public:
-  static const TypeAry *make(  const Type *elem, const TypeInt *size);
+  static const TypeAry* make(const Type* elem, const TypeInt* size, bool stable = false);
 
   virtual const Type *xmeet( const Type *t ) const;
   virtual const Type *xdual() const;    // Compute dual right now.
@@ -959,6 +963,7 @@
   const TypeAry* ary() const  { return _ary; }
   const Type*    elem() const { return _ary->_elem; }
   const TypeInt* size() const { return _ary->_size; }
+  bool         stable() const { return _ary->_stable; }
 
   static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot);
   // Constant pointer to array
@@ -980,6 +985,9 @@
   virtual const Type *xmeet( const Type *t ) const;
   virtual const Type *xdual() const;    // Compute dual right now.
 
+  const TypeAryPtr* cast_to_stable(bool stable, int stable_dimension = 1) const;
+  int stable_dimension() const;
+
   // Convenience common pre-built types.
   static const TypeAryPtr *RANGE;
   static const TypeAryPtr *OOPS;
diff --git a/src/share/vm/utilities/accessFlags.hpp b/src/share/vm/utilities/accessFlags.hpp
--- a/src/share/vm/utilities/accessFlags.hpp
+++ b/src/share/vm/utilities/accessFlags.hpp
@@ -78,11 +78,13 @@
   JVM_ACC_FIELD_ACCESS_WATCHED       = 0x00002000,  // field access is watched by JVMTI
   JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000,  // field modification is watched by JVMTI
   JVM_ACC_FIELD_INTERNAL             = 0x00000400,  // internal field, same as JVM_ACC_ABSTRACT
+  JVM_ACC_FIELD_STABLE               = 0x00000020,  // @Stable field, same as JVM_ACC_SYNCHRONIZED
   JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature
 
   JVM_ACC_FIELD_INTERNAL_FLAGS       = JVM_ACC_FIELD_ACCESS_WATCHED |
                                        JVM_ACC_FIELD_MODIFICATION_WATCHED |
                                        JVM_ACC_FIELD_INTERNAL |
+                                       JVM_ACC_FIELD_STABLE |
                                        JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE,
 
                                                     // flags accepted by set_field_flags()
@@ -148,6 +150,7 @@
                                         { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
   bool on_stack() const                 { return (_flags & JVM_ACC_ON_STACK) != 0; }
   bool is_internal() const              { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; }
+  bool is_stable() const                { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
   bool field_has_generic_signature() const
                                         { return (_flags & JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) != 0; }