8269004: Implement ResizableResourceHashtable
Reviewed-by: coleenp, kbarrett
This commit is contained in:
parent
390d1025ca
commit
4da52eaf53
src/hotspot/share
@ -54,7 +54,7 @@
|
||||
volatile Thread* ClassListParser::_parsing_thread = NULL;
|
||||
ClassListParser* ClassListParser::_instance = NULL;
|
||||
|
||||
ClassListParser::ClassListParser(const char* file) : _id2klass_table(INITIAL_TABLE_SIZE) {
|
||||
ClassListParser::ClassListParser(const char* file) : _id2klass_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE) {
|
||||
_classlist_file = file;
|
||||
_file = NULL;
|
||||
// Use os::open() because neither fopen() nor os::fopen()
|
||||
@ -507,7 +507,7 @@ void ClassListParser::populate_cds_indy_info(const constantPoolHandle &pool, int
|
||||
}
|
||||
}
|
||||
|
||||
bool ClassListParser::is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS) {
|
||||
bool ClassListParser::is_matching_cp_entry(const constantPoolHandle &pool, int cp_index, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
CDSIndyInfo cii;
|
||||
populate_cds_indy_info(pool, cp_index, &cii, CHECK_0);
|
||||
@ -643,11 +643,14 @@ Klass* ClassListParser::load_current_class(Symbol* class_name_symbol, TRAPS) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(klass);
|
||||
int id = this->id();
|
||||
SystemDictionaryShared::update_shared_entry(ik, id);
|
||||
InstanceKlass** old_ptr = table()->lookup(id);
|
||||
if (old_ptr != NULL) {
|
||||
bool created;
|
||||
id2klass_table()->put_if_absent(id, ik, &created);
|
||||
if (!created) {
|
||||
error("Duplicated ID %d for class %s", id, _class_name);
|
||||
}
|
||||
table()->add(id, ik);
|
||||
if (id2klass_table()->maybe_grow()) {
|
||||
log_info(cds, hashtables)("Expanded id2klass_table() to %d", id2klass_table()->table_size());
|
||||
}
|
||||
}
|
||||
|
||||
return klass;
|
||||
@ -658,7 +661,7 @@ bool ClassListParser::is_loading_from_source() {
|
||||
}
|
||||
|
||||
InstanceKlass* ClassListParser::lookup_class_by_id(int id) {
|
||||
InstanceKlass** klass_ptr = table()->lookup(id);
|
||||
InstanceKlass** klass_ptr = id2klass_table()->get(id);
|
||||
if (klass_ptr == NULL) {
|
||||
error("Class ID %d has not been defined", id);
|
||||
}
|
||||
|
@ -28,11 +28,12 @@
|
||||
#include "utilities/exceptions.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
#include "utilities/resizeableResourceHash.hpp"
|
||||
|
||||
#define LAMBDA_PROXY_TAG "@lambda-proxy"
|
||||
#define LAMBDA_FORM_TAG "@lambda-form-invoker"
|
||||
|
||||
class constantPoolHandle;
|
||||
class Thread;
|
||||
|
||||
class CDSIndyInfo {
|
||||
@ -66,7 +67,9 @@ public:
|
||||
};
|
||||
|
||||
class ClassListParser : public StackObj {
|
||||
typedef KVHashtable<int, InstanceKlass*, mtInternal> ID2KlassTable;
|
||||
// Must be C_HEAP allocated -- we don't want nested resource allocations.
|
||||
typedef ResizeableResourceHashtable<int, InstanceKlass*,
|
||||
ResourceObj::C_HEAP, mtClassShared> ID2KlassTable;
|
||||
|
||||
enum {
|
||||
_unspecified = -999,
|
||||
@ -80,7 +83,9 @@ class ClassListParser : public StackObj {
|
||||
_line_buf_size = _max_allowed_line_len + _line_buf_extra
|
||||
};
|
||||
|
||||
static const int INITIAL_TABLE_SIZE = 1987;
|
||||
// Use a small initial size in debug build to test resizing logic
|
||||
static const int INITIAL_TABLE_SIZE = DEBUG_ONLY(17) NOT_DEBUG(1987);
|
||||
static const int MAX_TABLE_SIZE = 61333;
|
||||
static volatile Thread* _parsing_thread; // the thread that created _instance
|
||||
static ClassListParser* _instance; // the singleton.
|
||||
const char* _classlist_file;
|
||||
@ -106,13 +111,13 @@ class ClassListParser : public StackObj {
|
||||
bool parse_int_option(const char* option_name, int* value);
|
||||
bool parse_uint_option(const char* option_name, int* value);
|
||||
InstanceKlass* load_class_from_source(Symbol* class_name, TRAPS);
|
||||
ID2KlassTable* table() {
|
||||
ID2KlassTable* id2klass_table() {
|
||||
return &_id2klass_table;
|
||||
}
|
||||
InstanceKlass* lookup_class_by_id(int id);
|
||||
void print_specified_interfaces();
|
||||
void print_actual_interfaces(InstanceKlass *ik);
|
||||
bool is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS);
|
||||
bool is_matching_cp_entry(const constantPoolHandle &pool, int cp_index, TRAPS);
|
||||
|
||||
void resolve_indy(JavaThread* current, Symbol* class_name_symbol);
|
||||
void resolve_indy_impl(Symbol* class_name_symbol, TRAPS);
|
||||
@ -161,7 +166,7 @@ public:
|
||||
return _super;
|
||||
}
|
||||
void check_already_loaded(const char* which, int id) {
|
||||
if (_id2klass_table.lookup(id) == NULL) {
|
||||
if (!id2klass_table()->contains(id)) {
|
||||
error("%s id %d is not yet loaded", which, id);
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,7 @@
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "runtime/vmOperations.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2021, 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
|
||||
@ -95,11 +95,11 @@ MetaspaceClosure::~MetaspaceClosure() {
|
||||
|
||||
bool UniqueMetaspaceClosure::do_ref(MetaspaceClosure::Ref* ref, bool read_only) {
|
||||
bool created;
|
||||
_has_been_visited.add_if_absent(ref->obj(), read_only, &created);
|
||||
_has_been_visited.put_if_absent(ref->obj(), read_only, &created);
|
||||
if (!created) {
|
||||
return false; // Already visited: no need to iterate embedded pointers.
|
||||
} else {
|
||||
if (_has_been_visited.maybe_grow(MAX_TABLE_SIZE)) {
|
||||
if (_has_been_visited.maybe_grow()) {
|
||||
log_info(cds, hashtables)("Expanded _has_been_visited table to %d", _has_been_visited.table_size());
|
||||
}
|
||||
return do_unique_ref(ref, read_only);
|
||||
|
@ -31,8 +31,8 @@
|
||||
#include "oops/array.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/resizeableResourceHash.hpp"
|
||||
#include <type_traits>
|
||||
|
||||
// The metadata hierarchy is separate from the oop hierarchy
|
||||
@ -393,10 +393,11 @@ class UniqueMetaspaceClosure : public MetaspaceClosure {
|
||||
public:
|
||||
// Gets called the first time we discover an object.
|
||||
virtual bool do_unique_ref(Ref* ref, bool read_only) = 0;
|
||||
UniqueMetaspaceClosure() : _has_been_visited(INITIAL_TABLE_SIZE) {}
|
||||
UniqueMetaspaceClosure() : _has_been_visited(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE) {}
|
||||
|
||||
private:
|
||||
KVHashtable<address, bool, mtInternal> _has_been_visited;
|
||||
ResizeableResourceHashtable<address, bool, ResourceObj::C_HEAP,
|
||||
mtClassShared> _has_been_visited;
|
||||
};
|
||||
|
||||
#endif // SHARE_MEMORY_METASPACECLOSURE_HPP
|
||||
|
136
src/hotspot/share/utilities/resizeableResourceHash.hpp
Normal file
136
src/hotspot/share/utilities/resizeableResourceHash.hpp
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_UTILITIES_RESIZEABLERESOURCEHASH_HPP
|
||||
#define SHARE_UTILITIES_RESIZEABLERESOURCEHASH_HPP
|
||||
|
||||
#include "utilities/resourceHash.hpp"
|
||||
|
||||
template<
|
||||
typename K, typename V,
|
||||
ResourceObj::allocation_type ALLOC_TYPE,
|
||||
MEMFLAGS MEM_TYPE>
|
||||
class ResizeableResourceHashtableStorage : public ResourceObj {
|
||||
using Node = ResourceHashtableNode<K, V>;
|
||||
|
||||
protected:
|
||||
unsigned _table_size;
|
||||
Node** _table;
|
||||
|
||||
ResizeableResourceHashtableStorage(unsigned table_size) {
|
||||
_table_size = table_size;
|
||||
_table = alloc_table(table_size);
|
||||
}
|
||||
|
||||
~ResizeableResourceHashtableStorage() {
|
||||
if (ALLOC_TYPE == C_HEAP) {
|
||||
FREE_C_HEAP_ARRAY(Node*, _table);
|
||||
}
|
||||
}
|
||||
|
||||
Node** alloc_table(unsigned table_size) {
|
||||
Node** table;
|
||||
if (ALLOC_TYPE == C_HEAP) {
|
||||
table = NEW_C_HEAP_ARRAY(Node*, table_size, MEM_TYPE);
|
||||
} else {
|
||||
table = NEW_RESOURCE_ARRAY(Node*, table_size);
|
||||
}
|
||||
memset(table, 0, table_size * sizeof(Node*));
|
||||
return table;
|
||||
}
|
||||
|
||||
unsigned table_size() const {
|
||||
return _table_size;
|
||||
}
|
||||
|
||||
Node** table() const {
|
||||
return _table;
|
||||
}
|
||||
};
|
||||
|
||||
template<
|
||||
typename K, typename V,
|
||||
ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA,
|
||||
MEMFLAGS MEM_TYPE = mtInternal,
|
||||
unsigned (*HASH) (K const&) = primitive_hash<K>,
|
||||
bool (*EQUALS)(K const&, K const&) = primitive_equals<K>
|
||||
>
|
||||
class ResizeableResourceHashtable : public ResourceHashtableBase<
|
||||
ResizeableResourceHashtableStorage<K, V, ALLOC_TYPE, MEM_TYPE>,
|
||||
K, V, HASH, EQUALS, ALLOC_TYPE, MEM_TYPE> {
|
||||
unsigned _max_size;
|
||||
|
||||
using BASE = ResourceHashtableBase<ResizeableResourceHashtableStorage<K, V, ALLOC_TYPE, MEM_TYPE>,
|
||||
K, V, HASH, EQUALS, ALLOC_TYPE, MEM_TYPE>;
|
||||
using Node = ResourceHashtableNode<K, V>;
|
||||
NONCOPYABLE(ResizeableResourceHashtable);
|
||||
public:
|
||||
ResizeableResourceHashtable(unsigned size, unsigned max_size = 0)
|
||||
: BASE(size), _max_size(max_size) {
|
||||
assert(size <= 0x3fffffff && max_size <= 0x3fffffff, "avoid overflow in resize");
|
||||
}
|
||||
|
||||
bool maybe_grow(int load_factor = 8) {
|
||||
unsigned old_size = BASE::_table_size;
|
||||
if (old_size >= _max_size) {
|
||||
return false;
|
||||
}
|
||||
if (BASE::number_of_entries() / int(old_size) > load_factor) {
|
||||
unsigned new_size = MIN2<unsigned>(old_size * 2, _max_size);
|
||||
resize(old_size, new_size);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void resize(unsigned old_size, unsigned new_size) {
|
||||
Node** old_table = BASE::_table;
|
||||
Node** new_table = BASE::alloc_table(new_size);
|
||||
|
||||
Node* const* bucket = old_table;
|
||||
while (bucket < &old_table[old_size]) {
|
||||
Node* node = *bucket;
|
||||
while (node != NULL) {
|
||||
Node* next = node->_next;
|
||||
unsigned hash = HASH(node->_key);
|
||||
unsigned index = hash % new_size;
|
||||
|
||||
node->_next = new_table[index];
|
||||
new_table[index] = node;
|
||||
|
||||
node = next;
|
||||
}
|
||||
++bucket;
|
||||
}
|
||||
|
||||
if (ALLOC_TYPE == ResourceObj::C_HEAP) {
|
||||
FREE_C_HEAP_ARRAY(Node*, old_table);
|
||||
}
|
||||
BASE::_table = new_table;
|
||||
BASE::_table_size = new_size;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_UTILITIES_RESIZEABLERESOURCEHASH_HPP
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2021, 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
|
||||
@ -27,44 +27,45 @@
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
template<typename K, typename V>
|
||||
class ResourceHashtableNode : public ResourceObj {
|
||||
public:
|
||||
unsigned _hash;
|
||||
K _key;
|
||||
V _value;
|
||||
ResourceHashtableNode* _next;
|
||||
|
||||
ResourceHashtableNode(unsigned hash, K const& key, V const& value) :
|
||||
_hash(hash), _key(key), _value(value), _next(NULL) {}
|
||||
|
||||
// Create a node with a default-constructed value.
|
||||
ResourceHashtableNode(unsigned hash, K const& key) :
|
||||
_hash(hash), _key(key), _value(), _next(NULL) {}
|
||||
};
|
||||
|
||||
template<
|
||||
class STORAGE,
|
||||
typename K, typename V,
|
||||
// xlC does not compile this:
|
||||
// http://stackoverflow.com/questions/8532961/template-argument-of-type-that-is-defined-by-inner-typedef-from-other-template-c
|
||||
//typename ResourceHashtableFns<K>::hash_fn HASH = primitive_hash<K>,
|
||||
//typename ResourceHashtableFns<K>::equals_fn EQUALS = primitive_equals<K>,
|
||||
unsigned (*HASH) (K const&) = primitive_hash<K>,
|
||||
bool (*EQUALS)(K const&, K const&) = primitive_equals<K>,
|
||||
unsigned SIZE = 256,
|
||||
ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA,
|
||||
MEMFLAGS MEM_TYPE = mtInternal
|
||||
unsigned (*HASH) (K const&),
|
||||
bool (*EQUALS)(K const&, K const&),
|
||||
ResourceObj::allocation_type ALLOC_TYPE,
|
||||
MEMFLAGS MEM_TYPE
|
||||
>
|
||||
class ResourceHashtable : public ResourceObj {
|
||||
class ResourceHashtableBase : public STORAGE {
|
||||
using Node = ResourceHashtableNode<K, V>;
|
||||
private:
|
||||
int _number_of_entries;
|
||||
|
||||
class Node : public ResourceObj {
|
||||
public:
|
||||
unsigned _hash;
|
||||
K _key;
|
||||
V _value;
|
||||
Node* _next;
|
||||
|
||||
Node(unsigned hash, K const& key, V const& value) :
|
||||
_hash(hash), _key(key), _value(value), _next(NULL) {}
|
||||
|
||||
// Create a node with a default-constructed value.
|
||||
Node(unsigned hash, K const& key) :
|
||||
_hash(hash), _key(key), _value(), _next(NULL) {}
|
||||
|
||||
};
|
||||
|
||||
Node* _table[SIZE];
|
||||
Node** bucket_at(unsigned index) const {
|
||||
Node** t = table();
|
||||
return &t[index];
|
||||
}
|
||||
|
||||
// Returns a pointer to where the node where the value would reside if
|
||||
// it's in the table.
|
||||
Node** lookup_node(unsigned hash, K const& key) {
|
||||
unsigned index = hash % SIZE;
|
||||
Node** ptr = &_table[index];
|
||||
unsigned index = hash % table_size();
|
||||
Node** ptr = bucket_at(index);
|
||||
while (*ptr != NULL) {
|
||||
Node* node = *ptr;
|
||||
if (node->_hash == hash && EQUALS(key, node->_key)) {
|
||||
@ -77,16 +78,21 @@ class ResourceHashtable : public ResourceObj {
|
||||
|
||||
Node const** lookup_node(unsigned hash, K const& key) const {
|
||||
return const_cast<Node const**>(
|
||||
const_cast<ResourceHashtable*>(this)->lookup_node(hash, key));
|
||||
const_cast<ResourceHashtableBase*>(this)->lookup_node(hash, key));
|
||||
}
|
||||
|
||||
public:
|
||||
ResourceHashtable() { memset(_table, 0, SIZE * sizeof(Node*)); }
|
||||
protected:
|
||||
Node** table() const { return STORAGE::table(); }
|
||||
|
||||
~ResourceHashtable() {
|
||||
if (ALLOC_TYPE == C_HEAP) {
|
||||
Node* const* bucket = _table;
|
||||
while (bucket < &_table[SIZE]) {
|
||||
ResourceHashtableBase() : STORAGE(), _number_of_entries(0) {}
|
||||
ResourceHashtableBase(unsigned size) : STORAGE(size), _number_of_entries(0) {}
|
||||
NONCOPYABLE(ResourceHashtableBase);
|
||||
|
||||
~ResourceHashtableBase() {
|
||||
if (ALLOC_TYPE == ResourceObj::C_HEAP) {
|
||||
Node* const* bucket = table();
|
||||
const unsigned sz = table_size();
|
||||
while (bucket < bucket_at(sz)) {
|
||||
Node* node = *bucket;
|
||||
while (node != NULL) {
|
||||
Node* cur = node;
|
||||
@ -98,6 +104,10 @@ class ResourceHashtable : public ResourceObj {
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned table_size() const { return STORAGE::table_size(); }
|
||||
int number_of_entries() const { return _number_of_entries; }
|
||||
|
||||
bool contains(K const& key) const {
|
||||
return get(key) != NULL;
|
||||
}
|
||||
@ -125,6 +135,7 @@ class ResourceHashtable : public ResourceObj {
|
||||
return false;
|
||||
} else {
|
||||
*ptr = new (ALLOC_TYPE, MEM_TYPE) Node(hv, key, value);
|
||||
_number_of_entries ++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -140,6 +151,7 @@ class ResourceHashtable : public ResourceObj {
|
||||
if (*ptr == NULL) {
|
||||
*ptr = new (ALLOC_TYPE, MEM_TYPE) Node(hv, key);
|
||||
*p_created = true;
|
||||
_number_of_entries ++;
|
||||
} else {
|
||||
*p_created = false;
|
||||
}
|
||||
@ -157,6 +169,7 @@ class ResourceHashtable : public ResourceObj {
|
||||
if (*ptr == NULL) {
|
||||
*ptr = new (ALLOC_TYPE, MEM_TYPE) Node(hv, key, value);
|
||||
*p_created = true;
|
||||
_number_of_entries ++;
|
||||
} else {
|
||||
*p_created = false;
|
||||
}
|
||||
@ -171,9 +184,10 @@ class ResourceHashtable : public ResourceObj {
|
||||
Node* node = *ptr;
|
||||
if (node != NULL) {
|
||||
*ptr = node->_next;
|
||||
if (ALLOC_TYPE == C_HEAP) {
|
||||
if (ALLOC_TYPE == ResourceObj::C_HEAP) {
|
||||
delete node;
|
||||
}
|
||||
_number_of_entries --;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -184,8 +198,9 @@ class ResourceHashtable : public ResourceObj {
|
||||
// the iteration is cancelled.
|
||||
template<class ITER>
|
||||
void iterate(ITER* iter) const {
|
||||
Node* const* bucket = _table;
|
||||
while (bucket < &_table[SIZE]) {
|
||||
Node* const* bucket = table();
|
||||
const unsigned sz = table_size();
|
||||
while (bucket < bucket_at(sz)) {
|
||||
Node* node = *bucket;
|
||||
while (node != NULL) {
|
||||
bool cont = iter->do_entry(node->_key, node->_value);
|
||||
@ -197,5 +212,39 @@ class ResourceHashtable : public ResourceObj {
|
||||
}
|
||||
};
|
||||
|
||||
template<unsigned TABLE_SIZE, typename K, typename V>
|
||||
class FixedResourceHashtableStorage : public ResourceObj {
|
||||
using Node = ResourceHashtableNode<K, V>;
|
||||
|
||||
Node* _table[TABLE_SIZE];
|
||||
protected:
|
||||
FixedResourceHashtableStorage() : _table() {}
|
||||
~FixedResourceHashtableStorage() = default;
|
||||
|
||||
constexpr unsigned table_size() const {
|
||||
return TABLE_SIZE;
|
||||
}
|
||||
|
||||
Node** table() const {
|
||||
return const_cast<Node**>(_table);
|
||||
}
|
||||
};
|
||||
|
||||
template<
|
||||
typename K, typename V,
|
||||
unsigned (*HASH) (K const&) = primitive_hash<K>,
|
||||
bool (*EQUALS)(K const&, K const&) = primitive_equals<K>,
|
||||
unsigned SIZE = 256,
|
||||
ResourceObj::allocation_type ALLOC_TYPE = ResourceObj::RESOURCE_AREA,
|
||||
MEMFLAGS MEM_TYPE = mtInternal
|
||||
>
|
||||
class ResourceHashtable : public ResourceHashtableBase<
|
||||
FixedResourceHashtableStorage<SIZE, K, V>,
|
||||
K, V, HASH, EQUALS, ALLOC_TYPE, MEM_TYPE> {
|
||||
NONCOPYABLE(ResourceHashtable);
|
||||
public:
|
||||
ResourceHashtable() : ResourceHashtableBase<FixedResourceHashtableStorage<SIZE, K, V>,
|
||||
K, V, HASH, EQUALS, ALLOC_TYPE, MEM_TYPE>() {}
|
||||
};
|
||||
|
||||
#endif // SHARE_UTILITIES_RESOURCEHASH_HPP
|
||||
|
Loading…
x
Reference in New Issue
Block a user