sqstate.cpp

00001 /*
00002   see copyright notice in squirrel.h
00003 */
00004 #include "sqpcheader.h"
00005 #include "sqopcodes.h"
00006 #include "sqvm.h"
00007 #include "sqfuncproto.h"
00008 #include "sqclosure.h"
00009 #include "sqstring.h"
00010 #include "sqtable.h"
00011 #include "sqarray.h"
00012 #include "squserdata.h"
00013 #include "sqclass.h"
00014 
00015 SQObjectPtr _null_;
00016 SQObjectPtr _true_(true);
00017 SQObjectPtr _false_(false);
00018 SQObjectPtr _one_((SQInteger)1);
00019 SQObjectPtr _minusone_((SQInteger)-1);
00020 
00021 SQSharedState::SQSharedState()
00022 {
00023   _compilererrorhandler = NULL;
00024   _printfunc = NULL;
00025   _debuginfo = false;
00026   _notifyallexceptions = false;
00027 }
00028 
00029 #define newsysstring(s) { \
00030   _systemstrings->push_back(SQString::Create(this,s));  \
00031   }
00032 
00033 #define newmetamethod(s) {  \
00034   _metamethods->push_back(SQString::Create(this,s));  \
00035   _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
00036   }
00037 
00038 bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
00039 {
00040   SQInteger i = 0;
00041 
00042   SQInteger mask = 0;
00043   while(typemask[i] != 0) {
00044 
00045     switch(typemask[i]){
00046         case 'o': mask |= _RT_NULL; break;
00047         case 'i': mask |= _RT_INTEGER; break;
00048         case 'f': mask |= _RT_FLOAT; break;
00049         case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;
00050         case 's': mask |= _RT_STRING; break;
00051         case 't': mask |= _RT_TABLE; break;
00052         case 'a': mask |= _RT_ARRAY; break;
00053         case 'u': mask |= _RT_USERDATA; break;
00054         case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;
00055         case 'b': mask |= _RT_BOOL; break;
00056         case 'g': mask |= _RT_GENERATOR; break;
00057         case 'p': mask |= _RT_USERPOINTER; break;
00058         case 'v': mask |= _RT_THREAD; break;
00059         case 'x': mask |= _RT_INSTANCE; break;
00060         case 'y': mask |= _RT_CLASS; break;
00061         case 'r': mask |= _RT_WEAKREF; break;
00062         case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
00063         case ' ': i++; continue; //ignores spaces
00064         default:
00065           return false;
00066     }
00067     i++;
00068     if(typemask[i] == '|') {
00069       i++;
00070       if(typemask[i] == 0)
00071         return false;
00072       continue;
00073     }
00074     res.push_back(mask);
00075     mask = 0;
00076 
00077   }
00078   return true;
00079 }
00080 
00081 SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz)
00082 {
00083   SQInteger i=0;
00084   SQTable *t=SQTable::Create(ss,0);
00085   while(funcz[i].name!=0){
00086     SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f);
00087     nc->_nparamscheck = funcz[i].nparamscheck;
00088     nc->_name = SQString::Create(ss,funcz[i].name);
00089     if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))
00090       return NULL;
00091     t->NewSlot(SQString::Create(ss,funcz[i].name),nc);
00092     i++;
00093   }
00094   return t;
00095 }
00096 
00097 void SQSharedState::Init()
00098 {
00099   _scratchpad=NULL;
00100   _scratchpadsize=0;
00101 #ifndef NO_GARBAGE_COLLECTOR
00102   _gc_chain=NULL;
00103 #endif
00104   sq_new(_stringtable,StringTable);
00105   sq_new(_metamethods,SQObjectPtrVec);
00106   sq_new(_systemstrings,SQObjectPtrVec);
00107   sq_new(_types,SQObjectPtrVec);
00108   _metamethodsmap = SQTable::Create(this,MT_LAST-1);
00109   //adding type strings to avoid memory trashing
00110   //types names
00111   newsysstring(_SC("null"));
00112   newsysstring(_SC("table"));
00113   newsysstring(_SC("array"));
00114   newsysstring(_SC("closure"));
00115   newsysstring(_SC("string"));
00116   newsysstring(_SC("userdata"));
00117   newsysstring(_SC("integer"));
00118   newsysstring(_SC("float"));
00119   newsysstring(_SC("userpointer"));
00120   newsysstring(_SC("function"));
00121   newsysstring(_SC("generator"));
00122   newsysstring(_SC("thread"));
00123   newsysstring(_SC("class"));
00124   newsysstring(_SC("instance"));
00125   newsysstring(_SC("bool"));
00126   //meta methods
00127   newmetamethod(MM_ADD);
00128   newmetamethod(MM_SUB);
00129   newmetamethod(MM_MUL);
00130   newmetamethod(MM_DIV);
00131   newmetamethod(MM_UNM);
00132   newmetamethod(MM_MODULO);
00133   newmetamethod(MM_SET);
00134   newmetamethod(MM_GET);
00135   newmetamethod(MM_TYPEOF);
00136   newmetamethod(MM_NEXTI);
00137   newmetamethod(MM_CMP);
00138   newmetamethod(MM_CALL);
00139   newmetamethod(MM_CLONED);
00140   newmetamethod(MM_NEWSLOT);
00141   newmetamethod(MM_DELSLOT);
00142   newmetamethod(MM_TOSTRING);
00143   newmetamethod(MM_NEWMEMBER);
00144   newmetamethod(MM_INHERITED);
00145 
00146   _constructoridx = SQString::Create(this,_SC("constructor"));
00147   _registry = SQTable::Create(this,0);
00148   _consts = SQTable::Create(this,0);
00149   _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);
00150   _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);
00151   _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);
00152   _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);
00153   _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);
00154   _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);
00155   _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);
00156   _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);
00157   _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);
00158   _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
00159 
00160 }
00161 
00162 SQSharedState::~SQSharedState()
00163 {
00164   _constructoridx = _null_;
00165   _table(_registry)->Finalize();
00166   _table(_consts)->Finalize();
00167   _table(_metamethodsmap)->Finalize();
00168   _registry = _null_;
00169   _consts = _null_;
00170   _metamethodsmap = _null_;
00171   while(!_systemstrings->empty()) {
00172     _systemstrings->back()=_null_;
00173     _systemstrings->pop_back();
00174   }
00175   _thread(_root_vm)->Finalize();
00176   _root_vm = _null_;
00177   _table_default_delegate = _null_;
00178   _array_default_delegate = _null_;
00179   _string_default_delegate = _null_;
00180   _number_default_delegate = _null_;
00181   _closure_default_delegate = _null_;
00182   _generator_default_delegate = _null_;
00183   _thread_default_delegate = _null_;
00184   _class_default_delegate = _null_;
00185   _instance_default_delegate = _null_;
00186   _weakref_default_delegate = _null_;
00187   _refs_table.Finalize();
00188 #ifndef NO_GARBAGE_COLLECTOR
00189   SQCollectable *t = _gc_chain;
00190   SQCollectable *nx = NULL;
00191   while(t) {
00192     t->_uiRef++;
00193     t = t->_next;
00194   }
00195   t = _gc_chain;
00196   while(t) {
00197     t->UnMark();
00198     t->Finalize();
00199     nx = t->_next;
00200     if(--t->_uiRef == 0)
00201       t->Release();
00202     t=nx;
00203   }
00204 //  assert(_gc_chain==NULL); //just to proove a theory
00205   while(_gc_chain){
00206     _gc_chain->_uiRef--;
00207     _gc_chain->Release();
00208   }
00209 #endif
00210 
00211   sq_delete(_types,SQObjectPtrVec);
00212   sq_delete(_systemstrings,SQObjectPtrVec);
00213   sq_delete(_metamethods,SQObjectPtrVec);
00214   sq_delete(_stringtable,StringTable);
00215   if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
00216 }
00217 
00218 
00219 SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
00220 {
00221   if(type(name) != OT_STRING)
00222     return -1;
00223   SQObjectPtr ret;
00224   if(_table(_metamethodsmap)->Get(name,ret)) {
00225     return _integer(ret);
00226   }
00227   return -1;
00228 }
00229 
00230 #ifndef NO_GARBAGE_COLLECTOR
00231 
00232 void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
00233 {
00234   switch(type(o)){
00235   case OT_TABLE:_table(o)->Mark(chain);break;
00236   case OT_ARRAY:_array(o)->Mark(chain);break;
00237   case OT_USERDATA:_userdata(o)->Mark(chain);break;
00238   case OT_CLOSURE:_closure(o)->Mark(chain);break;
00239   case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
00240   case OT_GENERATOR:_generator(o)->Mark(chain);break;
00241   case OT_THREAD:_thread(o)->Mark(chain);break;
00242   case OT_CLASS:_class(o)->Mark(chain);break;
00243   case OT_INSTANCE:_instance(o)->Mark(chain);break;
00244   default: break; //shutup compiler
00245   }
00246 }
00247 
00248 
00249 SQInteger SQSharedState::CollectGarbage(SQVM *vm)
00250 {
00251   SQInteger n=0;
00252   SQCollectable *tchain=NULL;
00253   SQVM *vms = _thread(_root_vm);
00254 
00255   vms->Mark(&tchain);
00256   SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed();
00257   _refs_table.Mark(&tchain);
00258   MarkObject(_registry,&tchain);
00259   MarkObject(_consts,&tchain);
00260   MarkObject(_metamethodsmap,&tchain);
00261   MarkObject(_table_default_delegate,&tchain);
00262   MarkObject(_array_default_delegate,&tchain);
00263   MarkObject(_string_default_delegate,&tchain);
00264   MarkObject(_number_default_delegate,&tchain);
00265   MarkObject(_generator_default_delegate,&tchain);
00266   MarkObject(_thread_default_delegate,&tchain);
00267   MarkObject(_closure_default_delegate,&tchain);
00268   MarkObject(_class_default_delegate,&tchain);
00269   MarkObject(_instance_default_delegate,&tchain);
00270   MarkObject(_weakref_default_delegate,&tchain);
00271 
00272   SQCollectable *t = _gc_chain;
00273   SQCollectable *nx = NULL;
00274   while(t) {
00275     t->_uiRef++;
00276     t->Finalize();
00277     nx = t->_next;
00278     if(--t->_uiRef == 0)
00279       t->Release();
00280     t = nx;
00281     n++;
00282   }
00283 
00284   t = tchain;
00285   while(t) {
00286     t->UnMark();
00287     t = t->_next;
00288   }
00289   _gc_chain = tchain;
00290   SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed();
00291   assert(z == x);
00292   return n;
00293 }
00294 #endif
00295 
00296 #ifndef NO_GARBAGE_COLLECTOR
00297 void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)
00298 {
00299     c->_prev = NULL;
00300   c->_next = *chain;
00301   if(*chain) (*chain)->_prev = c;
00302   *chain = c;
00303 }
00304 
00305 void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
00306 {
00307   if(c->_prev) c->_prev->_next = c->_next;
00308   else *chain = c->_next;
00309   if(c->_next)
00310     c->_next->_prev = c->_prev;
00311   c->_next = NULL;
00312   c->_prev = NULL;
00313 }
00314 #endif
00315 
00316 SQChar* SQSharedState::GetScratchPad(SQInteger size)
00317 {
00318   SQInteger newsize;
00319   if(size>0) {
00320     if(_scratchpadsize < size) {
00321       newsize = size + (size>>1);
00322       _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
00323       _scratchpadsize = newsize;
00324 
00325     }else if(_scratchpadsize >= (size<<5)) {
00326       newsize = _scratchpadsize >> 1;
00327       _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
00328       _scratchpadsize = newsize;
00329     }
00330   }
00331   return _scratchpad;
00332 }
00333 
00334 RefTable::RefTable()
00335 {
00336   AllocNodes(4);
00337 }
00338 
00339 void RefTable::Finalize()
00340 {
00341   RefNode *nodes = _nodes;
00342   for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
00343     nodes->obj = _null_;
00344     nodes++;
00345   }
00346 }
00347 
00348 RefTable::~RefTable()
00349 {
00350   SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
00351 }
00352 
00353 #ifndef NO_GARBAGE_COLLECTOR
00354 void RefTable::Mark(SQCollectable **chain)
00355 {
00356   RefNode *nodes = (RefNode *)_nodes;
00357   for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
00358     if(type(nodes->obj) != OT_NULL) {
00359       SQSharedState::MarkObject(nodes->obj,chain);
00360     }
00361     nodes++;
00362   }
00363 }
00364 #endif
00365 
00366 void RefTable::AddRef(SQObject &obj)
00367 {
00368   SQHash mainpos;
00369   RefNode *prev;
00370   RefNode *ref = Get(obj,mainpos,&prev,true);
00371   ref->refs++;
00372 }
00373 
00374 SQBool RefTable::Release(SQObject &obj)
00375 {
00376   SQHash mainpos;
00377   RefNode *prev;
00378   RefNode *ref = Get(obj,mainpos,&prev,false);
00379   if(ref) {
00380     if(--ref->refs == 0) {
00381       SQObjectPtr o = ref->obj;
00382       if(prev) {
00383         prev->next = ref->next;
00384       }
00385       else {
00386         _buckets[mainpos] = ref->next;
00387       }
00388       ref->next = _freelist;
00389       _freelist = ref;
00390       _slotused--;
00391       ref->obj = _null_;
00392       //<<FIXME>>test for shrink?
00393       return SQTrue;
00394     }
00395   }
00396   else {
00397     assert(0);
00398   }
00399   return SQFalse;
00400 }
00401 
00402 void RefTable::Resize(SQUnsignedInteger size)
00403 {
00404   RefNode **oldbucks = _buckets;
00405   RefNode *t = _nodes;
00406   SQUnsignedInteger oldnumofslots = _numofslots;
00407   AllocNodes(size);
00408   //rehash
00409   SQUnsignedInteger nfound = 0;
00410   for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
00411     if(type(t->obj) != OT_NULL) {
00412       //add back;
00413       assert(t->refs != 0);
00414       RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
00415       nn->refs = t->refs;
00416       t->obj = _null_;
00417       nfound++;
00418     }
00419     t++;
00420   }
00421   assert(nfound == oldnumofslots);
00422   SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
00423 }
00424 
00425 RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)
00426 {
00427   RefNode *t = _buckets[mainpos];
00428   RefNode *newnode = _freelist;
00429   newnode->obj = obj;
00430   _buckets[mainpos] = newnode;
00431   _freelist = _freelist->next;
00432   newnode->next = t;
00433   assert(newnode->refs == 0);
00434   _slotused++;
00435   return newnode;
00436 }
00437 
00438 RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)
00439 {
00440   RefNode *ref;
00441   mainpos = ::HashObj(obj)&(_numofslots-1);
00442   *prev = NULL;
00443   for (ref = _buckets[mainpos]; ref; ) {
00444     if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))
00445       break;
00446     *prev = ref;
00447     ref = ref->next;
00448   }
00449   if(ref == NULL && add) {
00450     if(_numofslots == _slotused) {
00451       assert(_freelist == 0);
00452       Resize(_numofslots*2);
00453       mainpos = ::HashObj(obj)&(_numofslots-1);
00454     }
00455     ref = Add(mainpos,obj);
00456   }
00457   return ref;
00458 }
00459 
00460 void RefTable::AllocNodes(SQUnsignedInteger size)
00461 {
00462   RefNode **bucks;
00463   RefNode *nodes;
00464   bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
00465   nodes = (RefNode *)&bucks[size];
00466   RefNode *temp = nodes;
00467   SQUnsignedInteger n;
00468   for(n = 0; n < size - 1; n++) {
00469     bucks[n] = NULL;
00470     temp->refs = 0;
00471     new (&temp->obj) SQObjectPtr;
00472     temp->next = temp+1;
00473     temp++;
00474   }
00475   bucks[n] = NULL;
00476   temp->refs = 0;
00477   new (&temp->obj) SQObjectPtr;
00478   temp->next = NULL;
00479   _freelist = nodes;
00480   _nodes = nodes;
00481   _buckets = bucks;
00482   _slotused = 0;
00483   _numofslots = size;
00484 }
00486 //StringTable
00487 /*
00488 * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
00489 * http://www.lua.org/copyright.html#4
00490 * http://www.lua.org/source/4.0.1/src_lstring.c.html
00491 */
00492 
00493 StringTable::StringTable()
00494 {
00495   AllocNodes(4);
00496   _slotused = 0;
00497 }
00498 
00499 StringTable::~StringTable()
00500 {
00501   SQ_FREE(_strings,sizeof(SQString*)*_numofslots);
00502   _strings = NULL;
00503 }
00504 
00505 void StringTable::AllocNodes(SQInteger size)
00506 {
00507   _numofslots = size;
00508   _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
00509   memset(_strings,0,sizeof(SQString*)*_numofslots);
00510 }
00511 
00512 SQString *StringTable::Add(const SQChar *news,SQInteger len)
00513 {
00514   if(len<0)
00515     len = (SQInteger)scstrlen(news);
00516   SQHash h = ::_hashstr(news,len)&(_numofslots-1);
00517   SQString *s;
00518   for (s = _strings[h]; s; s = s->_next){
00519     if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))
00520       return s; //found
00521   }
00522 
00523   SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));
00524   new (t) SQString;
00525   memcpy(t->_val,news,rsl(len));
00526   t->_val[len] = _SC('\0');
00527   t->_len = len;
00528   t->_hash = ::_hashstr(news,len);
00529   t->_next = _strings[h];
00530   _strings[h] = t;
00531   _slotused++;
00532   if (_slotused > _numofslots)  /* too crowded? */
00533     Resize(_numofslots*2);
00534   return t;
00535 }
00536 
00537 void StringTable::Resize(SQInteger size)
00538 {
00539   SQInteger oldsize=_numofslots;
00540   SQString **oldtable=_strings;
00541   AllocNodes(size);
00542   for (SQInteger i=0; i<oldsize; i++){
00543     SQString *p = oldtable[i];
00544     while(p){
00545       SQString *next = p->_next;
00546       SQHash h = p->_hash&(_numofslots-1);
00547       p->_next = _strings[h];
00548       _strings[h] = p;
00549       p = next;
00550     }
00551   }
00552   SQ_FREE(oldtable,oldsize*sizeof(SQString*));
00553 }
00554 
00555 void StringTable::Remove(SQString *bs)
00556 {
00557   SQString *s;
00558   SQString *prev=NULL;
00559   SQHash h = bs->_hash&(_numofslots - 1);
00560 
00561   for (s = _strings[h]; s; ){
00562     if(s == bs){
00563       if(prev)
00564         prev->_next = s->_next;
00565       else
00566         _strings[h] = s->_next;
00567       _slotused--;
00568       SQInteger slen = s->_len;
00569       s->~SQString();
00570       SQ_FREE(s,sizeof(SQString) + rsl(slen));
00571       return;
00572     }
00573     prev = s;
00574     s = s->_next;
00575   }
00576   assert(0);//if this fail something is wrong
00577 }

Generated on Fri Jul 31 22:33:12 2009 for OpenTTD by  doxygen 1.5.6