racket/src/wxcommon/wxGC.cxx
2007-01-23 22:08:27 +00:00

402 lines
7.9 KiB
C++

/*************************************************************************
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 <stddef.h>
#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 <stdio.h>
# include <stdlib.h>
# else
# define DONT_DEFINE_BUILTIN_NEW
# endif
#endif
#ifdef COMPACT_BACKTRACE_GC
# include <stdio.h>
#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;
}
}