8035946: Use ResourceHashtable for dependency checking
Use ResourceHashtable for dependency checking and delete GenericHashtable Reviewed-by: kvn, coleenp
This commit is contained in:
parent
ad8d066a4a
commit
7722b3d097
@ -725,13 +725,13 @@ Klass* Dependencies::DepStream::context_type() {
|
||||
}
|
||||
|
||||
// ----------------- DependencySignature --------------------------------------
|
||||
bool DependencySignature::equals(DependencySignature* sig) const {
|
||||
if ((type() != sig->type()) || (args_count() != sig->args_count())) {
|
||||
bool DependencySignature::equals(DependencySignature const& s1, DependencySignature const& s2) {
|
||||
if ((s1.type() != s2.type()) || (s1.args_count() != s2.args_count())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sig->args_count(); i++) {
|
||||
if (arg(i) != sig->arg(i)) {
|
||||
for (int i = 0; i < s1.args_count(); i++) {
|
||||
if (s1.arg(i) != s2.arg(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ class Dependencies: public ResourceObj {
|
||||
};
|
||||
|
||||
|
||||
class DependencySignature : public GenericHashtableEntry<DependencySignature, ResourceObj> {
|
||||
class DependencySignature : public ResourceObj {
|
||||
private:
|
||||
int _args_count;
|
||||
uintptr_t _argument_hash[Dependencies::max_arg_count];
|
||||
@ -542,12 +542,13 @@ class DependencySignature : public GenericHashtableEntry<DependencySignature, Re
|
||||
}
|
||||
}
|
||||
|
||||
bool equals(DependencySignature* sig) const;
|
||||
uintptr_t key() const { return _argument_hash[0] >> 2; }
|
||||
static bool equals(DependencySignature const& s1, DependencySignature const& s2);
|
||||
static unsigned hash (DependencySignature const& s1) { return s1.arg(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; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "prims/jvmtiImpl.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/sweeper.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
#include "utilities/dtrace.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/xmlstream.hpp"
|
||||
@ -2135,7 +2136,11 @@ void nmethod::check_all_dependencies(DepChange& changes) {
|
||||
// Turn off dependency tracing while actually testing dependencies.
|
||||
NOT_PRODUCT( FlagSetting fs(TraceDependencies, false) );
|
||||
|
||||
GenericHashtable<DependencySignature, ResourceObj>* table = new GenericHashtable<DependencySignature, ResourceObj>(11027);
|
||||
typedef ResourceHashtable<DependencySignature, int, &DependencySignature::hash,
|
||||
&DependencySignature::equals, 11027> DepTable;
|
||||
|
||||
DepTable* table = new DepTable();
|
||||
|
||||
// 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))) {
|
||||
@ -2143,9 +2148,10 @@ void nmethod::check_all_dependencies(DepChange& changes) {
|
||||
for (Dependencies::DepStream deps(nm); deps.next(); ) {
|
||||
// Construct abstraction of a dependency.
|
||||
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)) {
|
||||
|
||||
// Determine if dependency is already checked. table->put(...) returns
|
||||
// 'true' if the dependency is added (i.e., was not in the hashtable).
|
||||
if (table->put(*current_sig, 1)) {
|
||||
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
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/altHashing.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "code/dependencies.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/filemap.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
@ -353,116 +352,6 @@ template <MEMFLAGS F> void BasicHashtable<F>::verify_lookup_length(double load)
|
||||
#endif
|
||||
|
||||
|
||||
template<class T, class M> GenericHashtable<T, M>::GenericHashtable(int size, bool C_heap, MEMFLAGS memflag) {
|
||||
assert(size > 0, " Invalid hashtable size");
|
||||
_size = size;
|
||||
_C_heap = C_heap;
|
||||
_memflag = memflag;
|
||||
// Perform subtype-specific resource allocation
|
||||
_items = (C_heap) ? NEW_C_HEAP_ARRAY(T*, size, memflag) : NEW_RESOURCE_ARRAY(T*, size);
|
||||
memset(_items, 0, sizeof(T*) * size);
|
||||
|
||||
DEBUG_ONLY(_num_items = 0;)
|
||||
}
|
||||
|
||||
template<class T, class M> GenericHashtable<T, M>::~GenericHashtable() {
|
||||
if (on_C_heap()) {
|
||||
// Check backing array
|
||||
for (int i = 0; i < size(); i++) {
|
||||
T* item = head(i);
|
||||
// Delete all items in linked list
|
||||
while (item != NULL) {
|
||||
T* next_item = item->next();
|
||||
delete item;
|
||||
DEBUG_ONLY(_num_items--);
|
||||
item = next_item;
|
||||
}
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(T*, _items, _memflag);
|
||||
_items = NULL;
|
||||
assert (_num_items == 0, "Not all memory released");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pointer to the item 'I' that is stored in the hashtable for
|
||||
* which match_item->equals(I) == true. If no such item is found, NULL
|
||||
* is returned.
|
||||
*/
|
||||
template<class T, class F> T* GenericHashtable<T, F>::contains(T* match_item) {
|
||||
if (match_item != NULL) {
|
||||
int idx = index(match_item);
|
||||
return contains_impl(match_item, idx);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item to the hashtable. Return 'true' if the item was added
|
||||
* and false otherwise.
|
||||
*/
|
||||
template<class T, class F> bool GenericHashtable<T, F>::add(T* item) {
|
||||
if (item != NULL) {
|
||||
int idx = index(item);
|
||||
T* found_item = contains_impl(item, idx);
|
||||
if (found_item == NULL) {
|
||||
T* list_head = head(idx);
|
||||
item->set_next(list_head);
|
||||
item->set_prev(NULL);
|
||||
|
||||
if (list_head != NULL) {
|
||||
list_head->set_prev(item);
|
||||
}
|
||||
set_head(item, idx);
|
||||
DEBUG_ONLY(_num_items++);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item 'I' from the hashtable, if present. 'I' is removed, if
|
||||
* match_item->equals(I) == true. Removing an item from the hashtable does
|
||||
* not free memory.
|
||||
*/
|
||||
template<class T, class F> T* GenericHashtable<T, F>::remove(T* match_item) {
|
||||
if (match_item != NULL) {
|
||||
int idx = index(match_item);
|
||||
T* found_item = contains_impl(match_item, idx);
|
||||
if (found_item != NULL) {
|
||||
// Remove item from linked list
|
||||
T* prev = found_item->prev();
|
||||
T* next = found_item->next();
|
||||
if (prev != NULL) {
|
||||
prev->set_next(next);
|
||||
} else {
|
||||
set_head(next, idx);
|
||||
}
|
||||
if (next != NULL) {
|
||||
next->set_prev(prev);
|
||||
}
|
||||
|
||||
DEBUG_ONLY(_num_items--);
|
||||
return found_item;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class F> T* GenericHashtable<T, F>::contains_impl(T* item, int idx) {
|
||||
T* current_item = head(idx);
|
||||
while (current_item != NULL) {
|
||||
if (current_item->equals(item)) {
|
||||
return current_item;
|
||||
}
|
||||
current_item = current_item->next();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Explicitly instantiate these types
|
||||
template class Hashtable<ConstantPool*, mtClass>;
|
||||
template class Hashtable<Symbol*, mtSymbol>;
|
||||
@ -482,5 +371,3 @@ template class BasicHashtable<mtClass>;
|
||||
template class BasicHashtable<mtSymbol>;
|
||||
template class BasicHashtable<mtCode>;
|
||||
template class BasicHashtable<mtInternal>;
|
||||
|
||||
template class GenericHashtable<DependencySignature, ResourceObj>;
|
||||
|
@ -327,86 +327,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Usage of GenericHashtable:
|
||||
*
|
||||
* class X : public GenericHashtableEntry<X, ResourceObj> {
|
||||
*
|
||||
* // Implement virtual functions in class X
|
||||
* bool equals(X* sig) const;
|
||||
* uintptr_t hash() const;
|
||||
* };
|
||||
*
|
||||
* void foo() {
|
||||
* GenericHashtable<X, ResourceObj>* table = new GenericHashtable<X, ResourceObj>(11027, false);
|
||||
*
|
||||
* X* elem = new X();
|
||||
* table->add(elem);
|
||||
* table->contains(elem);
|
||||
* }
|
||||
*
|
||||
* You can choose other allocation types as well. For example, to store the hashtable to a
|
||||
* particular region (CHeapObj<type>) simply replace ResourceObj with the desired type:
|
||||
*
|
||||
* class X : public GenericHashtableEntry<X, CHeapObj<mtCode> > { ... };
|
||||
*
|
||||
* To make the destructor (and remove) of the hashtable work:
|
||||
* 1) override the delete operator of X
|
||||
* 2) provide a destructor of the X
|
||||
*
|
||||
* You may also find it convenient to override the new operator.
|
||||
*
|
||||
* If you use this templates do not forget to add an explicit initialization
|
||||
* (at the end of hashtable.cpp).
|
||||
*
|
||||
* template class GenericHashtable<X, ResourceObj>;
|
||||
*/
|
||||
template <class T, class M> class GenericHashtableEntry : public M {
|
||||
private:
|
||||
T* _next;
|
||||
T* _prev;
|
||||
public:
|
||||
// Must be implemented by subclass.
|
||||
virtual uintptr_t key() const = 0;
|
||||
virtual bool equals(T* other) const = 0;
|
||||
|
||||
T* next() const { return _next; }
|
||||
T* prev() const { return _prev; }
|
||||
void set_next(T* item) { _next = item; }
|
||||
void set_prev(T* item) { _prev = item; }
|
||||
|
||||
// Constructor and destructor
|
||||
GenericHashtableEntry() : _next(NULL), _prev(NULL) { };
|
||||
virtual ~GenericHashtableEntry() {};
|
||||
};
|
||||
|
||||
template <class T, class M> class GenericHashtable : public M {
|
||||
private:
|
||||
T** _items;
|
||||
int _size;
|
||||
bool _C_heap;
|
||||
MEMFLAGS _memflag;
|
||||
|
||||
// Accessor methods
|
||||
T* head (int idx) const { return _items[idx]; }
|
||||
void set_head(T* item, int idx) { _items[idx] = item; }
|
||||
int index (T* item) { assert(item != NULL, "missing null check"); return item->key() % size(); }
|
||||
|
||||
// Helper function
|
||||
T* contains_impl(T* item, int idx);
|
||||
|
||||
DEBUG_ONLY(int _num_items;)
|
||||
public:
|
||||
GenericHashtable(int size, bool C_heap = false, MEMFLAGS memflag = mtNone);
|
||||
~GenericHashtable();
|
||||
T* contains(T* match_item);
|
||||
T* remove (T* match_item);
|
||||
bool add (T* item);
|
||||
|
||||
|
||||
bool on_C_heap() const { return _C_heap; }
|
||||
int size() const { return _size; }
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_UTILITIES_HASHTABLE_HPP
|
||||
|
@ -105,14 +105,20 @@ class ResourceHashtable : public ResourceObj {
|
||||
}
|
||||
}
|
||||
|
||||
// Inserts or replaces a value in the table
|
||||
void put(K const& key, V const& value) {
|
||||
/**
|
||||
* Inserts or replaces a value in the table.
|
||||
* @return: true: if a new item is added
|
||||
* false: if the item already existed and the value is updated
|
||||
*/
|
||||
bool put(K const& key, V const& value) {
|
||||
unsigned hv = HASH(key);
|
||||
Node** ptr = lookup_node(hv, key);
|
||||
if (*ptr != NULL) {
|
||||
(*ptr)->_value = value;
|
||||
return false;
|
||||
} else {
|
||||
*ptr = new Node(hv, key, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user