changeset 503:e3ab72281c5f

anno-stable.patch: update
author jrose
date Fri, 28 Sep 2012 00:23:15 -0700
parents c9a86414879e
children c7d00d950bdb
files anno-stable.patch
diffstat 1 files changed, 407 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/anno-stable.patch	Wed Sep 26 00:10:25 2012 -0700
+++ b/anno-stable.patch	Fri Sep 28 00:23:15 2012 -0700
@@ -72,6 +72,14 @@
    } 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
@@ -109,12 +117,67 @@
 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
-@@ -1777,13 +1777,17 @@
+@@ -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(java_lang_invoke_Stable_signature):
-+    if (_location != _in_field)  break;  // only allow for fields
++    if (_location != _in_field)   break;  // only allow for fields
++    if (!privileged)              break;  // only allow in privileged code
 +    return _field_Stable;
    default: break;
    }
@@ -128,6 +191,25 @@
  }
  
  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
@@ -139,6 +221,25 @@
        _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
@@ -171,7 +272,42 @@
 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
-@@ -1542,7 +1542,7 @@
+@@ -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);
@@ -183,36 +319,117 @@
 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
-@@ -129,7 +129,8 @@
+@@ -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
+@@ -3791,7 +3791,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),
+@@ -3814,7 +3814,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
-@@ -937,7 +937,7 @@
+@@ -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()) {
+-      atp->field() != NULL && !atp->field()->is_volatile()) {
++      ((atp->field() != NULL && !atp->field()->is_volatile())
++       || (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,6 +972,7 @@
+@@ -972,7 +973,6 @@
      }
    }
  
-+  //@@ FIXME: allow stable array elements to be viewed this way also
- 
+-
    // 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++) {
+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
@@ -227,24 +444,49 @@
 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
-@@ -162,7 +162,15 @@
+@@ -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 (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))
-+        bool use_constant = true;
-+        if (field->is_stable()) {
-+          if (constant.is_null_or_zero()) {
-+            use_constant = false;  // not initialized yet
-+          } else if (field->type()->is_array_klass()) {
-+            //@@ FIXME: mark the constant value as multi-level
-+          }
+-          return;
++        if (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;
 +        }
-+        if (use_constant && push_constant(constant, true))
-           return;
        }
      }
-@@ -302,7 +310,9 @@
+   }
+@@ -302,13 +313,15 @@
    // 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.
@@ -255,6 +497,150 @@
      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) {
+   switch (constant.basic_type()) {
+   case T_BOOLEAN:  push( intcon(constant.as_boolean()) ); break;
+   case T_INT:      push( intcon(constant.as_int())     ); break;
+@@ -329,7 +342,11 @@
+       push( zerocon(T_OBJECT) );
+       break;
+     } else if (require_constant || oop_constant->should_be_constant()) {
+-      push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant)) );
++      const Type* con_type = TypeOopPtr::make_from_constant(oop_constant, require_constant);
++      assert(con_type != NULL, "");
++      if (stable_type != NULL)
++        con_type = con_type->join(stable_type);
++      push( makecon(con_type) );
+       break;
+     } else {
+       // we cannot inline the oop, but we can use it later to narrow a type
+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
+@@ -1804,12 +1804,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 +1831,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 +1845,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---------------------------------------------
+@@ -3387,11 +3389,22 @@
+   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 == this->stable())  return this;
++  const Type* elem = this->elem();
++  if (stable_dimension > 1 && elem->base() == Type::AryPtr)
++    elem = elem->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);
++}
++
+ //------------------------------eq---------------------------------------------
+ // Structural equality check for Type representations
+ bool TypeAryPtr::eq( const Type *t ) const {
+@@ -3499,7 +3512,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 +3526,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
+@@ -573,8 +573,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 +584,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 +960,7 @@
+   const TypeAry* ary() const  { return _ary; }
+   const Type*    elem() const { return _ary->_elem; }
+   const TypeInt* size() const { return _ary->_size; }
++  const 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 +982,8 @@
+   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;
++
+   // 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
@@ -262,7 +648,7 @@
    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               = 0x00000040,  // @Stable field, same as JVM_ACC_SYNCHRONIZED
++  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 |