#include "Subzone.h"
#include "Large.h"
#include "Zone.h"
#include "Admin.h"
namespace Auto {
class SubzoneBlockRef {
Subzone * const _subzone;
const usword_t _q;
public:
SubzoneBlockRef(Subzone *subzone, usword_t q) : _subzone(subzone), _q(q) {}
SubzoneBlockRef(void *ptr) : _subzone(Subzone::subzone(ptr)), _q(_subzone->quantum_index_unchecked(ptr)) {}
inline Subzone * subzone() const { return _subzone; }
inline usword_t q() const { return _q; }
inline Zone * zone() const { return subzone()->admin()->zone(); }
inline usword_t size() const { return subzone()->size(q()); }
inline void * address() const { return subzone()->quantum_address(q()); }
inline bool has_refcount() const { return subzone()->has_refcount(q()); }
inline bool is_garbage() const { return subzone()->is_garbage(q()); }
inline bool is_scanned() const { return ::is_scanned(layout()); }
inline bool is_object() const { return ::is_object(layout()); }
inline auto_memory_type_t layout() const { return subzone()->layout(q()); }
inline bool is_thread_local() const { return subzone()->is_thread_local(q()); }
inline bool is_live_thread_local() const { return subzone()->is_live_thread_local(q()); }
inline bool is_local_garbage() const { return subzone()->is_local_garbage(q()); }
inline bool should_scan_local_block() const { return subzone()->should_scan_local_block(q()); }
inline void set_scan_local_block() const { subzone()->set_scan_local_block(q()); }
inline void mark_card(const void *addr) const { if (is_scanned()) subzone()->write_barrier().mark_card((void *)addr); }
inline bool is_new() const { return subzone()->is_new(q()); }
inline bool is_marked() const { return subzone()->is_marked(q()); }
inline void get_description(char *buf, usword_t bufsz) const { snprintf(buf, bufsz, "Subzone=%p, q=%ld", subzone(), (long)q()); }
inline void make_global() const { subzone()->make_global(q()); }
inline void set_layout(auto_memory_type_t layout) const { subzone()->set_layout(q(), layout); }
inline void enliven() const {
if (!subzone()->test_and_set_mark(q()) && subzone()->is_scanned(q()))
subzone()->test_and_set_pending(q(), true);
}
usword_t refcount() const;
usword_t inc_refcount() const;
usword_t dec_refcount_no_lock() const;
usword_t dec_refcount() const;
};
class LargeBlockRef {
Large * const _large;
public:
LargeBlockRef(Large *large) : _large(large) {}
inline Large * large() const { return _large; }
inline Zone * zone() const { return _large->zone(); }
inline usword_t size() const { return large()->size(); }
inline bool has_refcount() const { return refcount() != 0; }
inline void * address() const { return _large->address(); }
inline bool is_garbage() const { return _large->is_garbage(); }
inline bool is_scanned() const { return _large->is_scanned(); }
inline bool is_object() const { return _large->is_object(); }
inline auto_memory_type_t layout() const { return _large->layout(); }
inline bool is_thread_local() const { return false; }
inline bool is_live_thread_local() const { return false; }
inline bool is_local_garbage() const { return false; }
inline bool should_scan_local_block() const { return false; }
inline void set_scan_local_block() const { }
inline void mark_card(const void *addr) const { if (is_scanned()) _large->write_barrier().mark_card((void *)addr); }
inline bool is_new() const { return _large->is_new(); }
inline bool is_marked() const { return _large->is_marked(); }
inline void get_description(char *buf, usword_t bufsz) const { snprintf(buf, bufsz, "Large=%p", _large); }
inline void make_global() const { }
inline void set_layout(auto_memory_type_t layout) const { _large->set_layout(layout); }
inline void enliven() const {
if (!_large->test_and_set_mark() && _large->is_scanned())
_large->set_pending();
}
inline usword_t refcount() const { return _large->refcount(); }
usword_t inc_refcount() const;
usword_t dec_refcount_no_lock() const;
usword_t dec_refcount() const;
};
class sieve_base {
public:
template <class Sieve> static inline void sieve_base_pointer(Zone *zone, const void *ptr, Sieve &sieve) TEMPLATE_INLINE {
if (auto_expect_true(zone->address_in_arena(ptr))) {
if (auto_expect_true(zone->in_subzone_bitmap((void *)ptr))) {
Subzone *sz = Subzone::subzone((void *)ptr);
usword_t q;
if (auto_expect_true(sz->block_is_start((void *)ptr, &q))) {
SubzoneBlockRef block(sz, q);
sieve.processBlock(block);
} else {
sieve.nonBlock(ptr);
}
} else if (auto_expect_true(zone->block_is_start_large((void *)ptr))) {
LargeBlockRef block(Large::large((void *)ptr));
sieve.processBlock(block);
} else {
sieve.nonBlock(ptr);
}
} else {
sieve.nonBlock(ptr);
}
}
template <class Sieve> static inline void sieve_interior_pointer(Zone *zone, const void *ptr, Sieve &sieve) TEMPLATE_INLINE {
if (auto_expect_true(zone->address_in_arena(ptr))) {
if (auto_expect_true(zone->in_subzone_bitmap((void *)ptr))) {
Subzone *sz = Subzone::subzone((void *)ptr);
usword_t q;
if (auto_expect_true(sz->block_start((void *)ptr, q) != NULL)) {
SubzoneBlockRef block(sz, q);
sieve.processBlock(block);
} else {
sieve.nonBlock(ptr);
}
} else {
Large *large = zone->block_start_large((void *)ptr);
if (auto_expect_true(large != NULL)) {
LargeBlockRef block(large);
sieve.processBlock(block);
} else {
sieve.nonBlock(ptr);
}
}
} else {
sieve.nonBlock(ptr);
}
}
inline void nonBlock(const void *ptr) {
}
};
enum {
AUTO_BLOCK_INFO_IS_BLOCK = 0, AUTO_BLOCK_INFO_LAYOUT = 1,
AUTO_BLOCK_INFO_SIZE = 2,
AUTO_BLOCK_INFO_REFCOUNT = 4,
AUTO_BLOCK_INFO_BASE_POINTER = 8,
};
template <int requested_info> class auto_block_info_sieve : public sieve_base {
private:
auto_memory_type_t _layout;
usword_t _refcount;
size_t _size;
boolean_t _is_block;
void *_base;
public:
auto_block_info_sieve(Zone *zone, const void *ptr) __attribute__((always_inline)) {
if (requested_info & AUTO_BLOCK_INFO_BASE_POINTER) {
sieve_interior_pointer(zone, ptr, *this);
} else {
sieve_base_pointer(zone, ptr, *this);
}
}
template <class BlockRef> void processBlock(BlockRef ref) TEMPLATE_INLINE {
_is_block = true;
if (requested_info & AUTO_BLOCK_INFO_LAYOUT)
_layout = ref.layout();
if (requested_info & AUTO_BLOCK_INFO_SIZE)
_size = ref.size();
if (requested_info & AUTO_BLOCK_INFO_REFCOUNT)
_refcount = ref.refcount();
if (requested_info & AUTO_BLOCK_INFO_BASE_POINTER)
_base = ref.address();
}
void nonBlock(const void *ptr) __attribute__((always_inline)) {
_is_block = false;
if (requested_info & AUTO_BLOCK_INFO_LAYOUT)
_layout = AUTO_TYPE_UNKNOWN;
if (requested_info & AUTO_BLOCK_INFO_SIZE)
_size = 0;
if (requested_info & AUTO_BLOCK_INFO_REFCOUNT)
_refcount = 0;
if (requested_info & AUTO_BLOCK_INFO_BASE_POINTER)
_base = NULL;
}
inline boolean_t is_block() const { return _is_block; }
inline auto_memory_type_t layout() const { if (!(requested_info & AUTO_BLOCK_INFO_LAYOUT)) __builtin_trap(); return _layout; }
inline size_t size() const { if (!(requested_info & AUTO_BLOCK_INFO_SIZE)) __builtin_trap(); return _size; }
inline usword_t refcount() const { if (!(requested_info & AUTO_BLOCK_INFO_REFCOUNT)) __builtin_trap(); return _refcount; }
inline void * base() const { if (!(requested_info & AUTO_BLOCK_INFO_BASE_POINTER)) __builtin_trap(); return _base; }
};
enum {
AUTO_REFCOUNT_INCREMENT,
AUTO_REFCOUNT_DECREMENT
};
template <int refcount_op> class auto_refcount_sieve : public sieve_base {
public:
Zone *zone;
usword_t refcount;
inline auto_refcount_sieve(Zone *z, const void *ptr) __attribute__((always_inline)) : zone(z), refcount(0) {
sieve_base_pointer(zone, ptr, *this);
}
template <class BlockRef> inline void processBlock(BlockRef ref) TEMPLATE_INLINE {
if (refcount_op == AUTO_REFCOUNT_INCREMENT) {
refcount = zone->block_increment_refcount(ref);
} else if (refcount_op == AUTO_REFCOUNT_DECREMENT) {
refcount = zone->block_decrement_refcount(ref);
} else {
__builtin_trap();
}
}
};
}