First import of dmd-2.065-b1 (7088593).

The CPP mangling is not integrated yet.
This commit is contained in:
Kai Nacke
2013-12-06 16:59:41 +01:00
parent 2fa997e6ad
commit 1de68a45b8
78 changed files with 3480 additions and 4561 deletions

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

@@ -520,6 +520,16 @@ int ld_type(longdouble x)
size_t ld_sprint(char* str, int fmt, longdouble x)
{
// ensure dmc compatible strings for nan and inf
switch(ld_type(x))
{
case LD_TYPE_QNAN:
case LD_TYPE_SNAN:
return sprintf(str, "nan");
case LD_TYPE_INFINITE:
return sprintf(str, x.sign ? "-inf" : "inf");
}
// fmt is 'a','A','f' or 'g'
if(fmt != 'a' && fmt != 'A')
{
@@ -537,16 +547,8 @@ size_t ld_sprint(char* str, int fmt, longdouble x)
unsigned short exp = x.exponent;
unsigned long long mantissa = x.mantissa;
switch(ld_type(x))
{
case LD_TYPE_ZERO:
if(ld_type(x) == LD_TYPE_ZERO)
return sprintf(str, "0x0.0L");
case LD_TYPE_QNAN:
case LD_TYPE_SNAN:
return sprintf(str, "NAN");
case LD_TYPE_INFINITE:
return sprintf(str, x.sign ? "-INF" : "INF");
}
size_t len = 0;
if(x.sign)

View File

@@ -763,7 +763,7 @@ int Port::isInfinity(double r)
longdouble Port::fmodl(longdouble x, longdouble y)
{
#if __FreeBSD__ || __OpenBSD__
#if __FreeBSD__ && __FreeBSD_version < 800000 || __OpenBSD__
return ::fmod(x, y); // hack for now, fix later
#else
return ::fmodl(x, y);

View File

@@ -18,10 +18,6 @@
Mem mem;
void Mem::init()
{
}
char *Mem::strdup(const char *s)
{
char *p;
@@ -118,24 +114,6 @@ void Mem::error()
exit(EXIT_FAILURE);
}
void Mem::fullcollect()
{
}
void Mem::mark(void *pointer)
{
(void) pointer; // necessary for VC /W4
}
void Mem::setStackBottom(void *bottom)
{
}
void Mem::addroots(char* pStart, char* pEnd)
{
}
/* =================================================== */
#if defined(__has_feature)

View File

@@ -15,44 +15,17 @@
#endif
#include <stddef.h> // for size_t
typedef void (*FINALIZERPROC)(void* pObj, void* pClientData);
struct GC; // thread specific allocator
struct Mem
{
GC *gc; // pointer to our thread specific allocator
Mem() { gc = NULL; }
void init();
// Derive from Mem to get these storage allocators instead of global new/delete
void * operator new(size_t m_size);
void * operator new(size_t m_size, Mem *mem);
void * operator new(size_t m_size, GC *gc);
void operator delete(void *p);
void * operator new[](size_t m_size);
void operator delete[](void *p);
Mem() { }
char *strdup(const char *s);
void *malloc(size_t size);
void *malloc_uncollectable(size_t size);
void *calloc(size_t size, size_t n);
void *realloc(void *p, size_t size);
void free(void *p);
void free_uncollectable(void *p);
void *mallocdup(void *o, size_t size);
void error();
void check(void *p); // validate pointer
void fullcollect(); // do full garbage collection
void fullcollectNoStack(); // do full garbage collection, no scan stack
void mark(void *pointer);
void addroots(char* pStart, char* pEnd);
void removeroots(char* pStart);
void setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData);
void setStackBottom(void *bottom);
GC *getThreadGC(); // get apartment allocator for this thread
};
extern Mem mem;

View File

@@ -103,11 +103,6 @@ bool RootObject::equals(RootObject *o)
return o == this;
}
hash_t RootObject::hashCode()
{
return (hash_t) this;
}
int RootObject::compare(RootObject *obj)
{
return this - obj;
@@ -133,104 +128,10 @@ void RootObject::toBuffer(OutBuffer *b)
b->writestring("Object");
}
void RootObject::mark()
{
}
/****************************** String ********************************/
String::String(const char *str)
: str(mem.strdup(str))
{
}
String::~String()
{
mem.free((void *)str);
}
void String::mark()
{
mem.mark((void *)str);
}
hash_t String::calcHash(const char *str, size_t len)
{
hash_t hash = 0;
for (;;)
{
switch (len)
{
case 0:
return hash;
case 1:
hash *= 37;
hash += *(uint8_t *)str;
return hash;
case 2:
hash *= 37;
hash += *(uint16_t *)str;
return hash;
case 3:
hash *= 37;
hash += (*(uint16_t *)str << 8) +
((uint8_t *)str)[2];
return hash;
default:
hash *= 37;
hash += *(uint32_t *)str;
str += 4;
len -= 4;
break;
}
}
}
hash_t String::calcHash(const char *str)
{
return calcHash(str, strlen(str));
}
hash_t String::hashCode()
{
return calcHash(str, strlen(str));
}
size_t String::len()
{
return strlen(str);
}
bool String::equals(RootObject *obj)
{
return strcmp(str,((String *)obj)->str) == 0;
}
int String::compare(RootObject *obj)
{
return strcmp(str,((String *)obj)->str);
}
char *String::toChars()
{
return (char *)str; // toChars() should really be const
}
void String::print()
{
printf("String '%s'\n",str);
}
/****************************** FileName ********************************/
FileName::FileName(const char *str)
: String(str)
: str(mem.strdup(str))
{
}
@@ -339,51 +240,6 @@ Strings *FileName::splitPath(const char *path)
return array;
}
hash_t FileName::hashCode()
{
#if _WIN32
// We need a different hashCode because it must be case-insensitive
size_t len = strlen(str);
hash_t hash = 0;
utf8_t *s = (utf8_t *)str;
for (;;)
{
switch (len)
{
case 0:
return hash;
case 1:
hash *= 37;
hash += *(uint8_t *)s | 0x20;
return hash;
case 2:
hash *= 37;
hash += *(uint16_t *)s | 0x2020;
return hash;
case 3:
hash *= 37;
hash += ((*(uint16_t *)s << 8) +
((uint8_t *)s)[2]) | 0x202020;
break;
default:
hash *= 37;
hash += *(uint32_t *)s | 0x20202020;
s += 4;
len -= 4;
break;
}
}
#else
// darwin HFS is case insensitive, though...
return String::hashCode();
#endif
}
int FileName::compare(RootObject *obj)
{
return compare(str, ((FileName *)obj)->str);
@@ -941,6 +797,11 @@ void FileName::free(const char *str)
mem.free((void *)str);
}
char *FileName::toChars()
{
return (char *)str; // toChars() should really be const
}
/****************************** File ********************************/
@@ -969,7 +830,7 @@ File::~File()
if (ref == 0)
mem.free(buffer);
#if _WIN32
else if (ref == 2)
if (ref == 2)
UnmapViewOfFile(buffer);
#endif
}
@@ -977,13 +838,6 @@ File::~File()
mem.free(touchtime);
}
void File::mark()
{
mem.mark(buffer);
mem.mark(touchtime);
mem.mark(name);
}
/*************************************
*/
@@ -1394,9 +1248,9 @@ Files *File::match(FileName *n)
char *fn;
File *f;
fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1);
fn = (char *)mem.malloc(name - c + strlen(&fileinfo.cFileName[0]) + 1);
memcpy(fn, c, name - c);
strcpy(fn + (name - c), fileinfo.cFileName);
strcpy(fn + (name - c), &fileinfo.cFileName[0]);
f = new File(fn);
f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA));
memcpy(f->touchtime, &fileinfo, sizeof(fileinfo));
@@ -1490,11 +1344,6 @@ char *OutBuffer::extractData()
return p;
}
void OutBuffer::mark()
{
mem.mark(data);
}
void OutBuffer::reserve(size_t nbytes)
{
//printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
@@ -1861,97 +1710,3 @@ char *OutBuffer::toChars()
writeByte(0);
return (char *)data;
}
// TODO: Remove (only used by disabled GC)
/********************************* Bits ****************************/
Bits::Bits()
{
data = NULL;
bitdim = 0;
allocdim = 0;
}
Bits::~Bits()
{
mem.free(data);
}
void Bits::mark()
{
mem.mark(data);
}
void Bits::resize(unsigned bitdim)
{
unsigned allocdim;
unsigned mask;
allocdim = (bitdim + 31) / 32;
data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0]));
if (this->allocdim < allocdim)
memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0]));
// Clear other bits in last word
mask = (1 << (bitdim & 31)) - 1;
if (mask)
data[allocdim - 1] &= ~mask;
this->bitdim = bitdim;
this->allocdim = allocdim;
}
void Bits::set(unsigned bitnum)
{
data[bitnum / 32] |= 1 << (bitnum & 31);
}
void Bits::clear(unsigned bitnum)
{
data[bitnum / 32] &= ~(1 << (bitnum & 31));
}
int Bits::test(unsigned bitnum)
{
return data[bitnum / 32] & (1 << (bitnum & 31));
}
void Bits::set()
{ unsigned mask;
memset(data, ~0, allocdim * sizeof(data[0]));
// Clear other bits in last word
mask = (1 << (bitdim & 31)) - 1;
if (mask)
data[allocdim - 1] &= mask;
}
void Bits::clear()
{
memset(data, 0, allocdim * sizeof(data[0]));
}
void Bits::copy(Bits *from)
{
assert(bitdim == from->bitdim);
memcpy(data, from->data, allocdim * sizeof(data[0]));
}
Bits *Bits::clone()
{
Bits *b;
b = new Bits();
b->resize(bitdim);
b->copy(this);
return b;
}
void Bits::sub(Bits *b)
{
unsigned u;
for (u = 0; u < allocdim; u++)
data[u] &= ~b->data[u];
}

