# HG changeset patch # User never # Date 1278108107 25200 # Node ID 65b0c03b165d75aa5d172b468f756ece91b2f71c # Parent fcbb92a1ab3b1e819915c4b7e50d25c79de21b1c 6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1 Reviewed-by: kvn, dcubed diff -r fcbb92a1ab3b -r 65b0c03b165d src/share/vm/prims/jvmtiCodeBlobEvents.cpp --- a/src/share/vm/prims/jvmtiCodeBlobEvents.cpp Tue Jun 29 16:09:57 2010 -0700 +++ b/src/share/vm/prims/jvmtiCodeBlobEvents.cpp Fri Jul 02 15:01:47 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,34 +118,13 @@ for (int i=0; i<_global_code_blobs->length(); i++) { JvmtiCodeBlobDesc* scb = _global_code_blobs->at(i); if (addr == scb->code_begin()) { + ShouldNotReachHere(); return; } } - // we must name the CodeBlob - some CodeBlobs already have names :- - // - stubs used by compiled code to call a (static) C++ runtime routine - // - non-relocatable machine code such as the interpreter, stubroutines, etc. - // - various singleton blobs - // - // others are unnamed so we create a name :- - // - OSR adapter (interpreter frame that has been on-stack replaced) - // - I2C and C2I adapters - const char* name = NULL; - if (cb->is_runtime_stub()) { - name = ((RuntimeStub*)cb)->name(); - } - if (cb->is_buffer_blob()) { - name = ((BufferBlob*)cb)->name(); - } - if (cb->is_deoptimization_stub() || cb->is_safepoint_stub()) { - name = ((SingletonBlob*)cb)->name(); - } - if (cb->is_uncommon_trap_stub() || cb->is_exception_stub()) { - name = ((SingletonBlob*)cb)->name(); - } - // record the CodeBlob details as a JvmtiCodeBlobDesc - JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(name, cb->instructions_begin(), + JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(cb->name(), cb->instructions_begin(), cb->instructions_end()); _global_code_blobs->append(scb); } @@ -197,7 +176,10 @@ jvmtiError JvmtiCodeBlobEvents::generate_dynamic_code_events(JvmtiEnv* env) { CodeBlobCollector collector; - // first collect all the code blobs + // First collect all the code blobs. This has to be done in a + // single pass over the code cache with CodeCache_lock held because + // there isn't any safe way to iterate over regular CodeBlobs since + // they can be freed at any point. { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); collector.collect(); @@ -213,166 +195,28 @@ } -// Support class to describe a nmethod in the CodeCache - -class nmethodDesc: public CHeapObj { - private: - jmethodID _jmethod_id; - address _code_begin; - address _code_end; - jvmtiAddrLocationMap* _map; - jint _map_length; - public: - nmethodDesc(jmethodID jmethod_id, address code_begin, address code_end, - jvmtiAddrLocationMap* map, jint map_length) { - _jmethod_id = jmethod_id; - _code_begin = code_begin; - _code_end = code_end; - _map = map; - _map_length = map_length; - } - jmethodID jmethod_id() const { return _jmethod_id; } - address code_begin() const { return _code_begin; } - address code_end() const { return _code_end; } - jvmtiAddrLocationMap* map() const { return _map; } - jint map_length() const { return _map_length; } -}; - - -// Support class to collect a list of the nmethod CodeBlobs in -// the CodeCache. -// -// Usage :- -// -// nmethodCollector collector; -// -// collector.collect(); -// JvmtiCodeBlobDesc* blob = collector.first(); -// while (blob != NULL) { -// : -// blob = collector.next(); -// } -// -class nmethodCollector : StackObj { - private: - GrowableArray* _nmethods; // collect nmethods - int _pos; // iteration support - - // used during a collection - static GrowableArray* _global_nmethods; - static void do_nmethod(nmethod* nm); - public: - nmethodCollector() { - _nmethods = NULL; - _pos = -1; - } - ~nmethodCollector() { - if (_nmethods != NULL) { - for (int i=0; i<_nmethods->length(); i++) { - nmethodDesc* blob = _nmethods->at(i); - if (blob->map()!= NULL) { - FREE_C_HEAP_ARRAY(jvmtiAddrLocationMap, blob->map()); - } - } - delete _nmethods; - } - } - - // collect list of nmethods in the cache - void collect(); - - // iteration support - return first code blob - nmethodDesc* first() { - assert(_nmethods != NULL, "not collected"); - if (_nmethods->length() == 0) { - return NULL; - } - _pos = 0; - return _nmethods->at(0); - } - - // iteration support - return next code blob - nmethodDesc* next() { - assert(_pos >= 0, "iteration not started"); - if (_pos+1 >= _nmethods->length()) { - return NULL; - } - return _nmethods->at(++_pos); - } -}; - -// used during collection -GrowableArray* nmethodCollector::_global_nmethods; - - -// called for each nmethod in the CodeCache -// -// This function simply adds a descriptor for each nmethod to the global list. - -void nmethodCollector::do_nmethod(nmethod* nm) { - // ignore zombies - if (!nm->is_alive()) { - return; - } - - assert(nm->method() != NULL, "checking"); - - // create the location map for the nmethod. - jvmtiAddrLocationMap* map; - jint map_length; - JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nm, &map, &map_length); - - // record the nmethod details - nmethodDesc* snm = new nmethodDesc(nm->get_and_cache_jmethod_id(), - nm->code_begin(), - nm->code_end(), - map, - map_length); - _global_nmethods->append(snm); -} - -// collects a list of nmethod in the CodeCache. -// -// The created list is growable array of nmethodDesc - each one describes -// a nmethod and includs its JVMTI address location map. - -void nmethodCollector::collect() { - assert_locked_or_safepoint(CodeCache_lock); - assert(_global_nmethods == NULL, "checking"); - - // create the list - _global_nmethods = new (ResourceObj::C_HEAP) GrowableArray(100,true); - - // any a descriptor for each nmethod to the list. - CodeCache::nmethods_do(do_nmethod); - - // make the list the instance list - _nmethods = _global_nmethods; - _global_nmethods = NULL; -} - // Generate a COMPILED_METHOD_LOAD event for each nnmethod - jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* env) { HandleMark hm; - nmethodCollector collector; - - // first collect all nmethods - { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - collector.collect(); - } - // iterate over the list and post an event for each nmethod - nmethodDesc* nm_desc = collector.first(); - while (nm_desc != NULL) { - jmethodID mid = nm_desc->jmethod_id(); - assert(mid != NULL, "checking"); - JvmtiExport::post_compiled_method_load(env, mid, - (jint)(nm_desc->code_end() - nm_desc->code_begin()), - nm_desc->code_begin(), nm_desc->map_length(), - nm_desc->map()); - nm_desc = collector.next(); + // Walk the CodeCache notifying for live nmethods. The code cache + // may be changing while this is happening which is ok since newly + // created nmethod will notify normally and nmethods which are freed + // can be safely skipped. + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + nmethod* current = CodeCache::first_nmethod(); + while (current != NULL) { + // Lock the nmethod so it can't be freed + nmethodLocker nml(current); + + // Only notify for live nmethods + if (current->is_alive()) { + // Don't hold the lock over the notify or jmethodID creation + MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + current->get_and_cache_jmethod_id(); + JvmtiExport::post_compiled_method_load(current); + } + current = CodeCache::next_nmethod(current); } return JVMTI_ERROR_NONE; }