2 see copyright notice in squirrel.h
\r
4 #include "sqpcheader.h"
\r
5 #include "sqopcodes.h"
\r
7 #include "sqfuncproto.h"
\r
8 #include "sqclosure.h"
\r
9 #include "sqstring.h"
\r
10 #include "sqtable.h"
\r
11 #include "sqarray.h"
\r
12 #include "squserdata.h"
\r
13 #include "sqclass.h"
\r
15 //SQObjectPtr _null_;
\r
16 //SQObjectPtr _true_(true);
\r
17 //SQObjectPtr _false_(false);
\r
18 //SQObjectPtr _one_((SQInteger)1);
\r
19 //SQObjectPtr _minusone_((SQInteger)-1);
\r
21 SQSharedState::SQSharedState()
\r
23 _compilererrorhandler = NULL;
\r
27 _notifyallexceptions = false;
\r
30 #define newsysstring(s) { \
\r
31 _systemstrings->push_back(SQString::Create(this,s)); \
\r
34 #define newmetamethod(s) { \
\r
35 _metamethods->push_back(SQString::Create(this,s)); \
\r
36 _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
\r
39 bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
\r
44 while(typemask[i] != 0) {
\r
46 switch(typemask[i]){
\r
47 case 'o': mask |= _RT_NULL; break;
\r
48 case 'i': mask |= _RT_INTEGER; break;
\r
49 case 'f': mask |= _RT_FLOAT; break;
\r
50 case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;
\r
51 case 's': mask |= _RT_STRING; break;
\r
52 case 't': mask |= _RT_TABLE; break;
\r
53 case 'a': mask |= _RT_ARRAY; break;
\r
54 case 'u': mask |= _RT_USERDATA; break;
\r
55 case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;
\r
56 case 'b': mask |= _RT_BOOL; break;
\r
57 case 'g': mask |= _RT_GENERATOR; break;
\r
58 case 'p': mask |= _RT_USERPOINTER; break;
\r
59 case 'v': mask |= _RT_THREAD; break;
\r
60 case 'x': mask |= _RT_INSTANCE; break;
\r
61 case 'y': mask |= _RT_CLASS; break;
\r
62 case 'r': mask |= _RT_WEAKREF; break;
\r
63 case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
\r
64 case ' ': i++; continue; //ignores spaces
\r
69 if(typemask[i] == '|') {
\r
71 if(typemask[i] == 0)
\r
75 res.push_back(mask);
\r
82 SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz)
\r
85 SQTable *t=SQTable::Create(ss,0);
\r
86 while(funcz[i].name!=0){
\r
87 SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f,0);
\r
88 nc->_nparamscheck = funcz[i].nparamscheck;
\r
89 nc->_name = SQString::Create(ss,funcz[i].name);
\r
90 if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))
\r
92 t->NewSlot(SQString::Create(ss,funcz[i].name),nc);
\r
98 void SQSharedState::Init()
\r
102 #ifndef NO_GARBAGE_COLLECTOR
\r
105 _stringtable = (SQStringTable*)SQ_MALLOC(sizeof(SQStringTable));
\r
106 new (_stringtable) SQStringTable(this);
\r
107 sq_new(_metamethods,SQObjectPtrVec);
\r
108 sq_new(_systemstrings,SQObjectPtrVec);
\r
109 sq_new(_types,SQObjectPtrVec);
\r
110 _metamethodsmap = SQTable::Create(this,MT_LAST-1);
\r
111 //adding type strings to avoid memory trashing
\r
113 newsysstring(_SC("null"));
\r
114 newsysstring(_SC("table"));
\r
115 newsysstring(_SC("array"));
\r
116 newsysstring(_SC("closure"));
\r
117 newsysstring(_SC("string"));
\r
118 newsysstring(_SC("userdata"));
\r
119 newsysstring(_SC("integer"));
\r
120 newsysstring(_SC("float"));
\r
121 newsysstring(_SC("userpointer"));
\r
122 newsysstring(_SC("function"));
\r
123 newsysstring(_SC("generator"));
\r
124 newsysstring(_SC("thread"));
\r
125 newsysstring(_SC("class"));
\r
126 newsysstring(_SC("instance"));
\r
127 newsysstring(_SC("bool"));
\r
129 newmetamethod(MM_ADD);
\r
130 newmetamethod(MM_SUB);
\r
131 newmetamethod(MM_MUL);
\r
132 newmetamethod(MM_DIV);
\r
133 newmetamethod(MM_UNM);
\r
134 newmetamethod(MM_MODULO);
\r
135 newmetamethod(MM_SET);
\r
136 newmetamethod(MM_GET);
\r
137 newmetamethod(MM_TYPEOF);
\r
138 newmetamethod(MM_NEXTI);
\r
139 newmetamethod(MM_CMP);
\r
140 newmetamethod(MM_CALL);
\r
141 newmetamethod(MM_CLONED);
\r
142 newmetamethod(MM_NEWSLOT);
\r
143 newmetamethod(MM_DELSLOT);
\r
144 newmetamethod(MM_TOSTRING);
\r
145 newmetamethod(MM_NEWMEMBER);
\r
146 newmetamethod(MM_INHERITED);
\r
148 _constructoridx = SQString::Create(this,_SC("constructor"));
\r
149 _registry = SQTable::Create(this,0);
\r
150 _consts = SQTable::Create(this,0);
\r
151 _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);
\r
152 _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);
\r
153 _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);
\r
154 _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);
\r
155 _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);
\r
156 _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);
\r
157 _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);
\r
158 _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);
\r
159 _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);
\r
160 _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
\r
164 SQSharedState::~SQSharedState()
\r
166 _constructoridx.Null();
\r
167 _table(_registry)->Finalize();
\r
168 _table(_consts)->Finalize();
\r
169 _table(_metamethodsmap)->Finalize();
\r
172 _metamethodsmap.Null();
\r
173 while(!_systemstrings->empty()) {
\r
174 _systemstrings->back().Null();
\r
175 _systemstrings->pop_back();
\r
177 _thread(_root_vm)->Finalize();
\r
179 _table_default_delegate.Null();
\r
180 _array_default_delegate.Null();
\r
181 _string_default_delegate.Null();
\r
182 _number_default_delegate.Null();
\r
183 _closure_default_delegate.Null();
\r
184 _generator_default_delegate.Null();
\r
185 _thread_default_delegate.Null();
\r
186 _class_default_delegate.Null();
\r
187 _instance_default_delegate.Null();
\r
188 _weakref_default_delegate.Null();
\r
189 _refs_table.Finalize();
\r
190 #ifndef NO_GARBAGE_COLLECTOR
\r
191 SQCollectable *t = _gc_chain;
\r
192 SQCollectable *nx = NULL;
\r
198 if(nx) nx->_uiRef++;
\r
199 if(--t->_uiRef == 0)
\r
204 assert(_gc_chain==NULL); //just to proove a theory
\r
206 _gc_chain->_uiRef++;
\r
207 _gc_chain->Release();
\r
211 sq_delete(_types,SQObjectPtrVec);
\r
212 sq_delete(_systemstrings,SQObjectPtrVec);
\r
213 sq_delete(_metamethods,SQObjectPtrVec);
\r
214 sq_delete(_stringtable,SQStringTable);
\r
215 if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
\r
219 SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
\r
221 if(type(name) != OT_STRING)
\r
224 if(_table(_metamethodsmap)->Get(name,ret)) {
\r
225 return _integer(ret);
\r
230 #ifndef NO_GARBAGE_COLLECTOR
\r
232 void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
\r
235 case OT_TABLE:_table(o)->Mark(chain);break;
\r
236 case OT_ARRAY:_array(o)->Mark(chain);break;
\r
237 case OT_USERDATA:_userdata(o)->Mark(chain);break;
\r
238 case OT_CLOSURE:_closure(o)->Mark(chain);break;
\r
239 case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
\r
240 case OT_GENERATOR:_generator(o)->Mark(chain);break;
\r
241 case OT_THREAD:_thread(o)->Mark(chain);break;
\r
242 case OT_CLASS:_class(o)->Mark(chain);break;
\r
243 case OT_INSTANCE:_instance(o)->Mark(chain);break;
\r
244 case OT_OUTER:_outer(o)->Mark(chain);break;
\r
245 case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break;
\r
246 default: break; //shutup compiler
\r
251 void SQSharedState::RunMark(SQVM *vm,SQCollectable **tchain)
\r
253 SQVM *vms = _thread(_root_vm);
\r
257 _refs_table.Mark(tchain);
\r
258 MarkObject(_registry,tchain);
\r
259 MarkObject(_consts,tchain);
\r
260 MarkObject(_metamethodsmap,tchain);
\r
261 MarkObject(_table_default_delegate,tchain);
\r
262 MarkObject(_array_default_delegate,tchain);
\r
263 MarkObject(_string_default_delegate,tchain);
\r
264 MarkObject(_number_default_delegate,tchain);
\r
265 MarkObject(_generator_default_delegate,tchain);
\r
266 MarkObject(_thread_default_delegate,tchain);
\r
267 MarkObject(_closure_default_delegate,tchain);
\r
268 MarkObject(_class_default_delegate,tchain);
\r
269 MarkObject(_instance_default_delegate,tchain);
\r
270 MarkObject(_weakref_default_delegate,tchain);
\r
274 SQInteger SQSharedState::ResurrectUnreachable(SQVM *vm)
\r
277 SQCollectable *tchain=NULL;
\r
279 RunMark(vm,&tchain);
\r
281 SQCollectable *resurrected = _gc_chain;
\r
282 SQCollectable *t = resurrected;
\r
283 //SQCollectable *nx = NULL;
\r
285 _gc_chain = tchain;
\r
287 SQArray *ret = NULL;
\r
289 ret = SQArray::Create(this,0);
\r
290 SQCollectable *rlast = NULL;
\r
293 SQObjectType type = t->GetType();
\r
294 if(type != OT_FUNCPROTO && type != OT_OUTER) {
\r
297 sqo._unVal.pRefCounted = t;
\r
304 assert(rlast->_next == NULL);
\r
305 rlast->_next = _gc_chain;
\r
308 _gc_chain->_prev = rlast;
\r
310 _gc_chain = resurrected;
\r
320 SQObjectPtr temp = ret;
\r
329 SQInteger SQSharedState::CollectGarbage(SQVM *vm)
\r
332 SQCollectable *tchain = NULL;
\r
334 RunMark(vm,&tchain);
\r
336 SQCollectable *t = _gc_chain;
\r
337 SQCollectable *nx = NULL;
\r
343 if(nx) nx->_uiRef++;
\r
344 if(--t->_uiRef == 0)
\r
356 _gc_chain = tchain;
\r
362 #ifndef NO_GARBAGE_COLLECTOR
\r
363 void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)
\r
367 if(*chain) (*chain)->_prev = c;
\r
371 void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
\r
373 if(c->_prev) c->_prev->_next = c->_next;
\r
374 else *chain = c->_next;
\r
376 c->_next->_prev = c->_prev;
\r
382 SQChar* SQSharedState::GetScratchPad(SQInteger size)
\r
386 if(_scratchpadsize < size) {
\r
387 newsize = size + (size>>1);
\r
388 _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
\r
389 _scratchpadsize = newsize;
\r
391 }else if(_scratchpadsize >= (size<<5)) {
\r
392 newsize = _scratchpadsize >> 1;
\r
393 _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
\r
394 _scratchpadsize = newsize;
\r
397 return _scratchpad;
\r
400 RefTable::RefTable()
\r
405 void RefTable::Finalize()
\r
407 RefNode *nodes = _nodes;
\r
408 for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
\r
414 RefTable::~RefTable()
\r
416 SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
\r
419 #ifndef NO_GARBAGE_COLLECTOR
\r
420 void RefTable::Mark(SQCollectable **chain)
\r
422 RefNode *nodes = (RefNode *)_nodes;
\r
423 for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
\r
424 if(type(nodes->obj) != OT_NULL) {
\r
425 SQSharedState::MarkObject(nodes->obj,chain);
\r
432 void RefTable::AddRef(SQObject &obj)
\r
436 RefNode *ref = Get(obj,mainpos,&prev,true);
\r
440 SQUnsignedInteger RefTable::GetRefCount(SQObject &obj)
\r
444 RefNode *ref = Get(obj,mainpos,&prev,true);
\r
449 SQBool RefTable::Release(SQObject &obj)
\r
453 RefNode *ref = Get(obj,mainpos,&prev,false);
\r
455 if(--ref->refs == 0) {
\r
456 SQObjectPtr o = ref->obj;
\r
458 prev->next = ref->next;
\r
461 _buckets[mainpos] = ref->next;
\r
463 ref->next = _freelist;
\r
467 //<<FIXME>>test for shrink?
\r
477 void RefTable::Resize(SQUnsignedInteger size)
\r
479 RefNode **oldbucks = _buckets;
\r
480 RefNode *t = _nodes;
\r
481 SQUnsignedInteger oldnumofslots = _numofslots;
\r
484 SQUnsignedInteger nfound = 0;
\r
485 for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
\r
486 if(type(t->obj) != OT_NULL) {
\r
488 assert(t->refs != 0);
\r
489 RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
\r
490 nn->refs = t->refs;
\r
496 assert(nfound == oldnumofslots);
\r
497 SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
\r
500 RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)
\r
502 RefNode *t = _buckets[mainpos];
\r
503 RefNode *newnode = _freelist;
\r
504 newnode->obj = obj;
\r
505 _buckets[mainpos] = newnode;
\r
506 _freelist = _freelist->next;
\r
508 assert(newnode->refs == 0);
\r
513 RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)
\r
516 mainpos = ::HashObj(obj)&(_numofslots-1);
\r
518 for (ref = _buckets[mainpos]; ref; ) {
\r
519 if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))
\r
524 if(ref == NULL && add) {
\r
525 if(_numofslots == _slotused) {
\r
526 assert(_freelist == 0);
\r
527 Resize(_numofslots*2);
\r
528 mainpos = ::HashObj(obj)&(_numofslots-1);
\r
530 ref = Add(mainpos,obj);
\r
535 void RefTable::AllocNodes(SQUnsignedInteger size)
\r
539 bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
\r
540 nodes = (RefNode *)&bucks[size];
\r
541 RefNode *temp = nodes;
\r
542 SQUnsignedInteger n;
\r
543 for(n = 0; n < size - 1; n++) {
\r
546 new (&temp->obj) SQObjectPtr;
\r
547 temp->next = temp+1;
\r
552 new (&temp->obj) SQObjectPtr;
\r
558 _numofslots = size;
\r
560 //////////////////////////////////////////////////////////////////////////
\r
563 * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
\r
564 * http://www.lua.org/copyright.html#4
\r
565 * http://www.lua.org/source/4.0.1/src_lstring.c.html
\r
568 SQStringTable::SQStringTable(SQSharedState *ss)
\r
575 SQStringTable::~SQStringTable()
\r
577 SQ_FREE(_strings,sizeof(SQString*)*_numofslots);
\r
581 void SQStringTable::AllocNodes(SQInteger size)
\r
583 _numofslots = size;
\r
584 _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
\r
585 memset(_strings,0,sizeof(SQString*)*_numofslots);
\r
588 SQString *SQStringTable::Add(const SQChar *news,SQInteger len)
\r
591 len = (SQInteger)scstrlen(news);
\r
592 SQHash newhash = ::_hashstr(news,len);
\r
593 SQHash h = newhash&(_numofslots-1);
\r
595 for (s = _strings[h]; s; s = s->_next){
\r
596 if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))
\r
600 SQString *t = (SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));
\r
602 t->_sharedstate = _sharedstate;
\r
603 memcpy(t->_val,news,rsl(len));
\r
604 t->_val[len] = _SC('\0');
\r
606 t->_hash = newhash;
\r
607 t->_next = _strings[h];
\r
610 if (_slotused > _numofslots) /* too crowded? */
\r
611 Resize(_numofslots*2);
\r
615 void SQStringTable::Resize(SQInteger size)
\r
617 SQInteger oldsize=_numofslots;
\r
618 SQString **oldtable=_strings;
\r
620 for (SQInteger i=0; i<oldsize; i++){
\r
621 SQString *p = oldtable[i];
\r
623 SQString *next = p->_next;
\r
624 SQHash h = p->_hash&(_numofslots-1);
\r
625 p->_next = _strings[h];
\r
630 SQ_FREE(oldtable,oldsize*sizeof(SQString*));
\r
633 void SQStringTable::Remove(SQString *bs)
\r
636 SQString *prev=NULL;
\r
637 SQHash h = bs->_hash&(_numofslots - 1);
\r
639 for (s = _strings[h]; s; ){
\r
642 prev->_next = s->_next;
\r
644 _strings[h] = s->_next;
\r
646 SQInteger slen = s->_len;
\r
648 SQ_FREE(s,sizeof(SQString) + rsl(slen));
\r
654 assert(0);//if this fail something is wrong
\r