collectable.h

Go to the documentation of this file.
00001 /*  Collectable.h - Collectables include
00002  *
00003  *          Copyright (c) John Wainwright, 1996
00004  *
00005  */
00006 
00007 #pragma once
00008 
00009 #include "..\ScripterExport.h"
00010 #include "..\..\WindowsDefines.h"
00011 #include "..\..\assert1.h"
00012 
00013 enum collectable_state
00014 {
00015     booting, 
00016     pre_gc, 
00017     in_mutator, 
00018     in_mark, 
00019     in_sweep, 
00020     closing_down, 
00021     in_coalesce
00022 };
00023 
00024 // free mem linked list entry
00025 struct free_mem
00026 {
00027     free_mem*   next;
00028     free_mem*   prev;
00029     size_t      size;
00030 };
00031         
00032 // collection flag bits ...
00033 enum gc_flags
00034 {
00035     GC_IN_USE           = 0x0001,
00036     GC_GARBAGE          = 0x0002,
00037     GC_PERMANENT        = 0x0004,
00038     GC_IN_HEAP          = 0x0008,
00039     GC_NOT_NEW          = 0x0010,
00040     GC_STATIC           = 0x0020,
00041     GC_ON_STACK         = 0x0040,
00042     GC_MIGRATED_TO_HEAP = 0x0080,
00043 };
00044 
00045 // general purpose Collectable flag bits ...
00046 enum gp_flags2
00047 {
00048     COLLECTABLE_IN_SPRIN1   = 0x0001, // used by values that can recursively call sprin1. For example, arrays
00049     COLLECTABLE_UNUSED2     = 0x0002,
00050     COLLECTABLE_UNUSED3     = 0x0004,
00051     COLLECTABLE_UNUSED4     = 0x0008,
00052     COLLECTABLE_UNUSED5     = 0x0010,
00053     COLLECTABLE_UNUSED6     = 0x0020,
00054     COLLECTABLE_UNUSED7     = 0x0040,
00055     COLLECTABLE_UNUSED8     = 0x0080,
00056 };
00057 
00058 // general purpose Value flag bits ...
00059 enum gp_flags3
00060 {
00061     VALUE_FLAGBIT_0     = 0x0001, 
00062     VALUE_FLAGBIT_1     = 0x0002,
00063     VALUE_FLAGBIT_2     = 0x0004,
00064     VALUE_FLAGBIT_3     = 0x0008,
00065     VALUE_FLAGBIT_4     = 0x0010,
00066     VALUE_FLAGBIT_5     = 0x0020,
00067     VALUE_FLAGBIT_6     = 0x0040,
00068     VALUE_FLAGBIT_7     = 0x0080,
00069     VALUE_FLAGBIT_8     = 0x0100, 
00070     VALUE_FLAGBIT_9     = 0x0200,
00071     VALUE_FLAGBIT_10    = 0x0400,
00072     VALUE_FLAGBIT_11    = 0x0800,
00073     VALUE_FLAGBIT_12    = 0x1000,
00074     VALUE_FLAGBIT_13    = 0x2000,
00075     VALUE_FLAGBIT_14    = 0x4000,
00076     VALUE_FLAGBIT_15    = 0x8000,
00077 };
00078 
00079 class Value;
00080 class ValueMapper;
00081 class ValueMetaClass;
00082 
00083 #define ALLOCATOR_STACK_SIZE 2048000     // initial size of allocation stack per thread
00084 #define STACK_LIMIT_BUFFER_SIZE 64000 // amount of stack reserved for handling stack overflow exception
00085 
00086 static const int STACK_FRAME_HEADER_SIZE = 9; // used internally as the fixed header size when a new stack frame is allocated
00087 
00088 extern ScripterExport void push_alloc_frame();                  // manage alloc stack...
00089 extern ScripterExport void pop_alloc_frame();
00090 extern ScripterExport void pop_alloc_frame(Value*& result); // pops & moves result into callers frame if only on stack
00091 
00092 #define ENABLE_STACK_ALLOCATE(_class)                                           \
00093     ScripterExport void* operator new (size_t sz) { return stack_alloc(sz); }   \
00094     ScripterExport void* operator new (size_t sz, char flag) { return Collectable::operator new (sz, flag); }
00095 
00096 // free-list is kept in a number of separate size-related sub-lists, specifically
00097 // for the high-bandwidth low size allocs.
00098 // the heads of these are in the free_list static array in Collectable.
00099 // each consecutive sub-list is for chunks one GC_ALLOC_MULTIPLE greater than the previous.
00100 // the following defines determine the number of sub-lists.  
00101 
00102 #define GC_NUM_SUBLISTS             128 
00103 #define GC_LOW_SUBLIST              16   // <16, 16, 20, 24, 28, 32, ... 512, >512
00104 #define GC_SUBLIST_INDEX_SHIFT      4    // log2(LOW_SUBLIST)
00105 
00106 class Collectable
00107 {
00108 public:
00109     Collectable*    next;                   // in heap: links (in whichever collector list this value is in); 
00110                                             // on stack: pointer to heap migrated value, NULL if not migrated
00111     Collectable*    prev;
00112     static CRITICAL_SECTION heap_update;    // for syncing allocation list updates
00113     byte            flags;                  // collection flags - see enum gc_flags
00114     byte            flags2;                 // general purpose flags - only to be used by Collectable - see enum gp_flags2
00115     short           flags3;                 // general purpose flags - can be used by Values
00116 
00117     static Collectable* collectable_list;   // head of the collectable list
00118     static Collectable* permanent_list;     // head of the permanent list
00119     static free_mem* free_list[GC_NUM_SUBLISTS];                // head of the free list
00120     static size_t heap_allocated;           // running count of MAXScript heap usage
00121     static size_t heap_size;                // alloc'd heap size
00122     // LAM: 2/23/01 - need to export following for ms_make_collectable (see below) to link in DLXs.
00123     ScripterExport static collectable_state state;  // current collector state 
00124     ScripterExport static bool fullCollectNextHoldFlush;    // if true, perform gc on next Hold system flush
00125     static bool gc_light;                   // if true, no Hold system flush during current gc
00126     static bool in_gc;                      // if true, in a gc
00127     
00128     static HANDLE hGCCompletedEvent;    // for syncing with debugger. Event is set when exiting a garbage collection
00129     
00130     ScripterExport Collectable();
00131     ScripterExport virtual ~Collectable();
00132 
00133     static ScripterExport void for_all_values(void (*map_fn)(Value* val), ValueMapper* mapper = NULL, ValueMetaClass* c = NULL);
00134 
00135     ScripterExport static void* heap_alloc(size_t sz);
00136     ScripterExport static void* stack_alloc(size_t sz);
00137     ScripterExport static void  heap_free(void* p);
00138 
00139     ScripterExport void* operator new (size_t sz, char flag);
00140     ScripterExport void* operator new (size_t sz) { return heap_alloc(sz); }
00141     ScripterExport void operator delete (void* val);
00142     #pragma warning(push)
00143     #pragma warning(disable:4100)
00144     ScripterExport void operator delete (void* val, char flag) { Collectable::operator delete(val); }
00145     #pragma warning(pop)
00146 
00147     static void mark();
00148     static void sweep();
00149     static void setup(size_t);
00150     ScripterExport static void  gc();
00151     static void coalesce_free_list();
00152     virtual void collect() = 0;               // does the actual collecting, needs to be virtual to get right size to operator delete
00153     virtual void gc_trace() { mark_in_use(); } // the marking scanner, default is mark me in use
00154     static void close_down();
00155     static void drop_maxwrapper_refs();
00156 
00157     ScripterExport void make_collectable();
00158                    void make_permanent();   // no long exported, must use make_heap_permanent AND use its result as the made-permament value
00159                    void make_static();      //    "    "          "       make_heap_static AND      "       "      "
00160 
00161     ScripterExport static void push_alloc_stack_frame();
00162     ScripterExport static void pop_alloc_stack_frame();
00163 
00164     int     is_marked()         { return (flags & GC_IN_USE); }
00165     int     is_not_marked()     
00166     { 
00167         DbgAssert (!is_on_stack());   // debugging new stack-based collector
00168         return !is_marked(); 
00169     }
00170     int     is_garbage()        { return is_not_marked(); }
00171     int     is_permanent()      { return (flags & GC_PERMANENT); }
00172     void    mark_in_use()       { flags |= GC_IN_USE; }
00173     void    unmark_in_use()     { flags &= ~GC_IN_USE; }
00174     int     has_heap_copy()     { return (flags & (GC_IN_HEAP | GC_MIGRATED_TO_HEAP | GC_STATIC)); }
00175     int     is_in_heap()        { return (flags & GC_IN_HEAP); }
00176     int     is_on_stack()       { return (flags & GC_ON_STACK); }
00177 
00178     // Returns the total number of maxscript values created so far
00179     ScripterExport static ULONGLONG get_num_values_created();
00180 
00181 private:
00182     static void increment_num_values_created();
00183     static volatile LONGLONG& get_num_values_created_counter();
00184 };
00185 
00186 // mapping object for Collectable::for_all_values()
00187 class ValueMapper 
00188 {
00189 public:
00190     virtual ~ValueMapper() {;}
00191     virtual void map(Value* val)=0;
00192 };
00193 
00194 ScripterExport void ms_free(void* p);
00195 ScripterExport void* ms_malloc(size_t sz);
00196 ScripterExport void* ms_realloc(void* p, size_t sz);
00197 inline void ms_make_collectable(Collectable* v)
00198 {
00199     if (v != NULL && Collectable::state != closing_down)
00200         v->make_collectable();
00201 }
00202