View File

@@ -31,8 +31,8 @@ struct OutBuffer;
// Can't include arraytypes.h here, need to declare these directly.
template <typename TYPE> struct Array;
typedef Array<class File> Files;
typedef Array<char> Strings;
typedef Array<struct File> Files;
typedef Array<const char> Strings;
class RootObject
@@ -43,11 +43,6 @@ public:
virtual bool equals(RootObject *o);
/**
* Returns a hash code, useful for things like building hash tables of Objects.
*/
virtual hash_t hashCode();
/**
* Return <0, ==0, or >0 if this is less than, equal to, or greater than obj.
* Useful for sorting Objects.
@@ -67,38 +62,13 @@ public:
* defined by the library user. For Object, the return value is 0.
*/
virtual int dyncast();
/**
* Marks pointers for garbage collector by calling mem.mark() for all pointers into heap.
*/
/*virtual*/ // not used, disable for now
void mark();
};
class String : public RootObject
{
public:
const char *str; // the string itself
String(const char *str);
~String();
static hash_t calcHash(const char *str, size_t len);
static hash_t calcHash(const char *str);
hash_t hashCode();
size_t len();
bool equals(RootObject *obj);
int compare(RootObject *obj);
char *toChars();
void print();
void mark();
};
class FileName : public String
struct FileName
{
public:
const char *str;
FileName(const char *str);
hash_t hashCode();
bool equals(RootObject *obj);
static int equals(const char *name1, const char *name2);
int compare(RootObject *obj);
@@ -129,9 +99,10 @@ public:
static const char *canonicalName(const char *name);
static void free(const char *str);
char *toChars();
};
class File : public RootObject
struct File
{
public:
int ref; // != 0 if this is a reference to someone else's buffer
@@ -145,8 +116,6 @@ public:
File(const FileName *);
~File();
void mark();
char *toChars();
/* Read file, return !=0 if error
@@ -250,7 +219,6 @@ struct OutBuffer
OutBuffer();
~OutBuffer();
char *extractData();
void mark();
void reserve(size_t nbytes);
void setsize(size_t size);
@@ -308,13 +276,6 @@ struct Array
mem.free(data);
}
void mark()
{
mem.mark(data);
for (size_t u = 0; u < dim; u++)
mem.mark(data[u]); // BUG: what if arrays of Object's?
}
char *toChars()
{
char **buf = (char **)malloc(dim * sizeof(char *));
@@ -522,30 +483,4 @@ struct Array
}
};
// TODO: Remove (only used by disabled GC)
class Bits : public RootObject
{
public:
unsigned bitdim;
unsigned allocdim;
unsigned *data;
Bits();
~Bits();
void mark();
void resize(unsigned bitdim);
void set(unsigned bitnum);
void clear(unsigned bitnum);
int test(unsigned bitnum);
void set();
void clear();
void copy(Bits *from);
Bits *clone();
void sub(Bits *b);
};
#endif

View File

@@ -203,7 +203,8 @@ void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset)
{
size_t seedlen = strlen(seed);
for (int distance = 0; distance < 2; distance++)
size_t maxdist = seedlen < 3 ? seedlen - 1 : 2;
for (int distance = 0; distance < maxdist; distance++)
{ void *p = spellerX(seed, seedlen, fp, fparg, charset, distance);
if (p)
return p;