changeset 504:c7d00d950bdb

anno-stable.patch: working
author jrose
date Sun, 30 Sep 2012 21:35:21 -0700
parents e3ab72281c5f
children b900129cef2e
files anno-stable.patch
diffstat 1 files changed, 403 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/anno-stable.patch	Fri Sep 28 00:23:15 2012 -0700
+++ b/anno-stable.patch	Sun Sep 30 21:35:21 2012 -0700
@@ -1,5 +1,139 @@
 Summary: @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
@@ -114,6 +248,32 @@
  
    // 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
@@ -269,6 +429,19 @@
    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
@@ -400,10 +573,11 @@
 -  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 &&
+-  if (EliminateAutoBox && atp != NULL && atp->index() >= Compile::AliasIdxRaw &&
 -      atp->field() != NULL && !atp->field()->is_volatile()) {
-+      ((atp->field() != NULL && !atp->field()->is_volatile())
-+       || (tp->isa_aryptr() && (tp->is_aryptr()->stable())))) {
++  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();
@@ -418,6 +592,71 @@
    // 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
@@ -451,7 +690,7 @@
 -    // final field
 +    // final or stable field
 +    const Type* stable_type = NULL;
-+    if (field->is_stable()) {
++    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();
@@ -477,7 +716,7 @@
          ciConstant constant = field->constant_value_of(constant_oop);
 -        if (push_constant(constant, true))
 -          return;
-+        if (field->is_stable() && constant.is_null_or_zero()) {
++        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))
@@ -486,7 +725,7 @@
        }
      }
    }
-@@ -302,13 +313,15 @@
+@@ -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.
@@ -501,26 +740,109 @@
  
 -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;
-@@ -329,7 +342,11 @@
-       push( zerocon(T_OBJECT) );
-       break;
-     } else if (require_constant || oop_constant->should_be_constant()) {
+-  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)) );
-+      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
+-      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
-@@ -1804,12 +1804,13 @@
+@@ -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-------------------------------------------
@@ -536,7 +858,7 @@
  }
  
  //------------------------------meet-------------------------------------------
-@@ -1830,7 +1831,8 @@
+@@ -1830,7 +1863,8 @@
    case Array: {                 // Meeting 2 arrays?
      const TypeAry *a = t->is_ary();
      return TypeAry::make(_elem->meet(a->_elem),
@@ -546,7 +868,7 @@
    }
    case Top:
      break;
-@@ -1843,7 +1845,7 @@
+@@ -1843,7 +1877,7 @@
  const Type *TypeAry::xdual() const {
    const TypeInt* size_dual = _size->dual()->is_int();
    size_dual = normalize_array_size(size_dual);
@@ -555,7 +877,31 @@
  }
  
  //------------------------------eq---------------------------------------------
-@@ -3387,11 +3389,22 @@
+@@ -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;
@@ -568,18 +914,30 @@
 +//------------------------------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;
++  if (stable_dimension <= 0 || stable_dimension == 1 && 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 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 +3512,7 @@
+@@ -3499,7 +3558,7 @@
          // Something like byte[int+] meets char[int+].
          // This must fall to bottom, not (int[-128..65535])[int+].
          instance_id = InstanceBot;
@@ -588,7 +946,7 @@
        }
      } else // Non integral arrays.
      // Must fall to bottom if exact klasses in upper lattice
-@@ -3513,7 +3526,7 @@
+@@ -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())))) {
@@ -600,7 +958,17 @@
 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 @@
+@@ -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 {
@@ -611,7 +979,7 @@
  public:
    virtual bool eq( const Type *t ) const;
    virtual int  hash() const;             // Type specific hashing
-@@ -584,10 +584,11 @@
+@@ -584,10 +587,11 @@
  private:
    const Type *_elem;            // Element type of array
    const TypeInt *_size;         // Elements in array
@@ -624,19 +992,20 @@
  
    virtual const Type *xmeet( const Type *t ) const;
    virtual const Type *xdual() const;    // Compute dual right now.
-@@ -959,6 +960,7 @@
+@@ -959,6 +963,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; }
++  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 @@
+@@ -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;