--- old/src/share/vm/interpreter/rewriter.cpp 2016-12-19 14:46:42.719378538 +0100 +++ new/src/share/vm/interpreter/rewriter.cpp 2016-12-19 14:46:42.583378544 +0100 @@ -396,10 +396,45 @@ break; } + case Bytecodes::_putstatic : + case Bytecodes::_putfield : { + if (!reverse) { + // Check if any final field of the class given as parameter is modified + // outside of initializer methods of the class. Fields that are modified + // are marked with a flag. For marked fields, the compilers do not perform + // constant folding (as the field can be changed after initialization). + // + // The check is performed after verification and only if verification has + // succeeded. Therefore, the class is guaranteed to be well-formed. + InstanceKlass* klass = method->method_holder(); + u2 bc_index = Bytes::get_Java_u2(bcp + prefix_length + 1); + constantPoolHandle cp(method->constants()); + Symbol* field_name = cp->name_ref_at(bc_index); + Symbol* field_sig = cp->signature_ref_at(bc_index); + Symbol* ref_class_name = cp->klass_name_at(cp->klass_ref_index_at(bc_index)); + + if (klass->name() == ref_class_name) { + fieldDescriptor fd; + klass->find_field(field_name, field_sig, &fd); + if (fd.access_flags().is_final()) { + if (fd.access_flags().is_static()) { + assert(c == Bytecodes::_putstatic, "must be putstatic"); + if (!method->is_static_initializer()) { + fd.set_has_initialized_final_update(true); + } + } else { + assert(c == Bytecodes::_putfield, "must be putfield"); + if (!method->is_object_initializer()) { + fd.set_has_initialized_final_update(true); + } + } + } + } + } + } + // fall through case Bytecodes::_getstatic : // fall through - case Bytecodes::_putstatic : // fall through case Bytecodes::_getfield : // fall through - case Bytecodes::_putfield : // fall through case Bytecodes::_invokevirtual : // fall through case Bytecodes::_invokestatic : case Bytecodes::_invokeinterface: --- old/src/share/vm/oops/method.hpp 2016-12-19 14:46:42.743378537 +0100 +++ new/src/share/vm/oops/method.hpp 2016-12-19 14:46:42.611378543 +0100 @@ -627,6 +627,9 @@ // valid static initializer flags. bool is_static_initializer() const; + // returns true if the method name is + bool is_object_initializer() const; + // compiled code support // NOTE: code() is inherently racy as deopt can be clearing code // simultaneously. Use with caution. --- old/src/share/vm/ci/ciFlags.hpp 2016-12-19 14:46:42.759378536 +0100 +++ new/src/share/vm/ci/ciFlags.hpp 2016-12-19 14:46:42.611378543 +0100 @@ -46,20 +46,25 @@ public: // Java access flags - bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; } - bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; } - bool is_protected () const { return (_flags & JVM_ACC_PROTECTED ) != 0; } - bool is_static () const { return (_flags & JVM_ACC_STATIC ) != 0; } - bool is_final () const { return (_flags & JVM_ACC_FINAL ) != 0; } - bool is_synchronized() const { return (_flags & JVM_ACC_SYNCHRONIZED) != 0; } - bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; } - bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; } - bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; } - bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; } - 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; } + bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; } + bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; } + bool is_protected () const { return (_flags & JVM_ACC_PROTECTED ) != 0; } + bool is_static () const { return (_flags & JVM_ACC_STATIC ) != 0; } + bool is_final () const { return (_flags & JVM_ACC_FINAL ) != 0; } + bool is_synchronized () const { return (_flags & JVM_ACC_SYNCHRONIZED ) != 0; } + bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; } + bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; } + bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; } + bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; } + 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; } + // In case the current object represents a field, return true if + // the field is modified outside of instance initializer methods + // (or class/initializer methods if the field is static) and false + // otherwise. + bool has_initialized_final_update() const { return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 0; }; // Conversion jint as_int() { return _flags; } --- old/src/share/vm/ci/ciField.cpp 2016-12-19 14:46:42.823378533 +0100 +++ new/src/share/vm/ci/ciField.cpp 2016-12-19 14:46:42.655378541 +0100 @@ -207,7 +207,7 @@ // Check to see if the field is constant. bool is_final = this->is_final(); bool is_stable = FoldStableValues && this->is_stable(); - if (_holder->is_initialized() && (is_final || is_stable)) { + if (_holder->is_initialized() && ((is_final && !has_initialized_final_update()) || 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 --- old/src/share/vm/runtime/fieldDescriptor.hpp 2016-12-19 14:46:42.859378532 +0100 +++ new/src/share/vm/runtime/fieldDescriptor.hpp 2016-12-19 14:46:42.691378539 +0100 @@ -106,6 +106,7 @@ bool is_field_access_watched() const { return access_flags().is_field_access_watched(); } bool is_field_modification_watched() const { return access_flags().is_field_modification_watched(); } + bool has_initialized_final_update() const { return access_flags().has_field_initialized_final_update(); } bool has_generic_signature() const { return access_flags().field_has_generic_signature(); } void set_is_field_access_watched(const bool value) { @@ -118,6 +119,11 @@ update_klass_field_access_flag(); } + void set_has_initialized_final_update(const bool value) { + _access_flags.set_has_field_initialized_final_update(value); + update_klass_field_access_flag(); + } + // Initialization void reinitialize(InstanceKlass* ik, int index); --- old/src/share/vm/oops/method.cpp 2016-12-19 14:46:42.851378532 +0100 +++ new/src/share/vm/oops/method.cpp 2016-12-19 14:46:42.611378543 +0100 @@ -590,7 +590,7 @@ } bool Method::is_initializer() const { - return name() == vmSymbols::object_initializer_name() || is_static_initializer(); + return is_object_initializer() || is_static_initializer(); } bool Method::has_valid_initializer_flags() const { @@ -606,6 +606,9 @@ has_valid_initializer_flags(); } +bool Method::is_object_initializer() const { + return name() == vmSymbols::object_initializer_name(); +} objArrayHandle Method::resolved_checked_exceptions_impl(Method* this_oop, TRAPS) { int length = this_oop->checked_exceptions_length(); --- old/src/share/vm/ci/ciField.hpp 2016-12-19 14:46:42.863378531 +0100 +++ new/src/share/vm/ci/ciField.hpp 2016-12-19 14:46:42.627378542 +0100 @@ -124,22 +124,8 @@ return _holder->is_shared() && !is_static(); } - // Is this field a constant? - // - // Clarification: A field is considered constant if: - // 1. The field is both static and final - // 2. The canonical holder of the field has undergone - // static initialization. - // 3. If the field is an object or array, then the oop - // in question is allocated in perm space. - // 4. The field is not one of the special static/final - // non-constant fields. These are java.lang.System.in - // and java.lang.System.out. Abomination. - // - // 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(). + // Is this field a constant? See ciField::initialize_from() for details + // about how a field is determined to be constant. bool is_constant() { return _is_constant; } // Get the constant value of this field. @@ -176,6 +162,9 @@ bool is_stable () { return flags().is_stable(); } bool is_volatile () { return flags().is_volatile(); } bool is_transient () { return flags().is_transient(); } + // The field is modified outside of instance initializer methods + // (or class/initializer methods if the field is static). + bool has_initialized_final_update() { return flags().has_initialized_final_update(); } bool is_call_site_target() { ciInstanceKlass* callsite_klass = CURRENT_ENV->CallSite_klass(); --- old/src/share/vm/utilities/accessFlags.hpp 2016-12-19 14:46:42.891378530 +0100 +++ new/src/share/vm/utilities/accessFlags.hpp 2016-12-19 14:46:42.775378535 +0100 @@ -76,11 +76,12 @@ // These bits must not conflict with any other field-related access flags // (e.g., ACC_ENUM). // Note that the class-related ACC_ANNOTATION bit conflicts with these flags. - 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_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 and JVM_ACC_SUPER + JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE = 0x00000100, // (static) final field updated outside (class) initializer, same as JVM_ACC_NATIVE + 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 | @@ -150,6 +151,8 @@ bool is_field_access_watched() const { return (_flags & JVM_ACC_FIELD_ACCESS_WATCHED) != 0; } bool is_field_modification_watched() const { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; } + bool has_field_initialized_final_update() const + { return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 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; } @@ -229,6 +232,15 @@ atomic_clear_bits(JVM_ACC_FIELD_MODIFICATION_WATCHED); } } + + void set_has_field_initialized_final_update(const bool value) { + if (value) { + atomic_set_bits(JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE); + } else { + atomic_clear_bits(JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE); + } + } + void set_field_has_generic_signature() { atomic_set_bits(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE);