0001
0002
0003
0004 #include "pspcheader.h"
0005 #include "psopcodes.h"
0006 #include "psvm.h"
0007 #include "psfuncproto.h"
0008 #include "psclosure.h"
0009 #include "psstring.h"
0010 #include "pstable.h"
0011 #include "psarray.h"
0012 #include "psuserdata.h"
0013 #include "psclass.h"
0014
0015
0016
0017
0018
0019
0020
0021 PSSharedState::PSSharedState()
0022 {
0023 _compilererrorhandler = NULL;
0024 _printfunc = NULL;
0025 _errorfunc = NULL;
0026 _debuginfo = false;
0027 _notifyallexceptions = false;
0028 _foreignptr = NULL;
0029 _releasehook = NULL;
0030 }
0031
0032 #define newsysstring(s) { \
0033 _systemstrings->push_back(PSString::Create(this,s)); \
0034 }
0035
0036 #define newmetamethod(s) { \
0037 _metamethods->push_back(PSString::Create(this,s)); \
0038 _table(_metamethodsmap)->NewSlot(_metamethods->back(),(PSInteger)(_metamethods->size()-1)); \
0039 }
0040
0041 bool CompileTypemask(PSIntVec &res,const PSChar *typemask)
0042 {
0043 PSInteger i = 0;
0044
0045 PSInteger mask = 0;
0046 while(typemask[i] != 0) {
0047
0048 switch(typemask[i]){
0049 case 'o': mask |= _RT_NULL; break;
0050 case 'i': mask |= _RT_INTEGER; break;
0051 case 'f': mask |= _RT_FLOAT; break;
0052 case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;
0053 case 's': mask |= _RT_STRING; break;
0054 case 't': mask |= _RT_TABLE; break;
0055 case 'a': mask |= _RT_ARRAY; break;
0056 case 'u': mask |= _RT_USERDATA; break;
0057 case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;
0058 case 'b': mask |= _RT_BOOL; break;
0059 case 'g': mask |= _RT_GENERATOR; break;
0060 case 'p': mask |= _RT_USERPOINTER; break;
0061 case 'v': mask |= _RT_THREAD; break;
0062 case 'x': mask |= _RT_INSTANCE; break;
0063 case 'y': mask |= _RT_CLASS; break;
0064 case 'r': mask |= _RT_WEAKREF; break;
0065 case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
0066 case ' ': i++; continue;
0067 default:
0068 return false;
0069 }
0070 i++;
0071 if(typemask[i] == '|') {
0072 i++;
0073 if(typemask[i] == 0)
0074 return false;
0075 continue;
0076 }
0077 res.push_back(mask);
0078 mask = 0;
0079
0080 }
0081 return true;
0082 }
0083
0084 PSTable *CreateDefaultDelegate(PSSharedState *ss,const PSRegFunction *funcz)
0085 {
0086 PSInteger i=0;
0087 PSTable *t=PSTable::Create(ss,0);
0088 while(funcz[i].name!=0){
0089 PSNativeClosure *nc = PSNativeClosure::Create(ss,funcz[i].f,0);
0090 nc->_nparamscheck = funcz[i].nparamscheck;
0091 nc->_name = PSString::Create(ss,funcz[i].name);
0092 if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))
0093 return NULL;
0094 t->NewSlot(PSString::Create(ss,funcz[i].name),nc);
0095 i++;
0096 }
0097 return t;
0098 }
0099
0100 void PSSharedState::Init()
0101 {
0102 _scratchpad=NULL;
0103 _scratchpadsize=0;
0104 #ifndef NO_GARBAGE_COLLECTOR
0105 _gc_chain=NULL;
0106 #endif
0107 _stringtable = (PSStringTable*)PS_MALLOC(sizeof(PSStringTable));
0108 new (_stringtable) PSStringTable(this);
0109 ps_new(_metamethods,PSObjectPtrVec);
0110 ps_new(_systemstrings,PSObjectPtrVec);
0111 ps_new(_types,PSObjectPtrVec);
0112 _metamethodsmap = PSTable::Create(this,MT_LAST-1);
0113
0114
0115 newsysstring(_SC("null"));
0116 newsysstring(_SC("table"));
0117 newsysstring(_SC("array"));
0118 newsysstring(_SC("closure"));
0119 newsysstring(_SC("string"));
0120 newsysstring(_SC("userdata"));
0121 newsysstring(_SC("integer"));
0122 newsysstring(_SC("float"));
0123 newsysstring(_SC("userpointer"));
0124 newsysstring(_SC("function"));
0125 newsysstring(_SC("generator"));
0126 newsysstring(_SC("thread"));
0127 newsysstring(_SC("class"));
0128 newsysstring(_SC("instance"));
0129 newsysstring(_SC("bool"));
0130
0131 newmetamethod(MM_ADD);
0132 newmetamethod(MM_SUB);
0133 newmetamethod(MM_MUL);
0134 newmetamethod(MM_DIV);
0135 newmetamethod(MM_UNM);
0136 newmetamethod(MM_MODULO);
0137 newmetamethod(MM_SET);
0138 newmetamethod(MM_GET);
0139 newmetamethod(MM_TYPEOF);
0140 newmetamethod(MM_NEXTI);
0141 newmetamethod(MM_CMP);
0142 newmetamethod(MM_CALL);
0143 newmetamethod(MM_CLONED);
0144 newmetamethod(MM_NEWSLOT);
0145 newmetamethod(MM_DELSLOT);
0146 newmetamethod(MM_TOSTRING);
0147 newmetamethod(MM_NEWMEMBER);
0148 newmetamethod(MM_INHERITED);
0149
0150 _constructoridx = PSString::Create(this,_SC("constructor"));
0151 _registry = PSTable::Create(this,0);
0152 _consts = PSTable::Create(this,0);
0153 _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);
0154 _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);
0155 _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);
0156 _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);
0157 _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);
0158 _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);
0159 _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);
0160 _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);
0161 _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);
0162 _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
0163
0164 }
0165
0166 PSSharedState::~PSSharedState()
0167 {
0168 if(_releasehook) { _releasehook(_foreignptr,0); _releasehook = NULL; }
0169 _constructoridx.Null();
0170 _table(_registry)->Finalize();
0171 _table(_consts)->Finalize();
0172 _table(_metamethodsmap)->Finalize();
0173 _registry.Null();
0174 _consts.Null();
0175 _metamethodsmap.Null();
0176 while(!_systemstrings->empty()) {
0177 _systemstrings->back().Null();
0178 _systemstrings->pop_back();
0179 }
0180 _thread(_root_vm)->Finalize();
0181 _root_vm.Null();
0182 _table_default_delegate.Null();
0183 _array_default_delegate.Null();
0184 _string_default_delegate.Null();
0185 _number_default_delegate.Null();
0186 _closure_default_delegate.Null();
0187 _generator_default_delegate.Null();
0188 _thread_default_delegate.Null();
0189 _class_default_delegate.Null();
0190 _instance_default_delegate.Null();
0191 _weakref_default_delegate.Null();
0192 _refs_table.Finalize();
0193 #ifndef NO_GARBAGE_COLLECTOR
0194 PSCollectable *t = _gc_chain;
0195 PSCollectable *nx = NULL;
0196 if(t) {
0197 t->_uiRef++;
0198 while(t) {
0199 t->Finalize();
0200 nx = t->_next;
0201 if(nx) nx->_uiRef++;
0202 if(--t->_uiRef == 0)
0203 t->Release();
0204 t = nx;
0205 }
0206 }
0207 assert(_gc_chain==NULL);
0208 while(_gc_chain){
0209 _gc_chain->_uiRef++;
0210 _gc_chain->Release();
0211 }
0212 #endif
0213
0214 ps_delete(_types,PSObjectPtrVec);
0215 ps_delete(_systemstrings,PSObjectPtrVec);
0216 ps_delete(_metamethods,PSObjectPtrVec);
0217 ps_delete(_stringtable,PSStringTable);
0218 if(_scratchpad)PS_FREE(_scratchpad,_scratchpadsize);
0219 }
0220
0221
0222 PSInteger PSSharedState::GetMetaMethodIdxByName(const PSObjectPtr &name)
0223 {
0224 if(type(name) != OT_STRING)
0225 return -1;
0226 PSObjectPtr ret;
0227 if(_table(_metamethodsmap)->Get(name,ret)) {
0228 return _integer(ret);
0229 }
0230 return -1;
0231 }
0232
0233 #ifndef NO_GARBAGE_COLLECTOR
0234
0235 void PSSharedState::MarkObject(PSObjectPtr &o,PSCollectable **chain)
0236 {
0237 switch(type(o)){
0238 case OT_TABLE:_table(o)->Mark(chain);break;
0239 case OT_ARRAY:_array(o)->Mark(chain);break;
0240 case OT_USERDATA:_userdata(o)->Mark(chain);break;
0241 case OT_CLOSURE:_closure(o)->Mark(chain);break;
0242 case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
0243 case OT_GENERATOR:_generator(o)->Mark(chain);break;
0244 case OT_THREAD:_thread(o)->Mark(chain);break;
0245 case OT_CLASS:_class(o)->Mark(chain);break;
0246 case OT_INSTANCE:_instance(o)->Mark(chain);break;
0247 case OT_OUTER:_outer(o)->Mark(chain);break;
0248 case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break;
0249 default: break;
0250 }
0251 }
0252
0253 void PSSharedState::RunMark(PSVM PS_UNUSED_ARG(*vm),PSCollectable **tchain)
0254 {
0255 PSVM *vms = _thread(_root_vm);
0256
0257 vms->Mark(tchain);
0258
0259 _refs_table.Mark(tchain);
0260 MarkObject(_registry,tchain);
0261 MarkObject(_consts,tchain);
0262 MarkObject(_metamethodsmap,tchain);
0263 MarkObject(_table_default_delegate,tchain);
0264 MarkObject(_array_default_delegate,tchain);
0265 MarkObject(_string_default_delegate,tchain);
0266 MarkObject(_number_default_delegate,tchain);
0267 MarkObject(_generator_default_delegate,tchain);
0268 MarkObject(_thread_default_delegate,tchain);
0269 MarkObject(_closure_default_delegate,tchain);
0270 MarkObject(_class_default_delegate,tchain);
0271 MarkObject(_instance_default_delegate,tchain);
0272 MarkObject(_weakref_default_delegate,tchain);
0273
0274 }
0275
0276 PSInteger PSSharedState::ResurrectUnreachable(PSVM *vm)
0277 {
0278 PSInteger n=0;
0279 PSCollectable *tchain=NULL;
0280
0281 RunMark(vm,&tchain);
0282
0283 PSCollectable *resurrected = _gc_chain;
0284 PSCollectable *t = resurrected;
0285
0286
0287 _gc_chain = tchain;
0288
0289 PSArray *ret = NULL;
0290 if(resurrected) {
0291 ret = PSArray::Create(this,0);
0292 PSCollectable *rlast = NULL;
0293 while(t) {
0294 rlast = t;
0295 PSObjectType type = t->GetType();
0296 if(type != OT_FUNCPROTO && type != OT_OUTER) {
0297 PSObject pso;
0298 pso._type = type;
0299 pso._unVal.pRefCounted = t;
0300 ret->Append(pso);
0301 }
0302 t = t->_next;
0303 n++;
0304 }
0305
0306 assert(rlast->_next == NULL);
0307 rlast->_next = _gc_chain;
0308 if(_gc_chain)
0309 {
0310 _gc_chain->_prev = rlast;
0311 }
0312 _gc_chain = resurrected;
0313 }
0314
0315 t = _gc_chain;
0316 while(t) {
0317 t->UnMark();
0318 t = t->_next;
0319 }
0320
0321 if(ret) {
0322 PSObjectPtr temp = ret;
0323 vm->Push(temp);
0324 }
0325 else {
0326 vm->PushNull();
0327 }
0328 return n;
0329 }
0330
0331 PSInteger PSSharedState::CollectGarbage(PSVM *vm)
0332 {
0333 PSInteger n = 0;
0334 PSCollectable *tchain = NULL;
0335
0336 RunMark(vm,&tchain);
0337
0338 PSCollectable *t = _gc_chain;
0339 PSCollectable *nx = NULL;
0340 if(t) {
0341 t->_uiRef++;
0342 while(t) {
0343 t->Finalize();
0344 nx = t->_next;
0345 if(nx) nx->_uiRef++;
0346 if(--t->_uiRef == 0)
0347 t->Release();
0348 t = nx;
0349 n++;
0350 }
0351 }
0352
0353 t = tchain;
0354 while(t) {
0355 t->UnMark();
0356 t = t->_next;
0357 }
0358 _gc_chain = tchain;
0359
0360 return n;
0361 }
0362 #endif
0363
0364 #ifndef NO_GARBAGE_COLLECTOR
0365 void PSCollectable::AddToChain(PSCollectable **chain,PSCollectable *c)
0366 {
0367 c->_prev = NULL;
0368 c->_next = *chain;
0369 if(*chain) (*chain)->_prev = c;
0370 *chain = c;
0371 }
0372
0373 void PSCollectable::RemoveFromChain(PSCollectable **chain,PSCollectable *c)
0374 {
0375 if(c->_prev) c->_prev->_next = c->_next;
0376 else *chain = c->_next;
0377 if(c->_next)
0378 c->_next->_prev = c->_prev;
0379 c->_next = NULL;
0380 c->_prev = NULL;
0381 }
0382 #endif
0383
0384 PSChar* PSSharedState::GetScratchPad(PSInteger size)
0385 {
0386 PSInteger newsize;
0387 if(size>0) {
0388 if(_scratchpadsize < size) {
0389 newsize = size + (size>>1);
0390 _scratchpad = (PSChar *)PS_REALLOC(_scratchpad,_scratchpadsize,newsize);
0391 _scratchpadsize = newsize;
0392
0393 }else if(_scratchpadsize >= (size<<5)) {
0394 newsize = _scratchpadsize >> 1;
0395 _scratchpad = (PSChar *)PS_REALLOC(_scratchpad,_scratchpadsize,newsize);
0396 _scratchpadsize = newsize;
0397 }
0398 }
0399 return _scratchpad;
0400 }
0401
0402 RefTable::RefTable()
0403 {
0404 AllocNodes(4);
0405 }
0406
0407 void RefTable::Finalize()
0408 {
0409 RefNode *nodes = _nodes;
0410 for(PSUnsignedInteger n = 0; n < _numofslots; n++) {
0411 nodes->obj.Null();
0412 nodes++;
0413 }
0414 }
0415
0416 RefTable::~RefTable()
0417 {
0418 PS_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
0419 }
0420
0421 #ifndef NO_GARBAGE_COLLECTOR
0422 void RefTable::Mark(PSCollectable **chain)
0423 {
0424 RefNode *nodes = (RefNode *)_nodes;
0425 for(PSUnsignedInteger n = 0; n < _numofslots; n++) {
0426 if(type(nodes->obj) != OT_NULL) {
0427 PSSharedState::MarkObject(nodes->obj,chain);
0428 }
0429 nodes++;
0430 }
0431 }
0432 #endif
0433
0434 void RefTable::AddRef(PSObject &obj)
0435 {
0436 PSHash mainpos;
0437 RefNode *prev;
0438 RefNode *ref = Get(obj,mainpos,&prev,true);
0439 ref->refs++;
0440 }
0441
0442 PSUnsignedInteger RefTable::GetRefCount(PSObject &obj)
0443 {
0444 PSHash mainpos;
0445 RefNode *prev;
0446 RefNode *ref = Get(obj,mainpos,&prev,true);
0447 return ref->refs;
0448 }
0449
0450
0451 PSBool RefTable::Release(PSObject &obj)
0452 {
0453 PSHash mainpos;
0454 RefNode *prev;
0455 RefNode *ref = Get(obj,mainpos,&prev,false);
0456 if(ref) {
0457 if(--ref->refs == 0) {
0458 PSObjectPtr o = ref->obj;
0459 if(prev) {
0460 prev->next = ref->next;
0461 }
0462 else {
0463 _buckets[mainpos] = ref->next;
0464 }
0465 ref->next = _freelist;
0466 _freelist = ref;
0467 _slotused--;
0468 ref->obj.Null();
0469
0470 return PSTrue;
0471 }
0472 }
0473 else {
0474 assert(0);
0475 }
0476 return PSFalse;
0477 }
0478
0479 void RefTable::Resize(PSUnsignedInteger size)
0480 {
0481 RefNode **oldbucks = _buckets;
0482 RefNode *t = _nodes;
0483 PSUnsignedInteger oldnumofslots = _numofslots;
0484 AllocNodes(size);
0485
0486 PSUnsignedInteger nfound = 0;
0487 for(PSUnsignedInteger n = 0; n < oldnumofslots; n++) {
0488 if(type(t->obj) != OT_NULL) {
0489
0490 assert(t->refs != 0);
0491 RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
0492 nn->refs = t->refs;
0493 t->obj.Null();
0494 nfound++;
0495 }
0496 t++;
0497 }
0498 assert(nfound == oldnumofslots);
0499 PS_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
0500 }
0501
0502 RefTable::RefNode *RefTable::Add(PSHash mainpos,PSObject &obj)
0503 {
0504 RefNode *t = _buckets[mainpos];
0505 RefNode *newnode = _freelist;
0506 newnode->obj = obj;
0507 _buckets[mainpos] = newnode;
0508 _freelist = _freelist->next;
0509 newnode->next = t;
0510 assert(newnode->refs == 0);
0511 _slotused++;
0512 return newnode;
0513 }
0514
0515 RefTable::RefNode *RefTable::Get(PSObject &obj,PSHash &mainpos,RefNode **prev,bool add)
0516 {
0517 RefNode *ref;
0518 mainpos = ::HashObj(obj)&(_numofslots-1);
0519 *prev = NULL;
0520 for (ref = _buckets[mainpos]; ref; ) {
0521 if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))
0522 break;
0523 *prev = ref;
0524 ref = ref->next;
0525 }
0526 if(ref == NULL && add) {
0527 if(_numofslots == _slotused) {
0528 assert(_freelist == 0);
0529 Resize(_numofslots*2);
0530 mainpos = ::HashObj(obj)&(_numofslots-1);
0531 }
0532 ref = Add(mainpos,obj);
0533 }
0534 return ref;
0535 }
0536
0537 void RefTable::AllocNodes(PSUnsignedInteger size)
0538 {
0539 RefNode **bucks;
0540 RefNode *nodes;
0541 bucks = (RefNode **)PS_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
0542 nodes = (RefNode *)&bucks[size];
0543 RefNode *temp = nodes;
0544 PSUnsignedInteger n;
0545 for(n = 0; n < size - 1; n++) {
0546 bucks[n] = NULL;
0547 temp->refs = 0;
0548 new (&temp->obj) PSObjectPtr;
0549 temp->next = temp+1;
0550 temp++;
0551 }
0552 bucks[n] = NULL;
0553 temp->refs = 0;
0554 new (&temp->obj) PSObjectPtr;
0555 temp->next = NULL;
0556 _freelist = nodes;
0557 _nodes = nodes;
0558 _buckets = bucks;
0559 _slotused = 0;
0560 _numofslots = size;
0561 }
0562
0563
0564
0565
0566
0567
0568
0569
0570 PSStringTable::PSStringTable(PSSharedState *ss)
0571 {
0572 _sharedstate = ss;
0573 AllocNodes(4);
0574 _slotused = 0;
0575 }
0576
0577 PSStringTable::~PSStringTable()
0578 {
0579 PS_FREE(_strings,sizeof(PSString*)*_numofslots);
0580 _strings = NULL;
0581 }
0582
0583 void PSStringTable::AllocNodes(PSInteger size)
0584 {
0585 _numofslots = size;
0586 _strings = (PSString**)PS_MALLOC(sizeof(PSString*)*_numofslots);
0587 memset(_strings,0,sizeof(PSString*)*_numofslots);
0588 }
0589
0590 PSString *PSStringTable::Add(const PSChar *news,PSInteger len)
0591 {
0592 if(len<0)
0593 len = (PSInteger)scstrlen(news);
0594 PSHash newhash = ::_hashstr(news,len);
0595 PSHash h = newhash&(_numofslots-1);
0596 PSString *s;
0597 for (s = _strings[h]; s; s = s->_next){
0598 if(s->_len == len && (!memcmp(news,s->_val,ps_rsl(len))))
0599 return s;
0600 }
0601
0602 PSString *t = (PSString *)PS_MALLOC(ps_rsl(len)+sizeof(PSString));
0603 new (t) PSString;
0604 t->_sharedstate = _sharedstate;
0605 memcpy(t->_val,news,ps_rsl(len));
0606 t->_val[len] = _SC('\0');
0607 t->_len = len;
0608 t->_hash = newhash;
0609 t->_next = _strings[h];
0610 _strings[h] = t;
0611 _slotused++;
0612 if (_slotused > _numofslots)
0613 Resize(_numofslots*2);
0614 return t;
0615 }
0616
0617 void PSStringTable::Resize(PSInteger size)
0618 {
0619 PSInteger oldsize=_numofslots;
0620 PSString **oldtable=_strings;
0621 AllocNodes(size);
0622 for (PSInteger i=0; i<oldsize; i++){
0623 PSString *p = oldtable[i];
0624 while(p){
0625 PSString *next = p->_next;
0626 PSHash h = p->_hash&(_numofslots-1);
0627 p->_next = _strings[h];
0628 _strings[h] = p;
0629 p = next;
0630 }
0631 }
0632 PS_FREE(oldtable,oldsize*sizeof(PSString*));
0633 }
0634
0635 void PSStringTable::Remove(PSString *bs)
0636 {
0637 PSString *s;
0638 PSString *prev=NULL;
0639 PSHash h = bs->_hash&(_numofslots - 1);
0640
0641 for (s = _strings[h]; s; ){
0642 if(s == bs){
0643 if(prev)
0644 prev->_next = s->_next;
0645 else
0646 _strings[h] = s->_next;
0647 _slotused--;
0648 PSInteger slen = s->_len;
0649 s->~PSString();
0650 PS_FREE(s,sizeof(PSString) + ps_rsl(slen));
0651 return;
0652 }
0653 prev = s;
0654 s = s->_next;
0655 }
0656 assert(0);
0657 }