diff --git a/CMakeLists.txt b/CMakeLists.txt index b5266a28..c65cfc90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -260,8 +260,6 @@ if(MSVC) ) endif() endif() -# disable dmd gc -list(REMOVE_ITEM FE_SRC ${PROJECT_SOURCE_DIR}/${DMDFE_PATH}/root/dmgcmem.c) set(LDC_SOURCE_FILES ${LDC_GENERATED} ${FE_SRC} diff --git a/dmd2/root/dmgcmem.c b/dmd2/root/dmgcmem.c deleted file mode 100644 index 02d1c0d1..00000000 --- a/dmd2/root/dmgcmem.c +++ /dev/null @@ -1,499 +0,0 @@ - - -// Copyright (c) 2000-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun -#include -#include -#endif - -#include "rmem.h" -#include "gc/gc.h" -//#include "printf.h" - -/* This implementation of the storage allocator uses the Digital Mars gc. - */ - -Mem mem; - -//static int nuncollectable; - -extern "C" -{ - void gc_init(); - GC *gc_get(); -} - -void Mem::init() -{ - gc_init(); -} - -char *Mem::strdup(const char *s) -{ - return gc_get()->strdup(s); -} - -void *Mem::malloc(size_t size) -{ - if (gc) // if cached allocator - { -// PRINTF("Using cached gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line); -// GC::file = NULL; -// GC::line = 0; - return ((GC *)gc)->malloc(size); - } - if (this == &mem) // don't cache global mem - { -// PRINTF("Using global gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line); -// GC::file = NULL; -// GC::line = 0; - return gc_get()->malloc(size); - } -// PRINTF("Generating cached gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line); - gc = gc_get(); - return gc->malloc(size); -} - -void *Mem::malloc_uncollectable(size_t size) -{ void *p; - - p = ::malloc(size); - if (!p) - error(); - addroots((char *)p, (char *)p + size); - -#if 0 - ++nuncollectable; - WPRINTF(L"malloc_uncollectable(%u) = %x, n=%d\n", size, p, nuncollectable); -#endif - - return p; -} - -void *Mem::calloc(size_t size, size_t n) -{ - return gc_get()->calloc(size, n); -} - -void *Mem::realloc(void *p, size_t size) -{ - return gc_get()->realloc(p, size); -} - -void Mem::free(void *p) -{ - gc_get()->free(p); -} - -void Mem::free_uncollectable(void *p) -{ - if (p) - { removeroots((char *)p); - ::free(p); - -#if 0 - --nuncollectable; - WPRINTF(L"free_uncollectable(%x) n=%d\n", p, nuncollectable); -#endif - -#if 0 - gc_get()->fullcollect(); - - GCStats stats; - - getStats(&stats); - WPRINTF(L"poolsize = %x, usedsize = %x, freelistsize = %x\n", - stats.poolsize, stats.usedsize, stats.freelistsize); -#endif - } -} - -void *Mem::mallocdup(void *o, size_t size) -{ - return gc_get()->mallocdup(o, size); -} - -void Mem::check(void *p) -{ - if (gc) - gc->check(p); - else - gc_get()->check(p); -} - -void Mem::error() -{ -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun - assert(0); -#endif - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); -} - -void Mem::fullcollect() -{ - gc_get()->fullcollect(); - -#if 0 - { - GCStats stats; - - gc_get()->getStats(&stats); - WPRINTF(L"Thread %x ", Thread::getId()); - WPRINTF(L"poolsize=x%x, usedsize=x%x, freelistsize=x%x, freeblocks=%d, pageblocks=%d\n", - stats.poolsize, stats.usedsize, stats.freelistsize, stats.freeblocks, stats.pageblocks); - } -#endif -} - - -void Mem::fullcollectNoStack() -{ - gc_get()->fullcollectNoStack(); - -#if 0 - { - GCStats stats; - - gc_get()->getStats(&stats); - WPRINTF(L"Thread %x ", Thread::getId()); - WPRINTF(L"poolsize=x%x, usedsize=x%x, freelistsize=x%x, freeblocks=%d, pageblocks=%d\n", - stats.poolsize, stats.usedsize, stats.freelistsize, stats.freeblocks, stats.pageblocks); - } -#endif -} - - -void Mem::mark(void *pointer) -{ - (void) pointer; // for VC /W4 compatibility -} - - -void Mem::addroots(char* pStart, char* pEnd) -{ - gc_get()->addRange(pStart, pEnd); -} - - -void Mem::removeroots(char* pStart) -{ - gc_get()->removeRange(pStart); -} - - -void Mem::setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData) -{ - (void)pClientData; - gc_get()->setFinalizer(pObj, pFn); -} - - -void Mem::setStackBottom(void *stackbottom) -{ - gc_get()->setStackBottom(stackbottom); -} - - -GC *Mem::getThreadGC() -{ - return gc_get(); -} - - -/* =================================================== */ - -#if 1 -void * operator new(size_t m_size) -{ - //PRINTF("Call to global operator new(%d), file = '%s', line = %d\n", m_size, GC::file ? GC::file : "(null)", GC::line); - GC::file = NULL; - GC::line = 0; - return mem.malloc(m_size); -} - -void operator delete(void *p) -{ - //WPRINTF(L"Call to global operator delete\n"); - mem.free(p); -} - -void* operator new[](size_t size) -{ - return operator new(size); -} - -void operator delete[](void *pv) -{ - operator delete(pv); -} -#endif - -void * Mem::operator new(size_t m_size) -{ void *p; - - p = gc_get()->malloc(m_size); - //printf("Mem::operator new(%d) = %p\n", m_size, p); - if (!p) - mem.error(); - return p; -} - -void * Mem::operator new(size_t m_size, Mem *mem) -{ void *p; - - p = mem->malloc(m_size); - //printf("Mem::operator new(%d) = %p\n", m_size, p); - if (!p) - ::mem.error(); - return p; -} - -void * Mem::operator new(size_t m_size, GC *gc) -{ void *p; - -// if (!gc) -// WPRINTF(L"gc is NULL\n"); - p = gc->malloc(m_size); - //printf("Mem::operator new(%d) = %p\n", m_size, p); - if (!p) - ::mem.error(); - return p; -} - -void Mem::operator delete(void *p) -{ -// printf("Mem::operator delete(%p)\n", p); - gc_get()->free(p); -} - -/* ============================================================ */ - -/* The following section of code exists to find the right - * garbage collector for this thread. There is one independent instance - * of the collector per thread. - */ - -/* ===================== linux ================================ */ - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun - -#include - -#define LOG 0 // log thread creation / destruction - -extern "C" -{ - -// Key identifying the thread-specific data -static pthread_key_t gc_key; - -/* "Once" variable ensuring that the key for gc_alloc will be allocated - * exactly once. - */ -static pthread_once_t gc_alloc_key_once = PTHREAD_ONCE_INIT; - -/* Forward functions */ -static void gc_alloc_key(); -static void gc_alloc_destroy_gc(void * accu); - - -void gc_init() -{ -#if LOG - WPRINTF(L"Thread %lx: gc_init()\n", pthread_self()); -#endif - pthread_once(&gc_alloc_key_once, gc_alloc_key); -#if LOG - WPRINTF(L"Thread %lx: gc_init() return\n", pthread_self()); -#endif -} - -GC *gc_get() -{ - GC *gc; - - // Get the thread-specific data associated with the key - gc = (GC *) pthread_getspecific(gc_key); - - // It's initially NULL, meaning that we must allocate the buffer first. - if (gc == NULL) - { - GC_LOG(); - gc = new GC(); - gc->init(); - - // Store the buffer pointer in the thread-specific data. - pthread_setspecific(gc_key, (void *) gc); -#if LOG - WPRINTF(L"Thread %lx: allocating gc at %x\n", pthread_self(), gc); -#endif - } - return gc; -} - -// Function to allocate the key for gc_alloc thread-specific data. - -static void gc_alloc_key() -{ - pthread_key_create(&gc_key, gc_alloc_destroy_gc); -#if LOG - WPRINTF(L"Thread %lx: allocated gc key %d\n", pthread_self(), gc_key); -#endif -} - -// Function to free the buffer when the thread exits. -// Called only when the thread-specific data is not NULL. - -static void gc_alloc_destroy_gc(void *gc) -{ -#if LOG - WPRINTF(L"Thread %x: freeing gc at %x\n", pthread_self(), gc); -#endif - delete (GC *)gc; -} - -} - -#endif - -/* ===================== win32 ================================ */ - -#if !defined(linux) && defined(_WIN32) - -#if 1 // single threaded version - -extern "C" -{ - -static GC *gc; - -void gc_init() -{ - if (!gc) - { gc = (GC *)::malloc(sizeof(GC)); - gc->init(); - } -} - -GC *gc_get() -{ - return gc; -} - -} - -#else // multi threaded version - -#include "mutex.h" -#include "thread.h" - -/* This is the win32 version. It suffers from the bug that - * when the thread exits the data structure is not cleared, - * but the memory pool it points to is free'd. - * Thus, if a new thread comes along with the same thread id, - * the data will look initialized, but will point to garbage. - * - * What needs to happen is when a thread exits, the associated - * GC_context data struct is cleared. - */ - -struct GC_context -{ - ThreadId threadid; // identifier of current thread - GC *gc; -}; - -Mutex gc_mutex; - -static GC_context array[64]; - -// Array of pointers to GC_context objects, one per threadid -GC_context *gccontext = array; -unsigned gccontext_allocdim = 64; -unsigned gccontext_dim; - -ThreadId gc_cache_ti; -GC_context *gc_cache_cc; - -extern "C" void gc_init() -{ -} - - -extern "C" GC *gc_get() -{ - /* This works by creating an array of GC_context's, one - * for each thread. We match up by thread id. - */ - - ThreadId ti; - GC_context *cc; - - //PRINTF("gc_get()\n"); - - ti = Thread::getId(); - gc_mutex.acquire(); - - // Used cached version if we can - if (ti == gc_cache_ti) - { - cc = gc_cache_cc; - //exception(L"getGC_context(): cache x%x", ti); - } - else - { - // This does a linear search through gccontext[]. - // A hash table might be faster if there are more - // than a dozen threads. - GC_context *ccp; - GC_context *ccptop = &gccontext[gccontext_dim]; - for (ccp = gccontext; ccp < ccptop; ccp++) - { - cc = ccp; - if (cc->threadid == ti) - { - WPRINTF(L"getGC_context(): existing x%x", ti); - goto Lret; - } - } - - // Do not allocate with garbage collector, as this must reside - // global to all threads. - - assert(gccontext_dim < gccontext_allocdim); - cc = ccp; - memset(cc, 0, sizeof(*cc)); - cc->threadid = ti; - cc->gc = new GC(); - cc->gc->init(); - - gccontext_dim++; - WPRINTF(L"getGC_context(): new x%x\n", ti); - - Lret: - // Cache for next time - gc_cache_ti = ti; - gc_cache_cc = cc; - } - - gc_mutex.release(); - return cc->gc; -} - -#endif - - -#endif