Code::Blocks  SVN r11506
sqstate.cpp
Go to the documentation of this file.
1 /*
2  see copyright notice in squirrel.h
3 */
4 #include "sqpcheader.h"
5 #include "sqopcodes.h"
6 #include "sqvm.h"
7 #include "sqfuncproto.h"
8 #include "sqclosure.h"
9 #include "sqstring.h"
10 #include "sqtable.h"
11 #include "sqarray.h"
12 #include "squserdata.h"
13 #include "sqclass.h"
14 
15 SQObjectPtr _null_;
16 SQObjectPtr _true_(true);
17 SQObjectPtr _false_(false);
18 SQObjectPtr _one_((SQInteger)1);
19 SQObjectPtr _minusone_((SQInteger)-1);
20 
21 SQSharedState::SQSharedState()
22 {
23  _compilererrorhandler = NULL;
24  _printfunc = NULL;
25  _debuginfo = false;
26  _notifyallexceptions = false;
27 }
28 
29 #define newsysstring(s) { \
30  _systemstrings->push_back(SQString::Create(this,s)); \
31  }
32 
33 #define newmetamethod(s) { \
34  _metamethods->push_back(SQString::Create(this,s)); \
35  _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
36  }
37 
38 bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
39 {
40  SQInteger i = 0;
41 
42  SQInteger mask = 0;
43  while(typemask[i] != 0) {
44 
45  switch(typemask[i]){
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
64  default:
65  return false;
66  }
67  i++;
68  if(typemask[i] == '|') {
69  i++;
70  if(typemask[i] == 0)
71  return false;
72  continue;
73  }
74  res.push_back(mask);
75  mask = 0;
76 
77  }
78  return true;
79 }
80 
81 SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz)
82 {
83  SQInteger i=0;
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))
90  return NULL;
91  t->NewSlot(SQString::Create(ss,funcz[i].name),nc);
92  i++;
93  }
94  return t;
95 }
96 
97 void SQSharedState::Init()
98 {
99  _scratchpad=NULL;
100  _scratchpadsize=0;
101 #ifndef NO_GARBAGE_COLLECTOR
102  _gc_chain=NULL;
103 #endif
104  sq_new(_stringtable,SQStringTable);
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
110  //types names
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"));
126  //meta methods
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);
145 
146  _constructoridx = SQString::Create(this,_SC("constructor"));
147  _registry = SQTable::Create(this,0);
148  _consts = SQTable::Create(this,0);
149  _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);
150  _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);
151  _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);
152  _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);
153  _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);
154  _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);
155  _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);
156  _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);
157  _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);
158  _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
159 
160 }
161 
162 SQSharedState::~SQSharedState()
163 {
164  _constructoridx = _null_;
165  _table(_registry)->Finalize();
166  _table(_consts)->Finalize();
167  _table(_metamethodsmap)->Finalize();
168  _registry = _null_;
169  _consts = _null_;
170  _metamethodsmap = _null_;
171  while(!_systemstrings->empty()) {
172  _systemstrings->back()=_null_;
173  _systemstrings->pop_back();
174  }
175  _thread(_root_vm)->Finalize();
176  _root_vm = _null_;
177  _table_default_delegate = _null_;
178  _array_default_delegate = _null_;
179  _string_default_delegate = _null_;
180  _number_default_delegate = _null_;
181  _closure_default_delegate = _null_;
182  _generator_default_delegate = _null_;
183  _thread_default_delegate = _null_;
184  _class_default_delegate = _null_;
185  _instance_default_delegate = _null_;
186  _weakref_default_delegate = _null_;
187  _refs_table.Finalize();
188 #ifndef NO_GARBAGE_COLLECTOR
189  SQCollectable *t = _gc_chain;
190  SQCollectable *nx = NULL;
191  if(t) {
192  t->_uiRef++;
193  while(t) {
194  t->Finalize();
195  nx = t->_next;
196  if(nx) nx->_uiRef++;
197  if(--t->_uiRef == 0)
198  t->Release();
199  t = nx;
200  }
201  }
202  assert(_gc_chain==NULL); //just to proove a theory
203  while(_gc_chain){
204  _gc_chain->_uiRef++;
205  _gc_chain->Release();
206  }
207 #endif
208 
209  sq_delete(_types,SQObjectPtrVec);
210  sq_delete(_systemstrings,SQObjectPtrVec);
211  sq_delete(_metamethods,SQObjectPtrVec);
212  sq_delete(_stringtable,SQStringTable);
213  if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
214 }
215 
216 
217 SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
218 {
219  if(type(name) != OT_STRING)
220  return -1;
221  SQObjectPtr ret;
222  if(_table(_metamethodsmap)->Get(name,ret)) {
223  return _integer(ret);
224  }
225  return -1;
226 }
227 
228 #ifndef NO_GARBAGE_COLLECTOR
229 
230 void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
231 {
232  switch(type(o)){
233  case OT_TABLE:_table(o)->Mark(chain);break;
234  case OT_ARRAY:_array(o)->Mark(chain);break;
235  case OT_USERDATA:_userdata(o)->Mark(chain);break;
236  case OT_CLOSURE:_closure(o)->Mark(chain);break;
237  case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
238  case OT_GENERATOR:_generator(o)->Mark(chain);break;
239  case OT_THREAD:_thread(o)->Mark(chain);break;
240  case OT_CLASS:_class(o)->Mark(chain);break;
241  case OT_INSTANCE:_instance(o)->Mark(chain);break;
242  default: break; //shutup compiler
243  }
244 }
245 
246 
247 // C::B patch: Make the compiler happy by commenting unused variables
248 SQInteger SQSharedState::CollectGarbage(SQVM * /*vm*/)
249 {
250  SQInteger n=0;
251  SQCollectable *tchain=NULL;
252  SQVM *vms = _thread(_root_vm);
253 
254  vms->Mark(&tchain);
255  SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed();
256  _refs_table.Mark(&tchain);
257  MarkObject(_registry,&tchain);
258  MarkObject(_consts,&tchain);
259  MarkObject(_metamethodsmap,&tchain);
260  MarkObject(_table_default_delegate,&tchain);
261  MarkObject(_array_default_delegate,&tchain);
262  MarkObject(_string_default_delegate,&tchain);
263  MarkObject(_number_default_delegate,&tchain);
264  MarkObject(_generator_default_delegate,&tchain);
265  MarkObject(_thread_default_delegate,&tchain);
266  MarkObject(_closure_default_delegate,&tchain);
267  MarkObject(_class_default_delegate,&tchain);
268  MarkObject(_instance_default_delegate,&tchain);
269  MarkObject(_weakref_default_delegate,&tchain);
270 
271  SQCollectable *t = _gc_chain;
272  SQCollectable *nx = NULL;
273  if(t) {
274  t->_uiRef++;
275  while(t) {
276  t->Finalize();
277  nx = t->_next;
278  if(nx) nx->_uiRef++;
279  if(--t->_uiRef == 0)
280  t->Release();
281  t = nx;
282  n++;
283  }
284  }
285 
286  t = tchain;
287  while(t) {
288  t->UnMark();
289  t = t->_next;
290  }
291  _gc_chain = tchain;
292  SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed();
293  assert(z == x);
294  return n;
295 }
296 #endif
297 
298 #ifndef NO_GARBAGE_COLLECTOR
299 void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)
300 {
301  c->_prev = NULL;
302  c->_next = *chain;
303  if(*chain) (*chain)->_prev = c;
304  *chain = c;
305 }
306 
307 void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
308 {
309  if(c->_prev) c->_prev->_next = c->_next;
310  else *chain = c->_next;
311  if(c->_next)
312  c->_next->_prev = c->_prev;
313  c->_next = NULL;
314  c->_prev = NULL;
315 }
316 #endif
317 
318 SQChar* SQSharedState::GetScratchPad(SQInteger size)
319 {
320  SQInteger newsize;
321  if(size>0) {
322  if(_scratchpadsize < size) {
323  newsize = size + (size>>1);
324  _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
325  _scratchpadsize = newsize;
326 
327  }else if(_scratchpadsize >= (size<<5)) {
328  newsize = _scratchpadsize >> 1;
329  _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
330  _scratchpadsize = newsize;
331  }
332  }
333  return _scratchpad;
334 }
335 
336 RefTable::RefTable()
337 {
338  AllocNodes(4);
339 }
340 
341 void RefTable::Finalize()
342 {
343  RefNode *nodes = _nodes;
344  for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
345  nodes->obj = _null_;
346  nodes++;
347  }
348 }
349 
350 RefTable::~RefTable()
351 {
352  SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
353 }
354 
355 #ifndef NO_GARBAGE_COLLECTOR
356 void RefTable::Mark(SQCollectable **chain)
357 {
358  RefNode *nodes = (RefNode *)_nodes;
359  for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
360  if(type(nodes->obj) != OT_NULL) {
361  SQSharedState::MarkObject(nodes->obj,chain);
362  }
363  nodes++;
364  }
365 }
366 #endif
367 
368 void RefTable::AddRef(SQObject &obj)
369 {
370  SQHash mainpos;
371  RefNode *prev;
372  RefNode *ref = Get(obj,mainpos,&prev,true);
373  ref->refs++;
374 }
375 
376 SQBool RefTable::Release(SQObject &obj)
377 {
378  SQHash mainpos;
379  RefNode *prev;
380  RefNode *ref = Get(obj,mainpos,&prev,false);
381  if(ref) {
382  if(--ref->refs == 0) {
383  SQObjectPtr o = ref->obj;
384  if(prev) {
385  prev->next = ref->next;
386  }
387  else {
388  _buckets[mainpos] = ref->next;
389  }
390  ref->next = _freelist;
391  _freelist = ref;
392  _slotused--;
393  ref->obj = _null_;
394  //<<FIXME>>test for shrink?
395  return SQTrue;
396  }
397  }
398  else {
399  assert(0);
400  }
401  return SQFalse;
402 }
403 
404 void RefTable::Resize(SQUnsignedInteger size)
405 {
406  RefNode **oldbucks = _buckets;
407  RefNode *t = _nodes;
408  SQUnsignedInteger oldnumofslots = _numofslots;
409  AllocNodes(size);
410  //rehash
411  SQUnsignedInteger nfound = 0;
412  for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
413  if(type(t->obj) != OT_NULL) {
414  //add back;
415  assert(t->refs != 0);
416  RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
417  nn->refs = t->refs;
418  t->obj = _null_;
419  nfound++;
420  }
421  t++;
422  }
423  assert(nfound == oldnumofslots);
424  SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
425 }
426 
427 RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)
428 {
429  RefNode *t = _buckets[mainpos];
430  RefNode *newnode = _freelist;
431  newnode->obj = obj;
432  _buckets[mainpos] = newnode;
433  _freelist = _freelist->next;
434  newnode->next = t;
435  assert(newnode->refs == 0);
436  _slotused++;
437  return newnode;
438 }
439 
440 RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)
441 {
442  RefNode *ref;
443  mainpos = ::HashObj(obj)&(_numofslots-1);
444  *prev = NULL;
445  for (ref = _buckets[mainpos]; ref; ) {
446  if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))
447  break;
448  *prev = ref;
449  ref = ref->next;
450  }
451  if(ref == NULL && add) {
452  if(_numofslots == _slotused) {
453  assert(_freelist == 0);
454  Resize(_numofslots*2);
455  mainpos = ::HashObj(obj)&(_numofslots-1);
456  }
457  ref = Add(mainpos,obj);
458  }
459  return ref;
460 }
461 
462 void RefTable::AllocNodes(SQUnsignedInteger size)
463 {
464  RefNode **bucks;
465  RefNode *nodes;
466  bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
467  nodes = (RefNode *)&bucks[size];
468  RefNode *temp = nodes;
469  SQUnsignedInteger n;
470  for(n = 0; n < size - 1; n++) {
471  bucks[n] = NULL;
472  temp->refs = 0;
473  new (&temp->obj) SQObjectPtr;
474  temp->next = temp+1;
475  temp++;
476  }
477  bucks[n] = NULL;
478  temp->refs = 0;
479  new (&temp->obj) SQObjectPtr;
480  temp->next = NULL;
481  _freelist = nodes;
482  _nodes = nodes;
483  _buckets = bucks;
484  _slotused = 0;
485  _numofslots = size;
486 }
488 //SQStringTable
489 /*
490 * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
491 * http://www.lua.org/copyright.html#4
492 * http://www.lua.org/source/4.0.1/src_lstring.c.html
493 */
494 
495 SQStringTable::SQStringTable()
496 {
497  AllocNodes(4);
498  _slotused = 0;
499 }
500 
501 SQStringTable::~SQStringTable()
502 {
503  SQ_FREE(_strings,sizeof(SQString*)*_numofslots);
504  _strings = NULL;
505 }
506 
507 void SQStringTable::AllocNodes(SQInteger size)
508 {
509  _numofslots = size;
510  _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
511  memset(_strings,0,sizeof(SQString*)*_numofslots);
512 }
513 
514 SQString *SQStringTable::Add(const SQChar *news,SQInteger len)
515 {
516  if(len<0)
517  len = (SQInteger)scstrlen(news);
518  SQHash h = ::_hashstr(news,len)&(_numofslots-1);
519  SQString *s;
520  for (s = _strings[h]; s; s = s->_next){
521  if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))
522  return s; //found
523  }
524 
525  SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));
526  new (t) SQString;
527  memcpy(t->_val,news,rsl(len));
528  t->_val[len] = _SC('\0');
529  t->_len = len;
530  t->_hash = ::_hashstr(news,len);
531  t->_next = _strings[h];
532  _strings[h] = t;
533  _slotused++;
534  if (_slotused > _numofslots) /* too crowded? */
535  Resize(_numofslots*2);
536  return t;
537 }
538 
539 void SQStringTable::Resize(SQInteger size)
540 {
541  SQInteger oldsize=_numofslots;
542  SQString **oldtable=_strings;
543  AllocNodes(size);
544  for (SQInteger i=0; i<oldsize; i++){
545  SQString *p = oldtable[i];
546  while(p){
547  SQString *next = p->_next;
548  SQHash h = p->_hash&(_numofslots-1);
549  p->_next = _strings[h];
550  _strings[h] = p;
551  p = next;
552  }
553  }
554  SQ_FREE(oldtable,oldsize*sizeof(SQString*));
555 }
556 
557 void SQStringTable::Remove(SQString *bs)
558 {
559  SQString *s;
560  SQString *prev=NULL;
561  SQHash h = bs->_hash&(_numofslots - 1);
562 
563  for (s = _strings[h]; s; ){
564  if(s == bs){
565  if(prev)
566  prev->_next = s->_next;
567  else
568  _strings[h] = s->_next;
569  _slotused--;
570  SQInteger slen = s->_len;
571  s->~SQString();
572  SQ_FREE(s,sizeof(SQString) + rsl(slen));
573  return;
574  }
575  prev = s;
576  s = s->_next;
577  }
578  assert(0);//if this fail something is wrong
579 }
DLLIMPORT bool Add(const wxString &name, const wxString &mask)
Add a new extension filter.
Definition: filefilters.cpp:41
SQObjectPtr _false_(false)
SQObjectPtr _null_
Definition: sqstate.cpp:15
SQObjectPtr _one_((SQInteger) 1)
#define newmetamethod(s)
Definition: sqstate.cpp:33
bool CompileTypemask(SQIntVec &res, const SQChar *typemask)
Definition: sqstate.cpp:38
const wxString ref(_T("&"))
SQObjectPtr _minusone_((SQInteger) -1)
#define newsysstring(s)
Definition: sqstate.cpp:29
SQTable * CreateDefaultDelegate(SQSharedState *ss, SQRegFunction *funcz)
Definition: sqstate.cpp:81
char SQChar
SQObjectPtr _true_(true)
#define NULL
Definition: prefix.cpp:59