Merge branch 'master' into merge-2.064

Conflicts:
	dmd2/root/rmem.c
This commit is contained in:
Kai Nacke 2014-01-03 15:56:01 +01:00
commit 731f2a8fdf
10 changed files with 17 additions and 565 deletions

View file

@ -260,8 +260,6 @@ if(MSVC)
) )
endif() endif()
endif() endif()
# disable dmd gc
list(REMOVE_ITEM FE_SRC ${PROJECT_SOURCE_DIR}/${DMDFE_PATH}/root/dmgcmem.c)
set(LDC_SOURCE_FILES set(LDC_SOURCE_FILES
${LDC_GENERATED} ${LDC_GENERATED}
${FE_SRC} ${FE_SRC}

View file

@ -16,7 +16,7 @@
#include <string> #include <string>
#include <cstdarg> #include <cstdarg>
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun #if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
#include <errno.h> #include <errno.h>
#endif #endif
@ -604,7 +604,7 @@ int tryMain(size_t argc, char *argv[])
#if _WIN32 #if _WIN32
inifilename = inifile(argv[0], "sc.ini", "Environment"); inifilename = inifile(argv[0], "sc.ini", "Environment");
#elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun #elif __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
inifilename = inifile(argv[0], "dmd.conf", "Environment"); inifilename = inifile(argv[0], "dmd.conf", "Environment");
#else #else
#error "fix this" #error "fix this"
@ -1023,7 +1023,7 @@ Language changes listed by -transition=id:\n\
browse("http://dlang.org/dmd-windows.html"); browse("http://dlang.org/dmd-windows.html");
#endif #endif
#endif #endif
#if linux #if __linux__
#if DMDV1 #if DMDV1
browse("http://www.digitalmars.com/d/1.0/dmd-linux.html"); browse("http://www.digitalmars.com/d/1.0/dmd-linux.html");
#else #else

View file

@ -119,7 +119,7 @@ unsigned __stdcall startthread(void *p)
return EXIT_SUCCESS; // if skidding return EXIT_SUCCESS; // if skidding
} }
#elif linux // Posix #elif __linux__ // Posix
#include <errno.h> #include <errno.h>
#include <pthread.h> #include <pthread.h>

View file

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
#include <unistd.h>
#include <pthread.h>
#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 <pthread.h>
#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

View file

@ -26,7 +26,7 @@ void browse(const char *url)
#endif #endif
#if linux || __FreeBSD__ || __OpenBSD__ || __sun #if __linux__ || __FreeBSD__ || __OpenBSD__ || __sun
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>

View file

@ -624,10 +624,10 @@ longdouble Port::strtold(const char *p, char **endp)
#endif #endif
#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __HAIKU__ #if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __HAIKU__
#include <math.h> #include <math.h>
#if linux #if __linux__
#include <bits/nan.h> #include <bits/nan.h>
#include <bits/mathdef.h> #include <bits/mathdef.h>
#endif #endif

View file

