X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fsquirrel%2Fsquirrel%2Fsqstate.cpp;h=85da8c8c3e950457c5be58b014a0134963fff78f;hb=a113d3bd1feddd510e3b2852b0d42522735eee40;hp=475afe96c33cce79feace1b3984b8fd396898de9;hpb=ff4c6994b952e26b854461d739eb3bcbfc30719f;p=supertux.git diff --git a/src/squirrel/squirrel/sqstate.cpp b/src/squirrel/squirrel/sqstate.cpp index 475afe96c..85da8c8c3 100644 --- a/src/squirrel/squirrel/sqstate.cpp +++ b/src/squirrel/squirrel/sqstate.cpp @@ -1,562 +1,562 @@ -/* - see copyright notice in squirrel.h -*/ -#include "sqpcheader.h" -#include "sqopcodes.h" -#include "sqvm.h" -#include "sqfuncproto.h" -#include "sqclosure.h" -#include "sqstring.h" -#include "sqtable.h" -#include "sqarray.h" -#include "squserdata.h" -#include "sqclass.h" - -SQObjectPtr _null_; -SQObjectPtr _true_(true); -SQObjectPtr _false_(false); -SQObjectPtr _one_((SQInteger)1); -SQObjectPtr _minusone_((SQInteger)-1); - -SQSharedState::SQSharedState() -{ - _compilererrorhandler = NULL; - _printfunc = NULL; - _debuginfo = false; - _notifyallexceptions = false; -} - -#define newsysstring(s) { \ - _systemstrings->push_back(SQString::Create(this,s)); \ - } - -#define newmetamethod(s) { \ - _metamethods->push_back(SQString::Create(this,s)); \ - _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \ - } - -bool CompileTypemask(SQIntVec &res,const SQChar *typemask) -{ - SQInteger i = 0; - - SQInteger mask = 0; - while(typemask[i] != 0) { - - switch(typemask[i]){ - case 'o': mask |= _RT_NULL; break; - case 'i': mask |= _RT_INTEGER; break; - case 'f': mask |= _RT_FLOAT; break; - case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break; - case 's': mask |= _RT_STRING; break; - case 't': mask |= _RT_TABLE; break; - case 'a': mask |= _RT_ARRAY; break; - case 'u': mask |= _RT_USERDATA; break; - case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break; - case 'b': mask |= _RT_BOOL; break; - case 'g': mask |= _RT_GENERATOR; break; - case 'p': mask |= _RT_USERPOINTER; break; - case 'v': mask |= _RT_THREAD; break; - case 'x': mask |= _RT_INSTANCE; break; - case 'y': mask |= _RT_CLASS; break; - case 'r': mask |= _RT_WEAKREF; break; - case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue; - case ' ': i++; continue; //ignores spaces - default: - return false; - } - i++; - if(typemask[i] == '|') { - i++; - if(typemask[i] == 0) - return false; - continue; - } - res.push_back(mask); - mask = 0; - - } - return true; -} - -SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz) -{ - SQInteger i=0; - SQTable *t=SQTable::Create(ss,0); - while(funcz[i].name!=0){ - SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f); - nc->_nparamscheck = funcz[i].nparamscheck; - nc->_name = SQString::Create(ss,funcz[i].name); - if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask)) - return NULL; - t->NewSlot(SQString::Create(ss,funcz[i].name),nc); - i++; - } - return t; -} - -void SQSharedState::Init() -{ - _scratchpad=NULL; - _scratchpadsize=0; -#ifndef NO_GARBAGE_COLLECTOR - _gc_chain=NULL; -#endif - sq_new(_stringtable,StringTable); - sq_new(_metamethods,SQObjectPtrVec); - sq_new(_systemstrings,SQObjectPtrVec); - sq_new(_types,SQObjectPtrVec); - _metamethodsmap = SQTable::Create(this,MT_LAST-1); - //adding type strings to avoid memory trashing - //types names - newsysstring(_SC("null")); - newsysstring(_SC("table")); - newsysstring(_SC("array")); - newsysstring(_SC("closure")); - newsysstring(_SC("string")); - newsysstring(_SC("userdata")); - newsysstring(_SC("integer")); - newsysstring(_SC("float")); - newsysstring(_SC("userpointer")); - newsysstring(_SC("function")); - newsysstring(_SC("generator")); - newsysstring(_SC("thread")); - newsysstring(_SC("class")); - newsysstring(_SC("instance")); - newsysstring(_SC("bool")); - //meta methods - newmetamethod(MM_ADD); - newmetamethod(MM_SUB); - newmetamethod(MM_MUL); - newmetamethod(MM_DIV); - newmetamethod(MM_UNM); - newmetamethod(MM_MODULO); - newmetamethod(MM_SET); - newmetamethod(MM_GET); - newmetamethod(MM_TYPEOF); - newmetamethod(MM_NEXTI); - newmetamethod(MM_CMP); - newmetamethod(MM_CALL); - newmetamethod(MM_CLONED); - newmetamethod(MM_NEWSLOT); - newmetamethod(MM_DELSLOT); - newmetamethod(MM_TOSTRING); - newmetamethod(MM_NEWMEMBER); - newmetamethod(MM_INHERITED); - - _constructoridx = SQString::Create(this,_SC("constructor")); - _registry = SQTable::Create(this,0); - _table_default_delegate=CreateDefaultDelegate(this,_table_default_delegate_funcz); - _array_default_delegate=CreateDefaultDelegate(this,_array_default_delegate_funcz); - _string_default_delegate=CreateDefaultDelegate(this,_string_default_delegate_funcz); - _number_default_delegate=CreateDefaultDelegate(this,_number_default_delegate_funcz); - _closure_default_delegate=CreateDefaultDelegate(this,_closure_default_delegate_funcz); - _generator_default_delegate=CreateDefaultDelegate(this,_generator_default_delegate_funcz); - _thread_default_delegate=CreateDefaultDelegate(this,_thread_default_delegate_funcz); - _class_default_delegate=CreateDefaultDelegate(this,_class_default_delegate_funcz); - _instance_default_delegate=CreateDefaultDelegate(this,_instance_default_delegate_funcz); - _weakref_default_delegate=CreateDefaultDelegate(this,_weakref_default_delegate_funcz); - -} - -SQSharedState::~SQSharedState() -{ - _constructoridx = _null_; - _refs_table.Finalize(); - _table(_registry)->Finalize(); - _table(_metamethodsmap)->Finalize(); -// _refs_table = _null_; - _registry = _null_; - _metamethodsmap = _null_; - while(!_systemstrings->empty()){ - _systemstrings->back()=_null_; - _systemstrings->pop_back(); - } - _thread(_root_vm)->Finalize(); - _root_vm = _null_; - _table_default_delegate=_null_; - _array_default_delegate=_null_; - _string_default_delegate=_null_; - _number_default_delegate=_null_; - _closure_default_delegate=_null_; - _generator_default_delegate=_null_; - _thread_default_delegate=_null_; - _class_default_delegate=_null_; - _instance_default_delegate=_null_; - _weakref_default_delegate=_null_; - -#ifndef NO_GARBAGE_COLLECTOR - - - SQCollectable *t=_gc_chain; - SQCollectable *nx=NULL; - while(t){ - t->_uiRef++; - t->Finalize(); - nx=t->_next; - if(--t->_uiRef==0) - t->Release(); - t=nx; - } - assert(_gc_chain==NULL); //just to proove a theory - while(_gc_chain){ - _gc_chain->_uiRef++; - _gc_chain->Release(); - } -#endif - sq_delete(_types,SQObjectPtrVec); - sq_delete(_systemstrings,SQObjectPtrVec); - sq_delete(_metamethods,SQObjectPtrVec); - sq_delete(_stringtable,StringTable); - if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize); -} - - -SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) -{ - if(type(name) != OT_STRING) - return -1; - SQObjectPtr ret; - if(_table(_metamethodsmap)->Get(name,ret)) { - return _integer(ret); - } - return -1; -} - -#ifndef NO_GARBAGE_COLLECTOR - -void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) -{ - switch(type(o)){ - case OT_TABLE:_table(o)->Mark(chain);break; - case OT_ARRAY:_array(o)->Mark(chain);break; - case OT_USERDATA:_userdata(o)->Mark(chain);break; - case OT_CLOSURE:_closure(o)->Mark(chain);break; - case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; - case OT_GENERATOR:_generator(o)->Mark(chain);break; - case OT_THREAD:_thread(o)->Mark(chain);break; - case OT_CLASS:_class(o)->Mark(chain);break; - case OT_INSTANCE:_instance(o)->Mark(chain);break; - default: break; //shutup compiler - } -} - - -SQInteger SQSharedState::CollectGarbage(SQVM *vm) -{ - SQInteger n=0; - SQCollectable *tchain=NULL; - SQVM *vms=_thread(_root_vm); - - vms->Mark(&tchain); - SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed(); - _refs_table.Mark(&tchain); - MarkObject(_registry,&tchain); - MarkObject(_metamethodsmap,&tchain); - MarkObject(_table_default_delegate,&tchain); - MarkObject(_array_default_delegate,&tchain); - MarkObject(_string_default_delegate,&tchain); - MarkObject(_number_default_delegate,&tchain); - MarkObject(_generator_default_delegate,&tchain); - MarkObject(_thread_default_delegate,&tchain); - MarkObject(_closure_default_delegate,&tchain); - MarkObject(_class_default_delegate,&tchain); - MarkObject(_instance_default_delegate,&tchain); - MarkObject(_weakref_default_delegate,&tchain); - - SQCollectable *t=_gc_chain; - SQCollectable *nx=NULL; - while(t){ - t->_uiRef++; - t->Finalize(); - nx=t->_next; - if(--t->_uiRef==0) - t->Release(); - t=nx; - n++; - } - - t=tchain; - while(t){ - t->UnMark(); - t=t->_next; - } - _gc_chain=tchain; - SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed(); - assert(z == x); - return n; -} -#endif - -#ifndef NO_GARBAGE_COLLECTOR -void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c) -{ - c->_prev=NULL; - c->_next=*chain; - if(*chain) (*chain)->_prev=c; - *chain=c; -} - -void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c) -{ - if(c->_prev) c->_prev->_next=c->_next; - else *chain=c->_next; - if(c->_next) - c->_next->_prev=c->_prev; - c->_next=NULL; - c->_prev=NULL; -} -#endif - -SQChar* SQSharedState::GetScratchPad(SQInteger size) -{ - SQInteger newsize; - if(size>0){ - if(_scratchpadsize>1); - _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); - _scratchpadsize=newsize; - - }else if(_scratchpadsize>=(size<<5)){ - newsize=_scratchpadsize>>1; - _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); - _scratchpadsize=newsize; - } - } - return _scratchpad; -} - -RefTable::RefTable() -{ - AllocNodes(4); -} - -void RefTable::Finalize() -{ - RefNode *nodes = (RefNode *)&_buckets[_numofslots]; - for(SQUnsignedInteger n = 0; n < _numofslots; n++) { - nodes->obj = _null_; - nodes++; - } -} - -RefTable::~RefTable() -{ - SQ_FREE(_buckets,_buffersize); -} -#ifndef NO_GARBAGE_COLLECTOR -void RefTable::Mark(SQCollectable **chain) -{ - RefNode *nodes = (RefNode *)&_buckets[_numofslots]; - for(SQUnsignedInteger n = 0; n < _numofslots; n++) { - if(type(nodes->obj) != OT_NULL) { - SQSharedState::MarkObject(nodes->obj,chain); - } - nodes++; - } -} -#endif -void RefTable::AddRef(SQObject &obj) -{ - SQHash mainpos; - RefNode *prev; - RefNode *ref = Get(obj,mainpos,&prev,true); - ref->refs++; -} - -SQBool RefTable::Release(SQObject &obj) -{ - SQHash mainpos; - RefNode *prev; - RefNode *ref = Get(obj,mainpos,&prev,false); - if(ref) { - if(--ref->refs == 0) { - ref->obj = _null_; - if(prev) { - prev->next = ref->next; - } - else { - _buckets[mainpos] = ref->next; - } - ref->next = _freelist; - _freelist = ref; - _slotused--; - //<>test for shrink? - return SQTrue; - } - } - return SQFalse; -} - -void RefTable::Resize(SQUnsignedInteger size) -{ - RefNode **oldbuffer = _buckets; - RefNode *oldnodes = (RefNode *)&_buckets[_numofslots]; - SQUnsignedInteger oldnumofslots = _numofslots; - SQUnsignedInteger oldbuffersize = _buffersize; - AllocNodes(size); - //rehash - for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) { - if(type(oldnodes->obj) != OT_NULL) { - //add back; - assert(oldnodes->refs != 0); - RefNode *nn = Add(::HashObj(oldnodes->obj)&(_numofslots-1),oldnodes->obj); - nn->refs = oldnodes->refs; - oldnodes->obj = _null_; - } - oldnodes++; - } - SQ_FREE(oldbuffer,oldbuffersize); -} - -RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj) -{ - RefNode *t = _buckets[mainpos]; - RefNode *newnode = _freelist; - newnode->obj = obj; - _buckets[mainpos] = newnode; - _freelist = _freelist->next; - newnode->next = t; - assert(newnode->refs == 0); - _slotused++; - return newnode; -} - -RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add) -{ - RefNode *ref; - mainpos = ::HashObj(obj)&(_numofslots-1); - *prev = NULL; - for (ref = _buckets[mainpos]; ref; ) { - if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj)) - break; - *prev = ref; - ref = ref->next; - } - if(ref == NULL && add) { - if(_numofslots == _slotused) { - Resize(_numofslots*2); - } - ref = Add(mainpos,obj); - } - return ref; -} - -void RefTable::AllocNodes(SQUnsignedInteger size) -{ - RefNode **bucks; - RefNode *firstnode; - _buffersize = size * sizeof(RefNode *) + size * sizeof(RefNode); - bucks = (RefNode **)SQ_MALLOC(_buffersize); - firstnode = (RefNode *)&bucks[size]; - RefNode *temp = firstnode; - SQUnsignedInteger n; - for(n = 0; n < size - 1; n++) { - bucks[n] = NULL; - temp->refs = 0; - new (&temp->obj) SQObjectPtr; - temp->next = temp+1; - temp++; - } - bucks[n] = NULL; - temp->refs = 0; - new (&temp->obj) SQObjectPtr; - temp->next = NULL; - _freelist = firstnode; - _buckets = bucks; - _slotused = 0; - _numofslots = size; -} -////////////////////////////////////////////////////////////////////////// -//StringTable -/* -* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) -* http://www.lua.org/copyright.html#4 -* http://www.lua.org/source/4.0.1/src_lstring.c.html -*/ - -StringTable::StringTable() -{ - AllocNodes(4); - _slotused = 0; -} - -StringTable::~StringTable() -{ - SQ_FREE(_strings,sizeof(SQString*)*_numofslots); - _strings=NULL; -} - -void StringTable::AllocNodes(SQInteger size) -{ - _numofslots=size; - //_slotused=0; - _strings=(SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots); - memset(_strings,0,sizeof(SQString*)*_numofslots); -} - -SQString *StringTable::Add(const SQChar *news,SQInteger len) -{ - if(len<0) - len = (SQInteger)scstrlen(news); - SQHash h = ::_hashstr(news,len)&(_numofslots-1); - SQString *s; - for (s = _strings[h]; s; s = s->_next){ - if(s->_len == len && (!memcmp(news,s->_val,rsl(len)))) - return s; //found - } - - SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString)); - new (t) SQString; - memcpy(t->_val,news,rsl(len)); - t->_val[len] = _SC('\0'); - t->_len = len; - t->_hash = ::_hashstr(news,len); - t->_next = _strings[h]; - _strings[h] = t; - _slotused++; - if (_slotused > _numofslots) /* too crowded? */ - Resize(_numofslots*2); - return t; -} - -void StringTable::Resize(SQInteger size) -{ - SQInteger oldsize=_numofslots; - SQString **oldtable=_strings; - AllocNodes(size); - for (SQInteger i=0; i_next; - SQHash h = p->_hash&(_numofslots-1); - p->_next = _strings[h]; - _strings[h] = p; - p = next; - } - } - SQ_FREE(oldtable,oldsize*sizeof(SQString*)); -} - -void StringTable::Remove(SQString *bs) -{ - SQString *s; - SQString *prev=NULL; - SQHash h = bs->_hash&(_numofslots - 1); - - for (s = _strings[h]; s; ){ - if(s == bs){ - if(prev) - prev->_next = s->_next; - else - _strings[h] = s->_next; - _slotused--; - SQInteger slen = s->_len; - s->~SQString(); - SQ_FREE(s,sizeof(SQString) + rsl(slen)); - return; - } - prev = s; - s = s->_next; - } - assert(0);//if this fail something is wrong -} +/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqopcodes.h" +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "squserdata.h" +#include "sqclass.h" + +SQObjectPtr _null_; +SQObjectPtr _true_(true); +SQObjectPtr _false_(false); +SQObjectPtr _one_((SQInteger)1); +SQObjectPtr _minusone_((SQInteger)-1); + +SQSharedState::SQSharedState() +{ + _compilererrorhandler = NULL; + _printfunc = NULL; + _debuginfo = false; + _notifyallexceptions = false; +} + +#define newsysstring(s) { \ + _systemstrings->push_back(SQString::Create(this,s)); \ + } + +#define newmetamethod(s) { \ + _metamethods->push_back(SQString::Create(this,s)); \ + _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \ + } + +bool CompileTypemask(SQIntVec &res,const SQChar *typemask) +{ + SQInteger i = 0; + + SQInteger mask = 0; + while(typemask[i] != 0) { + + switch(typemask[i]){ + case 'o': mask |= _RT_NULL; break; + case 'i': mask |= _RT_INTEGER; break; + case 'f': mask |= _RT_FLOAT; break; + case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break; + case 's': mask |= _RT_STRING; break; + case 't': mask |= _RT_TABLE; break; + case 'a': mask |= _RT_ARRAY; break; + case 'u': mask |= _RT_USERDATA; break; + case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break; + case 'b': mask |= _RT_BOOL; break; + case 'g': mask |= _RT_GENERATOR; break; + case 'p': mask |= _RT_USERPOINTER; break; + case 'v': mask |= _RT_THREAD; break; + case 'x': mask |= _RT_INSTANCE; break; + case 'y': mask |= _RT_CLASS; break; + case 'r': mask |= _RT_WEAKREF; break; + case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue; + case ' ': i++; continue; //ignores spaces + default: + return false; + } + i++; + if(typemask[i] == '|') { + i++; + if(typemask[i] == 0) + return false; + continue; + } + res.push_back(mask); + mask = 0; + + } + return true; +} + +SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz) +{ + SQInteger i=0; + SQTable *t=SQTable::Create(ss,0); + while(funcz[i].name!=0){ + SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f); + nc->_nparamscheck = funcz[i].nparamscheck; + nc->_name = SQString::Create(ss,funcz[i].name); + if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask)) + return NULL; + t->NewSlot(SQString::Create(ss,funcz[i].name),nc); + i++; + } + return t; +} + +void SQSharedState::Init() +{ + _scratchpad=NULL; + _scratchpadsize=0; +#ifndef NO_GARBAGE_COLLECTOR + _gc_chain=NULL; +#endif + sq_new(_stringtable,StringTable); + sq_new(_metamethods,SQObjectPtrVec); + sq_new(_systemstrings,SQObjectPtrVec); + sq_new(_types,SQObjectPtrVec); + _metamethodsmap = SQTable::Create(this,MT_LAST-1); + //adding type strings to avoid memory trashing + //types names + newsysstring(_SC("null")); + newsysstring(_SC("table")); + newsysstring(_SC("array")); + newsysstring(_SC("closure")); + newsysstring(_SC("string")); + newsysstring(_SC("userdata")); + newsysstring(_SC("integer")); + newsysstring(_SC("float")); + newsysstring(_SC("userpointer")); + newsysstring(_SC("function")); + newsysstring(_SC("generator")); + newsysstring(_SC("thread")); + newsysstring(_SC("class")); + newsysstring(_SC("instance")); + newsysstring(_SC("bool")); + //meta methods + newmetamethod(MM_ADD); + newmetamethod(MM_SUB); + newmetamethod(MM_MUL); + newmetamethod(MM_DIV); + newmetamethod(MM_UNM); + newmetamethod(MM_MODULO); + newmetamethod(MM_SET); + newmetamethod(MM_GET); + newmetamethod(MM_TYPEOF); + newmetamethod(MM_NEXTI); + newmetamethod(MM_CMP); + newmetamethod(MM_CALL); + newmetamethod(MM_CLONED); + newmetamethod(MM_NEWSLOT); + newmetamethod(MM_DELSLOT); + newmetamethod(MM_TOSTRING); + newmetamethod(MM_NEWMEMBER); + newmetamethod(MM_INHERITED); + + _constructoridx = SQString::Create(this,_SC("constructor")); + _registry = SQTable::Create(this,0); + _table_default_delegate=CreateDefaultDelegate(this,_table_default_delegate_funcz); + _array_default_delegate=CreateDefaultDelegate(this,_array_default_delegate_funcz); + _string_default_delegate=CreateDefaultDelegate(this,_string_default_delegate_funcz); + _number_default_delegate=CreateDefaultDelegate(this,_number_default_delegate_funcz); + _closure_default_delegate=CreateDefaultDelegate(this,_closure_default_delegate_funcz); + _generator_default_delegate=CreateDefaultDelegate(this,_generator_default_delegate_funcz); + _thread_default_delegate=CreateDefaultDelegate(this,_thread_default_delegate_funcz); + _class_default_delegate=CreateDefaultDelegate(this,_class_default_delegate_funcz); + _instance_default_delegate=CreateDefaultDelegate(this,_instance_default_delegate_funcz); + _weakref_default_delegate=CreateDefaultDelegate(this,_weakref_default_delegate_funcz); + +} + +SQSharedState::~SQSharedState() +{ + _constructoridx = _null_; + _refs_table.Finalize(); + _table(_registry)->Finalize(); + _table(_metamethodsmap)->Finalize(); +// _refs_table = _null_; + _registry = _null_; + _metamethodsmap = _null_; + while(!_systemstrings->empty()){ + _systemstrings->back()=_null_; + _systemstrings->pop_back(); + } + _thread(_root_vm)->Finalize(); + _root_vm = _null_; + _table_default_delegate=_null_; + _array_default_delegate=_null_; + _string_default_delegate=_null_; + _number_default_delegate=_null_; + _closure_default_delegate=_null_; + _generator_default_delegate=_null_; + _thread_default_delegate=_null_; + _class_default_delegate=_null_; + _instance_default_delegate=_null_; + _weakref_default_delegate=_null_; + +#ifndef NO_GARBAGE_COLLECTOR + + + SQCollectable *t=_gc_chain; + SQCollectable *nx=NULL; + while(t){ + t->_uiRef++; + t->Finalize(); + nx=t->_next; + if(--t->_uiRef==0) + t->Release(); + t=nx; + } + assert(_gc_chain==NULL); //just to proove a theory + while(_gc_chain){ + _gc_chain->_uiRef++; + _gc_chain->Release(); + } +#endif + sq_delete(_types,SQObjectPtrVec); + sq_delete(_systemstrings,SQObjectPtrVec); + sq_delete(_metamethods,SQObjectPtrVec); + sq_delete(_stringtable,StringTable); + if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize); +} + + +SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) +{ + if(type(name) != OT_STRING) + return -1; + SQObjectPtr ret; + if(_table(_metamethodsmap)->Get(name,ret)) { + return _integer(ret); + } + return -1; +} + +#ifndef NO_GARBAGE_COLLECTOR + +void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) +{ + switch(type(o)){ + case OT_TABLE:_table(o)->Mark(chain);break; + case OT_ARRAY:_array(o)->Mark(chain);break; + case OT_USERDATA:_userdata(o)->Mark(chain);break; + case OT_CLOSURE:_closure(o)->Mark(chain);break; + case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; + case OT_GENERATOR:_generator(o)->Mark(chain);break; + case OT_THREAD:_thread(o)->Mark(chain);break; + case OT_CLASS:_class(o)->Mark(chain);break; + case OT_INSTANCE:_instance(o)->Mark(chain);break; + default: break; //shutup compiler + } +} + + +SQInteger SQSharedState::CollectGarbage(SQVM *vm) +{ + SQInteger n=0; + SQCollectable *tchain=NULL; + SQVM *vms=_thread(_root_vm); + + vms->Mark(&tchain); + SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed(); + _refs_table.Mark(&tchain); + MarkObject(_registry,&tchain); + MarkObject(_metamethodsmap,&tchain); + MarkObject(_table_default_delegate,&tchain); + MarkObject(_array_default_delegate,&tchain); + MarkObject(_string_default_delegate,&tchain); + MarkObject(_number_default_delegate,&tchain); + MarkObject(_generator_default_delegate,&tchain); + MarkObject(_thread_default_delegate,&tchain); + MarkObject(_closure_default_delegate,&tchain); + MarkObject(_class_default_delegate,&tchain); + MarkObject(_instance_default_delegate,&tchain); + MarkObject(_weakref_default_delegate,&tchain); + + SQCollectable *t=_gc_chain; + SQCollectable *nx=NULL; + while(t){ + t->_uiRef++; + t->Finalize(); + nx=t->_next; + if(--t->_uiRef==0) + t->Release(); + t=nx; + n++; + } + + t=tchain; + while(t){ + t->UnMark(); + t=t->_next; + } + _gc_chain=tchain; + SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed(); + assert(z == x); + return n; +} +#endif + +#ifndef NO_GARBAGE_COLLECTOR +void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c) +{ + c->_prev=NULL; + c->_next=*chain; + if(*chain) (*chain)->_prev=c; + *chain=c; +} + +void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c) +{ + if(c->_prev) c->_prev->_next=c->_next; + else *chain=c->_next; + if(c->_next) + c->_next->_prev=c->_prev; + c->_next=NULL; + c->_prev=NULL; +} +#endif + +SQChar* SQSharedState::GetScratchPad(SQInteger size) +{ + SQInteger newsize; + if(size>0){ + if(_scratchpadsize>1); + _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize=newsize; + + }else if(_scratchpadsize>=(size<<5)){ + newsize=_scratchpadsize>>1; + _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize=newsize; + } + } + return _scratchpad; +} + +RefTable::RefTable() +{ + AllocNodes(4); +} + +void RefTable::Finalize() +{ + RefNode *nodes = (RefNode *)&_buckets[_numofslots]; + for(SQUnsignedInteger n = 0; n < _numofslots; n++) { + nodes->obj = _null_; + nodes++; + } +} + +RefTable::~RefTable() +{ + SQ_FREE(_buckets,_buffersize); +} +#ifndef NO_GARBAGE_COLLECTOR +void RefTable::Mark(SQCollectable **chain) +{ + RefNode *nodes = (RefNode *)&_buckets[_numofslots]; + for(SQUnsignedInteger n = 0; n < _numofslots; n++) { + if(type(nodes->obj) != OT_NULL) { + SQSharedState::MarkObject(nodes->obj,chain); + } + nodes++; + } +} +#endif +void RefTable::AddRef(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,true); + ref->refs++; +} + +SQBool RefTable::Release(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,false); + if(ref) { + if(--ref->refs == 0) { + ref->obj = _null_; + if(prev) { + prev->next = ref->next; + } + else { + _buckets[mainpos] = ref->next; + } + ref->next = _freelist; + _freelist = ref; + _slotused--; + //<>test for shrink? + return SQTrue; + } + } + return SQFalse; +} + +void RefTable::Resize(SQUnsignedInteger size) +{ + RefNode **oldbuffer = _buckets; + RefNode *oldnodes = (RefNode *)&_buckets[_numofslots]; + SQUnsignedInteger oldnumofslots = _numofslots; + SQUnsignedInteger oldbuffersize = _buffersize; + AllocNodes(size); + //rehash + for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) { + if(type(oldnodes->obj) != OT_NULL) { + //add back; + assert(oldnodes->refs != 0); + RefNode *nn = Add(::HashObj(oldnodes->obj)&(_numofslots-1),oldnodes->obj); + nn->refs = oldnodes->refs; + oldnodes->obj = _null_; + } + oldnodes++; + } + SQ_FREE(oldbuffer,oldbuffersize); +} + +RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj) +{ + RefNode *t = _buckets[mainpos]; + RefNode *newnode = _freelist; + newnode->obj = obj; + _buckets[mainpos] = newnode; + _freelist = _freelist->next; + newnode->next = t; + assert(newnode->refs == 0); + _slotused++; + return newnode; +} + +RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add) +{ + RefNode *ref; + mainpos = ::HashObj(obj)&(_numofslots-1); + *prev = NULL; + for (ref = _buckets[mainpos]; ref; ) { + if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj)) + break; + *prev = ref; + ref = ref->next; + } + if(ref == NULL && add) { + if(_numofslots == _slotused) { + Resize(_numofslots*2); + } + ref = Add(mainpos,obj); + } + return ref; +} + +void RefTable::AllocNodes(SQUnsignedInteger size) +{ + RefNode **bucks; + RefNode *firstnode; + _buffersize = size * sizeof(RefNode *) + size * sizeof(RefNode); + bucks = (RefNode **)SQ_MALLOC(_buffersize); + firstnode = (RefNode *)&bucks[size]; + RefNode *temp = firstnode; + SQUnsignedInteger n; + for(n = 0; n < size - 1; n++) { + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) SQObjectPtr; + temp->next = temp+1; + temp++; + } + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) SQObjectPtr; + temp->next = NULL; + _freelist = firstnode; + _buckets = bucks; + _slotused = 0; + _numofslots = size; +} +////////////////////////////////////////////////////////////////////////// +//StringTable +/* +* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) +* http://www.lua.org/copyright.html#4 +* http://www.lua.org/source/4.0.1/src_lstring.c.html +*/ + +StringTable::StringTable() +{ + AllocNodes(4); + _slotused = 0; +} + +StringTable::~StringTable() +{ + SQ_FREE(_strings,sizeof(SQString*)*_numofslots); + _strings=NULL; +} + +void StringTable::AllocNodes(SQInteger size) +{ + _numofslots=size; + //_slotused=0; + _strings=(SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots); + memset(_strings,0,sizeof(SQString*)*_numofslots); +} + +SQString *StringTable::Add(const SQChar *news,SQInteger len) +{ + if(len<0) + len = (SQInteger)scstrlen(news); + SQHash h = ::_hashstr(news,len)&(_numofslots-1); + SQString *s; + for (s = _strings[h]; s; s = s->_next){ + if(s->_len == len && (!memcmp(news,s->_val,rsl(len)))) + return s; //found + } + + SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString)); + new (t) SQString; + memcpy(t->_val,news,rsl(len)); + t->_val[len] = _SC('\0'); + t->_len = len; + t->_hash = ::_hashstr(news,len); + t->_next = _strings[h]; + _strings[h] = t; + _slotused++; + if (_slotused > _numofslots) /* too crowded? */ + Resize(_numofslots*2); + return t; +} + +void StringTable::Resize(SQInteger size) +{ + SQInteger oldsize=_numofslots; + SQString **oldtable=_strings; + AllocNodes(size); + for (SQInteger i=0; i_next; + SQHash h = p->_hash&(_numofslots-1); + p->_next = _strings[h]; + _strings[h] = p; + p = next; + } + } + SQ_FREE(oldtable,oldsize*sizeof(SQString*)); +} + +void StringTable::Remove(SQString *bs) +{ + SQString *s; + SQString *prev=NULL; + SQHash h = bs->_hash&(_numofslots - 1); + + for (s = _strings[h]; s; ){ + if(s == bs){ + if(prev) + prev->_next = s->_next; + else + _strings[h] = s->_next; + _slotused--; + SQInteger slen = s->_len; + s->~SQString(); + SQ_FREE(s,sizeof(SQString) + rsl(slen)); + return; + } + prev = s; + s = s->_next; + } + assert(0);//if this fail something is wrong +}