#include "Configuration.h"
#include "Definitions.h"
#include "Range.h"
#include "WriteBarrier.h"
#include "Zone.h"
namespace Auto {
void WriteBarrier::scan_marked_ranges(void *address, const usword_t size, write_barrier_scanner_t scanner) {
void *end = displace(address, size);
void *last = displace(address, size - 1);
usword_t i = card_index(address);
const usword_t j = card_index(last);
Range sub_range;
while (true) {
for ( ; i <= j && !is_card_marked(i); i++) {}
if (i > j) break;
usword_t k = i;
for ( ; i <= j && is_card_marked(i); i++) {}
void *range_begin = card_address(k);
void *range_end = card_address(i);
if (range_begin < address) range_begin = address;
if (range_end > end) range_end = end;
sub_range.set_range(range_begin, range_end);
scanner(sub_range, this);
}
}
#ifndef __BLOCKS__
class write_barrier_scanner_helper : public WriteBarrier::write_barrier_scanner {
void (*_scanner) (Range&, WriteBarrier*, void*);
void *_arg;
public:
write_barrier_scanner_helper(void (*scanner) (const Range&, WriteBarrier*, void*), void *arg) : _scanner(scanner), _arg(arg) {}
virtual void operator() (const Range &range, WriteBarrier *wb) { _scanner(range, wb, _arg); }
};
#endif
void WriteBarrier::scan_marked_ranges(void *address, const usword_t size, void (*scanner) (const Range&, WriteBarrier*, void*), void *arg) {
#ifdef __BLOCKS__
scan_marked_ranges(address, size, ^(const Range &range, WriteBarrier *wb) { scanner(range, wb, arg); });
#else
write_barrier_scanner_helper helper(scanner, arg);
scan_marked_ranges(address, size, helper);
#endif
}
bool WriteBarrier::range_has_marked_cards(void *address, const usword_t size) {
void *last = displace(address, size - 1);
usword_t i = card_index(address);
const usword_t j = card_index(last);
while (i <= j) if (is_card_marked(i++)) return true;
return false;
}
inline bool compare_and_swap(unsigned char *card, unsigned char old_value, unsigned char new_value) {
#if defined(__arm__)
if (*card == old_value) {
*card = new_value;
return true;
}
return false;
#else
return __sync_bool_compare_and_swap(card, old_value, new_value);
#endif
}
usword_t WriteBarrier::mark_cards_untouched() {
usword_t count = 0;
for (unsigned char *card = (unsigned char*)address() + _protect, *limit = (unsigned char *)end(); card != limit; ++card) {
if (*card != card_unmarked) {
if (compare_and_swap(card, (unsigned char)card_marked, (unsigned char)card_marked_untouched))
++count;
}
}
return count;
}
usword_t WriteBarrier::clear_untouched_cards() {
usword_t count = 0;
for (unsigned char *card = (unsigned char*)address() + _protect, *limit = (unsigned char *)end(); card != limit; ++card) {
if (*card == card_marked_untouched) {
if (compare_and_swap(card, (unsigned char)card_marked_untouched, (unsigned char)card_unmarked))
++count;
}
}
return count;
}
};