@ -8,7 +8,7 @@
// See the included readme.txt for details. // See the included readme.txt for details.
#ifndef POSIX #ifndef POSIX
#define POSIX (linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun) #define POSIX (__linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun)
#endif #endif
#include <stdio.h> #include <stdio.h>
@ -880,11 +880,11 @@ void FileName::ensurePathToNameExists(const char *name)
*/ */
const char *FileName::canonicalName(const char *name) const char *FileName::canonicalName(const char *name)
{ {
#if linux #if __linux__
// Lovely glibc extension to do it for us // Lovely glibc extension to do it for us
return canonicalize_file_name(name); return canonicalize_file_name(name);
#elif POSIX #elif POSIX
#if _POSIX_VERSION >= 200809L || defined (linux) #if _POSIX_VERSION >= 200809L || defined (__linux__)
// NULL destination buffer is allowed and preferred // NULL destination buffer is allowed and preferred
return realpath(name, NULL); return realpath(name, NULL);
#else #else

View file

@ -1003,7 +1003,7 @@ int main(int argc, char *argv[])
std::string ldcPath = locateBinary(LDC_EXE_NAME, argv[0]); std::string ldcPath = locateBinary(LDC_EXE_NAME, argv[0]);
if (ldcPath.empty()) if (ldcPath.empty())
{ {
error("Could not locate "LDC_EXE_NAME" executable."); error("Could not locate " LDC_EXE_NAME " executable.");
} }
// We need to manually set up argv[0] and the terminating NULL. // We need to manually set up argv[0] and the terminating NULL.

View file

@ -379,25 +379,23 @@ LLFunction* DtoInlineIRFunction(FuncDeclaration* fdecl)
static llvm::FunctionType* DtoVaFunctionType(FuncDeclaration* fdecl) static llvm::FunctionType* DtoVaFunctionType(FuncDeclaration* fdecl)
{ {
IrFuncTy &irFty = fdecl->irFty; IrFuncTy &irFty = fdecl->irFty;
LLFunctionType* type = 0; if (irFty.funcType) return irFty.funcType;
// create new ir funcTy
irFty.reset();
irFty.ret = new IrFuncTyArg(Type::tvoid, false); irFty.ret = new IrFuncTyArg(Type::tvoid, false);
irFty.args.push_back(new IrFuncTyArg(Type::tvoid->pointerTo(), false)); irFty.args.push_back(new IrFuncTyArg(Type::tvoid->pointerTo(), false));
if (fdecl->llvmInternal == LLVMva_start) if (fdecl->llvmInternal == LLVMva_start)
type = GET_INTRINSIC_DECL(vastart)->getFunctionType(); irFty.funcType = GET_INTRINSIC_DECL(vastart)->getFunctionType();
else if (fdecl->llvmInternal == LLVMva_copy) { else if (fdecl->llvmInternal == LLVMva_copy) {
type = GET_INTRINSIC_DECL(vacopy)->getFunctionType(); irFty.funcType = GET_INTRINSIC_DECL(vacopy)->getFunctionType();
irFty.args.push_back(new IrFuncTyArg(Type::tvoid->pointerTo(), false)); irFty.args.push_back(new IrFuncTyArg(Type::tvoid->pointerTo(), false));
} }
else if (fdecl->llvmInternal == LLVMva_end) else if (fdecl->llvmInternal == LLVMva_end)
type = GET_INTRINSIC_DECL(vaend)->getFunctionType(); irFty.funcType = GET_INTRINSIC_DECL(vaend)->getFunctionType();
assert(type); assert(irFty.funcType);
return type; return irFty.funcType;
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////

View file

@ -127,51 +127,6 @@ struct IrFuncTy
reverseParams(false) reverseParams(false)
{} {}
#if defined(_MSC_VER)
// Copy constructor and operator= seems to be required for MSC
IrFuncTy(const IrFuncTy& rhs)
: funcType(rhs.funcType),
ret(rhs.ret),
args(IrFuncTy::ArgList(rhs.args)),
arg_sret(rhs.arg_sret),
arg_this(rhs.arg_this),
arg_nest(rhs.arg_nest),
arg_arguments(rhs.arg_arguments),
arg_argptr(rhs.arg_argptr),
c_vararg(rhs.c_vararg),
reverseParams(rhs.reverseParams)
{}
IrFuncTy& operator=(const IrFuncTy& rhs)
{
funcType = rhs.funcType;
ret = rhs.ret;
args = IrFuncTy::ArgList(rhs.args);
arg_sret = rhs.arg_sret;
arg_this = rhs.arg_this;
arg_nest = rhs.arg_nest;
arg_arguments = rhs.arg_arguments;
arg_argptr = rhs.arg_argptr;
c_vararg = rhs.c_vararg;
reverseParams = rhs.reverseParams;
return *this;
}
#endif
void reset() {
funcType = 0;
ret = NULL;
arg_sret = arg_this = arg_nest = arg_arguments = arg_argptr = NULL;
#if defined(_MSC_VER)
args = IrFuncTy::ArgList();
#else
args.clear();
#endif
c_vararg = false;
reverseParams = false;
}
llvm::Value* putRet(Type* dty, DValue* dval); llvm::Value* putRet(Type* dty, DValue* dval);
llvm::Value* getRet(Type* dty, DValue* dval); llvm::Value* getRet(Type* dty, DValue* dval);