/* Set by the -securegc command line argument */
extern bool secure_gc;

/* generational copying GC divides memory into zones */
struct F_ZONE {
	/* allocation pointer is 'here'; its offset is hardcoded in the
	compiler backends */
	CELL start;
	CELL here;
	CELL size;
	CELL end;
};

struct F_DATA_HEAP {
	F_SEGMENT *segment;

	CELL young_size;
	CELL aging_size;
	CELL tenured_size;

	CELL gen_count;

	F_ZONE *generations;
	F_ZONE* semispaces;

	CELL *allot_markers;
	CELL *allot_markers_end;

	CELL *cards;
	CELL *cards_end;

	CELL *decks;
	CELL *decks_end;
};

extern F_DATA_HEAP *data_heap;

/* the 0th generation is where new objects are allocated. */
#define NURSERY 0
/* where objects hang around */
#define AGING (data_heap->gen_count-2)
#define HAVE_AGING_P (data_heap->gen_count>2)
/* the oldest generation */
#define TENURED (data_heap->gen_count-1)

#define MIN_GEN_COUNT 1
#define MAX_GEN_COUNT 3

/* new objects are allocated here */
extern F_ZONE nursery;

INLINE bool in_zone(F_ZONE *z, CELL pointer)
{
	return pointer >= z->start && pointer < z->end;
}

CELL init_zone(F_ZONE *z, CELL size, CELL base);

void init_card_decks(void);

F_DATA_HEAP *grow_data_heap(F_DATA_HEAP *data_heap, CELL requested_bytes);

void dealloc_data_heap(F_DATA_HEAP *data_heap);

void clear_cards(CELL from, CELL to);
void clear_decks(CELL from, CELL to);
void clear_allot_markers(CELL from, CELL to);
void reset_generation(CELL i);
void reset_generations(CELL from, CELL to);

void set_data_heap(F_DATA_HEAP *data_heap_);

void init_data_heap(CELL gens,
	CELL young_size,
	CELL aging_size,
	CELL tenured_size,
	bool secure_gc_);

/* set up guard pages to check for under/overflow.
size must be a multiple of the page size */
F_SEGMENT *alloc_segment(CELL size);
void dealloc_segment(F_SEGMENT *block);

CELL untagged_object_size(CELL pointer);
CELL unaligned_object_size(CELL pointer);
CELL object_size(CELL pointer);
CELL binary_payload_start(CELL pointer);

void begin_scan(void);
CELL next_object(void);

void primitive_data_room(void);
void primitive_size(void);

void primitive_begin_scan(void);
void primitive_next_object(void);
void primitive_end_scan(void);

/* GC is off during heap walking */
extern bool gc_off;

INLINE void *allot_zone(F_ZONE *z, CELL a)
{
	CELL h = z->here;
	z->here = h + align8(a);
	return (void*)h;
}

CELL find_all_words(void);

/* Every object has a regular representation in the runtime, which makes GC
much simpler. Every slot of the object until binary_payload_start is a pointer
to some other object. */
INLINE void do_slots(CELL obj, void (* iter)(CELL *))
{
	CELL scan = obj;
	CELL payload_start = binary_payload_start(obj);
	CELL end = obj + payload_start;

	scan += CELLS;

	while(scan < end)
	{
		iter((CELL *)scan);
		scan += CELLS;
	}
}