8155951: VM crash in nsk/jvmti/RedefineClasses/StressRedefine: assert failed: Corrupted constant pool

Tue, 03 Sep 2019 06:57:35 +0100

author
zgu
date
Tue, 03 Sep 2019 06:57:35 +0100
changeset 9745
0e3d6188f198
parent 9744
b02fb6a07ed5
child 9746
b13d79420363

8155951: VM crash in nsk/jvmti/RedefineClasses/StressRedefine: assert failed: Corrupted constant pool
8151066: assert(0 <= i && i < length()) failed: index out of bounds
Summary: lock classes for redefinition because constant pool merging isn't thread safe, use method constant pool because constant pool merging doesn't make equivalent cpCaches because of invokedynamic
Reviewed-by: shade, andrew

src/share/vm/ci/ciStreams.cpp file | annotate | diff | comparison | revisions
src/share/vm/ci/ciStreams.hpp file | annotate | diff | comparison | revisions
src/share/vm/oops/instanceKlass.hpp file | annotate | diff | comparison | revisions
src/share/vm/prims/jvmtiRedefineClasses.cpp file | annotate | diff | comparison | revisions
src/share/vm/prims/jvmtiRedefineClasses.hpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/mutexLocker.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/mutexLocker.hpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/ci/ciStreams.cpp	Tue Sep 03 06:41:37 2019 +0100
     1.2 +++ b/src/share/vm/ci/ciStreams.cpp	Tue Sep 03 06:57:35 2019 +0100
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
     1.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8   *
     1.9   * This code is free software; you can redistribute it and/or modify it
    1.10 @@ -361,14 +361,14 @@
    1.11  ciMethod* ciBytecodeStream::get_method(bool& will_link, ciSignature* *declared_signature_result) {
    1.12    VM_ENTRY_MARK;
    1.13    ciEnv* env = CURRENT_ENV;
    1.14 -  constantPoolHandle cpool(_method->get_Method()->constants());
    1.15 +  constantPoolHandle cpool(THREAD, _method->get_Method()->constants());
    1.16    ciMethod* m = env->get_method_by_index(cpool, get_method_index(), cur_bc(), _holder);
    1.17    will_link = m->is_loaded();
    1.18  
    1.19    // Use the MethodType stored in the CP cache to create a signature
    1.20    // with correct types (in respect to class loaders).
    1.21    if (has_method_type()) {
    1.22 -    ciSymbol*     sig_sym     = env->get_symbol(cpool->symbol_at(get_method_signature_index()));
    1.23 +    ciSymbol*     sig_sym     = env->get_symbol(cpool->symbol_at(get_method_signature_index(cpool)));
    1.24      ciKlass*      pool_holder = env->get_klass(cpool->pool_holder());
    1.25      ciMethodType* method_type = get_method_type();
    1.26      ciSignature* declared_signature = new (env->arena()) ciSignature(pool_holder, sig_sym, method_type);
    1.27 @@ -465,9 +465,8 @@
    1.28  // Get the constant pool index of the signature of the method
    1.29  // referenced by the current bytecode.  Used for generating
    1.30  // deoptimization information.
    1.31 -int ciBytecodeStream::get_method_signature_index() {
    1.32 +int ciBytecodeStream::get_method_signature_index(const constantPoolHandle& cpool) {
    1.33    GUARDED_VM_ENTRY(
    1.34 -    ConstantPool* cpool = _holder->get_instanceKlass()->constants();
    1.35      const int method_index = get_method_index();
    1.36      const int name_and_type_index = cpool->name_and_type_ref_index_at(method_index);
    1.37      return cpool->signature_ref_index_at(name_and_type_index);
     2.1 --- a/src/share/vm/ci/ciStreams.hpp	Tue Sep 03 06:41:37 2019 +0100
     2.2 +++ b/src/share/vm/ci/ciStreams.hpp	Tue Sep 03 06:57:35 2019 +0100
     2.3 @@ -1,5 +1,5 @@
     2.4  /*
     2.5 - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
     2.6 + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
     2.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.8   *
     2.9   * This code is free software; you can redistribute it and/or modify it
    2.10 @@ -264,7 +264,7 @@
    2.11    ciMethodType* get_method_type();
    2.12    ciKlass*      get_declared_method_holder();
    2.13    int           get_method_holder_index();
    2.14 -  int           get_method_signature_index();
    2.15 +  int           get_method_signature_index(const constantPoolHandle& cpool);
    2.16  
    2.17    // Get the resolved references arrays from the constant pool
    2.18    ciObjArray* get_resolved_references();
     3.1 --- a/src/share/vm/oops/instanceKlass.hpp	Tue Sep 03 06:41:37 2019 +0100
     3.2 +++ b/src/share/vm/oops/instanceKlass.hpp	Tue Sep 03 06:57:35 2019 +0100
     3.3 @@ -225,6 +225,7 @@
     3.4    // _is_marked_dependent can be set concurrently, thus cannot be part of the
     3.5    // _misc_flags.
     3.6    bool            _is_marked_dependent;  // used for marking during flushing and deoptimization
     3.7 +  bool            _is_being_redefined;   // used for locking redefinition
     3.8    bool            _has_unloaded_dependent;
     3.9  
    3.10    enum {
    3.11 @@ -667,6 +668,10 @@
    3.12      _nonstatic_oop_map_size = words;
    3.13    }
    3.14  
    3.15 +  // Redefinition locking.  Class can only be redefined by one thread at a time.
    3.16 +  bool is_being_redefined() const          { return _is_being_redefined; }
    3.17 +  void set_is_being_redefined(bool value)  { _is_being_redefined = value; }
    3.18 +
    3.19    // RedefineClasses() support for previous versions:
    3.20    void add_previous_version(instanceKlassHandle ikh, int emcp_method_count);
    3.21  
     4.1 --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp	Tue Sep 03 06:41:37 2019 +0100
     4.2 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp	Tue Sep 03 06:57:35 2019 +0100
     4.3 @@ -67,6 +67,43 @@
     4.4    _res = JVMTI_ERROR_NONE;
     4.5  }
     4.6  
     4.7 +static inline InstanceKlass* get_ik(jclass def) {
     4.8 +  oop mirror = JNIHandles::resolve_non_null(def);
     4.9 +  return InstanceKlass::cast(java_lang_Class::as_Klass(mirror));
    4.10 +}
    4.11 +
    4.12 +// If any of the classes are being redefined, wait
    4.13 +// Parallel constant pool merging leads to indeterminate constant pools.
    4.14 +void VM_RedefineClasses::lock_classes() {
    4.15 +  MutexLocker ml(RedefineClasses_lock);
    4.16 +  bool has_redefined;
    4.17 +  do {
    4.18 +    has_redefined = false;
    4.19 +    // Go through classes each time until none are being redefined.
    4.20 +    for (int i = 0; i < _class_count; i++) {
    4.21 +      if (get_ik(_class_defs[i].klass)->is_being_redefined()) {
    4.22 +        RedefineClasses_lock->wait();
    4.23 +        has_redefined = true;
    4.24 +        break;  // for loop
    4.25 +      }
    4.26 +    }
    4.27 +  } while (has_redefined);
    4.28 +  for (int i = 0; i < _class_count; i++) {
    4.29 +    get_ik(_class_defs[i].klass)->set_is_being_redefined(true);
    4.30 +  }
    4.31 +  RedefineClasses_lock->notify_all();
    4.32 +}
    4.33 +
    4.34 +void VM_RedefineClasses::unlock_classes() {
    4.35 +  MutexLocker ml(RedefineClasses_lock);
    4.36 +  for (int i = 0; i < _class_count; i++) {
    4.37 +    assert(get_ik(_class_defs[i].klass)->is_being_redefined(),
    4.38 +           "should be being redefined to get here");
    4.39 +    get_ik(_class_defs[i].klass)->set_is_being_redefined(false);
    4.40 +  }
    4.41 +  RedefineClasses_lock->notify_all();
    4.42 +}
    4.43 +
    4.44  bool VM_RedefineClasses::doit_prologue() {
    4.45    if (_class_count == 0) {
    4.46      _res = JVMTI_ERROR_NONE;
    4.47 @@ -89,12 +126,21 @@
    4.48        _res = JVMTI_ERROR_NULL_POINTER;
    4.49        return false;
    4.50      }
    4.51 +
    4.52 +    oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
    4.53 +    // classes for primitives and arrays cannot be redefined
    4.54 +    // check here so following code can assume these classes are InstanceKlass
    4.55 +    if (!is_modifiable_class(mirror)) {
    4.56 +      _res = JVMTI_ERROR_UNMODIFIABLE_CLASS;
    4.57 +      return false;
    4.58 +    }
    4.59    }
    4.60  
    4.61    // Start timer after all the sanity checks; not quite accurate, but
    4.62    // better than adding a bunch of stop() calls.
    4.63    RC_TIMER_START(_timer_vm_op_prologue);
    4.64  
    4.65 +  lock_classes();
    4.66    // We first load new class versions in the prologue, because somewhere down the
    4.67    // call chain it is required that the current thread is a Java thread.
    4.68    _res = load_new_class_versions(Thread::current());
    4.69 @@ -111,6 +157,7 @@
    4.70      // Free os::malloc allocated memory in load_new_class_version.
    4.71      os::free(_scratch_classes);
    4.72      RC_TIMER_STOP(_timer_vm_op_prologue);
    4.73 +    unlock_classes();
    4.74      return false;
    4.75    }
    4.76  
    4.77 @@ -170,6 +217,8 @@
    4.78  }
    4.79  
    4.80  void VM_RedefineClasses::doit_epilogue() {
    4.81 +  unlock_classes();
    4.82 +
    4.83    // Free os::malloc allocated memory.
    4.84    os::free(_scratch_classes);
    4.85  
    4.86 @@ -961,14 +1010,7 @@
    4.87      // versions are deleted. Constant pools are deallocated while merging
    4.88      // constant pools
    4.89      HandleMark hm(THREAD);
    4.90 -
    4.91 -    oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
    4.92 -    // classes for primitives cannot be redefined
    4.93 -    if (!is_modifiable_class(mirror)) {
    4.94 -      return JVMTI_ERROR_UNMODIFIABLE_CLASS;
    4.95 -    }
    4.96 -    Klass* the_class_oop = java_lang_Class::as_Klass(mirror);
    4.97 -    instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop);
    4.98 +    instanceKlassHandle the_class(THREAD, get_ik(_class_defs[i].klass));
    4.99      Symbol*  the_class_sym = the_class->name();
   4.100  
   4.101      // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark
   4.102 @@ -3855,22 +3897,19 @@
   4.103    HandleMark hm(THREAD);   // make sure handles from this call are freed
   4.104    RC_TIMER_START(_timer_rsc_phase1);
   4.105  
   4.106 -  instanceKlassHandle scratch_class(scratch_class_oop);
   4.107 -
   4.108 -  oop the_class_mirror = JNIHandles::resolve_non_null(the_jclass);
   4.109 -  Klass* the_class_oop = java_lang_Class::as_Klass(the_class_mirror);
   4.110 -  instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop);
   4.111 +  instanceKlassHandle scratch_class(THREAD, scratch_class_oop);
   4.112 +  instanceKlassHandle the_class(THREAD, get_ik(the_jclass));
   4.113  
   4.114    // Remove all breakpoints in methods of this class
   4.115    JvmtiBreakpoints& jvmti_breakpoints = JvmtiCurrentBreakpoints::get_jvmti_breakpoints();
   4.116 -  jvmti_breakpoints.clearall_in_class_at_safepoint(the_class_oop);
   4.117 +  jvmti_breakpoints.clearall_in_class_at_safepoint(the_class());
   4.118  
   4.119    // Deoptimize all compiled code that depends on this class
   4.120    flush_dependent_code(the_class, THREAD);
   4.121  
   4.122    _old_methods = the_class->methods();
   4.123    _new_methods = scratch_class->methods();
   4.124 -  _the_class_oop = the_class_oop;
   4.125 +  _the_class_oop = the_class();
   4.126    compute_added_deleted_matching_methods();
   4.127    update_jmethod_ids();
   4.128  
   4.129 @@ -4094,14 +4133,14 @@
   4.130    RC_TRACE_WITH_THREAD(0x00000001, THREAD,
   4.131      ("redefined name=%s, count=%d (avail_mem=" UINT64_FORMAT "K)",
   4.132      the_class->external_name(),
   4.133 -    java_lang_Class::classRedefinedCount(the_class_mirror),
   4.134 +    java_lang_Class::classRedefinedCount(the_class->java_mirror()),
   4.135      os::available_memory() >> 10));
   4.136  
   4.137    {
   4.138      ResourceMark rm(THREAD);
   4.139      Events::log_redefinition(THREAD, "redefined class name=%s, count=%d",
   4.140                               the_class->external_name(),
   4.141 -                             java_lang_Class::classRedefinedCount(the_class_mirror));
   4.142 +                             java_lang_Class::classRedefinedCount(the_class->java_mirror()));
   4.143  
   4.144    }
   4.145    RC_TIMER_STOP(_timer_rsc_phase2);
     5.1 --- a/src/share/vm/prims/jvmtiRedefineClasses.hpp	Tue Sep 03 06:41:37 2019 +0100
     5.2 +++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp	Tue Sep 03 06:57:35 2019 +0100
     5.3 @@ -490,6 +490,10 @@
     5.4  
     5.5    void flush_dependent_code(instanceKlassHandle k_h, TRAPS);
     5.6  
     5.7 +  // lock classes to redefine since constant pool merging isn't thread safe.
     5.8 +  void lock_classes();
     5.9 +  void unlock_classes();
    5.10 +
    5.11    static void dump_methods();
    5.12  
    5.13    // Check that there are no old or obsolete methods
     6.1 --- a/src/share/vm/runtime/mutexLocker.cpp	Tue Sep 03 06:41:37 2019 +0100
     6.2 +++ b/src/share/vm/runtime/mutexLocker.cpp	Tue Sep 03 06:57:35 2019 +0100
     6.3 @@ -125,6 +125,7 @@
     6.4  Mutex*   Management_lock              = NULL;
     6.5  Monitor* Service_lock                 = NULL;
     6.6  Monitor* PeriodicTask_lock            = NULL;
     6.7 +Monitor* RedefineClasses_lock         = NULL;
     6.8  
     6.9  #ifdef INCLUDE_TRACE
    6.10  Mutex*   JfrStacktrace_lock           = NULL;
    6.11 @@ -279,6 +280,7 @@
    6.12    def(ProfileVM_lock               , Monitor, special,   false); // used for profiling of the VMThread
    6.13    def(CompileThread_lock           , Monitor, nonleaf+5,   false );
    6.14    def(PeriodicTask_lock            , Monitor, nonleaf+5,   true);
    6.15 +  def(RedefineClasses_lock         , Monitor, nonleaf+5,   true);
    6.16  
    6.17  #ifdef INCLUDE_TRACE
    6.18    def(JfrMsg_lock                  , Monitor, leaf,        true);
     7.1 --- a/src/share/vm/runtime/mutexLocker.hpp	Tue Sep 03 06:41:37 2019 +0100
     7.2 +++ b/src/share/vm/runtime/mutexLocker.hpp	Tue Sep 03 06:57:35 2019 +0100
     7.3 @@ -141,6 +141,7 @@
     7.4  extern Mutex*   Management_lock;                 // a lock used to serialize JVM management
     7.5  extern Monitor* Service_lock;                    // a lock used for service thread operation
     7.6  extern Monitor* PeriodicTask_lock;               // protects the periodic task structure
     7.7 +extern Monitor* RedefineClasses_lock;            // locks classes from parallel redefinition
     7.8  
     7.9  #ifdef INCLUDE_TRACE
    7.10  extern Mutex*   JfrStacktrace_lock;              // used to guard access to the JFR stacktrace table

mercurial