/************************************************************************* MrEd interface to various garbage collectors, including the Boehm collector, SenoraGC, and MzScheme's precise collector. Copyright (c) 2004-2007 PLT Scheme Inc. *************************************************************************/ /************************************************************************* Based On: Copyright (c) 1994 by Xerox Corporation. All rights reserved. THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. Last modified on Sat Nov 19 19:31:14 PST 1994 by ellis on Sat Jun 8 15:10:00 PST 1994 by boehm Permission is hereby granted to copy this code for any purpose, provided the above notices are retained on all copies. Authors: John R. Ellis and Jesse Hull **************************************************************************/ /* Boehm, December 20, 1994 7:26 pm PST */ #include #include "wxGC.h" /* With extensions, or with x86 Mac OS X, MrEd's `new' gets used by libraries that shouldn't use it. So we can't define `new' on that platform. For PPC, we define `new' and `delete' to use malloc() and free(); for some reason, linking fails in Mac OS X 10.3 if we just omit `new' and `delete'. There should be no problem under Windows, due to the way DLL linking works. */ #ifndef wx_msw # if defined(OS_X) && defined(__POWERPC__) # define MALLOC_FOR_BUILTIN_NEW # include # include # else # define DONT_DEFINE_BUILTIN_NEW # endif #endif #ifdef COMPACT_BACKTRACE_GC # include #endif #ifdef MPW_CPLUS extern "C" { typedef void (*GC_F_PTR)(void *, void *); } # define CAST_GCP (GC_F_PTR) # define CAST_GCPP (GC_F_PTR *) #else # define CAST_GCP /* empty */ # define CAST_GCPP /* empty */ #endif #ifdef USE_SENORA_GC struct GC_Set *cpp_objects; typedef void (*GC_finalization_proc)(void *, void *); #if SGC_STD_DEBUGGING # define USE_WXOBJECT_TRACE_COUNTER #endif #endif #ifndef DONT_DEFINE_BUILTIN_NEW void *operator new(size_t size) { #ifdef MALLOC_FOR_BUILTIN_NEW return malloc(size); #else # ifdef USE_SENORA_GC if (!cpp_objects) cpp_objects = GC_new_set("C++", NULL, NULL, NULL, NULL, NULL, 0); return GC_malloc_specific(size, cpp_objects); # else return GC_malloc(size); #endif #endif } void operator delete(void *obj) { #ifdef MALLOC_FOR_BUILTIN_NEW free(obj); #endif } #endif void gc_cleanup::install_cleanup(void) { GC_finalization_proc old_fn; void *old_data; # ifdef MZ_PRECISE_GC # define ALLOW_NON_BASE 0 # define CHECK_BASE 0 # else # ifdef wx_xt # define ALLOW_NON_BASE 0 # define CHECK_BASE 0 # else # ifdef WIN32 # define ALLOW_NON_BASE 0 # define CHECK_BASE 1 # define CRASH_ON_NONBASE 1 # else # define ALLOW_NON_BASE 1 # define CHECK_BASE 0 # endif # endif # endif # if CHECK_BASE || ALLOW_NON_BASE if (GC_base(this) != (void *)this) { # if ALLOW_NON_BASE return; # else # ifdef CRASH_ON_NONBASE *(long *)0x0 = 1; # else printf("Clean-up object is not the base object\n"); abort(); # endif # endif } # endif GC_register_finalizer_ignore_self(gcOBJ_TO_PTR(this), CAST_GCP GC_cleanup, NULL, CAST_GCPP &old_fn, &old_data); # if CHECK_BASE if (old_fn) { # ifdef CRASH_ON_NONBASE *(long *)0x0 = 1; # else printf("Object already has a clean-up\n"); abort(); # endif } # endif } #define SHOW_CLEANUP_TIMES 0 #if SHOW_CLEANUP_TIMES extern "C" long scheme_get_process_milliseconds(); #endif void GC_cleanup(void *obj, void *) { gc *clean = (gc *)gcPTR_TO_OBJ(obj); #ifdef MZ_PRECISE_GC # ifdef COMPACT_BACKTRACE_GC # if SHOW_CLEANUP_TIMES long start; start = scheme_get_process_milliseconds(); char *s; s = clean->gcGetName(); printf("Cleanup: %s\n", s ? s : "???"); # endif # endif GC_cpp_delete(clean); # ifdef COMPACT_BACKTRACE_GC # if SHOW_CLEANUP_TIMES start = scheme_get_process_milliseconds() - start; printf(" done %d\n", start); # endif # endif #else clean->~gc(); #endif } /**********************************************************************/ #ifdef OPERATOR_NEW_ARRAY # ifndef DONT_DEFINE_BUILTIN_NEW void* operator new[](size_t size) { #ifdef MALLOC_FOR_BUILTIN_NEW return malloc(size); #else # ifdef USE_SENORA_GC if (!cpp_objects) cpp_objects = GC_new_set("C++", NULL, NULL, NULL, NULL, NULL, 0); return GC_malloc_specific(size, cpp_objects); # else return GC_malloc(size); # endif #endif } void operator delete[](void *obj) { #ifdef MALLOC_FOR_BUILTIN_NEW free(obj); #endif } # endif #endif /**********************************************************************/ #ifdef USE_SENORA_GC struct GC_Set *wx_objects; # ifdef USE_WXOBJECT_TRACE_COUNTER extern void wxTraceCount(void *, int); extern void wxTracePath(void *, unsigned long, void *); extern void wxTraceInit(void); extern void wxTraceDone(void); extern void wxObjectFinalize(void *); # endif void *GC_cpp_malloc(size_t size) { if (!wx_objects) wx_objects = GC_new_set("wxObjects", # ifdef USE_WXOBJECT_TRACE_COUNTER wxTraceInit, wxTraceDone, wxTraceCount, wxTracePath, wxObjectFinalize, # else NULL, NULL, NULL, NULL, NULL, # endif 0); return GC_malloc_specific(size, wx_objects); } # ifdef SGC_STD_DEBUGGING void GC_cpp_for_each(void (*f)(void *, int, void *), void *data) { if (wx_objects) GC_for_each_element(wx_objects, f, data); } int GC_is_wx_object(void *v) { return wx_objects && (GC_set(v) == wx_objects); } # endif #endif /**********************************************************************/ #ifdef MZ_PRECISE_GC # define ZERO_OUT_DISPATCH 1 # ifdef COMPACT_BACKTRACE_GC static char *get_xtagged_name(void *p); extern char *(*GC_get_xtagged_name)(void *p); # endif typedef struct { short tag; short filler_used_for_hashing; void *val; } GC_WB; void *GC_weak_box_val(void *b) { return ((GC_WB *)b)->val; } #include "scheme.h" static void mark_cpp_object(void *p) { gc *obj = (gc *)p; #if ZERO_OUT_DISPATCH if (*(long *)obj) #endif obj->gcMark(); } static void fixup_cpp_object(void *p) { gc *obj = (gc *)p; #if ZERO_OUT_DISPATCH if (*(long *)obj) #endif obj->gcFixup(); } static int is_initialized; static void initize(void) { /* Initialize: */ GC_mark_xtagged = mark_cpp_object; GC_fixup_xtagged = fixup_cpp_object; # ifdef COMPACT_BACKTRACE_GC GC_get_xtagged_name = get_xtagged_name; # endif is_initialized = 1; } void *GC_cpp_malloc(size_t size) { void *p; if (!is_initialized) initize(); p = GC_malloc_one_xtagged(size); return p; } void GC_cpp_delete(gc *v) { v->~gc(); #if ZERO_OUT_DISPATCH ((long *)v)[0] = 0; #endif } # ifdef COMPACT_BACKTRACE_GC static char name_buffer[256]; static char *get_xtagged_name(void *p) { char *s; s = ((gc *)gcPTR_TO_OBJ(p))->gcGetName(); sprintf(name_buffer, "<%s>", (s ? s : "XTAGGED")); return name_buffer; } char *gc::gcGetName() { return NULL; } # endif #endif /**********************************************************************/ /* The accounting shadow serves two purposes. First, it allocates largely untouched atomic memory to reflect the allocation of bitmaps outside the GC space, so that the nominal allocation total is related to the total taking into accoun bitmaps. Second, because bitmaps are released through finalizers, the accounting shadow forces a GC more frequently than might otherwise happen as the total size of bitmaps grows. */ static long total, accum = 1024 * 1024 * 5; void *GC_malloc_accounting_shadow(long a) { long *p; if (a < (long)sizeof(long)) a = sizeof(long); total += a; accum -= a; if (accum <= 0) { GC_gcollect(); accum = total >> 1; } p = (long *)GC_malloc_atomic(a); *p = a; return (void *)p; } void GC_free_accounting_shadow(void *p) { if (p) { total -= *(long *)p; accum += *(long *)p; } }