Mon, 08 Jan 2018 08:32:04 -0800
8055008: Clean up code that saves the previous versions of redefined classes
8156137: SIGSEGV in ReceiverTypeData::clean_weak_klass_links
8057570: RedefineClasses() tests fail assert(((Metadata*)obj)->is_valid()) failed: obj is valid
Reviewed-by: coleenp
1.1 --- a/src/share/vm/classfile/metadataOnStackMark.cpp Tue Apr 08 09:51:25 2014 +0200 1.2 +++ b/src/share/vm/classfile/metadataOnStackMark.cpp Mon Jan 08 08:32:04 2018 -0800 1.3 @@ -41,13 +41,13 @@ 1.4 // Walk metadata on the stack and mark it so that redefinition doesn't delete 1.5 // it. Class unloading also walks the previous versions and might try to 1.6 // delete it, so this class is used by class unloading also. 1.7 -MetadataOnStackMark::MetadataOnStackMark(bool visit_code_cache) { 1.8 +MetadataOnStackMark::MetadataOnStackMark(bool has_redefined_a_class) { 1.9 assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); 1.10 assert(_used_buffers == NULL, "sanity check"); 1.11 NOT_PRODUCT(_is_active = true;) 1.12 1.13 Threads::metadata_do(Metadata::mark_on_stack); 1.14 - if (visit_code_cache) { 1.15 + if (has_redefined_a_class) { 1.16 CodeCache::alive_nmethods_do(nmethod::mark_on_stack); 1.17 } 1.18 CompileBroker::mark_on_stack();
2.1 --- a/src/share/vm/classfile/metadataOnStackMark.hpp Tue Apr 08 09:51:25 2014 +0200 2.2 +++ b/src/share/vm/classfile/metadataOnStackMark.hpp Mon Jan 08 08:32:04 2018 -0800 2.3 @@ -47,7 +47,7 @@ 2.4 static void retire_buffer(MetadataOnStackBuffer* buffer); 2.5 2.6 public: 2.7 - MetadataOnStackMark(bool visit_code_cache); 2.8 + MetadataOnStackMark(bool has_redefined_a_class); 2.9 ~MetadataOnStackMark(); 2.10 2.11 static void record(Metadata* m, Thread* thread);
3.1 --- a/src/share/vm/code/nmethod.cpp Tue Apr 08 09:51:25 2014 +0200 3.2 +++ b/src/share/vm/code/nmethod.cpp Mon Jan 08 08:32:04 2018 -0800 3.3 @@ -2172,7 +2172,7 @@ 3.4 "metadata must be found in exactly one place"); 3.5 if (r->metadata_is_immediate() && r->metadata_value() != NULL) { 3.6 Metadata* md = r->metadata_value(); 3.7 - f(md); 3.8 + if (md != _method) f(md); 3.9 } 3.10 } else if (iter.type() == relocInfo::virtual_call_type) { 3.11 // Check compiledIC holders associated with this nmethod 3.12 @@ -2198,7 +2198,7 @@ 3.13 f(md); 3.14 } 3.15 3.16 - // Visit metadata not embedded in the other places. 3.17 + // Call function Method*, not embedded in these other places. 3.18 if (_method != NULL) f(_method); 3.19 } 3.20
4.1 --- a/src/share/vm/oops/instanceKlass.cpp Tue Apr 08 09:51:25 2014 +0200 4.2 +++ b/src/share/vm/oops/instanceKlass.cpp Mon Jan 08 08:32:04 2018 -0800 4.3 @@ -2582,16 +2582,6 @@ 4.4 assert(breakpoints() == 0x0, "should have cleared breakpoints"); 4.5 } 4.6 4.7 - // deallocate information about previous versions 4.8 - if (_previous_versions != NULL) { 4.9 - for (int i = _previous_versions->length() - 1; i >= 0; i--) { 4.10 - PreviousVersionNode * pv_node = _previous_versions->at(i); 4.11 - delete pv_node; 4.12 - } 4.13 - delete _previous_versions; 4.14 - _previous_versions = NULL; 4.15 - } 4.16 - 4.17 // deallocate the cached class file 4.18 if (_cached_class_file != NULL) { 4.19 os::free(_cached_class_file, mtClass); 4.20 @@ -3187,16 +3177,17 @@ 4.21 st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr(); 4.22 { 4.23 bool have_pv = false; 4.24 - PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this); 4.25 - for (PreviousVersionNode * pv_node = pvw.next_previous_version(); 4.26 - pv_node != NULL; pv_node = pvw.next_previous_version()) { 4.27 + // previous versions are linked together through the InstanceKlass 4.28 + for (InstanceKlass* pv_node = _previous_versions; 4.29 + pv_node != NULL; 4.30 + pv_node = pv_node->previous_versions()) { 4.31 if (!have_pv) 4.32 st->print(BULLET"previous version: "); 4.33 have_pv = true; 4.34 - pv_node->prev_constant_pool()->print_value_on(st); 4.35 + pv_node->constants()->print_value_on(st); 4.36 } 4.37 if (have_pv) st->cr(); 4.38 - } // pvw is cleaned up 4.39 + } 4.40 4.41 if (generic_signature() != NULL) { 4.42 st->print(BULLET"generic signature: "); 4.43 @@ -3610,92 +3601,93 @@ 4.44 // RedefineClasses() support for previous versions: 4.45 4.46 // Purge previous versions 4.47 -static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_count) { 4.48 +void InstanceKlass::purge_previous_versions(InstanceKlass* ik) { 4.49 if (ik->previous_versions() != NULL) { 4.50 // This klass has previous versions so see what we can cleanup 4.51 // while it is safe to do so. 4.52 4.53 int deleted_count = 0; // leave debugging breadcrumbs 4.54 int live_count = 0; 4.55 - ClassLoaderData* loader_data = ik->class_loader_data() == NULL ? 4.56 - ClassLoaderData::the_null_class_loader_data() : 4.57 - ik->class_loader_data(); 4.58 + ClassLoaderData* loader_data = ik->class_loader_data(); 4.59 + assert(loader_data != NULL, "should never be null"); 4.60 4.61 // RC_TRACE macro has an embedded ResourceMark 4.62 - RC_TRACE(0x00000200, ("purge: %s: previous version length=%d", 4.63 - ik->external_name(), ik->previous_versions()->length())); 4.64 - 4.65 - for (int i = ik->previous_versions()->length() - 1; i >= 0; i--) { 4.66 - // check the previous versions array 4.67 - PreviousVersionNode * pv_node = ik->previous_versions()->at(i); 4.68 - ConstantPool* cp_ref = pv_node->prev_constant_pool(); 4.69 - assert(cp_ref != NULL, "cp ref was unexpectedly cleared"); 4.70 - 4.71 - ConstantPool* pvcp = cp_ref; 4.72 + RC_TRACE(0x00000200, ("purge: %s: previous versions", ik->external_name())); 4.73 + 4.74 + // previous versions are linked together through the InstanceKlass 4.75 + InstanceKlass* pv_node = ik->previous_versions(); 4.76 + InstanceKlass* last = ik; 4.77 + int version = 0; 4.78 + 4.79 + // check the previous versions list 4.80 + for (; pv_node != NULL; ) { 4.81 + 4.82 + ConstantPool* pvcp = pv_node->constants(); 4.83 + assert(pvcp != NULL, "cp ref was unexpectedly cleared"); 4.84 + 4.85 + 4.86 if (!pvcp->on_stack()) { 4.87 // If the constant pool isn't on stack, none of the methods 4.88 - // are executing. Delete all the methods, the constant pool and 4.89 - // and this previous version node. 4.90 - GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods(); 4.91 - if (method_refs != NULL) { 4.92 - for (int j = method_refs->length() - 1; j >= 0; j--) { 4.93 - Method* method = method_refs->at(j); 4.94 - assert(method != NULL, "method ref was unexpectedly cleared"); 4.95 - method_refs->remove_at(j); 4.96 - // method will be freed with associated class. 4.97 - } 4.98 - } 4.99 - // Remove the constant pool 4.100 - delete pv_node; 4.101 - // Since we are traversing the array backwards, we don't have to 4.102 - // do anything special with the index. 4.103 - ik->previous_versions()->remove_at(i); 4.104 + // are executing. Unlink this previous_version. 4.105 + // The previous version InstanceKlass is on the ClassLoaderData deallocate list 4.106 + // so will be deallocated during the next phase of class unloading. 4.107 + pv_node = pv_node->previous_versions(); 4.108 + last->link_previous_versions(pv_node); 4.109 deleted_count++; 4.110 + version++; 4.111 continue; 4.112 } else { 4.113 - RC_TRACE(0x00000200, ("purge: previous version @%d is alive", i)); 4.114 + RC_TRACE(0x00000200, ("purge: previous version " INTPTR_FORMAT " is alive", 4.115 + pv_node)); 4.116 assert(pvcp->pool_holder() != NULL, "Constant pool with no holder"); 4.117 guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack"); 4.118 live_count++; 4.119 } 4.120 4.121 - // At least one method is live in this previous version, clean out 4.122 - // the others or mark them as obsolete. 4.123 - GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods(); 4.124 + // At least one method is live in this previous version so clean its MethodData. 4.125 + // Reset dead EMCP methods not to get breakpoints. 4.126 + // All methods are deallocated when all of the methods for this class are no 4.127 + // longer running. 4.128 + Array<Method*>* method_refs = pv_node->methods(); 4.129 if (method_refs != NULL) { 4.130 RC_TRACE(0x00000200, ("purge: previous methods length=%d", 4.131 method_refs->length())); 4.132 - for (int j = method_refs->length() - 1; j >= 0; j--) { 4.133 + for (int j = 0; j < method_refs->length(); j++) { 4.134 Method* method = method_refs->at(j); 4.135 - assert(method != NULL, "method ref was unexpectedly cleared"); 4.136 - 4.137 - // Remove the emcp method if it's not executing 4.138 - // If it's been made obsolete by a redefinition of a non-emcp 4.139 - // method, mark it as obsolete but leave it to clean up later. 4.140 + 4.141 if (!method->on_stack()) { 4.142 - method_refs->remove_at(j); 4.143 - } else if (emcp_method_count == 0) { 4.144 - method->set_is_obsolete(); 4.145 + // no breakpoints for non-running methods 4.146 + if (method->is_running_emcp()) { 4.147 + method->set_running_emcp(false); 4.148 + } 4.149 } else { 4.150 + assert (method->is_obsolete() || method->is_running_emcp(), 4.151 + "emcp method cannot run after emcp bit is cleared"); 4.152 // RC_TRACE macro has an embedded ResourceMark 4.153 RC_TRACE(0x00000200, 4.154 ("purge: %s(%s): prev method @%d in version @%d is alive", 4.155 method->name()->as_C_string(), 4.156 - method->signature()->as_C_string(), j, i)); 4.157 + method->signature()->as_C_string(), j, version)); 4.158 if (method->method_data() != NULL) { 4.159 - // Clean out any weak method links 4.160 + // Clean out any weak method links for running methods 4.161 + // (also should include not EMCP methods) 4.162 method->method_data()->clean_weak_method_links(); 4.163 } 4.164 } 4.165 } 4.166 } 4.167 + // next previous version 4.168 + last = pv_node; 4.169 + pv_node = pv_node->previous_versions(); 4.170 + version++; 4.171 } 4.172 - assert(ik->previous_versions()->length() == live_count, "sanity check"); 4.173 RC_TRACE(0x00000200, 4.174 ("purge: previous version stats: live=%d, deleted=%d", live_count, 4.175 deleted_count)); 4.176 } 4.177 4.178 + // Clean MethodData of this class's methods so they don't refer to 4.179 + // old methods that are no longer running. 4.180 Array<Method*>* methods = ik->methods(); 4.181 int num_methods = methods->length(); 4.182 for (int index2 = 0; index2 < num_methods; ++index2) { 4.183 @@ -3705,122 +3697,30 @@ 4.184 } 4.185 } 4.186 4.187 -// External interface for use during class unloading. 4.188 -void InstanceKlass::purge_previous_versions(InstanceKlass* ik) { 4.189 - // Call with >0 emcp methods since they are not currently being redefined. 4.190 - purge_previous_versions_internal(ik, 1); 4.191 -} 4.192 - 4.193 - 4.194 -// Potentially add an information node that contains pointers to the 4.195 -// interesting parts of the previous version of the_class. 4.196 -// This is also where we clean out any unused references. 4.197 -// Note that while we delete nodes from the _previous_versions 4.198 -// array, we never delete the array itself until the klass is 4.199 -// unloaded. The has_been_redefined() query depends on that fact. 4.200 -// 4.201 -void InstanceKlass::add_previous_version(instanceKlassHandle ikh, 4.202 - BitMap* emcp_methods, int emcp_method_count) { 4.203 - assert(Thread::current()->is_VM_thread(), 4.204 - "only VMThread can add previous versions"); 4.205 - 4.206 - if (_previous_versions == NULL) { 4.207 - // This is the first previous version so make some space. 4.208 - // Start with 2 elements under the assumption that the class 4.209 - // won't be redefined much. 4.210 - _previous_versions = new (ResourceObj::C_HEAP, mtClass) 4.211 - GrowableArray<PreviousVersionNode *>(2, true); 4.212 - } 4.213 - 4.214 - ConstantPool* cp_ref = ikh->constants(); 4.215 - 4.216 - // RC_TRACE macro has an embedded ResourceMark 4.217 - RC_TRACE(0x00000400, ("adding previous version ref for %s @%d, EMCP_cnt=%d " 4.218 - "on_stack=%d", 4.219 - ikh->external_name(), _previous_versions->length(), emcp_method_count, 4.220 - cp_ref->on_stack())); 4.221 - 4.222 - // If the constant pool for this previous version of the class 4.223 - // is not marked as being on the stack, then none of the methods 4.224 - // in this previous version of the class are on the stack so 4.225 - // we don't need to create a new PreviousVersionNode. However, 4.226 - // we still need to examine older previous versions below. 4.227 - Array<Method*>* old_methods = ikh->methods(); 4.228 - 4.229 - if (cp_ref->on_stack()) { 4.230 - PreviousVersionNode * pv_node = NULL; 4.231 - if (emcp_method_count == 0) { 4.232 - // non-shared ConstantPool gets a reference 4.233 - pv_node = new PreviousVersionNode(cp_ref, NULL); 4.234 - RC_TRACE(0x00000400, 4.235 - ("add: all methods are obsolete; flushing any EMCP refs")); 4.236 - } else { 4.237 - int local_count = 0; 4.238 - GrowableArray<Method*>* method_refs = new (ResourceObj::C_HEAP, mtClass) 4.239 - GrowableArray<Method*>(emcp_method_count, true); 4.240 - for (int i = 0; i < old_methods->length(); i++) { 4.241 - if (emcp_methods->at(i)) { 4.242 - // this old method is EMCP. Save it only if it's on the stack 4.243 - Method* old_method = old_methods->at(i); 4.244 - if (old_method->on_stack()) { 4.245 - method_refs->append(old_method); 4.246 - } 4.247 - if (++local_count >= emcp_method_count) { 4.248 - // no more EMCP methods so bail out now 4.249 - break; 4.250 - } 4.251 - } 4.252 - } 4.253 - // non-shared ConstantPool gets a reference 4.254 - pv_node = new PreviousVersionNode(cp_ref, method_refs); 4.255 - } 4.256 - // append new previous version. 4.257 - _previous_versions->append(pv_node); 4.258 - } 4.259 - 4.260 - // Since the caller is the VMThread and we are at a safepoint, this 4.261 - // is a good time to clear out unused references. 4.262 - 4.263 - RC_TRACE(0x00000400, ("add: previous version length=%d", 4.264 - _previous_versions->length())); 4.265 - 4.266 - // Purge previous versions not executing on the stack 4.267 - purge_previous_versions_internal(this, emcp_method_count); 4.268 - 4.269 +void InstanceKlass::mark_newly_obsolete_methods(Array<Method*>* old_methods, 4.270 + int emcp_method_count) { 4.271 int obsolete_method_count = old_methods->length() - emcp_method_count; 4.272 4.273 if (emcp_method_count != 0 && obsolete_method_count != 0 && 4.274 - _previous_versions->length() > 0) { 4.275 + _previous_versions != NULL) { 4.276 // We have a mix of obsolete and EMCP methods so we have to 4.277 // clear out any matching EMCP method entries the hard way. 4.278 int local_count = 0; 4.279 for (int i = 0; i < old_methods->length(); i++) { 4.280 - if (!emcp_methods->at(i)) { 4.281 + Method* old_method = old_methods->at(i); 4.282 + if (old_method->is_obsolete()) { 4.283 // only obsolete methods are interesting 4.284 - Method* old_method = old_methods->at(i); 4.285 Symbol* m_name = old_method->name(); 4.286 Symbol* m_signature = old_method->signature(); 4.287 4.288 - // we might not have added the last entry 4.289 - for (int j = _previous_versions->length() - 1; j >= 0; j--) { 4.290 - // check the previous versions array for non executing obsolete methods 4.291 - PreviousVersionNode * pv_node = _previous_versions->at(j); 4.292 - 4.293 - GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods(); 4.294 - if (method_refs == NULL) { 4.295 - // We have run into a PreviousVersion generation where 4.296 - // all methods were made obsolete during that generation's 4.297 - // RedefineClasses() operation. At the time of that 4.298 - // operation, all EMCP methods were flushed so we don't 4.299 - // have to go back any further. 4.300 - // 4.301 - // A NULL method_refs is different than an empty method_refs. 4.302 - // We cannot infer any optimizations about older generations 4.303 - // from an empty method_refs for the current generation. 4.304 - break; 4.305 - } 4.306 - 4.307 - for (int k = method_refs->length() - 1; k >= 0; k--) { 4.308 + // previous versions are linked together through the InstanceKlass 4.309 + int j = 0; 4.310 + for (InstanceKlass* prev_version = _previous_versions; 4.311 + prev_version != NULL; 4.312 + prev_version = prev_version->previous_versions(), j++) { 4.313 + 4.314 + Array<Method*>* method_refs = prev_version->methods(); 4.315 + for (int k = 0; k < method_refs->length(); k++) { 4.316 Method* method = method_refs->at(k); 4.317 4.318 if (!method->is_obsolete() && 4.319 @@ -3828,14 +3728,11 @@ 4.320 method->signature() == m_signature) { 4.321 // The current RedefineClasses() call has made all EMCP 4.322 // versions of this method obsolete so mark it as obsolete 4.323 - // and remove the reference. 4.324 RC_TRACE(0x00000400, 4.325 ("add: %s(%s): flush obsolete method @%d in version @%d", 4.326 m_name->as_C_string(), m_signature->as_C_string(), k, j)); 4.327 4.328 method->set_is_obsolete(); 4.329 - // Leave obsolete methods on the previous version list to 4.330 - // clean up later. 4.331 break; 4.332 } 4.333 } 4.334 @@ -3843,9 +3740,9 @@ 4.335 // The previous loop may not find a matching EMCP method, but 4.336 // that doesn't mean that we can optimize and not go any 4.337 // further back in the PreviousVersion generations. The EMCP 4.338 - // method for this generation could have already been deleted, 4.339 + // method for this generation could have already been made obsolete, 4.340 // but there still may be an older EMCP method that has not 4.341 - // been deleted. 4.342 + // been made obsolete. 4.343 } 4.344 4.345 if (++local_count >= obsolete_method_count) { 4.346 @@ -3855,30 +3752,67 @@ 4.347 } 4.348 } 4.349 } 4.350 -} // end add_previous_version() 4.351 - 4.352 - 4.353 -// Determine if InstanceKlass has a previous version. 4.354 -bool InstanceKlass::has_previous_version() const { 4.355 - return (_previous_versions != NULL && _previous_versions->length() > 0); 4.356 -} // end has_previous_version() 4.357 - 4.358 - 4.359 -InstanceKlass* InstanceKlass::get_klass_version(int version) { 4.360 - if (constants()->version() == version) { 4.361 - return this; 4.362 +} 4.363 + 4.364 +// Save the scratch_class as the previous version if any of the methods are running. 4.365 +// The previous_versions are used to set breakpoints in EMCP methods and they are 4.366 +// also used to clean MethodData links to redefined methods that are no longer running. 4.367 +void InstanceKlass::add_previous_version(instanceKlassHandle scratch_class, 4.368 + int emcp_method_count) { 4.369 + assert(Thread::current()->is_VM_thread(), 4.370 + "only VMThread can add previous versions"); 4.371 + 4.372 + // RC_TRACE macro has an embedded ResourceMark 4.373 + RC_TRACE(0x00000400, ("adding previous version ref for %s, EMCP_cnt=%d", 4.374 + scratch_class->external_name(), emcp_method_count)); 4.375 + 4.376 + // Clean out old previous versions 4.377 + purge_previous_versions(this); 4.378 + 4.379 + // Mark newly obsolete methods in remaining previous versions. An EMCP method from 4.380 + // a previous redefinition may be made obsolete by this redefinition. 4.381 + Array<Method*>* old_methods = scratch_class->methods(); 4.382 + mark_newly_obsolete_methods(old_methods, emcp_method_count); 4.383 + 4.384 + // If the constant pool for this previous version of the class 4.385 + // is not marked as being on the stack, then none of the methods 4.386 + // in this previous version of the class are on the stack so 4.387 + // we don't need to add this as a previous version. 4.388 + ConstantPool* cp_ref = scratch_class->constants(); 4.389 + if (!cp_ref->on_stack()) { 4.390 + RC_TRACE(0x00000400, ("add: scratch class not added; no methods are running")); 4.391 + return; 4.392 } 4.393 - PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this); 4.394 - for (PreviousVersionNode * pv_node = pvw.next_previous_version(); 4.395 - pv_node != NULL; pv_node = pvw.next_previous_version()) { 4.396 - ConstantPool* prev_cp = pv_node->prev_constant_pool(); 4.397 - if (prev_cp->version() == version) { 4.398 - return prev_cp->pool_holder(); 4.399 + 4.400 + if (emcp_method_count != 0) { 4.401 + // At least one method is still running, check for EMCP methods 4.402 + for (int i = 0; i < old_methods->length(); i++) { 4.403 + Method* old_method = old_methods->at(i); 4.404 + if (!old_method->is_obsolete() && old_method->on_stack()) { 4.405 + // if EMCP method (not obsolete) is on the stack, mark as EMCP so that 4.406 + // we can add breakpoints for it. 4.407 + 4.408 + // We set the method->on_stack bit during safepoints for class redefinition and 4.409 + // class unloading and use this bit to set the is_running_emcp bit. 4.410 + // After the safepoint, the on_stack bit is cleared and the running emcp 4.411 + // method may exit. If so, we would set a breakpoint in a method that 4.412 + // is never reached, but this won't be noticeable to the programmer. 4.413 + old_method->set_running_emcp(true); 4.414 + RC_TRACE(0x00000400, ("add: EMCP method %s is on_stack " INTPTR_FORMAT, 4.415 + old_method->name_and_sig_as_C_string(), old_method)); 4.416 + } else if (!old_method->is_obsolete()) { 4.417 + RC_TRACE(0x00000400, ("add: EMCP method %s is NOT on_stack " INTPTR_FORMAT, 4.418 + old_method->name_and_sig_as_C_string(), old_method)); 4.419 + } 4.420 } 4.421 } 4.422 - return NULL; // None found 4.423 -} 4.424 - 4.425 + 4.426 + // Add previous version if any methods are still running. 4.427 + RC_TRACE(0x00000400, ("add: scratch class added; one of its methods is on_stack")); 4.428 + assert(scratch_class->previous_versions() == NULL, "shouldn't have a previous version"); 4.429 + scratch_class->link_previous_versions(previous_versions()); 4.430 + link_previous_versions(scratch_class()); 4.431 +} // end add_previous_version() 4.432 4.433 Method* InstanceKlass::method_with_idnum(int idnum) { 4.434 Method* m = NULL; 4.435 @@ -3936,61 +3870,3 @@ 4.436 unsigned char * InstanceKlass::get_cached_class_file_bytes() { 4.437 return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file); 4.438 } 4.439 - 4.440 - 4.441 -// Construct a PreviousVersionNode entry for the array hung off 4.442 -// the InstanceKlass. 4.443 -PreviousVersionNode::PreviousVersionNode(ConstantPool* prev_constant_pool, 4.444 - GrowableArray<Method*>* prev_EMCP_methods) { 4.445 - 4.446 - _prev_constant_pool = prev_constant_pool; 4.447 - _prev_EMCP_methods = prev_EMCP_methods; 4.448 -} 4.449 - 4.450 - 4.451 -// Destroy a PreviousVersionNode 4.452 -PreviousVersionNode::~PreviousVersionNode() { 4.453 - if (_prev_constant_pool != NULL) { 4.454 - _prev_constant_pool = NULL; 4.455 - } 4.456 - 4.457 - if (_prev_EMCP_methods != NULL) { 4.458 - delete _prev_EMCP_methods; 4.459 - } 4.460 -} 4.461 - 4.462 -// Construct a helper for walking the previous versions array 4.463 -PreviousVersionWalker::PreviousVersionWalker(Thread* thread, InstanceKlass *ik) { 4.464 - _thread = thread; 4.465 - _previous_versions = ik->previous_versions(); 4.466 - _current_index = 0; 4.467 - _current_p = NULL; 4.468 - _current_constant_pool_handle = constantPoolHandle(thread, ik->constants()); 4.469 -} 4.470 - 4.471 - 4.472 -// Return the interesting information for the next previous version 4.473 -// of the klass. Returns NULL if there are no more previous versions. 4.474 -PreviousVersionNode* PreviousVersionWalker::next_previous_version() { 4.475 - if (_previous_versions == NULL) { 4.476 - // no previous versions so nothing to return 4.477 - return NULL; 4.478 - } 4.479 - 4.480 - _current_p = NULL; // reset to NULL 4.481 - _current_constant_pool_handle = NULL; 4.482 - 4.483 - int length = _previous_versions->length(); 4.484 - 4.485 - while (_current_index < length) { 4.486 - PreviousVersionNode * pv_node = _previous_versions->at(_current_index++); 4.487 - 4.488 - // Save a handle to the constant pool for this previous version, 4.489 - // which keeps all the methods from being deallocated. 4.490 - _current_constant_pool_handle = constantPoolHandle(_thread, pv_node->prev_constant_pool()); 4.491 - _current_p = pv_node; 4.492 - return pv_node; 4.493 - } 4.494 - 4.495 - return NULL; 4.496 -} // end next_previous_version()
5.1 --- a/src/share/vm/oops/instanceKlass.hpp Tue Apr 08 09:51:25 2014 +0200 5.2 +++ b/src/share/vm/oops/instanceKlass.hpp Mon Jan 08 08:32:04 2018 -0800 5.3 @@ -88,7 +88,6 @@ 5.4 class fieldDescriptor; 5.5 class DepChange; 5.6 class nmethodBucket; 5.7 -class PreviousVersionNode; 5.8 class JvmtiCachedClassFieldMap; 5.9 class MemberNameTable; 5.10 5.11 @@ -235,7 +234,8 @@ 5.12 _misc_is_anonymous = 1 << 3, // has embedded _host_klass field 5.13 _misc_is_contended = 1 << 4, // marked with contended annotation 5.14 _misc_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods 5.15 - _misc_declares_default_methods = 1 << 6 // directly declares default methods (any access) 5.16 + _misc_declares_default_methods = 1 << 6, // directly declares default methods (any access) 5.17 + _misc_has_been_redefined = 1 << 7 // class has been redefined 5.18 }; 5.19 u2 _misc_flags; 5.20 u2 _minor_version; // minor version number of class file 5.21 @@ -250,9 +250,8 @@ 5.22 nmethodBucket* _dependencies; // list of dependent nmethods 5.23 nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class 5.24 BreakpointInfo* _breakpoints; // bpt lists, managed by Method* 5.25 - // Array of interesting part(s) of the previous version(s) of this 5.26 - // InstanceKlass. See PreviousVersionWalker below. 5.27 - GrowableArray<PreviousVersionNode *>* _previous_versions; 5.28 + // Linked instanceKlasses of previous versions 5.29 + InstanceKlass* _previous_versions; 5.30 // JVMTI fields can be moved to their own structure - see 6315920 5.31 // JVMTI: cached class file, before retransformable agent modified it in CFLH 5.32 JvmtiCachedClassFileData* _cached_class_file; 5.33 @@ -669,21 +668,31 @@ 5.34 } 5.35 5.36 // RedefineClasses() support for previous versions: 5.37 - void add_previous_version(instanceKlassHandle ikh, BitMap *emcp_methods, 5.38 - int emcp_method_count); 5.39 - // If the _previous_versions array is non-NULL, then this klass 5.40 - // has been redefined at least once even if we aren't currently 5.41 - // tracking a previous version. 5.42 - bool has_been_redefined() const { return _previous_versions != NULL; } 5.43 - bool has_previous_version() const; 5.44 + void add_previous_version(instanceKlassHandle ikh, int emcp_method_count); 5.45 + 5.46 + InstanceKlass* previous_versions() const { return _previous_versions; } 5.47 + 5.48 + bool has_been_redefined() const { 5.49 + return (_misc_flags & _misc_has_been_redefined) != 0; 5.50 + } 5.51 + void set_has_been_redefined() { 5.52 + _misc_flags |= _misc_has_been_redefined; 5.53 + } 5.54 + 5.55 void init_previous_versions() { 5.56 _previous_versions = NULL; 5.57 } 5.58 - GrowableArray<PreviousVersionNode *>* previous_versions() const { 5.59 - return _previous_versions; 5.60 + 5.61 + 5.62 + InstanceKlass* get_klass_version(int version) { 5.63 + for (InstanceKlass* ik = this; ik != NULL; ik = ik->previous_versions()) { 5.64 + if (ik->constants()->version() == version) { 5.65 + return ik; 5.66 + } 5.67 + } 5.68 + return NULL; 5.69 } 5.70 5.71 - InstanceKlass* get_klass_version(int version); 5.72 static void purge_previous_versions(InstanceKlass* ik); 5.73 5.74 // JVMTI: Support for caching a class file before it is modified by an agent that can do retransformation 5.75 @@ -1124,6 +1133,10 @@ 5.76 5.77 // Free CHeap allocated fields. 5.78 void release_C_heap_structures(); 5.79 + 5.80 + // RedefineClasses support 5.81 + void link_previous_versions(InstanceKlass* pv) { _previous_versions = pv; } 5.82 + void mark_newly_obsolete_methods(Array<Method*>* old_methods, int emcp_method_count); 5.83 public: 5.84 // CDS support - remove and restore oops from metadata. Oops are not shared. 5.85 virtual void remove_unshareable_info(); 5.86 @@ -1222,62 +1235,6 @@ 5.87 }; 5.88 5.89 5.90 -// If breakpoints are more numerous than just JVMTI breakpoints, 5.91 -// consider compressing this data structure. 5.92 -// It is currently a simple linked list defined in method.hpp. 5.93 - 5.94 -class BreakpointInfo; 5.95 - 5.96 - 5.97 -// A collection point for interesting information about the previous 5.98 -// version(s) of an InstanceKlass. A GrowableArray of PreviousVersionNodes 5.99 -// is attached to the InstanceKlass as needed. See PreviousVersionWalker below. 5.100 -class PreviousVersionNode : public CHeapObj<mtClass> { 5.101 - private: 5.102 - ConstantPool* _prev_constant_pool; 5.103 - 5.104 - // If the previous version of the InstanceKlass doesn't have any 5.105 - // EMCP methods, then _prev_EMCP_methods will be NULL. If all the 5.106 - // EMCP methods have been collected, then _prev_EMCP_methods can 5.107 - // have a length of zero. 5.108 - GrowableArray<Method*>* _prev_EMCP_methods; 5.109 - 5.110 -public: 5.111 - PreviousVersionNode(ConstantPool* prev_constant_pool, 5.112 - GrowableArray<Method*>* prev_EMCP_methods); 5.113 - ~PreviousVersionNode(); 5.114 - ConstantPool* prev_constant_pool() const { 5.115 - return _prev_constant_pool; 5.116 - } 5.117 - GrowableArray<Method*>* prev_EMCP_methods() const { 5.118 - return _prev_EMCP_methods; 5.119 - } 5.120 -}; 5.121 - 5.122 - 5.123 -// Helper object for walking previous versions. 5.124 -class PreviousVersionWalker : public StackObj { 5.125 - private: 5.126 - Thread* _thread; 5.127 - GrowableArray<PreviousVersionNode *>* _previous_versions; 5.128 - int _current_index; 5.129 - 5.130 - // A pointer to the current node object so we can handle the deletes. 5.131 - PreviousVersionNode* _current_p; 5.132 - 5.133 - // The constant pool handle keeps all the methods in this class from being 5.134 - // deallocated from the metaspace during class unloading. 5.135 - constantPoolHandle _current_constant_pool_handle; 5.136 - 5.137 - public: 5.138 - PreviousVersionWalker(Thread* thread, InstanceKlass *ik); 5.139 - 5.140 - // Return the interesting information for the next previous version 5.141 - // of the klass. Returns NULL if there are no more previous versions. 5.142 - PreviousVersionNode* next_previous_version(); 5.143 -}; 5.144 - 5.145 - 5.146 // 5.147 // nmethodBucket is used to record dependent nmethods for 5.148 // deoptimization. nmethod dependencies are actually <klass, method>
6.1 --- a/src/share/vm/oops/klass.cpp Tue Apr 08 09:51:25 2014 +0200 6.2 +++ b/src/share/vm/oops/klass.cpp Mon Jan 08 08:32:04 2018 -0800 6.3 @@ -455,6 +455,12 @@ 6.4 if (clean_alive_klasses && current->oop_is_instance()) { 6.5 InstanceKlass* ik = InstanceKlass::cast(current); 6.6 ik->clean_weak_instanceklass_links(is_alive); 6.7 + 6.8 + // JVMTI RedefineClasses creates previous versions that are not in 6.9 + // the class hierarchy, so process them here. 6.10 + while ((ik = ik->previous_versions()) != NULL) { 6.11 + ik->clean_weak_instanceklass_links(is_alive); 6.12 + } 6.13 } 6.14 } 6.15 }
7.1 --- a/src/share/vm/oops/method.cpp Tue Apr 08 09:51:25 2014 +0200 7.2 +++ b/src/share/vm/oops/method.cpp Mon Jan 08 08:32:04 2018 -0800 7.3 @@ -91,6 +91,7 @@ 7.4 set_hidden(false); 7.5 set_dont_inline(false); 7.6 set_has_injected_profile(false); 7.7 + set_running_emcp(false); 7.8 set_method_data(NULL); 7.9 clear_method_counters(); 7.10 set_vtable_index(Method::garbage_vtable_index);
8.1 --- a/src/share/vm/oops/method.hpp Tue Apr 08 09:51:25 2014 +0200 8.2 +++ b/src/share/vm/oops/method.hpp Mon Jan 08 08:32:04 2018 -0800 8.3 @@ -111,6 +111,7 @@ 8.4 _caller_sensitive : 1, 8.5 _force_inline : 1, 8.6 _hidden : 1, 8.7 + _running_emcp : 1, 8.8 _dont_inline : 1, 8.9 _has_injected_profile : 1, 8.10 : 2; 8.11 @@ -712,6 +713,21 @@ 8.12 void set_is_obsolete() { _access_flags.set_is_obsolete(); } 8.13 bool is_deleted() const { return access_flags().is_deleted(); } 8.14 void set_is_deleted() { _access_flags.set_is_deleted(); } 8.15 + 8.16 + bool is_running_emcp() const { 8.17 + // EMCP methods are old but not obsolete or deleted. Equivalent 8.18 + // Modulo Constant Pool means the method is equivalent except 8.19 + // the constant pool and instructions that access the constant 8.20 + // pool might be different. 8.21 + // If a breakpoint is set in a redefined method, its EMCP methods that are 8.22 + // still running must have a breakpoint also. 8.23 + return _running_emcp; 8.24 + } 8.25 + 8.26 + void set_running_emcp(bool x) { 8.27 + _running_emcp = x; 8.28 + } 8.29 + 8.30 bool on_stack() const { return access_flags().on_stack(); } 8.31 void set_on_stack(const bool value); 8.32
9.1 --- a/src/share/vm/prims/jvmtiImpl.cpp Tue Apr 08 09:51:25 2014 +0200 9.2 +++ b/src/share/vm/prims/jvmtiImpl.cpp Mon Jan 08 08:32:04 2018 -0800 9.3 @@ -282,39 +282,22 @@ 9.4 void JvmtiBreakpoint::each_method_version_do(method_action meth_act) { 9.5 ((Method*)_method->*meth_act)(_bci); 9.6 9.7 - // add/remove breakpoint to/from versions of the method that 9.8 - // are EMCP. Directly or transitively obsolete methods are 9.9 - // not saved in the PreviousVersionNodes. 9.10 + // add/remove breakpoint to/from versions of the method that are EMCP. 9.11 Thread *thread = Thread::current(); 9.12 instanceKlassHandle ikh = instanceKlassHandle(thread, _method->method_holder()); 9.13 Symbol* m_name = _method->name(); 9.14 Symbol* m_signature = _method->signature(); 9.15 9.16 // search previous versions if they exist 9.17 - PreviousVersionWalker pvw(thread, (InstanceKlass *)ikh()); 9.18 - for (PreviousVersionNode * pv_node = pvw.next_previous_version(); 9.19 - pv_node != NULL; pv_node = pvw.next_previous_version()) { 9.20 - GrowableArray<Method*>* methods = pv_node->prev_EMCP_methods(); 9.21 - 9.22 - if (methods == NULL) { 9.23 - // We have run into a PreviousVersion generation where 9.24 - // all methods were made obsolete during that generation's 9.25 - // RedefineClasses() operation. At the time of that 9.26 - // operation, all EMCP methods were flushed so we don't 9.27 - // have to go back any further. 9.28 - // 9.29 - // A NULL methods array is different than an empty methods 9.30 - // array. We cannot infer any optimizations about older 9.31 - // generations from an empty methods array for the current 9.32 - // generation. 9.33 - break; 9.34 - } 9.35 + for (InstanceKlass* pv_node = ikh->previous_versions(); 9.36 + pv_node != NULL; 9.37 + pv_node = pv_node->previous_versions()) { 9.38 + Array<Method*>* methods = pv_node->methods(); 9.39 9.40 for (int i = methods->length() - 1; i >= 0; i--) { 9.41 Method* method = methods->at(i); 9.42 - // obsolete methods that are running are not deleted from 9.43 - // previous version array, but they are skipped here. 9.44 - if (!method->is_obsolete() && 9.45 + // Only set breakpoints in running EMCP methods. 9.46 + if (method->is_running_emcp() && 9.47 method->name() == m_name && 9.48 method->signature() == m_signature) { 9.49 RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)",
10.1 --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Tue Apr 08 09:51:25 2014 +0200 10.2 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Jan 08 08:32:04 2018 -0800 10.3 @@ -3435,13 +3435,12 @@ 10.4 } 10.5 10.6 // the previous versions' constant pool caches may need adjustment 10.7 - PreviousVersionWalker pvw(_thread, ik); 10.8 - for (PreviousVersionNode * pv_node = pvw.next_previous_version(); 10.9 - pv_node != NULL; pv_node = pvw.next_previous_version()) { 10.10 - other_cp = pv_node->prev_constant_pool(); 10.11 - cp_cache = other_cp->cache(); 10.12 + for (InstanceKlass* pv_node = ik->previous_versions(); 10.13 + pv_node != NULL; 10.14 + pv_node = pv_node->previous_versions()) { 10.15 + cp_cache = pv_node->constants()->cache(); 10.16 if (cp_cache != NULL) { 10.17 - cp_cache->adjust_method_entries(other_cp->pool_holder(), &trace_name_printed); 10.18 + cp_cache->adjust_method_entries(pv_node, &trace_name_printed); 10.19 } 10.20 } 10.21 } 10.22 @@ -3461,9 +3460,8 @@ 10.23 } 10.24 } 10.25 10.26 -void VM_RedefineClasses::check_methods_and_mark_as_obsolete( 10.27 - BitMap *emcp_methods, int * emcp_method_count_p) { 10.28 - *emcp_method_count_p = 0; 10.29 +int VM_RedefineClasses::check_methods_and_mark_as_obsolete() { 10.30 + int emcp_method_count = 0; 10.31 int obsolete_count = 0; 10.32 int old_index = 0; 10.33 for (int j = 0; j < _matching_methods_length; ++j, ++old_index) { 10.34 @@ -3537,9 +3535,9 @@ 10.35 // that we get from effectively overwriting the old methods 10.36 // when the new methods are attached to the_class. 10.37 10.38 - // track which methods are EMCP for add_previous_version() call 10.39 - emcp_methods->set_bit(old_index); 10.40 - (*emcp_method_count_p)++; 10.41 + // Count number of methods that are EMCP. The method will be marked 10.42 + // old but not obsolete if it is EMCP. 10.43 + emcp_method_count++; 10.44 10.45 // An EMCP method is _not_ obsolete. An obsolete method has a 10.46 // different jmethodID than the current method. An EMCP method 10.47 @@ -3589,10 +3587,11 @@ 10.48 old_method->name()->as_C_string(), 10.49 old_method->signature()->as_C_string())); 10.50 } 10.51 - assert((*emcp_method_count_p + obsolete_count) == _old_methods->length(), 10.52 + assert((emcp_method_count + obsolete_count) == _old_methods->length(), 10.53 "sanity check"); 10.54 - RC_TRACE(0x00000100, ("EMCP_cnt=%d, obsolete_cnt=%d", *emcp_method_count_p, 10.55 + RC_TRACE(0x00000100, ("EMCP_cnt=%d, obsolete_cnt=%d", emcp_method_count, 10.56 obsolete_count)); 10.57 + return emcp_method_count; 10.58 } 10.59 10.60 // This internal class transfers the native function registration from old methods 10.61 @@ -3973,11 +3972,8 @@ 10.62 old_constants->set_pool_holder(scratch_class()); 10.63 #endif 10.64 10.65 - // track which methods are EMCP for add_previous_version() call below 10.66 - BitMap emcp_methods(_old_methods->length()); 10.67 - int emcp_method_count = 0; 10.68 - emcp_methods.clear(); // clears 0..(length() - 1) 10.69 - check_methods_and_mark_as_obsolete(&emcp_methods, &emcp_method_count); 10.70 + // track number of methods that are EMCP for add_previous_version() call below 10.71 + int emcp_method_count = check_methods_and_mark_as_obsolete(); 10.72 transfer_old_native_function_registrations(the_class); 10.73 10.74 // The class file bytes from before any retransformable agents mucked 10.75 @@ -4064,9 +4060,10 @@ 10.76 scratch_class->enclosing_method_method_index()); 10.77 scratch_class->set_enclosing_method_indices(old_class_idx, old_method_idx); 10.78 10.79 + the_class->set_has_been_redefined(); 10.80 + 10.81 // keep track of previous versions of this class 10.82 - the_class->add_previous_version(scratch_class, &emcp_methods, 10.83 - emcp_method_count); 10.84 + the_class->add_previous_version(scratch_class, emcp_method_count); 10.85 10.86 RC_TIMER_STOP(_timer_rsc_phase1); 10.87 RC_TIMER_START(_timer_rsc_phase2);
11.1 --- a/src/share/vm/prims/jvmtiRedefineClasses.hpp Tue Apr 08 09:51:25 2014 +0200 11.2 +++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp Mon Jan 08 08:32:04 2018 -0800 11.3 @@ -403,14 +403,9 @@ 11.4 // Change jmethodIDs to point to the new methods 11.5 void update_jmethod_ids(); 11.6 11.7 - // In addition to marking methods as obsolete, this routine 11.8 - // records which methods are EMCP (Equivalent Module Constant 11.9 - // Pool) in the emcp_methods BitMap and returns the number of 11.10 - // EMCP methods via emcp_method_count_p. This information is 11.11 - // used when information about the previous version of the_class 11.12 - // is squirreled away. 11.13 - void check_methods_and_mark_as_obsolete(BitMap *emcp_methods, 11.14 - int * emcp_method_count_p); 11.15 + // In addition to marking methods as old and/or obsolete, this routine 11.16 + // counts the number of methods that are EMCP (Equivalent Module Constant Pool). 11.17 + int check_methods_and_mark_as_obsolete(); 11.18 void transfer_old_native_function_registrations(instanceKlassHandle the_class); 11.19 11.20 // Install the redefinition of a class
12.1 --- a/test/runtime/RedefineFinalizer/RedefineFinalizer.java Tue Apr 08 09:51:25 2014 +0200 12.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 12.3 @@ -1,64 +0,0 @@ 12.4 -/* 12.5 - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 12.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.7 - * 12.8 - * This code is free software; you can redistribute it and/or modify it 12.9 - * under the terms of the GNU General Public License version 2 only, as 12.10 - * published by the Free Software Foundation. 12.11 - * 12.12 - * This code is distributed in the hope that it will be useful, but WITHOUT 12.13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12.14 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12.15 - * version 2 for more details (a copy is included in the LICENSE file that 12.16 - * accompanied this code). 12.17 - * 12.18 - * You should have received a copy of the GNU General Public License version 12.19 - * 2 along with this work; if not, write to the Free Software Foundation, 12.20 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 12.21 - * 12.22 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 12.23 - * or visit www.oracle.com if you need additional information or have any 12.24 - * questions. 12.25 - */ 12.26 - 12.27 -/* 12.28 - * @test 12.29 - * @bug 6904403 12.30 - * @summary Don't assert if we redefine finalize method 12.31 - * @library /testlibrary 12.32 - * @build RedefineClassHelper 12.33 - * @run main RedefineClassHelper 12.34 - * @run main/othervm -javaagent:redefineagent.jar RedefineFinalizer 12.35 - */ 12.36 - 12.37 -/* 12.38 - * Regression test for hitting: 12.39 - * 12.40 - * assert(f == k->has_finalizer()) failed: inconsistent has_finalizer 12.41 - * 12.42 - * when redefining finalizer method 12.43 - */ 12.44 -public class RedefineFinalizer { 12.45 - 12.46 - public static String newB = 12.47 - "class RedefineFinalizer$B {" + 12.48 - " protected void finalize() { " + 12.49 - " System.out.println(\"Finalizer called\");" + 12.50 - " }" + 12.51 - "}"; 12.52 - 12.53 - public static void main(String[] args) throws Exception { 12.54 - RedefineClassHelper.redefineClass(B.class, newB); 12.55 - 12.56 - A a = new A(); 12.57 - } 12.58 - 12.59 - static class A extends B { 12.60 - } 12.61 - 12.62 - static class B { 12.63 - protected void finalize() { 12.64 - // should be empty 12.65 - } 12.66 - } 12.67 -}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/test/runtime/RedefineTests/RedefineFinalizer.java Mon Jan 08 08:32:04 2018 -0800 13.3 @@ -0,0 +1,64 @@ 13.4 +/* 13.5 + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. 13.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 13.7 + * 13.8 + * This code is free software; you can redistribute it and/or modify it 13.9 + * under the terms of the GNU General Public License version 2 only, as 13.10 + * published by the Free Software Foundation. 13.11 + * 13.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 13.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13.15 + * version 2 for more details (a copy is included in the LICENSE file that 13.16 + * accompanied this code). 13.17 + * 13.18 + * You should have received a copy of the GNU General Public License version 13.19 + * 2 along with this work; if not, write to the Free Software Foundation, 13.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 13.21 + * 13.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 13.23 + * or visit www.oracle.com if you need additional information or have any 13.24 + * questions. 13.25 + */ 13.26 + 13.27 +/* 13.28 + * @test 13.29 + * @bug 6904403 13.30 + * @summary Don't assert if we redefine finalize method 13.31 + * @library /testlibrary 13.32 + * @build RedefineClassHelper 13.33 + * @run main RedefineClassHelper 13.34 + * @run main/othervm -javaagent:redefineagent.jar RedefineFinalizer 13.35 + */ 13.36 + 13.37 +/* 13.38 + * Regression test for hitting: 13.39 + * 13.40 + * assert(f == k->has_finalizer()) failed: inconsistent has_finalizer 13.41 + * 13.42 + * when redefining finalizer method 13.43 + */ 13.44 +public class RedefineFinalizer { 13.45 + 13.46 + public static String newB = 13.47 + "class RedefineFinalizer$B {" + 13.48 + " protected void finalize() { " + 13.49 + " System.out.println(\"Finalizer called\");" + 13.50 + " }" + 13.51 + "}"; 13.52 + 13.53 + public static void main(String[] args) throws Exception { 13.54 + RedefineClassHelper.redefineClass(B.class, newB); 13.55 + 13.56 + A a = new A(); 13.57 + } 13.58 + 13.59 + static class A extends B { 13.60 + } 13.61 + 13.62 + static class B { 13.63 + protected void finalize() { 13.64 + // should be empty 13.65 + } 13.66 + } 13.67 +}
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/test/runtime/RedefineTests/RedefineRunningMethods.java Mon Jan 08 08:32:04 2018 -0800 14.3 @@ -0,0 +1,143 @@ 14.4 +/* 14.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.7 + * 14.8 + * This code is free software; you can redistribute it and/or modify it 14.9 + * under the terms of the GNU General Public License version 2 only, as 14.10 + * published by the Free Software Foundation. 14.11 + * 14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14.15 + * version 2 for more details (a copy is included in the LICENSE file that 14.16 + * accompanied this code). 14.17 + * 14.18 + * You should have received a copy of the GNU General Public License version 14.19 + * 2 along with this work; if not, write to the Free Software Foundation, 14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 14.21 + * 14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 14.23 + * or visit www.oracle.com if you need additional information or have any 14.24 + * questions. 14.25 + */ 14.26 + 14.27 +/* 14.28 + * @test 14.29 + * @bug 8055008 14.30 + * @summary Redefine EMCP and non-EMCP methods that are running in an infinite loop 14.31 + * @library /testlibrary 14.32 + * @build RedefineClassHelper 14.33 + * @run main RedefineClassHelper 14.34 + * @run main/othervm -javaagent:redefineagent.jar RedefineRunningMethods 14.35 + */ 14.36 +public class RedefineRunningMethods { 14.37 + 14.38 + public static String newB = 14.39 + "class RedefineRunningMethods$B {" + 14.40 + " static int count1 = 0;" + 14.41 + " static int count2 = 0;" + 14.42 + " public static volatile boolean stop = false;" + 14.43 + " static void localSleep() { " + 14.44 + " try{ " + 14.45 + " Thread.currentThread().sleep(10);" + 14.46 + " } catch(InterruptedException ie) { " + 14.47 + " } " + 14.48 + " } " + 14.49 + " public static void infinite() { " + 14.50 + " System.out.println(\"infinite called\");" + 14.51 + " }" + 14.52 + " public static void infinite_emcp() { " + 14.53 + " while (!stop) { count2++; localSleep(); }" + 14.54 + " }" + 14.55 + "}"; 14.56 + 14.57 + public static String evenNewerB = 14.58 + "class RedefineRunningMethods$B {" + 14.59 + " static int count1 = 0;" + 14.60 + " static int count2 = 0;" + 14.61 + " public static volatile boolean stop = false;" + 14.62 + " static void localSleep() { " + 14.63 + " try{ " + 14.64 + " Thread.currentThread().sleep(1);" + 14.65 + " } catch(InterruptedException ie) { " + 14.66 + " } " + 14.67 + " } " + 14.68 + " public static void infinite() { }" + 14.69 + " public static void infinite_emcp() { " + 14.70 + " System.out.println(\"infinite_emcp now obsolete called\");" + 14.71 + " }" + 14.72 + "}"; 14.73 + 14.74 + static class B { 14.75 + static int count1 = 0; 14.76 + static int count2 = 0; 14.77 + public static volatile boolean stop = false; 14.78 + static void localSleep() { 14.79 + try{ 14.80 + Thread.currentThread().sleep(10);//sleep for 10 ms 14.81 + } catch(InterruptedException ie) { 14.82 + } 14.83 + } 14.84 + 14.85 + public static void infinite() { 14.86 + while (!stop) { count1++; localSleep(); } 14.87 + } 14.88 + public static void infinite_emcp() { 14.89 + while (!stop) { count2++; localSleep(); } 14.90 + } 14.91 + } 14.92 + 14.93 + 14.94 + public static void main(String[] args) throws Exception { 14.95 + 14.96 + new Thread() { 14.97 + public void run() { 14.98 + B.infinite(); 14.99 + } 14.100 + }.start(); 14.101 + 14.102 + new Thread() { 14.103 + public void run() { 14.104 + B.infinite_emcp(); 14.105 + } 14.106 + }.start(); 14.107 + 14.108 + RedefineClassHelper.redefineClass(B.class, newB); 14.109 + 14.110 + System.gc(); 14.111 + 14.112 + B.infinite(); 14.113 + 14.114 + // Start a thread with the second version of infinite_emcp running 14.115 + new Thread() { 14.116 + public void run() { 14.117 + B.infinite_emcp(); 14.118 + } 14.119 + }.start(); 14.120 + 14.121 + for (int i = 0; i < 20 ; i++) { 14.122 + String s = new String("some garbage"); 14.123 + System.gc(); 14.124 + } 14.125 + 14.126 + RedefineClassHelper.redefineClass(B.class, evenNewerB); 14.127 + System.gc(); 14.128 + 14.129 + for (int i = 0; i < 20 ; i++) { 14.130 + B.infinite(); 14.131 + String s = new String("some garbage"); 14.132 + System.gc(); 14.133 + } 14.134 + 14.135 + B.infinite_emcp(); 14.136 + 14.137 + // purge should clean everything up. 14.138 + B.stop = true; 14.139 + 14.140 + for (int i = 0; i < 20 ; i++) { 14.141 + B.infinite(); 14.142 + String s = new String("some garbage"); 14.143 + System.gc(); 14.144 + } 14.145 + } 14.146 +}