#include "Admin.h"
#include "Bitmap.h"
#include "BlockIterator.h"
#include "Configuration.h"
#include "Definitions.h"
#include "Environment.h"
#include "Large.h"
#include "Locks.h"
#include "Range.h"
#include "Region.h"
#include "Statistics.h"
#include "Subzone.h"
#include "Thread.h"
#include "WriteBarrierIterator.h"
#include "ThreadLocalCollector.h"
#include "Zone.h"
#include "auto_weak.h"
#include "auto_trace.h"
namespace Auto {
struct dump_all_blocks_visitor {
void (^node_dump)(const void *address, unsigned long size, unsigned int layout, unsigned long refcount);
dump_all_blocks_visitor(void) {}
inline bool visit(Zone *zone, Subzone *subzone, usword_t q) {
void *block = subzone->quantum_address(q);
SubzoneBlockRef ref(subzone, q);
node_dump(block, subzone->size(q), subzone->layout(q), ref.refcount());
return true;
}
inline bool visit(Zone *zone, Large *large) {
node_dump(large->address(), large->size(), large->layout(), large->refcount());
return true;
}
};
void Zone::dump_zone(
auto_zone_stack_dump stack_dump,
auto_zone_register_dump register_dump,
auto_zone_node_dump thread_local_node_dump, auto_zone_root_dump root_dump,
auto_zone_node_dump global_node_dump,
auto_zone_weak_dump weak_dump_entry)
{
Mutex lock(&_registered_threads_mutex);
Thread *thread = threads();
while (thread != NULL) {
if (!thread->is_current_thread() && thread->is_bound()) {
thread->suspend();
}
thread = thread->next();
}
dump_all_blocks_visitor visitor;
visitor.node_dump = global_node_dump;
visitAllocatedBlocks(this, visitor);
thread = threads();
while (thread != NULL) {
thread->dump(stack_dump, register_dump, thread_local_node_dump);
thread = thread->next();
}
if (root_dump) {
Mutex lock(&_roots_lock);
PtrHashSet::iterator i = _roots.begin();
while (i != _roots.end()) {
root_dump((const void **)*i);
i++;
}
}
if (weak_dump_entry) {
SpinLock lock(&weak_refs_table_lock);
weak_enumerate_table(this, ^(const weak_referrer_t &ref) { weak_dump_entry((const void **)ref.referrer, *ref.referrer); });
}
thread = threads();
while (thread != NULL) {
if (!thread->is_current_thread() && thread->is_bound()) thread->resume();
thread = thread->next();
}
}
struct allocated_blocks_visitor {
auto_zone_visitor_t *_visitor;
allocated_blocks_visitor(auto_zone_visitor_t *visitor) : _visitor(visitor) {}
inline bool visit(Zone *zone, Subzone *subzone, usword_t q) {
void *block = subzone->quantum_address(q);
SubzoneBlockRef ref(subzone, q);
_visitor->visit_node(block, subzone->size(q), subzone->layout(q), ref.refcount(), subzone->is_thread_local(q));
return true;
}
inline bool visit(Zone *zone, Large *large) {
_visitor->visit_node(large->address(), large->size(), large->layout(), large->refcount(), false);
return true;
}
};
void Zone::visit_zone(auto_zone_visitor_t *visitor) {
suspend_all_registered_threads();
if (visitor->visit_thread) {
scan_registered_threads(^(Thread *thread) { thread->visit(visitor); });
}
if (visitor->visit_node) {
allocated_blocks_visitor ab_visitor(visitor);
visitAllocatedBlocks(this, ab_visitor);
}
if (visitor->visit_root) {
Mutex lock(&_roots_lock);
for (PtrHashSet::iterator i = _roots.begin(), end = _roots.end(); i != end; i++) {
visitor->visit_root((const void **)*i);
}
}
if (visitor->visit_weak) {
SpinLock lock(&weak_refs_table_lock);
weak_enumerate_table(this, ^(const weak_referrer_t &ref) {
visitor->visit_weak(*ref.referrer, ref.referrer, ref.block);
});
}
if (visitor->visit_association) {
ReadLock lock(&_associations_lock);
for (AssociationsHashMap::iterator i = _associations.begin(), iend = _associations.end(); i != iend; i++) {
void *block = i->first;
ObjectAssociationMap *refs = i->second;
for (ObjectAssociationMap::iterator j = refs->begin(), jend = refs->end(); j != jend; j++) {
ObjectAssociationMap::value_type &pair = *j;
visitor->visit_association(block, pair.first, pair.second);
}
}
}
resume_all_registered_threads();
}
};