2 see copyright notice in squirrel.h
4 #include "sqpcheader.h"
7 #include "sqfuncproto.h"
12 #include "squserdata.h"
16 SQObjectPtr _true_(true);
17 SQObjectPtr _false_(false);
18 SQObjectPtr _one_((SQInteger)1);
19 SQObjectPtr _minusone_((SQInteger)-1);
21 SQSharedState::SQSharedState()
23 _compilererrorhandler = NULL;
26 _notifyallexceptions = false;
29 #define newsysstring(s) { \
30 _systemstrings->push_back(SQString::Create(this,s)); \
33 #define newmetamethod(s) { \
34 _metamethods->push_back(SQString::Create(this,s)); \
35 _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
38 bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
43 while(typemask[i] != 0) {
46 case 'o': mask |= _RT_NULL; break;
47 case 'i': mask |= _RT_INTEGER; break;
48 case 'f': mask |= _RT_FLOAT; break;
49 case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;
50 case 's': mask |= _RT_STRING; break;
51 case 't': mask |= _RT_TABLE; break;
52 case 'a': mask |= _RT_ARRAY; break;
53 case 'u': mask |= _RT_USERDATA; break;
54 case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;
55 case 'b': mask |= _RT_BOOL; break;
56 case 'g': mask |= _RT_GENERATOR; break;
57 case 'p': mask |= _RT_USERPOINTER; break;
58 case 'v': mask |= _RT_THREAD; break;
59 case 'x': mask |= _RT_INSTANCE; break;
60 case 'y': mask |= _RT_CLASS; break;
61 case 'r': mask |= _RT_WEAKREF; break;
62 case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
63 case ' ': i++; continue; //ignores spaces
68 if(typemask[i] == '|') {
81 SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz)
84 SQTable *t=SQTable::Create(ss,0);
85 while(funcz[i].name!=0){
86 SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f);
87 nc->_nparamscheck = funcz[i].nparamscheck;
88 nc->_name = SQString::Create(ss,funcz[i].name);
89 if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))
91 t->NewSlot(SQString::Create(ss,funcz[i].name),nc);
97 void SQSharedState::Init()
101 #ifndef NO_GARBAGE_COLLECTOR
104 sq_new(_stringtable,StringTable);
105 sq_new(_metamethods,SQObjectPtrVec);
106 sq_new(_systemstrings,SQObjectPtrVec);
107 sq_new(_types,SQObjectPtrVec);
108 _metamethodsmap = SQTable::Create(this,MT_LAST-1);
109 //adding type strings to avoid memory trashing
111 newsysstring(_SC("null"));
112 newsysstring(_SC("table"));
113 newsysstring(_SC("array"));
114 newsysstring(_SC("closure"));
115 newsysstring(_SC("string"));
116 newsysstring(_SC("userdata"));
117 newsysstring(_SC("integer"));
118 newsysstring(_SC("float"));
119 newsysstring(_SC("userpointer"));
120 newsysstring(_SC("function"));
121 newsysstring(_SC("generator"));
122 newsysstring(_SC("thread"));
123 newsysstring(_SC("class"));
124 newsysstring(_SC("instance"));
125 newsysstring(_SC("bool"));
127 newmetamethod(MM_ADD);
128 newmetamethod(MM_SUB);
129 newmetamethod(MM_MUL);
130 newmetamethod(MM_DIV);
131 newmetamethod(MM_UNM);
132 newmetamethod(MM_MODULO);
133 newmetamethod(MM_SET);
134 newmetamethod(MM_GET);
135 newmetamethod(MM_TYPEOF);
136 newmetamethod(MM_NEXTI);
137 newmetamethod(MM_CMP);
138 newmetamethod(MM_CALL);
139 newmetamethod(MM_CLONED);
140 newmetamethod(MM_NEWSLOT);
141 newmetamethod(MM_DELSLOT);
142 newmetamethod(MM_TOSTRING);
143 newmetamethod(MM_NEWMEMBER);
144 newmetamethod(MM_INHERITED);
146 _constructoridx = SQString::Create(this,_SC("constructor"));
147 _registry = SQTable::Create(this,0);
148 _table_default_delegate=CreateDefaultDelegate(this,_table_default_delegate_funcz);
149 _array_default_delegate=CreateDefaultDelegate(this,_array_default_delegate_funcz);
150 _string_default_delegate=CreateDefaultDelegate(this,_string_default_delegate_funcz);
151 _number_default_delegate=CreateDefaultDelegate(this,_number_default_delegate_funcz);
152 _closure_default_delegate=CreateDefaultDelegate(this,_closure_default_delegate_funcz);
153 _generator_default_delegate=CreateDefaultDelegate(this,_generator_default_delegate_funcz);
154 _thread_default_delegate=CreateDefaultDelegate(this,_thread_default_delegate_funcz);
155 _class_default_delegate=CreateDefaultDelegate(this,_class_default_delegate_funcz);
156 _instance_default_delegate=CreateDefaultDelegate(this,_instance_default_delegate_funcz);
157 _weakref_default_delegate=CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
161 SQSharedState::~SQSharedState()
163 _constructoridx = _null_;
164 _refs_table.Finalize();
165 _table(_registry)->Finalize();
166 _table(_metamethodsmap)->Finalize();
168 _metamethodsmap = _null_;
169 while(!_systemstrings->empty()) {
170 _systemstrings->back()=_null_;
171 _systemstrings->pop_back();
173 _thread(_root_vm)->Finalize();
175 _table_default_delegate=_null_;
176 _array_default_delegate=_null_;
177 _string_default_delegate=_null_;
178 _number_default_delegate=_null_;
179 _closure_default_delegate=_null_;
180 _generator_default_delegate=_null_;
181 _thread_default_delegate=_null_;
182 _class_default_delegate=_null_;
183 _instance_default_delegate=_null_;
184 _weakref_default_delegate=_null_;
186 #ifndef NO_GARBAGE_COLLECTOR
187 SQCollectable *t=_gc_chain;
188 SQCollectable *nx=NULL;
197 assert(_gc_chain==NULL); //just to proove a theory
200 _gc_chain->Release();
204 sq_delete(_types,SQObjectPtrVec);
205 sq_delete(_systemstrings,SQObjectPtrVec);
206 sq_delete(_metamethods,SQObjectPtrVec);
207 sq_delete(_stringtable,StringTable);
208 if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
212 SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
214 if(type(name) != OT_STRING)
217 if(_table(_metamethodsmap)->Get(name,ret)) {
218 return _integer(ret);
223 #ifndef NO_GARBAGE_COLLECTOR
225 void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
228 case OT_TABLE:_table(o)->Mark(chain);break;
229 case OT_ARRAY:_array(o)->Mark(chain);break;
230 case OT_USERDATA:_userdata(o)->Mark(chain);break;
231 case OT_CLOSURE:_closure(o)->Mark(chain);break;
232 case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
233 case OT_GENERATOR:_generator(o)->Mark(chain);break;
234 case OT_THREAD:_thread(o)->Mark(chain);break;
235 case OT_CLASS:_class(o)->Mark(chain);break;
236 case OT_INSTANCE:_instance(o)->Mark(chain);break;
237 default: break; //shutup compiler
242 SQInteger SQSharedState::CollectGarbage(SQVM *vm)
245 SQCollectable *tchain=NULL;
246 SQVM *vms = _thread(_root_vm);
249 SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed();
250 _refs_table.Mark(&tchain);
251 MarkObject(_registry,&tchain);
252 MarkObject(_metamethodsmap,&tchain);
253 MarkObject(_table_default_delegate,&tchain);
254 MarkObject(_array_default_delegate,&tchain);
255 MarkObject(_string_default_delegate,&tchain);
256 MarkObject(_number_default_delegate,&tchain);
257 MarkObject(_generator_default_delegate,&tchain);
258 MarkObject(_thread_default_delegate,&tchain);
259 MarkObject(_closure_default_delegate,&tchain);
260 MarkObject(_class_default_delegate,&tchain);
261 MarkObject(_instance_default_delegate,&tchain);
262 MarkObject(_weakref_default_delegate,&tchain);
264 SQCollectable *t = _gc_chain;
265 SQCollectable *nx = NULL;
282 SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed();
288 #ifndef NO_GARBAGE_COLLECTOR
289 void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)
293 if(*chain) (*chain)->_prev = c;
297 void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
299 if(c->_prev) c->_prev->_next = c->_next;
300 else *chain = c->_next;
302 c->_next->_prev = c->_prev;
308 SQChar* SQSharedState::GetScratchPad(SQInteger size)
312 if(_scratchpadsize < size) {
313 newsize = size + (size>>1);
314 _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
315 _scratchpadsize = newsize;
317 }else if(_scratchpadsize >= (size<<5)) {
318 newsize = _scratchpadsize >> 1;
319 _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
320 _scratchpadsize = newsize;
331 void RefTable::Finalize()
333 RefNode *nodes = _nodes;
334 for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
340 RefTable::~RefTable()
342 SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
345 #ifndef NO_GARBAGE_COLLECTOR
346 void RefTable::Mark(SQCollectable **chain)
348 RefNode *nodes = (RefNode *)_nodes;
349 for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
350 if(type(nodes->obj) != OT_NULL) {
351 SQSharedState::MarkObject(nodes->obj,chain);
358 void RefTable::AddRef(SQObject &obj)
362 RefNode *ref = Get(obj,mainpos,&prev,true);
366 SQBool RefTable::Release(SQObject &obj)
370 RefNode *ref = Get(obj,mainpos,&prev,false);
372 if(--ref->refs == 0) {
373 SQObjectPtr o = ref->obj;
375 prev->next = ref->next;
378 _buckets[mainpos] = ref->next;
380 ref->next = _freelist;
384 //<<FIXME>>test for shrink?
394 void RefTable::Resize(SQUnsignedInteger size)
396 RefNode **oldbucks = _buckets;
398 SQUnsignedInteger oldnumofslots = _numofslots;
401 SQUnsignedInteger nfound = 0;
402 for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
403 if(type(t->obj) != OT_NULL) {
405 assert(t->refs != 0);
406 RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
413 assert(nfound == oldnumofslots);
414 SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
417 RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)
419 RefNode *t = _buckets[mainpos];
420 RefNode *newnode = _freelist;
422 _buckets[mainpos] = newnode;
423 _freelist = _freelist->next;
425 assert(newnode->refs == 0);
430 RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)
433 mainpos = ::HashObj(obj)&(_numofslots-1);
435 for (ref = _buckets[mainpos]; ref; ) {
436 if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))
441 if(ref == NULL && add) {
442 if(_numofslots == _slotused) {
443 assert(_freelist == 0);
444 Resize(_numofslots*2);
445 mainpos = ::HashObj(obj)&(_numofslots-1);
447 ref = Add(mainpos,obj);
452 void RefTable::AllocNodes(SQUnsignedInteger size)
456 bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
457 nodes = (RefNode *)&bucks[size];
458 RefNode *temp = nodes;
460 for(n = 0; n < size - 1; n++) {
463 new (&temp->obj) SQObjectPtr;
469 new (&temp->obj) SQObjectPtr;
477 //////////////////////////////////////////////////////////////////////////
480 * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
481 * http://www.lua.org/copyright.html#4
482 * http://www.lua.org/source/4.0.1/src_lstring.c.html
485 StringTable::StringTable()
491 StringTable::~StringTable()
493 SQ_FREE(_strings,sizeof(SQString*)*_numofslots);
497 void StringTable::AllocNodes(SQInteger size)
500 _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
501 memset(_strings,0,sizeof(SQString*)*_numofslots);
504 SQString *StringTable::Add(const SQChar *news,SQInteger len)
507 len = (SQInteger)scstrlen(news);
508 SQHash h = ::_hashstr(news,len)&(_numofslots-1);
510 for (s = _strings[h]; s; s = s->_next){
511 if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))
515 SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));
517 memcpy(t->_val,news,rsl(len));
518 t->_val[len] = _SC('\0');
520 t->_hash = ::_hashstr(news,len);
521 t->_next = _strings[h];
524 if (_slotused > _numofslots) /* too crowded? */
525 Resize(_numofslots*2);
529 void StringTable::Resize(SQInteger size)
531 SQInteger oldsize=_numofslots;
532 SQString **oldtable=_strings;
534 for (SQInteger i=0; i<oldsize; i++){
535 SQString *p = oldtable[i];
537 SQString *next = p->_next;
538 SQHash h = p->_hash&(_numofslots-1);
539 p->_next = _strings[h];
544 SQ_FREE(oldtable,oldsize*sizeof(SQString*));
547 void StringTable::Remove(SQString *bs)
551 SQHash h = bs->_hash&(_numofslots - 1);
553 for (s = _strings[h]; s; ){
556 prev->_next = s->_next;
558 _strings[h] = s->_next;
560 SQInteger slen = s->_len;
562 SQ_FREE(s,sizeof(SQString) + rsl(slen));
568 assert(0);//if this fail something is wrong