changeset 502:c9a86414879e

anno-stable.patch: first cut at @Stable, for method handle optimization
author jrose
date Wed, 26 Sep 2012 00:10:25 -0700
parents 1e154768463d
children e3ab72281c5f
files anno-stable.patch series
diffstat 2 files changed, 283 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/anno-stable.patch	Wed Sep 26 00:10:25 2012 -0700
@@ -0,0 +1,282 @@
+Summary: @Stable annotation for constant folding of lazily evaluated variables.
+
+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;
+   }
+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/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 @@
+   case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Hidden_signature):
+     if (_location != _in_method)  break;  // only allow for methods
+     return _method_LambdaForm_Hidden;
++  case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature):
++    if (_location != _in_field)  break;  // only allow for fields
++    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) {
+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;
+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(java_lang_invoke_Stable_signature,         "Ljava/lang/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/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 @@
+   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
+@@ -129,7 +129,8 @@
+     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 print_on(outputStream* st) PRODUCT_RETURN;
+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 @@
+   if (EliminateAutoBox && atp != NULL && atp->index() >= Compile::AliasIdxRaw &&
+       atp->field() != NULL && !atp->field()->is_volatile()) {
+     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 @@
+     }
+   }
+ 
++  //@@ 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.)
+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
+@@ -916,6 +916,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
+@@ -162,7 +162,15 @@
+         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
++          }
++        }
++        if (use_constant && push_constant(constant, true))
+           return;
+       }
+     }
+@@ -302,7 +310,9 @@
+   // 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);
+   }
+ }
+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               = 0x00000040,  // @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; }
+ 
--- a/series	Sat Sep 22 01:48:57 2012 -0700
+++ b/series	Wed Sep 26 00:10:25 2012 -0700
@@ -3,6 +3,7 @@
 # review pending before push to hotspot-comp:
 
 # non-pushed files are under review or development, or merely experimental:
+anno-stable.patch               #-/meth #+7eca5de9e0b6 #-buildable
 meth.patch                      #-/meth #+7eca5de9e0b6
 
 meth.proj.patch                 #-/meth #+projects