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->Finalize();
00194     nx = t->_next;
00195     if(--t->_uiRef == 0)
00196       t->Release();
00197     t=nx;
00198   }
00199 //  assert(_gc_chain==NULL); //just to proove a theory
00200   while(_gc_chain){
00201     _gc_chain->_uiRef++;
00202     _gc_chain->Release();
00203   }
00204 #endif
00205 
00206   sq_delete(_types,SQObjectPtrVec);
00207   sq_delete(_systemstrings,SQObjectPtrVec);
00208   sq_delete(_metamethods,SQObjectPtrVec);
00209   sq_delete(_stringtable,StringTable);
00210   if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
00211 }
00212 
00213 
00214 SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
00215 {
00216   if(type(name) != OT_STRING)
00217     return -1;
00218   SQObjectPtr ret;
00219   if(_table(_metamethodsmap)->Get(name,ret)) {
00220     return _integer(ret);
00221   }
00222   return -1;
00223 }
00224 
00225 #ifndef NO_GARBAGE_COLLECTOR
00226 
00227 void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
00228 {
00229   switch(type(o)){
00230   case OT_TABLE:_table(o)->Mark(chain);break;
00231   case OT_ARRAY:_array(o)->Mark(chain);break;
00232   case OT_USERDATA:_userdata(o)->Mark(chain);break;
00233   case OT_CLOSURE:_closure(o)->Mark(chain);break;
00234   case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
00235   case OT_GENERATOR:_generator(o)->Mark(chain);break;
00236   case OT_THREAD:_thread(o)->Mark(chain);break;
00237   case OT_CLASS:_class(o)->Mark(chain);break;
00238   case OT_INSTANCE:_instance(o)->Mark(chain);break;
00239   default: break; //shutup compiler
00240   }
00241 }
00242 
00243 
00244 SQInteger SQSharedState::CollectGarbage(SQVM *vm)
00245 {
00246   SQInteger n=0;
00247   SQCollectable *tchain=NULL;
00248   SQVM *vms = _thread(_root_vm);
00249 
00250   vms->Mark(&tchain);
00251   SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed();
00252   _refs_table.Mark(&tchain);
00253   MarkObject(_registry,&tchain);
00254   MarkObject(_consts,&tchain);
00255   MarkObject(_metamethodsmap,&tchain);
00256   MarkObject(_table_default_delegate,&tchain);
00257   MarkObject(_array_default_delegate,&tchain);
00258   MarkObject(_string_default_delegate,&tchain);
00259   MarkObject(_number_default_delegate,&tchain);
00260   MarkObject(_generator_default_delegate,&tchain);
00261   MarkObject(_thread_default_delegate,&tchain);
00262   MarkObject(_closure_default_delegate,&tchain);
00263   MarkObject(_class_default_delegate,&tchain);
00264   MarkObject(_instance_default_delegate,&tchain);
00265   MarkObject(_weakref_default_delegate,&tchain);
00266 
00267   SQCollectable *t = _gc_chain;
00268   SQCollectable *nx = NULL;
00269   while(t) {
00270     t->_uiRef++;
00271     t->Finalize();
00272     nx = t->_next;
00273     if(--t->_uiRef == 0)
00274       t->Release();
00275     t = nx;
00276     n++;
00277   }
00278 
00279   t = tchain;
00280   while(t) {
00281     t->UnMark();
00282     t = t->_next;
00283   }
00284   _gc_chain = tchain;
00285   SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed();
00286   assert(z == x);
00287   return n;
00288 }
00289 #endif
00290 
00291 #ifndef NO_GARBAGE_COLLECTOR
00292 void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)
00293 {
00294     c->_prev = NULL;
00295   c->_next = *chain;
00296   if(*chain) (*chain)->_prev = c;
00297   *chain = c;
00298 }
00299 
00300 void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
00301 {
00302   if(c->_prev) c->_prev->_next = c->_next;
00303   else *chain = c->_next;
00304   if(c->_next)
00305     c->_next->_prev = c->_prev;
00306   c->_next = NULL;
00307   c->_prev = NULL;
00308 }
00309 #endif
00310 
00311 SQChar* SQSharedState::GetScratchPad(SQInteger size)
00312 {
00313   SQInteger newsize;
00314   if(size>0) {
00315     if(_scratchpadsize < size) {
00316       newsize = size + (size>>1);
00317       _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
00318       _scratchpadsize = newsize;
00319 
00320     }else if(_scratchpadsize >= (size<<5)) {
00321       newsize = _scratchpadsize >> 1;
00322       _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
00323       _scratchpadsize = newsize;
00324     }
00325   }
00326   return _scratchpad;
00327 }
00328 
00329 RefTable::RefTable()
00330 {
00331   AllocNodes(4);
00332 }
00333 
00334 void RefTable::Finalize()
00335 {
00336   RefNode *nodes = _nodes;
00337   for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
00338     nodes->obj = _null_;
00339     nodes++;
00340   }
00341 }
00342 
00343 RefTable::~RefTable()
00344 {
00345   SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
00346 }
00347 
00348 #ifndef NO_GARBAGE_COLLECTOR
00349 void RefTable::Mark(SQCollectable **chain)
00350 {
00351   RefNode *nodes = (RefNode *)_nodes;
00352   for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
00353     if(type(nodes->obj) != OT_NULL) {
00354       SQSharedState::MarkObject(nodes->obj,chain);
00355     }
00356     nodes++;
00357   }
00358 }
00359 #endif
00360 
00361 void RefTable::AddRef(SQObject &obj)
00362 {
00363   SQHash mainpos;
00364   RefNode *prev;
00365   RefNode *ref = Get(obj,mainpos,&prev,true);
00366   ref->refs++;
00367 }
00368 
00369 SQBool RefTable::Release(SQObject &obj)
00370 {
00371   SQHash mainpos;
00372   RefNode *prev;
00373   RefNode *ref = Get(obj,mainpos,&prev,false);
00374   if(ref) {
00375     if(--ref->refs == 0) {
00376       SQObjectPtr o = ref->obj;
00377       if(prev) {
00378         prev->next = ref->next;
00379       }
00380       else {
00381         _buckets[mainpos] = ref->next;
00382       }
00383       ref->next = _freelist;
00384       _freelist = ref;
00385       _slotused--;
00386       ref->obj = _null_;
00387       //<<FIXME>>test for shrink?
00388       return SQTrue;
00389     }
00390   }
00391   else {
00392     assert(0);
00393   }
00394   return SQFalse;
00395 }
00396 
00397 void RefTable::Resize(SQUnsignedInteger size)
00398 {
00399   RefNode **oldbucks = _buckets;
00400   RefNode *t = _nodes;
00401   SQUnsignedInteger oldnumofslots = _numofslots;
00402   AllocNodes(size);
00403   //rehash
00404   SQUnsignedInteger nfound = 0;
00405   for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
00406     if(type(t->obj) != OT_NULL) {
00407       //add back;
00408       assert(t->refs != 0);
00409       RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
00410       nn->refs = t->refs;
00411       t->obj = _null_;
00412       nfound++;
00413     }
00414     t++;
00415   }
00416   assert(nfound == oldnumofslots);
00417   SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
00418 }
00419 
00420 RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)
00421 {
00422   RefNode *t = _buckets[mainpos];
00423   RefNode *newnode = _freelist;
00424   newnode->obj = obj;
00425   _buckets[mainpos] = newnode;
00426   _freelist = _freelist->next;
00427   newnode->next = t;
00428   assert(newnode->refs == 0);
00429   _slotused++;
00430   return newnode;
00431 }
00432 
00433 RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)
00434 {
00435   RefNode *ref;
00436   mainpos = ::HashObj(obj)&(_numofslots-1);
00437   *prev = NULL;
00438   for (ref = _buckets[mainpos]; ref; ) {
00439     if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))
00440       break;
00441     *prev = ref;
00442     ref = ref->next;
00443   }
00444   if(ref == NULL && add) {
00445     if(_numofslots == _slotused) {
00446       assert(_freelist == 0);
00447       Resize(_numofslots*2);
00448       mainpos = ::HashObj(obj)&(_numofslots-1);
00449     }
00450     ref = Add(mainpos,obj);
00451   }
00452   return ref;
00453 }
00454 
00455 void RefTable::AllocNodes(SQUnsignedInteger size)
00456 {
00457   RefNode **bucks;
00458   RefNode *nodes;
00459   bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
00460   nodes = (RefNode *)&bucks[size];
00461   RefNode *temp = nodes;
00462   SQUnsignedInteger n;
00463   for(n = 0; n < size - 1; n++) {
00464     bucks[n] = NULL;
00465     temp->refs = 0;
00466     new (&temp->obj) SQObjectPtr;
00467     temp->next = temp+1;
00468     temp++;
00469   }
00470   bucks[n] = NULL;
00471   temp->refs = 0;
00472   new (&temp->obj) SQObjectPtr;
00473   temp->next = NULL;
00474   _freelist = nodes;
00475   _nodes = nodes;
00476   _buckets = bucks;
00477   _slotused = 0;
00478   _numofslots = size;
00479 }
00481 //StringTable
00482 /*
00483 * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
00484 * http://www.lua.org/copyright.html#4
00485 * http://www.lua.org/source/4.0.1/src_lstring.c.html
00486 */
00487 
00488 StringTable::StringTable()
00489 {
00490   AllocNodes(4);
00491   _slotused = 0;
00492 }
00493 
00494 StringTable::~StringTable()
00495 {
00496   SQ_FREE(_strings,sizeof(SQString*)*_numofslots);
00497   _strings = NULL;
00498 }
00499 
00500 void StringTable::AllocNodes(SQInteger size)
00501 {
00502   _numofslots = size;
00503   _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
00504   memset(_strings,0,sizeof(SQString*)*_numofslots);
00505 }
00506 
00507 SQString *StringTable::Add(const SQChar *news,SQInteger len)
00508 {
00509   if(len<0)
00510     len = (SQInteger)scstrlen(news);
00511   SQHash h = ::_hashstr(news,len)&(_numofslots-1);
00512   SQString *s;
00513   for (s = _strings[h]; s; s = s->_next){
00514     if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))
00515       return s; //found
00516   }
00517 
00518   SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));
00519   new (t) SQString;
00520   memcpy(t->_val,news,rsl(len));
00521   t->_val[len] = _SC('\0');
00522   t->_len = len;
00523   t->_hash = ::_hashstr(news,len);
00524   t->_next = _strings[h];
00525   _strings[h] = t;
00526   _slotused++;
00527   if (_slotused > _numofslots)  /* too crowded? */
00528     Resize(_numofslots*2);
00529   return t;
00530 }
00531 
00532 void StringTable::Resize(SQInteger size)
00533 {
00534   SQInteger oldsize=_numofslots;
00535   SQString **oldtable=_strings;
00536   AllocNodes(size);
00537   for (SQInteger i=0; i<oldsize; i++){
00538     SQString *p = oldtable[i];
00539     while(p){
00540       SQString *next = p->_next;
00541       SQHash h = p->_hash&(_numofslots-1);
00542       p->_next = _strings[h];
00543       _strings[h] = p;
00544       p = next;
00545     }
00546   }
00547   SQ_FREE(oldtable,oldsize*sizeof(SQString*));
00548 }
00549 
00550 void StringTable::Remove(SQString *bs)
00551 {
00552   SQString *s;
00553   SQString *prev=NULL;
00554   SQHash h = bs->_hash&(_numofslots - 1);
00555 
00556   for (s = _strings[h]; s; ){
00557     if(s == bs){
00558       if(prev)
00559         prev->_next = s->_next;
00560       else
00561         _strings[h] = s->_next;
00562       _slotused--;
00563       SQInteger slen = s->_len;
00564       s->~SQString();
00565       SQ_FREE(s,sizeof(SQString) + rsl(slen));
00566       return;
00567     }
00568     prev = s;
00569     s = s->_next;
00570   }
00571   assert(0);//if this fail something is wrong
00572 }

Generated on Mon Feb 16 23:12:04 2009 for openttd by  doxygen 1.5.6