PageRenderTime 59ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/SDK/External/squirrel/squirrel/sqstate.cpp

https://gitlab.com/_Infinity_/infinity
C++ | 578 lines | 513 code | 45 blank | 20 comment | 62 complexity | 8ceac6ecda15ed4b904adf6b14072956 MD5 | raw file
Possible License(s): BSD-3-Clause
  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. SQObjectPtr _null_;
  15. //SQObjectPtr _true_(true);
  16. //SQObjectPtr _false_(false);
  17. //SQObjectPtr _one_((SQInteger)1);
  18. //SQObjectPtr _minusone_((SQInteger)-1);
  19. SQSharedState::SQSharedState()
  20. {
  21. _compilererrorhandler = NULL;
  22. _printfunc = NULL;
  23. _errorfunc = NULL;
  24. _debuginfo = false;
  25. _notifyallexceptions = false;
  26. }
  27. #define newsysstring(s) { \
  28. _systemstrings->push_back(SQString::Create(this,s)); \
  29. }
  30. #define newmetamethod(s) { \
  31. _metamethods->push_back(SQString::Create(this,s)); \
  32. _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
  33. }
  34. bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
  35. {
  36. SQInteger i = 0;
  37. SQInteger mask = 0;
  38. while(typemask[i] != 0) {
  39. switch(typemask[i]){
  40. case 'o': mask |= _RT_NULL; break;
  41. case 'i': mask |= _RT_INTEGER; break;
  42. case 'f': mask |= _RT_FLOAT; break;
  43. case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;
  44. case 's': mask |= _RT_STRING; break;
  45. case 't': mask |= _RT_TABLE; break;
  46. case 'a': mask |= _RT_ARRAY; break;
  47. case 'u': mask |= _RT_USERDATA; break;
  48. case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;
  49. case 'b': mask |= _RT_BOOL; break;
  50. case 'g': mask |= _RT_GENERATOR; break;
  51. case 'p': mask |= _RT_USERPOINTER; break;
  52. case 'v': mask |= _RT_THREAD; break;
  53. case 'x': mask |= _RT_INSTANCE; break;
  54. case 'y': mask |= _RT_CLASS; break;
  55. case 'r': mask |= _RT_WEAKREF; break;
  56. case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
  57. case ' ': i++; continue; //ignores spaces
  58. default:
  59. return false;
  60. }
  61. i++;
  62. if(typemask[i] == '|') {
  63. i++;
  64. if(typemask[i] == 0)
  65. return false;
  66. continue;
  67. }
  68. res.push_back(mask);
  69. mask = 0;
  70. }
  71. return true;
  72. }
  73. SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz)
  74. {
  75. SQInteger i=0;
  76. SQTable *t=SQTable::Create(ss,0);
  77. while(funcz[i].name!=0){
  78. SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f);
  79. nc->_nparamscheck = funcz[i].nparamscheck;
  80. nc->_name = SQString::Create(ss,funcz[i].name);
  81. if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))
  82. return NULL;
  83. t->NewSlot(SQString::Create(ss,funcz[i].name),nc);
  84. i++;
  85. }
  86. return t;
  87. }
  88. void SQSharedState::Init()
  89. {
  90. _scratchpad=NULL;
  91. _scratchpadsize=0;
  92. #ifndef NO_GARBAGE_COLLECTOR
  93. _gc_chain=NULL;
  94. #endif
  95. _stringtable = (SQStringTable*)SQ_MALLOC(sizeof(SQStringTable));
  96. new (_stringtable) SQStringTable(this);
  97. sq_new(_metamethods,SQObjectPtrVec);
  98. sq_new(_systemstrings,SQObjectPtrVec);
  99. sq_new(_types,SQObjectPtrVec);
  100. _metamethodsmap = SQTable::Create(this,MT_LAST-1);
  101. //adding type strings to avoid memory trashing
  102. //types names
  103. newsysstring(_SC("null"));
  104. newsysstring(_SC("table"));
  105. newsysstring(_SC("array"));
  106. newsysstring(_SC("closure"));
  107. newsysstring(_SC("string"));
  108. newsysstring(_SC("userdata"));
  109. newsysstring(_SC("integer"));
  110. newsysstring(_SC("float"));
  111. newsysstring(_SC("userpointer"));
  112. newsysstring(_SC("function"));
  113. newsysstring(_SC("generator"));
  114. newsysstring(_SC("thread"));
  115. newsysstring(_SC("class"));
  116. newsysstring(_SC("instance"));
  117. newsysstring(_SC("bool"));
  118. //meta methods
  119. newmetamethod(MM_ADD);
  120. newmetamethod(MM_SUB);
  121. newmetamethod(MM_MUL);
  122. newmetamethod(MM_DIV);
  123. newmetamethod(MM_UNM);
  124. newmetamethod(MM_MODULO);
  125. newmetamethod(MM_SET);
  126. newmetamethod(MM_GET);
  127. newmetamethod(MM_TYPEOF);
  128. newmetamethod(MM_NEXTI);
  129. newmetamethod(MM_CMP);
  130. newmetamethod(MM_CALL);
  131. newmetamethod(MM_CLONED);
  132. newmetamethod(MM_NEWSLOT);
  133. newmetamethod(MM_DELSLOT);
  134. newmetamethod(MM_TOSTRING);
  135. newmetamethod(MM_NEWMEMBER);
  136. newmetamethod(MM_INHERITED);
  137. _constructoridx = SQString::Create(this,_SC("constructor"));
  138. _registry = SQTable::Create(this,0);
  139. _consts = SQTable::Create(this,0);
  140. _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);
  141. _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);
  142. _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);
  143. _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);
  144. _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);
  145. _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);
  146. _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);
  147. _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);
  148. _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);
  149. _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
  150. }
  151. SQSharedState::~SQSharedState()
  152. {
  153. _constructoridx = _null_;
  154. _table(_registry)->Finalize();
  155. _table(_consts)->Finalize();
  156. _table(_metamethodsmap)->Finalize();
  157. _registry = _null_;
  158. _consts = _null_;
  159. _metamethodsmap = _null_;
  160. while(!_systemstrings->empty()) {
  161. _systemstrings->back()=_null_;
  162. _systemstrings->pop_back();
  163. }
  164. _thread(_root_vm)->Finalize();
  165. _root_vm = _null_;
  166. _table_default_delegate = _null_;
  167. _array_default_delegate = _null_;
  168. _string_default_delegate = _null_;
  169. _number_default_delegate = _null_;
  170. _closure_default_delegate = _null_;
  171. _generator_default_delegate = _null_;
  172. _thread_default_delegate = _null_;
  173. _class_default_delegate = _null_;
  174. _instance_default_delegate = _null_;
  175. _weakref_default_delegate = _null_;
  176. _refs_table.Finalize();
  177. #ifndef NO_GARBAGE_COLLECTOR
  178. SQCollectable *t = _gc_chain;
  179. SQCollectable *nx = NULL;
  180. while(t) {
  181. t->_uiRef++;
  182. t->Finalize();
  183. nx = t->_next;
  184. if(--t->_uiRef == 0)
  185. t->Release();
  186. t=nx;
  187. }
  188. assert(_gc_chain==NULL); //just to proove a theory
  189. while(_gc_chain){
  190. _gc_chain->_uiRef++;
  191. _gc_chain->Release();
  192. }
  193. #endif
  194. sq_delete(_types,SQObjectPtrVec);
  195. sq_delete(_systemstrings,SQObjectPtrVec);
  196. sq_delete(_metamethods,SQObjectPtrVec);
  197. sq_delete(_stringtable,SQStringTable);
  198. if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
  199. }
  200. SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
  201. {
  202. if(type(name) != OT_STRING)
  203. return -1;
  204. SQObjectPtr ret;
  205. if(_table(_metamethodsmap)->Get(name,ret)) {
  206. return _integer(ret);
  207. }
  208. return -1;
  209. }
  210. #ifndef NO_GARBAGE_COLLECTOR
  211. void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
  212. {
  213. switch(type(o)){
  214. case OT_TABLE:_table(o)->Mark(chain);break;
  215. case OT_ARRAY:_array(o)->Mark(chain);break;
  216. case OT_USERDATA:_userdata(o)->Mark(chain);break;
  217. case OT_CLOSURE:_closure(o)->Mark(chain);break;
  218. case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
  219. case OT_GENERATOR:_generator(o)->Mark(chain);break;
  220. case OT_THREAD:_thread(o)->Mark(chain);break;
  221. case OT_CLASS:_class(o)->Mark(chain);break;
  222. case OT_INSTANCE:_instance(o)->Mark(chain);break;
  223. case OT_OUTER:_outer(o)->Mark(chain);break;
  224. case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break;
  225. default: break; //shutup compiler
  226. }
  227. }
  228. SQInteger SQSharedState::CollectGarbage(SQVM *vm)
  229. {
  230. SQInteger n=0;
  231. SQCollectable *tchain=NULL;
  232. SQVM *vms = _thread(_root_vm);
  233. vms->Mark(&tchain);
  234. SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed();
  235. _refs_table.Mark(&tchain);
  236. MarkObject(_registry,&tchain);
  237. MarkObject(_consts,&tchain);
  238. MarkObject(_metamethodsmap,&tchain);
  239. MarkObject(_table_default_delegate,&tchain);
  240. MarkObject(_array_default_delegate,&tchain);
  241. MarkObject(_string_default_delegate,&tchain);
  242. MarkObject(_number_default_delegate,&tchain);
  243. MarkObject(_generator_default_delegate,&tchain);
  244. MarkObject(_thread_default_delegate,&tchain);
  245. MarkObject(_closure_default_delegate,&tchain);
  246. MarkObject(_class_default_delegate,&tchain);
  247. MarkObject(_instance_default_delegate,&tchain);
  248. MarkObject(_weakref_default_delegate,&tchain);
  249. SQCollectable *t = _gc_chain;
  250. SQCollectable *nx = NULL;
  251. while(t) {
  252. t->_uiRef++;
  253. t->Finalize();
  254. nx = t->_next;
  255. if(--t->_uiRef == 0)
  256. t->Release();
  257. t = nx;
  258. n++;
  259. }
  260. t = tchain;
  261. while(t) {
  262. t->UnMark();
  263. t = t->_next;
  264. }
  265. _gc_chain = tchain;
  266. SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed();
  267. assert(z == x);
  268. return n;
  269. }
  270. #endif
  271. #ifndef NO_GARBAGE_COLLECTOR
  272. void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)
  273. {
  274. c->_prev = NULL;
  275. c->_next = *chain;
  276. if(*chain) (*chain)->_prev = c;
  277. *chain = c;
  278. }
  279. void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
  280. {
  281. if(c->_prev) c->_prev->_next = c->_next;
  282. else *chain = c->_next;
  283. if(c->_next)
  284. c->_next->_prev = c->_prev;
  285. c->_next = NULL;
  286. c->_prev = NULL;
  287. }
  288. #endif
  289. SQChar* SQSharedState::GetScratchPad(SQInteger size)
  290. {
  291. SQInteger newsize;
  292. if(size>0) {
  293. if(_scratchpadsize < size) {
  294. newsize = size + (size>>1);
  295. _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
  296. _scratchpadsize = newsize;
  297. }else if(_scratchpadsize >= (size<<5)) {
  298. newsize = _scratchpadsize >> 1;
  299. _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
  300. _scratchpadsize = newsize;
  301. }
  302. }
  303. return _scratchpad;
  304. }
  305. RefTable::RefTable()
  306. {
  307. AllocNodes(4);
  308. }
  309. void RefTable::Finalize()
  310. {
  311. RefNode *nodes = _nodes;
  312. for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
  313. nodes->obj.Null();
  314. nodes++;
  315. }
  316. }
  317. RefTable::~RefTable()
  318. {
  319. SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
  320. }
  321. #ifndef NO_GARBAGE_COLLECTOR
  322. void RefTable::Mark(SQCollectable **chain)
  323. {
  324. RefNode *nodes = (RefNode *)_nodes;
  325. for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
  326. if(type(nodes->obj) != OT_NULL) {
  327. SQSharedState::MarkObject(nodes->obj,chain);
  328. }
  329. nodes++;
  330. }
  331. }
  332. #endif
  333. void RefTable::AddRef(SQObject &obj)
  334. {
  335. SQHash mainpos;
  336. RefNode *prev;
  337. RefNode *ref = Get(obj,mainpos,&prev,true);
  338. ref->refs++;
  339. }
  340. SQBool RefTable::Release(SQObject &obj)
  341. {
  342. SQHash mainpos;
  343. RefNode *prev;
  344. RefNode *ref = Get(obj,mainpos,&prev,false);
  345. if(ref) {
  346. if(--ref->refs == 0) {
  347. SQObjectPtr o = ref->obj;
  348. if(prev) {
  349. prev->next = ref->next;
  350. }
  351. else {
  352. _buckets[mainpos] = ref->next;
  353. }
  354. ref->next = _freelist;
  355. _freelist = ref;
  356. _slotused--;
  357. ref->obj = _null_;
  358. //<<FIXME>>test for shrink?
  359. return SQTrue;
  360. }
  361. }
  362. else {
  363. assert(0);
  364. }
  365. return SQFalse;
  366. }
  367. void RefTable::Resize(SQUnsignedInteger size)
  368. {
  369. RefNode **oldbucks = _buckets;
  370. RefNode *t = _nodes;
  371. SQUnsignedInteger oldnumofslots = _numofslots;
  372. AllocNodes(size);
  373. //rehash
  374. SQUnsignedInteger nfound = 0;
  375. for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
  376. if(type(t->obj) != OT_NULL) {
  377. //add back;
  378. assert(t->refs != 0);
  379. RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
  380. nn->refs = t->refs;
  381. t->obj = _null_;
  382. nfound++;
  383. }
  384. t++;
  385. }
  386. assert(nfound == oldnumofslots);
  387. SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
  388. }
  389. RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)
  390. {
  391. RefNode *t = _buckets[mainpos];
  392. RefNode *newnode = _freelist;
  393. newnode->obj = obj;
  394. _buckets[mainpos] = newnode;
  395. _freelist = _freelist->next;
  396. newnode->next = t;
  397. assert(newnode->refs == 0);
  398. _slotused++;
  399. return newnode;
  400. }
  401. RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)
  402. {
  403. RefNode *ref;
  404. mainpos = ::HashObj(obj)&(_numofslots-1);
  405. *prev = NULL;
  406. for (ref = _buckets[mainpos]; ref; ) {
  407. if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))
  408. break;
  409. *prev = ref;
  410. ref = ref->next;
  411. }
  412. if(ref == NULL && add) {
  413. if(_numofslots == _slotused) {
  414. assert(_freelist == 0);
  415. Resize(_numofslots*2);
  416. mainpos = ::HashObj(obj)&(_numofslots-1);
  417. }
  418. ref = Add(mainpos,obj);
  419. }
  420. return ref;
  421. }
  422. void RefTable::AllocNodes(SQUnsignedInteger size)
  423. {
  424. RefNode **bucks;
  425. RefNode *nodes;
  426. bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
  427. nodes = (RefNode *)&bucks[size];
  428. RefNode *temp = nodes;
  429. SQUnsignedInteger n;
  430. for(n = 0; n < size - 1; n++) {
  431. bucks[n] = NULL;
  432. temp->refs = 0;
  433. new (&temp->obj) SQObjectPtr;
  434. temp->next = temp+1;
  435. temp++;
  436. }
  437. bucks[n] = NULL;
  438. temp->refs = 0;
  439. new (&temp->obj) SQObjectPtr;
  440. temp->next = NULL;
  441. _freelist = nodes;
  442. _nodes = nodes;
  443. _buckets = bucks;
  444. _slotused = 0;
  445. _numofslots = size;
  446. }
  447. //////////////////////////////////////////////////////////////////////////
  448. //SQStringTable
  449. /*
  450. * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
  451. * http://www.lua.org/copyright.html#4
  452. * http://www.lua.org/source/4.0.1/src_lstring.c.html
  453. */
  454. SQStringTable::SQStringTable(SQSharedState *ss)
  455. {
  456. _sharedstate = ss;
  457. AllocNodes(4);
  458. _slotused = 0;
  459. }
  460. SQStringTable::~SQStringTable()
  461. {
  462. SQ_FREE(_strings,sizeof(SQString*)*_numofslots);
  463. _strings = NULL;
  464. }
  465. void SQStringTable::AllocNodes(SQInteger size)
  466. {
  467. _numofslots = size;
  468. _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
  469. memset(_strings,0,sizeof(SQString*)*_numofslots);
  470. }
  471. SQString *SQStringTable::Add(const SQChar *news,SQInteger len)
  472. {
  473. if(len<0)
  474. len = (SQInteger)scstrlen(news);
  475. SQHash h = ::_hashstr(news,len)&(_numofslots-1);
  476. SQString *s;
  477. for (s = _strings[h]; s; s = s->_next){
  478. if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))
  479. return s; //found
  480. }
  481. SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));
  482. new (t) SQString;
  483. t->_sharedstate = _sharedstate;
  484. memcpy(t->_val,news,rsl(len));
  485. t->_val[len] = _SC('\0');
  486. t->_len = len;
  487. t->_hash = ::_hashstr(news,len);
  488. t->_next = _strings[h];
  489. _strings[h] = t;
  490. _slotused++;
  491. if (_slotused > _numofslots) /* too crowded? */
  492. Resize(_numofslots*2);
  493. return t;
  494. }
  495. void SQStringTable::Resize(SQInteger size)
  496. {
  497. SQInteger oldsize=_numofslots;
  498. SQString **oldtable=_strings;
  499. AllocNodes(size);
  500. for (SQInteger i=0; i<oldsize; i++){
  501. SQString *p = oldtable[i];
  502. while(p){
  503. SQString *next = p->_next;
  504. SQHash h = p->_hash&(_numofslots-1);
  505. p->_next = _strings[h];
  506. _strings[h] = p;
  507. p = next;
  508. }
  509. }
  510. SQ_FREE(oldtable,oldsize*sizeof(SQString*));
  511. }
  512. void SQStringTable::Remove(SQString *bs)
  513. {
  514. SQString *s;
  515. SQString *prev=NULL;
  516. SQHash h = bs->_hash&(_numofslots - 1);
  517. for (s = _strings[h]; s; ){
  518. if(s == bs){
  519. if(prev)
  520. prev->_next = s->_next;
  521. else
  522. _strings[h] = s->_next;
  523. _slotused--;
  524. SQInteger slen = s->_len;
  525. s->~SQString();
  526. SQ_FREE(s,sizeof(SQString) + rsl(slen));
  527. return;
  528. }
  529. prev = s;
  530. s = s->_next;
  531. }
  532. assert(0);//if this fail something is wrong
  533. }