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
16 SQObjectPtr _true_(true);
\r
17 SQObjectPtr _false_(false);
\r
18 SQObjectPtr _one_(1);
\r
19 SQObjectPtr _minusone_(-1);
\r
21 SQSharedState::SQSharedState()
\r
23 _compilererrorhandler = NULL;
\r
28 #define newsysstring(s) { \
\r
29 _systemstrings->push_back(SQString::Create(this,s)); \
\r
32 #define newmetamethod(s) { \
\r
33 _metamethods->push_back(SQString::Create(this,s)); \
\r
34 _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
\r
37 bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
\r
42 while(typemask[i] != 0) {
\r
44 switch(typemask[i]){
\r
45 case 'o': mask |= _RT_NULL; break;
\r
46 case 'i': mask |= _RT_INTEGER; break;
\r
47 case 'f': mask |= _RT_FLOAT; break;
\r
48 case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;
\r
49 case 's': mask |= _RT_STRING; break;
\r
50 case 't': mask |= _RT_TABLE; break;
\r
51 case 'a': mask |= _RT_ARRAY; break;
\r
52 case 'u': mask |= _RT_USERDATA; break;
\r
53 case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;
\r
54 case 'b': mask |= _RT_BOOL; break;
\r
55 case 'g': mask |= _RT_GENERATOR; break;
\r
56 case 'p': mask |= _RT_USERPOINTER; break;
\r
57 case 'v': mask |= _RT_THREAD; break;
\r
58 case 'x': mask |= _RT_INSTANCE; break;
\r
59 case 'y': mask |= _RT_CLASS; break;
\r
60 case 'r': mask |= _RT_WEAKREF; break;
\r
61 case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
\r
62 case ' ': i++; continue; //ignores spaces
\r
67 if(typemask[i] == '|') {
\r
69 if(typemask[i] == 0)
\r
73 res.push_back(mask);
\r
80 SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz)
\r
83 SQTable *t=SQTable::Create(ss,0);
\r
84 while(funcz[i].name!=0){
\r
85 SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f);
\r
86 nc->_nparamscheck = funcz[i].nparamscheck;
\r
87 nc->_name = SQString::Create(ss,funcz[i].name);
\r
88 if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))
\r
90 t->NewSlot(SQString::Create(ss,funcz[i].name),nc);
\r
96 void SQSharedState::Init()
\r
100 #ifndef NO_GARBAGE_COLLECTOR
\r
103 sq_new(_stringtable,StringTable);
\r
104 sq_new(_metamethods,SQObjectPtrVec);
\r
105 sq_new(_systemstrings,SQObjectPtrVec);
\r
106 sq_new(_types,SQObjectPtrVec);
\r
107 _metamethodsmap = SQTable::Create(this,MT_LAST-1);
\r
108 //adding type strings to avoid memory trashing
\r
110 newsysstring(_SC("null"));
\r
111 newsysstring(_SC("table"));
\r
112 newsysstring(_SC("array"));
\r
113 newsysstring(_SC("closure"));
\r
114 newsysstring(_SC("string"));
\r
115 newsysstring(_SC("userdata"));
\r
116 newsysstring(_SC("integer"));
\r
117 newsysstring(_SC("float"));
\r
118 newsysstring(_SC("userpointer"));
\r
119 newsysstring(_SC("function"));
\r
120 newsysstring(_SC("generator"));
\r
121 newsysstring(_SC("thread"));
\r
122 newsysstring(_SC("class"));
\r
123 newsysstring(_SC("instance"));
\r
124 newsysstring(_SC("bool"));
\r
126 newmetamethod(MM_ADD);
\r
127 newmetamethod(MM_SUB);
\r
128 newmetamethod(MM_MUL);
\r
129 newmetamethod(MM_DIV);
\r
130 newmetamethod(MM_UNM);
\r
131 newmetamethod(MM_MODULO);
\r
132 newmetamethod(MM_SET);
\r
133 newmetamethod(MM_GET);
\r
134 newmetamethod(MM_TYPEOF);
\r
135 newmetamethod(MM_NEXTI);
\r
136 newmetamethod(MM_CMP);
\r
137 newmetamethod(MM_CALL);
\r
138 newmetamethod(MM_CLONED);
\r
139 newmetamethod(MM_NEWSLOT);
\r
140 newmetamethod(MM_DELSLOT);
\r
141 newmetamethod(MM_TOSTRING);
\r
143 _constructoridx = SQString::Create(this,_SC("constructor"));
\r
144 _refs_table = SQTable::Create(this,0);
\r
145 _registry = SQTable::Create(this,0);
\r
146 _table_default_delegate=CreateDefaultDelegate(this,_table_default_delegate_funcz);
\r
147 _array_default_delegate=CreateDefaultDelegate(this,_array_default_delegate_funcz);
\r
148 _string_default_delegate=CreateDefaultDelegate(this,_string_default_delegate_funcz);
\r
149 _number_default_delegate=CreateDefaultDelegate(this,_number_default_delegate_funcz);
\r
150 _closure_default_delegate=CreateDefaultDelegate(this,_closure_default_delegate_funcz);
\r
151 _generator_default_delegate=CreateDefaultDelegate(this,_generator_default_delegate_funcz);
\r
152 _thread_default_delegate=CreateDefaultDelegate(this,_thread_default_delegate_funcz);
\r
153 _class_default_delegate=CreateDefaultDelegate(this,_class_default_delegate_funcz);
\r
154 _instance_default_delegate=CreateDefaultDelegate(this,_instance_default_delegate_funcz);
\r
155 _weakref_default_delegate=CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
\r
159 SQSharedState::~SQSharedState()
\r
161 _constructoridx = _null_;
\r
162 _table(_refs_table)->Finalize();
\r
163 _table(_registry)->Finalize();
\r
164 _table(_metamethodsmap)->Finalize();
\r
165 _refs_table = _null_;
\r
166 _registry = _null_;
\r
167 _metamethodsmap = _null_;
\r
168 while(!_systemstrings->empty()){
\r
169 _systemstrings->back()=_null_;
\r
170 _systemstrings->pop_back();
\r
172 _thread(_root_vm)->Finalize();
\r
174 _table_default_delegate=_null_;
\r
175 _array_default_delegate=_null_;
\r
176 _string_default_delegate=_null_;
\r
177 _number_default_delegate=_null_;
\r
178 _closure_default_delegate=_null_;
\r
179 _generator_default_delegate=_null_;
\r
180 _thread_default_delegate=_null_;
\r
181 _class_default_delegate=_null_;
\r
182 _instance_default_delegate=_null_;
\r
183 _weakref_default_delegate=_null_;
\r
185 #ifndef NO_GARBAGE_COLLECTOR
\r
188 SQCollectable *t=_gc_chain;
\r
189 SQCollectable *nx=NULL;
\r
198 assert(_gc_chain==NULL); //just to proove a theory
\r
200 _gc_chain->_uiRef++;
\r
201 _gc_chain->Release();
\r
204 sq_delete(_types,SQObjectPtrVec);
\r
205 sq_delete(_systemstrings,SQObjectPtrVec);
\r
206 sq_delete(_metamethods,SQObjectPtrVec);
\r
207 sq_delete(_stringtable,StringTable);
\r
208 if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
\r
212 SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
\r
214 if(type(name) != OT_STRING)
\r
217 if(_table(_metamethodsmap)->Get(name,ret)) {
\r
218 return _integer(ret);
\r
223 #ifndef NO_GARBAGE_COLLECTOR
\r
225 void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
\r
228 case OT_TABLE:_table(o)->Mark(chain);break;
\r
229 case OT_ARRAY:_array(o)->Mark(chain);break;
\r
230 case OT_USERDATA:_userdata(o)->Mark(chain);break;
\r
231 case OT_CLOSURE:_closure(o)->Mark(chain);break;
\r
232 case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
\r
233 case OT_GENERATOR:_generator(o)->Mark(chain);break;
\r
234 case OT_THREAD:_thread(o)->Mark(chain);break;
\r
235 case OT_CLASS:_class(o)->Mark(chain);break;
\r
236 case OT_INSTANCE:_instance(o)->Mark(chain);break;
\r
241 SQInteger SQSharedState::CollectGarbage(SQVM *vm)
\r
244 SQCollectable *tchain=NULL;
\r
245 SQVM *vms=_thread(_root_vm);
\r
247 vms->Mark(&tchain);
\r
248 SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed();
\r
249 MarkObject(_refs_table,&tchain);
\r
250 MarkObject(_registry,&tchain);
\r
251 MarkObject(_metamethodsmap,&tchain);
\r
252 MarkObject(_table_default_delegate,&tchain);
\r
253 MarkObject(_array_default_delegate,&tchain);
\r
254 MarkObject(_string_default_delegate,&tchain);
\r
255 MarkObject(_number_default_delegate,&tchain);
\r
256 MarkObject(_generator_default_delegate,&tchain);
\r
257 MarkObject(_thread_default_delegate,&tchain);
\r
258 MarkObject(_closure_default_delegate,&tchain);
\r
259 MarkObject(_class_default_delegate,&tchain);
\r
260 MarkObject(_instance_default_delegate,&tchain);
\r
261 MarkObject(_weakref_default_delegate,&tchain);
\r
263 SQCollectable *t=_gc_chain;
\r
264 SQCollectable *nx=NULL;
\r
281 SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed();
\r
287 #ifndef NO_GARBAGE_COLLECTOR
\r
288 void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)
\r
292 if(*chain) (*chain)->_prev=c;
\r
296 void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
\r
298 if(c->_prev) c->_prev->_next=c->_next;
\r
299 else *chain=c->_next;
\r
301 c->_next->_prev=c->_prev;
\r
307 SQChar* SQSharedState::GetScratchPad(SQInteger size)
\r
311 if(_scratchpadsize<size){
\r
312 newsize=size+(size>>1);
\r
313 _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
\r
314 _scratchpadsize=newsize;
\r
316 }else if(_scratchpadsize>=(size<<5)){
\r
317 newsize=_scratchpadsize>>1;
\r
318 _scratchpad=(SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
\r
319 _scratchpadsize=newsize;
\r
322 return _scratchpad;
\r
325 //////////////////////////////////////////////////////////////////////////
\r
328 * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
\r
329 * http://www.lua.org/copyright.html#4
\r
330 * http://www.lua.org/source/4.0.1/src_lstring.c.html
\r
333 SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
\r
335 SQInteger idx = (SQInteger)TranslateIndex(refpos);
\r
337 outkey = (SQInteger)idx;
\r
338 outval = SQInteger(_val[idx]);
\r
339 //return idx for the next iteration
\r
342 //nothing to iterate anymore
\r
346 StringTable::StringTable()
\r
352 StringTable::~StringTable()
\r
354 SQ_FREE(_strings,sizeof(SQString*)*_numofslots);
\r
358 void StringTable::AllocNodes(SQInteger size)
\r
362 _strings=(SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
\r
363 memset(_strings,0,sizeof(SQString*)*_numofslots);
\r
366 SQString *StringTable::Add(const SQChar *news,SQInteger len)
\r
369 len=scstrlen(news);
\r
370 SQHash h = ::_hashstr(news,len)&(_numofslots-1);
\r
372 for (s = _strings[h]; s; s = s->_next){
\r
373 if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))
\r
377 SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));
\r
379 memcpy(t->_val,news,rsl(len));
\r
380 t->_val[len] = _SC('\0');
\r
382 t->_hash = ::_hashstr(news,len);
\r
383 t->_next = _strings[h];
\r
386 if (_slotused > _numofslots) /* too crowded? */
\r
387 Resize(_numofslots*2);
\r
391 void StringTable::Resize(SQInteger size)
\r
393 SQInteger oldsize=_numofslots;
\r
394 SQString **oldtable=_strings;
\r
396 for (SQInteger i=0; i<oldsize; i++){
\r
397 SQString *p = oldtable[i];
\r
399 SQString *next = p->_next;
\r
400 SQHash h = p->_hash&(_numofslots-1);
\r
401 p->_next = _strings[h];
\r
406 SQ_FREE(oldtable,oldsize*sizeof(SQString*));
\r
409 void StringTable::Remove(SQString *bs)
\r
412 SQString *prev=NULL;
\r
413 SQHash h = bs->_hash&(_numofslots - 1);
\r
415 for (s = _strings[h]; s; ){
\r
418 prev->_next = s->_next;
\r
420 _strings[h] = s->_next;
\r
422 SQInteger slen = s->_len;
\r
424 SQ_FREE(s,sizeof(SQString) + rsl(slen));
\r
430 assert(0);//if this fail something is wrong
\r