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

Generated on Wed Apr 1 14:38:04 2009 for OpenTTD by  doxygen 1.5.6