#include "BlockRef.h"
namespace Auto {
usword_t SubzoneBlockRef::refcount() const {
int refcount = 0;
Admin *admin = subzone()->admin();
SpinLock lock(admin->lock());
if (has_refcount()) {
PtrIntHashMap &retains = admin->retains();
PtrIntHashMap::iterator retain_iter = retains.find(address());
if (retain_iter != retains.end() && retain_iter->first == address()) {
refcount = retain_iter->second;
} else {
refcount = 1;
}
}
return refcount;
}
usword_t SubzoneBlockRef::inc_refcount() const {
int refcount;
Admin *admin = subzone()->admin();
SpinLock lock(admin->lock());
void *block = address();
if (has_refcount()) {
PtrIntHashMap &retains = admin->retains();
PtrIntHashMap::iterator retain_iter = retains.find(block);
if (retain_iter != retains.end() && retain_iter->first == block) {
refcount = ++retain_iter->second;
} else {
refcount = (retains[block] = 2);
}
} else {
Thread &thread = admin->zone()->registered_thread();
thread.block_escaped(*this);
subzone()->set_has_refcount(q());
refcount = 1;
}
return refcount;
}
usword_t SubzoneBlockRef::dec_refcount_no_lock() const {
Admin *admin = subzone()->admin();
if (has_refcount()) {
PtrIntHashMap &retains = admin->retains();
PtrIntHashMap::iterator retain_iter = retains.find(address());
if (retain_iter != retains.end() && retain_iter->first == address()) {
if (--retain_iter->second == 1) {
retains.erase(retain_iter);
return 1;
} else {
return retain_iter->second;
}
} else {
subzone()->clear_has_refcount(q());
return 0;
}
}
malloc_printf("reference count underflow for %p, break on auto_refcount_underflow_error to debug.\n", address());
auto_refcount_underflow_error(address());
return -1;
}
usword_t SubzoneBlockRef::dec_refcount() const {
Admin *admin = subzone()->admin();
SpinLock lock(admin->lock());
return dec_refcount_no_lock();
}
usword_t LargeBlockRef::inc_refcount() const {
SpinLock lock(zone()->large_lock());
usword_t refcount = _large->refcount() + 1;
_large->set_refcount(refcount);
return refcount;
}
usword_t LargeBlockRef::dec_refcount_no_lock() const {
usword_t rc = refcount();
if (rc <= 0) {
malloc_printf("reference count underflow for %p, break on auto_refcount_underflow_error to debug\n", address());
auto_refcount_underflow_error(address());
} else {
rc = rc - 1;
_large->set_refcount(rc);
}
return rc;
}
usword_t LargeBlockRef::dec_refcount() const {
SpinLock lock(zone()->large_lock());
return dec_refcount_no_lock();
}
}