#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#define __attribute(x) /* disable inlining */
#include "HeapBitmap.h"
#undef __attribute
#define PAGE_SIZE 4096
#define HEAP_BASE ((void *)0x10000)
#define HEAP_SIZE (5 * PAGE_SIZE + 888)
#define VERBOSE 1
#if VERBOSE
#define TRACE(...) printf(__VA_ARGS__)
#else
#define TRACE(...) /**/
#endif
void
test_init()
{
HeapBitmap hb;
bool ok;
memset(&hb, 0x55, sizeof(hb));
ok = dvmHeapBitmapInit(&hb, HEAP_BASE, HEAP_SIZE, "test");
assert(ok);
assert(hb.bits != NULL);
assert(hb.bitsLen >= HB_OFFSET_TO_INDEX(HEAP_SIZE));
assert(hb.base == (uintptr_t)HEAP_BASE);
assert(hb.max < hb.base);
/* Make sure hb.bits is mapped.
*/
*hb.bits = 0x55;
assert(*hb.bits = 0x55);
*hb.bits = 0;
#define TEST_UNMAP 0
#if TEST_UNMAP
/* Hold onto this to make sure it's unmapped later.
*/
unsigned long int *bits = hb.bits;
#endif
dvmHeapBitmapDelete(&hb);
assert(hb.bits == NULL);
assert(hb.bitsLen == 0);
assert(hb.base == 0);
assert(hb.max == 0);
#if TEST_UNMAP
/* This pointer shouldn't be mapped anymore.
*/
*bits = 0x55;
assert(!"Should have segfaulted");
#endif
}
bool is_zeroed(const HeapBitmap *hb)
{
int i;
for (i = 0; i < hb->bitsLen / sizeof (*hb->bits); i++) {
if (hb->bits[i] != 0L) {
return false;
}
}
return true;
}
void assert_empty(const HeapBitmap *hb)
{
assert(hb->bits != NULL);
assert(hb->bitsLen >= HB_OFFSET_TO_INDEX(HEAP_SIZE));
assert(hb->base == (uintptr_t)HEAP_BASE);
assert(hb->max < hb->base);
assert(is_zeroed(hb));
assert(!dvmHeapBitmapMayContainObject(hb,
HEAP_BASE));
assert(!dvmHeapBitmapMayContainObject(hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(hb,
HEAP_BASE + HEAP_SIZE));
assert(!dvmHeapBitmapIsObjectBitSet(hb,
HEAP_BASE));
assert(!dvmHeapBitmapIsObjectBitSet(hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapIsObjectBitSet(hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
}
void
test_bits()
{
HeapBitmap hb;
bool ok;
ok = dvmHeapBitmapInit(&hb, HEAP_BASE, HEAP_SIZE, "test");
assert(ok);
assert_empty(&hb);
/* Set the lowest address.
*/
dvmHeapBitmapSetObjectBit(&hb, HEAP_BASE);
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE));
assert(dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
/* Set the highest address.
*/
dvmHeapBitmapSetObjectBit(&hb, HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT);
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE));
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE));
assert(dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
/* Clear the lowest address.
*/
dvmHeapBitmapClearObjectBit(&hb, HEAP_BASE);
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
assert(!is_zeroed(&hb));
/* Clear the highest address.
*/
dvmHeapBitmapClearObjectBit(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT);
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
assert(is_zeroed(&hb));
/* Clean up.
*/
dvmHeapBitmapDelete(&hb);
}
void
test_clear()
{
HeapBitmap hb;
bool ok;
ok = dvmHeapBitmapInit(&hb, HEAP_BASE, HEAP_SIZE, "test");
assert(ok);
assert_empty(&hb);
/* Set the highest address.
*/
dvmHeapBitmapSetObjectBit(&hb, HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT);
assert(!is_zeroed(&hb));
/* Clear the bitmap.
*/
dvmHeapBitmapZero(&hb);
assert_empty(&hb);
/* Clean up.
*/
dvmHeapBitmapDelete(&hb);
}
void
test_modify()
{
HeapBitmap hb;
bool ok;
unsigned long bit;
ok = dvmHeapBitmapInit(&hb, HEAP_BASE, HEAP_SIZE, "test");
assert(ok);
assert_empty(&hb);
/* Set the lowest address.
*/
bit = dvmHeapBitmapSetAndReturnObjectBit(&hb, HEAP_BASE);
assert(bit == 0);
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE));
assert(dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
/* Set the lowest address again.
*/
bit = dvmHeapBitmapSetAndReturnObjectBit(&hb, HEAP_BASE);
assert(bit != 0);
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE));
assert(dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
/* Set the highest address.
*/
bit = dvmHeapBitmapSetAndReturnObjectBit(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT);
assert(bit == 0);
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE));
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE));
assert(dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
/* Set the highest address again.
*/
bit = dvmHeapBitmapSetAndReturnObjectBit(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT);
assert(bit != 0);
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE));
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
assert(!dvmHeapBitmapMayContainObject(&hb,
HEAP_BASE + HEAP_SIZE));
assert(dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE));
assert(!dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HB_OBJECT_ALIGNMENT));
assert(dvmHeapBitmapIsObjectBitSet(&hb,
HEAP_BASE + HEAP_SIZE - HB_OBJECT_ALIGNMENT));
/* Clean up.
*/
dvmHeapBitmapDelete(&hb);
}
/*
* xor test support functions
*/
static void *gCallbackArg = NULL;
#define NUM_XOR_PTRS 128
static size_t gNumPtrs;
static void *gXorPtrs[NUM_XOR_PTRS];
static bool gClearedPtrs[NUM_XOR_PTRS];
static bool gSeenPtrs[NUM_XOR_PTRS];
bool
xorCallback(size_t numPtrs, void **ptrs, const void *finger, void *arg)
{
assert(numPtrs > 0);
assert(ptrs != NULL);
assert(arg == gCallbackArg);
size_t i;
for (i = 0; i < numPtrs; i++) {
assert(ptrs[i] < finger);
printf("callback: 0x%08x ( < 0x%08x )\n",
(uintptr_t)ptrs[i], (uintptr_t)finger);
}
return true;
}
bool
seenAndClearedMatch()
{
size_t i;
for (i = 0; i < gNumPtrs; i++) {
if (gClearedPtrs[i] != gSeenPtrs[i]) {
return false;
}
}
return true;
}
void
run_xor(ssize_t offset, size_t step)
{
assert(step != 0);
assert(step < HEAP_SIZE);
/* Figure out the range.
*/
uintptr_t base;
uintptr_t top;
if (offset >= 0) {
base = (uintptr_t)HEAP_BASE + offset;
} else {
base = (uintptr_t)HEAP_BASE + (uintptr_t)HEAP_SIZE + offset;
}
if (base < (uintptr_t)HEAP_BASE) {
base = (uintptr_t)HEAP_BASE;
} else if (base > (uintptr_t)(HEAP_BASE + HEAP_SIZE)) {
base = (uintptr_t)(HEAP_BASE + HEAP_SIZE);
} else {
base = (base + HB_OBJECT_ALIGNMENT - 1) & ~(HB_OBJECT_ALIGNMENT - 1);
}
step *= HB_OBJECT_ALIGNMENT;
top = base + step * NUM_XOR_PTRS;
if (top > (uintptr_t)(HEAP_BASE + HEAP_SIZE)) {
top = (uintptr_t)(HEAP_BASE + HEAP_SIZE);
}
/* Create the pointers.
*/
gNumPtrs = 0;
memset(gXorPtrs, 0, sizeof(gXorPtrs));
memset(gClearedPtrs, 0, sizeof(gClearedPtrs));
memset(gSeenPtrs, 0, sizeof(gSeenPtrs));
uintptr_t addr;
void **p = gXorPtrs;
for (addr = base; addr < top; addr += step) {
*p++ = (void *)addr;
gNumPtrs++;
}
assert(seenAndClearedMatch());
/* Set up the bitmaps.
*/
HeapBitmap hb1, hb2;
bool ok;
ok = dvmHeapBitmapInit(&hb1, HEAP_BASE, HEAP_SIZE, "test1");
assert(ok);
ok = dvmHeapBitmapInitFromTemplate(&hb2, &hb1, "test2");
assert(ok);
/* Walk two empty bitmaps.
*/
TRACE("walk 0\n");
ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
assert(ok);
assert(seenAndClearedMatch());
/* Walk one empty bitmap.
*/
TRACE("walk 1\n");
dvmHeapBitmapSetObjectBit(&hb1, (void *)base);
ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
assert(ok);
/* Make the bitmaps match.
*/
TRACE("walk 2\n");
dvmHeapBitmapSetObjectBit(&hb2, (void *)base);
ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
assert(ok);
/* Clear the bitmaps.
*/
dvmHeapBitmapZero(&hb1);
assert_empty(&hb1);
dvmHeapBitmapZero(&hb2);
assert_empty(&hb2);
/* Set the pointers we created in one of the bitmaps,
* then visit them.
*/
size_t i;
for (i = 0; i < gNumPtrs; i++) {
dvmHeapBitmapSetObjectBit(&hb1, gXorPtrs[i]);
}
TRACE("walk 3\n");
ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
assert(ok);
/* Set every third pointer in the other bitmap, and visit again.
*/
for (i = 0; i < gNumPtrs; i += 3) {
dvmHeapBitmapSetObjectBit(&hb2, gXorPtrs[i]);
}
TRACE("walk 4\n");
ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
assert(ok);
/* Set every other pointer in the other bitmap, and visit again.
*/
for (i = 0; i < gNumPtrs; i += 2) {
dvmHeapBitmapSetObjectBit(&hb2, gXorPtrs[i]);
}
TRACE("walk 5\n");
ok = dvmHeapBitmapXorWalk(&hb1, &hb2, xorCallback, gCallbackArg);
assert(ok);
/* Walk just one bitmap.
*/
TRACE("walk 6\n");
ok = dvmHeapBitmapWalk(&hb2, xorCallback, gCallbackArg);
assert(ok);
//xxx build an expect list for the callback
//xxx test where max points to beginning, middle, and end of a word
/* Clean up.
*/
dvmHeapBitmapDelete(&hb1);
dvmHeapBitmapDelete(&hb2);
}
void
test_xor()
{
run_xor(0, 1);
run_xor(100, 34);
}
int main(int argc, char *argv[])
{
printf("test_init...\n");
test_init();
printf("test_bits...\n");
test_bits();
printf("test_clear...\n");
test_clear();
printf("test_modify...\n");
test_modify();
printf("test_xor...\n");
test_xor();
printf("done.\n");
return 0;
}