mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-23 12:34:32 +02:00
8034839: jvm hangs with gc/gctests/LoadUnloadGC test
Provide fast lookup of checked dependencies via hashmap Reviewed-by: kvn, roland
This commit is contained in:
parent
683ea742f2
commit
aa570e227c
6 changed files with 212 additions and 67 deletions
|
@ -595,11 +595,8 @@ void CodeCache::clear_inline_caches() {
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Keeps track of time spent for checking dependencies
|
||||
static elapsedTimer dependentCheckTime;
|
||||
#endif
|
||||
|
||||
NOT_PRODUCT(static elapsedTimer dependentCheckTime;)
|
||||
|
||||
int CodeCache::mark_for_deoptimization(DepChange& changes) {
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
|
|
@ -725,56 +725,19 @@ Klass* Dependencies::DepStream::context_type() {
|
|||
}
|
||||
|
||||
// ----------------- DependencySignature --------------------------------------
|
||||
bool DependencySignature::equals(const DependencySignature& sig) const {
|
||||
if (type() != sig.type()) {
|
||||
bool DependencySignature::equals(DependencySignature* sig) const {
|
||||
if ((type() != sig->type()) || (args_count() != sig->args_count())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args_count() != sig.args_count()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sig.args_count(); i++) {
|
||||
if (arg(i) != sig.arg(i)) {
|
||||
for (int i = 0; i < sig->args_count(); i++) {
|
||||
if (arg(i) != sig->arg(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ----------------- DependencySignatureBuffer --------------------------------------
|
||||
DependencySignatureBuffer::DependencySignatureBuffer() {
|
||||
_signatures = NEW_RESOURCE_ARRAY(GrowableArray<DependencySignature*>*, Dependencies::TYPE_LIMIT);
|
||||
memset(_signatures, 0, sizeof(DependencySignature*) * Dependencies::TYPE_LIMIT);
|
||||
}
|
||||
|
||||
/* Check if arguments are identical. Two dependency signatures are considered
|
||||
* identical, if the type as well as all argument identifiers are identical.
|
||||
* If the dependency has not already been checked, the dependency signature is
|
||||
* added to the checked dependencies of the same type. The function returns
|
||||
* false, which causes the dependency to be checked in the caller.
|
||||
*/
|
||||
bool DependencySignatureBuffer::add_if_missing(const DependencySignature& sig) {
|
||||
const int index = sig.type();
|
||||
GrowableArray<DependencySignature*>* buffer = _signatures[index];
|
||||
if (buffer == NULL) {
|
||||
buffer = new GrowableArray<DependencySignature*>();
|
||||
_signatures[index] = buffer;
|
||||
}
|
||||
|
||||
// Check if we have already checked the dependency
|
||||
for (int i = 0; i < buffer->length(); i++) {
|
||||
DependencySignature* checked_signature = buffer->at(i);
|
||||
if (checked_signature->equals(sig)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
buffer->append((DependencySignature*)&sig);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// Checking dependencies:
|
||||
|
||||
// This hierarchy walker inspects subtypes of a given type,
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "code/compressedStream.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/hashtable.hpp"
|
||||
|
||||
//** Dependencies represent assertions (approximate invariants) within
|
||||
// the runtime system, e.g. class hierarchy changes. An example is an
|
||||
|
@ -526,13 +527,12 @@ class Dependencies: public ResourceObj {
|
|||
};
|
||||
|
||||
|
||||
class DependencySignature : public ResourceObj {
|
||||
class DependencySignature : public GenericHashtableEntry<DependencySignature, ResourceObj> {
|
||||
private:
|
||||
int _args_count;
|
||||
uintptr_t _argument_hash[Dependencies::max_arg_count];
|
||||
Dependencies::DepType _type;
|
||||
|
||||
|
||||
public:
|
||||
DependencySignature(Dependencies::DepStream& dep) {
|
||||
_args_count = dep.argument_count();
|
||||
|
@ -542,21 +542,14 @@ class DependencySignature : public ResourceObj {
|
|||
}
|
||||
}
|
||||
|
||||
bool equals(const DependencySignature& sig) const;
|
||||
bool equals(DependencySignature* sig) const;
|
||||
uintptr_t key() const { return _argument_hash[0] >> 2; }
|
||||
|
||||
int args_count() const { return _args_count; }
|
||||
uintptr_t arg(int idx) const { return _argument_hash[idx]; }
|
||||
Dependencies::DepType type() const { return _type; }
|
||||
};
|
||||
|
||||
class DependencySignatureBuffer : public StackObj {
|
||||
private:
|
||||
GrowableArray<DependencySignature*>** _signatures;
|
||||
|
||||
public:
|
||||
DependencySignatureBuffer();
|
||||
bool add_if_missing(const DependencySignature& sig);
|
||||
};
|
||||
|
||||
// Every particular DepChange is a sub-class of this class.
|
||||
class DepChange : public StackObj {
|
||||
|
|
|
@ -2168,25 +2168,21 @@ void nmethod::check_all_dependencies(DepChange& changes) {
|
|||
// Turn off dependency tracing while actually testing dependencies.
|
||||
NOT_PRODUCT( FlagSetting fs(TraceDependencies, false) );
|
||||
|
||||
// 'dep_signature_buffers' caches already checked dependencies.
|
||||
DependencySignatureBuffer dep_signature_buffers;
|
||||
|
||||
GenericHashtable<DependencySignature, ResourceObj>* table = new GenericHashtable<DependencySignature, ResourceObj>(11027);
|
||||
// Iterate over live nmethods and check dependencies of all nmethods that are not
|
||||
// marked for deoptimization. A particular dependency is only checked once.
|
||||
for(nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); nm != NULL; nm = CodeCache::alive_nmethod(CodeCache::next(nm))) {
|
||||
if (!nm->is_marked_for_deoptimization()) {
|
||||
for (Dependencies::DepStream deps(nm); deps.next(); ) {
|
||||
// Construct abstraction of a dependency.
|
||||
const DependencySignature* current_sig = new DependencySignature(deps);
|
||||
// Determine if 'deps' is already checked. If it is not checked,
|
||||
// 'add_if_missing()' adds the dependency signature and returns
|
||||
// false.
|
||||
if (!dep_signature_buffers.add_if_missing(*current_sig)) {
|
||||
DependencySignature* current_sig = new DependencySignature(deps);
|
||||
// Determine if 'deps' is already checked. table->add() returns
|
||||
// 'true' if the dependency was added (i.e., was not in the hashtable).
|
||||
if (table->add(current_sig)) {
|
||||
if (deps.check_dependency() != NULL) {
|
||||
// Dependency checking failed. Print out information about the failed
|
||||
// dependency and finally fail with an assert. We can fail here, since
|
||||
// dependency checking is never done in a product build.
|
||||
ResourceMark rm;
|
||||
changes.print();
|
||||
nm->print();
|
||||
nm->print_dependencies();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue