149 lines
5.7 KiB
C++
Executable File
149 lines
5.7 KiB
C++
Executable File
/* Collectable.h - Collectables include
|
|
*
|
|
* Copyright (c) John Wainwright, 1996
|
|
*
|
|
*/
|
|
|
|
#ifndef _H_COLLECTIBLE
|
|
#define _H_COLLECTIBLE
|
|
|
|
enum col_state {booting, pre_gc, in_mutator, in_mark, in_sweep, closing_down };
|
|
|
|
typedef struct free_mem free_mem; // free mem linked list entry
|
|
struct free_mem
|
|
{
|
|
free_mem* next;
|
|
free_mem* prev;
|
|
size_t size;
|
|
};
|
|
|
|
// collection flag bits ...
|
|
enum gc_flags
|
|
{
|
|
GC_IN_USE = 0x0001,
|
|
GC_GARBAGE = 0x0002,
|
|
GC_PERMANENT = 0x0004,
|
|
GC_IN_HEAP = 0x0008,
|
|
GC_NOT_NEW = 0x0010,
|
|
GC_STATIC = 0x0020,
|
|
GC_ON_STACK = 0x0040,
|
|
GC_MIGRATED_TO_HEAP = 0x0080,
|
|
};
|
|
|
|
// general purpose Collectable flag bits ...
|
|
enum gp_flags2
|
|
{
|
|
COLLECTABLE_IN_SPRIN1 = 0x0001, // used by values that can recursively call sprin1. For example, arrays
|
|
COLLECTABLE_UNUSED2 = 0x0002,
|
|
COLLECTABLE_UNUSED3 = 0x0004,
|
|
COLLECTABLE_UNUSED4 = 0x0008,
|
|
COLLECTABLE_UNUSED5 = 0x0010,
|
|
COLLECTABLE_UNUSED6 = 0x0020,
|
|
COLLECTABLE_UNUSED7 = 0x0040,
|
|
COLLECTABLE_UNUSED8 = 0x0080,
|
|
};
|
|
|
|
class Value;
|
|
class ValueMapper;
|
|
|
|
#define ALLOCATOR_STACK_SIZE 1024000 // initial size of allocation stack per thread
|
|
|
|
extern ScripterExport void push_alloc_frame(); // manage alloc stack...
|
|
extern ScripterExport void pop_alloc_frame();
|
|
extern ScripterExport void pop_alloc_frame(Value*& result); // pops & moves result into callers frame if only on stack
|
|
|
|
#define ENABLE_STACK_ALLOCATE(_class) \
|
|
ScripterExport void* operator new (size_t sz) { return stack_alloc(sz); } \
|
|
ScripterExport void* operator new (size_t sz, char flag) { return Collectable::operator new (sz, flag); }
|
|
|
|
// free-list is kept in a number of separate size-related sub-lists, specifically
|
|
// for the high-bandwidth low size allocs.
|
|
// the heads of these are in the free_list static array in Collectable.
|
|
// each consecutive sub-list is for chunks one GC_ALLOC_MULTIPLE greater than the previous.
|
|
// the following defines determine the number of sub-lists.
|
|
|
|
#define GC_NUM_SUBLISTS 128
|
|
#define GC_LOW_SUBLIST 16 // <16, 16, 20, 24, 28, 32, ... 512, >512
|
|
#define GC_SUBLIST_INDEX_SHIFT 4 // log2(LOW_SUBLIST)
|
|
|
|
class Collectable
|
|
{
|
|
public:
|
|
Collectable* next; // in heap: links (in whichever collector list this value is in);
|
|
// on stack: pointer to heap migrated value, NULL if not migrated
|
|
Collectable* prev;
|
|
static CRITICAL_SECTION heap_update; // for syncing allocation list updates
|
|
byte flags; // collection flags - see enum gc_flags
|
|
byte flags2; // general purpose flags - only to be used by Collectable - see enum gp_flags2
|
|
short flags3; // general purpose flags - can be used by Values
|
|
|
|
static Collectable* collectable_list; // head of the collectable list
|
|
static Collectable* permanent_list; // head of the permanent list
|
|
static free_mem* free_list[GC_NUM_SUBLISTS]; // head of the free list
|
|
static size_t heap_allocated; // running count of MAXScript heap usage
|
|
static size_t heap_size; // alloc'd heap size
|
|
// LAM: 2/23/01 - need to export following for ms_make_collectable (see below) to link in DLXs.
|
|
ScripterExport static col_state state; // current collector state
|
|
ScripterExport static bool fullCollectNextHoldFlush; // if true, perform gc on next Hold system flush
|
|
static bool gc_light; // if true, no Hold system flush during current gc
|
|
|
|
ScripterExport Collectable();
|
|
ScripterExport ~Collectable();
|
|
|
|
static ScripterExport void for_all_values(void (*map_fn)(Value* val), ValueMapper* mapper = NULL, ValueMetaClass* c = NULL);
|
|
|
|
ScripterExport static void* heap_alloc(size_t sz);
|
|
ScripterExport static void* stack_alloc(size_t sz);
|
|
ScripterExport static void heap_free(void* p);
|
|
|
|
ScripterExport void* operator new (size_t sz, char flag);
|
|
ScripterExport void* operator new (size_t sz) { return heap_alloc(sz); }
|
|
ScripterExport void operator delete (void* val);
|
|
ScripterExport void operator delete (void* val, char flag) { Collectable::operator delete(val); }
|
|
|
|
static void mark();
|
|
static void sweep();
|
|
static void setup(size_t);
|
|
ScripterExport static void gc();
|
|
static void coalesce_free_list();
|
|
virtual void collect() = 0; // does the actual collecting, needs to be virtual to get right size to operator delete
|
|
virtual void gc_trace() { mark_in_use(); } // the marking scanner, default is mark me in use
|
|
static void close_down();
|
|
static void drop_maxwrapper_refs();
|
|
|
|
ScripterExport void make_collectable();
|
|
void make_permanent(); // no long exported, must use make_heap_permanent AND use its result as the made-permament value
|
|
void make_static(); // " " " make_heap_static AND " " "
|
|
|
|
ScripterExport static void push_alloc_stack_frame();
|
|
ScripterExport static void pop_alloc_stack_frame();
|
|
|
|
int is_marked() { return (flags & GC_IN_USE); }
|
|
int is_not_marked()
|
|
{
|
|
assert (!is_on_stack()); // debugging new stack-based collector
|
|
return !is_marked();
|
|
}
|
|
int is_garbage() { return is_not_marked(); }
|
|
int is_permanent() { return (flags & GC_PERMANENT); }
|
|
void mark_in_use() { flags |= GC_IN_USE; }
|
|
void unmark_in_use() { flags &= ~GC_IN_USE; }
|
|
int has_heap_copy() { return (flags & (GC_IN_HEAP | GC_MIGRATED_TO_HEAP | GC_STATIC)); }
|
|
int is_in_heap() { return (flags & GC_IN_HEAP); }
|
|
int is_on_stack() { return (flags & GC_ON_STACK); }
|
|
|
|
};
|
|
|
|
// mapping object for Collectable::for_all_values()
|
|
class ValueMapper
|
|
{
|
|
public:
|
|
virtual void map(Value* val)=0;
|
|
};
|
|
|
|
ScripterExport void ms_free(void* p);
|
|
ScripterExport void* ms_malloc(size_t sz);
|
|
inline void ms_make_collectable(Collectable* v) { if (v != NULL && Collectable::state != closing_down) v->make_collectable(); }
|
|
|
|
#endif
|