00001
00002
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;
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
00110
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
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
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;
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
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
00409 SQUnsignedInteger nfound = 0;
00410 for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
00411 if(type(t->obj) != OT_NULL) {
00412
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
00487
00488
00489
00490
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;
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)
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);
00577 }