sqstate.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  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. _foreignptr = NULL;
  27. _releasehook = NULL;
  28. #ifdef SQ_WITH_DELAYED_RELEASE_HOOKS
  29. _already_in_CallDelayedReleaseHooks = false;
  30. #endif // SQ_WITH_DELAYED_RELEASE_HOOKS
  31. #ifdef SQ_JIT_LLVM
  32. //llvm::StructType::create(
  33. #endif
  34. }
  35. #define newsysstring(s) { \
  36. _systemstrings->push_back(SQString::Create(this,s)); \
  37. }
  38. #define newmetamethod(s) { \
  39. _metamethods->push_back(SQString::Create(this,s)); \
  40. _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
  41. }
  42. bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
  43. {
  44. SQInteger i = 0;
  45. SQInteger mask = 0;
  46. while(typemask[i] != 0) {
  47. switch(typemask[i]){
  48. case 'o': mask |= _RT_NULL; break;
  49. case 'i': mask |= _RT_INTEGER; break;
  50. case 'f': mask |= _RT_FLOAT; break;
  51. case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;
  52. case 's': mask |= _RT_STRING; break;
  53. case 't': mask |= _RT_TABLE; break;
  54. case 'a': mask |= _RT_ARRAY; break;
  55. case 'u': mask |= _RT_USERDATA; break;
  56. case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;
  57. case 'b': mask |= _RT_BOOL; break;
  58. case 'g': mask |= _RT_GENERATOR; break;
  59. case 'p': mask |= _RT_USERPOINTER; break;
  60. case 'v': mask |= _RT_THREAD; break;
  61. case 'x': mask |= _RT_INSTANCE; break;
  62. case 'y': mask |= _RT_CLASS; break;
  63. case 'r': mask |= _RT_WEAKREF; break;
  64. case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
  65. case ' ': i++; continue; //ignores spaces
  66. default:
  67. return false;
  68. }
  69. i++;
  70. if(typemask[i] == '|') {
  71. i++;
  72. if(typemask[i] == 0)
  73. return false;
  74. continue;
  75. }
  76. res.push_back(mask);
  77. mask = 0;
  78. }
  79. return true;
  80. }
  81. static SQTable *CreateDefaultDelegate(SQSharedState *ss,const 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,0);
  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. void SQSharedState::Init()
  97. {
  98. _scratchstr=NULL;
  99. _scratchpad=NULL;
  100. _scratchpadsize=0;
  101. #ifndef NO_GARBAGE_COLLECTOR
  102. _gc_chain=NULL;
  103. #endif
  104. _stringtable = (SQStringTable*)SQ_MALLOC(sizeof(SQStringTable));
  105. new (_stringtable) SQStringTable(this);
  106. sq_new(_metamethods,SQObjectPtrVec);
  107. sq_new(_systemstrings,SQObjectPtrVec);
  108. sq_new(_types,SQObjectPtrVec);
  109. _defined_names = SQTable::Create(this,0);
  110. #define SQUILU_NAME_BASE "__SQUILU_"
  111. _define_squilu = SQString::Create(this,_SC(SQUILU_NAME_BASE "_"));
  112. _define_squilu_int_sz = SQString::Create(this,
  113. _SC((sizeof(SQInteger) == 8) ? SQUILU_NAME_BASE "INT_SZ8__" :
  114. SQUILU_NAME_BASE "INT_SZ4__"));
  115. _define_squilu_float_sz = SQString::Create(this,
  116. _SC((sizeof(SQFloat) == 8) ? SQUILU_NAME_BASE "FLOAT_SZ8__" :
  117. SQUILU_NAME_BASE "FLOAT_SZ4__"));
  118. _define_squilu_ptr_sz = SQString::Create(this,
  119. _SC((sizeof(void *) == 8) ? SQUILU_NAME_BASE "PTR_SZ8__" :
  120. SQUILU_NAME_BASE "PTR_SZ4__"));
  121. #undef SQUILU_NAME_BASE
  122. SQObjectPtr value(true);
  123. _table(_defined_names)->NewSlot(_define_squilu, value);
  124. _table(_defined_names)->NewSlot(_define_squilu_int_sz, value);
  125. _table(_defined_names)->NewSlot(_define_squilu_float_sz, value);
  126. _table(_defined_names)->NewSlot(_define_squilu_ptr_sz, value);
  127. _metamethodsmap = SQTable::Create(this,MT_LAST-1);
  128. //adding type strings to avoid memory trashing
  129. //types names
  130. newsysstring(_SC("null"));
  131. newsysstring(_SC("table"));
  132. newsysstring(_SC("array"));
  133. newsysstring(_SC("closure"));
  134. newsysstring(_SC("string"));
  135. newsysstring(_SC("userdata"));
  136. newsysstring(_SC("integer"));
  137. newsysstring(_SC("float"));
  138. newsysstring(_SC("userpointer"));
  139. newsysstring(_SC("function"));
  140. newsysstring(_SC("generator"));
  141. newsysstring(_SC("thread"));
  142. newsysstring(_SC("class"));
  143. newsysstring(_SC("instance"));
  144. newsysstring(_SC("bool"));
  145. //meta methods
  146. newmetamethod(MM_ADD);
  147. newmetamethod(MM_SUB);
  148. newmetamethod(MM_MUL);
  149. newmetamethod(MM_DIV);
  150. newmetamethod(MM_UNM);
  151. newmetamethod(MM_MODULO);
  152. newmetamethod(MM_SET);
  153. newmetamethod(MM_GET);
  154. newmetamethod(MM_TYPEOF);
  155. newmetamethod(MM_NEXTI);
  156. newmetamethod(MM_CMP);
  157. newmetamethod(MM_CALL);
  158. newmetamethod(MM_CLONED);
  159. newmetamethod(MM_NEWSLOT);
  160. newmetamethod(MM_DELSLOT);
  161. newmetamethod(MM_TOSTRING);
  162. newmetamethod(MM_NEWMEMBER);
  163. newmetamethod(MM_INHERITED);
  164. _constructoridx = SQString::Create(this,_SC("constructor"));
  165. _destructoridx = SQString::Create(this,_SC("destructor"));
  166. _registry = SQTable::Create(this,0);
  167. _consts = SQTable::Create(this,0);
  168. _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);
  169. _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);
  170. _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);
  171. _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);
  172. _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);
  173. _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);
  174. _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);
  175. _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);
  176. _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);
  177. _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
  178. }
  179. SQSharedState::~SQSharedState()
  180. {
  181. if(_releasehook) { _releasehook(_foreignptr,0,0); _releasehook = NULL; }
  182. _constructoridx.Null();
  183. _destructoridx.Null();
  184. _define_squilu.Null();
  185. _define_squilu_int_sz.Null();
  186. _define_squilu_float_sz.Null();
  187. _define_squilu_ptr_sz.Null();
  188. _table(_registry)->Finalize();
  189. _table(_consts)->Finalize();
  190. _table(_metamethodsmap)->Finalize();
  191. _table(_defined_names)->Finalize();
  192. _registry.Null();
  193. _consts.Null();
  194. _metamethodsmap.Null();
  195. _defined_names.Null();
  196. while(!_systemstrings->empty()) {
  197. _systemstrings->back().Null();
  198. _systemstrings->pop_back();
  199. }
  200. if(sq_type(_root_vm) != OT_NULL)
  201. {
  202. _thread(_root_vm)->Finalize();
  203. _root_vm.Null();
  204. }
  205. _table_default_delegate.Null();
  206. _array_default_delegate.Null();
  207. _string_default_delegate.Null();
  208. _number_default_delegate.Null();
  209. _closure_default_delegate.Null();
  210. _generator_default_delegate.Null();
  211. _thread_default_delegate.Null();
  212. _class_default_delegate.Null();
  213. _instance_default_delegate.Null();
  214. _weakref_default_delegate.Null();
  215. _refs_table.Finalize();
  216. #ifndef NO_GARBAGE_COLLECTOR
  217. SQCollectable *t = _gc_chain;
  218. SQCollectable *nx = NULL;
  219. if(t) {
  220. t->_uiRef++;
  221. while(t) {
  222. t->Finalize();
  223. nx = t->_next;
  224. if(nx) nx->_uiRef++;
  225. if(--t->_uiRef == 0)
  226. t->Release();
  227. t = nx;
  228. }
  229. }
  230. assert(_gc_chain==NULL); //just to proove a theory
  231. while(_gc_chain){
  232. _gc_chain->_uiRef++;
  233. _gc_chain->Release();
  234. }
  235. #endif
  236. sq_delete(_types,SQObjectPtrVec);
  237. sq_delete(_systemstrings,SQObjectPtrVec);
  238. sq_delete(_metamethods,SQObjectPtrVec);
  239. if(_scratchstr) DelScratchStr(_scratchstr->_val);
  240. sq_delete(_stringtable,SQStringTable);
  241. if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
  242. }
  243. SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
  244. {
  245. if(sq_type(name) != OT_STRING)
  246. return -1;
  247. SQObjectPtr ret;
  248. if(_table(_metamethodsmap)->Get(name,ret)) {
  249. return _integer(ret);
  250. }
  251. return -1;
  252. }
  253. #ifdef SQ_WITH_DELAYED_RELEASE_HOOKS
  254. void SQSharedState::AddDelayedReleaseHook(SQRELEASEHOOK hook, SQUserPointer ptr, SQInteger size)
  255. {
  256. SQDelayedReleseHook dh;
  257. dh.hook = hook;
  258. dh.ptr = ptr;
  259. dh.size = size;
  260. _delayed_release_hook.push_back(dh);
  261. }
  262. void SQSharedState::CallDelayedReleaseHooks(SQVM *vm, int count)
  263. {
  264. if(_already_in_CallDelayedReleaseHooks) return;
  265. if(_delayed_release_hook.size()){
  266. _already_in_CallDelayedReleaseHooks = true;
  267. //get the count of release hooks before start
  268. //and only work on that number because while
  269. //calling each release hook new ones can be added
  270. //to the list, the new ones will be processed on next call
  271. if(count == 0) count = _delayed_release_hook.size();
  272. for(SQInteger i=count-1; i >= 0; --i){
  273. SQDelayedReleseHook &dh = _delayed_release_hook[i];
  274. dh.hook(dh.ptr, dh.size, vm);
  275. }
  276. _delayed_release_hook.removeFromBegining(count);
  277. _already_in_CallDelayedReleaseHooks = false;
  278. }
  279. }
  280. #endif // SQ_WITH_DELAYED_RELEASE_HOOKS
  281. #ifndef NO_GARBAGE_COLLECTOR
  282. void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
  283. {
  284. switch(sq_type(o)){
  285. case OT_TABLE:_table(o)->Mark(chain);break;
  286. case OT_ARRAY:_array(o)->Mark(chain);break;
  287. case OT_USERDATA:_userdata(o)->Mark(chain);break;
  288. case OT_CLOSURE:_closure(o)->Mark(chain);break;
  289. case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
  290. case OT_GENERATOR:_generator(o)->Mark(chain);break;
  291. case OT_THREAD:_thread(o)->Mark(chain);break;
  292. case OT_CLASS:_class(o)->Mark(chain);break;
  293. case OT_INSTANCE:_instance(o)->Mark(chain);break;
  294. case OT_OUTER:_outer(o)->Mark(chain);break;
  295. case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break;
  296. default: break; //shutup compiler
  297. }
  298. }
  299. void SQSharedState::RunMark(SQVM* SQ_UNUSED_ARG(vm),SQCollectable **tchain)
  300. {
  301. SQVM *vms = _thread(_root_vm);
  302. vms->Mark(tchain);
  303. _refs_table.Mark(tchain);
  304. MarkObject(_registry,tchain);
  305. MarkObject(_consts,tchain);
  306. MarkObject(_metamethodsmap,tchain);
  307. MarkObject(_table_default_delegate,tchain);
  308. MarkObject(_array_default_delegate,tchain);
  309. MarkObject(_string_default_delegate,tchain);
  310. MarkObject(_number_default_delegate,tchain);
  311. MarkObject(_generator_default_delegate,tchain);
  312. MarkObject(_thread_default_delegate,tchain);
  313. MarkObject(_closure_default_delegate,tchain);
  314. MarkObject(_class_default_delegate,tchain);
  315. MarkObject(_instance_default_delegate,tchain);
  316. MarkObject(_weakref_default_delegate,tchain);
  317. }
  318. SQInteger SQSharedState::ResurrectUnreachable(SQVM *vm)
  319. {
  320. SQInteger n=0;
  321. SQCollectable *tchain=NULL;
  322. RunMark(vm,&tchain);
  323. SQCollectable *resurrected = _gc_chain;
  324. SQCollectable *t = resurrected;
  325. //SQCollectable *nx = NULL;
  326. _gc_chain = tchain;
  327. SQArray *ret = NULL;
  328. if(resurrected) {
  329. ret = SQArray::Create(this,0);
  330. SQCollectable *rlast = NULL;
  331. while(t) {
  332. rlast = t;
  333. SQObjectType type = t->GetType();
  334. if(type != OT_FUNCPROTO && type != OT_OUTER) {
  335. SQObject sqo;
  336. sqo._type = type;
  337. sqo._unVal.pRefCounted = t;
  338. ret->Append(sqo);
  339. }
  340. t = t->_next;
  341. n++;
  342. }
  343. assert(rlast->_next == NULL);
  344. rlast->_next = _gc_chain;
  345. if(_gc_chain)
  346. {
  347. _gc_chain->_prev = rlast;
  348. }
  349. _gc_chain = resurrected;
  350. }
  351. t = _gc_chain;
  352. while(t) {
  353. t->UnMark();
  354. t = t->_next;
  355. }
  356. if(ret) {
  357. SQObjectPtr temp = ret;
  358. vm->Push(temp);
  359. }
  360. else {
  361. vm->PushNull();
  362. }
  363. return n;
  364. }
  365. SQInteger SQSharedState::CollectGarbage(SQVM *vm)
  366. {
  367. SQInteger n = 0;
  368. SQCollectable *tchain = NULL;
  369. RunMark(vm,&tchain);
  370. SQCollectable *t = _gc_chain;
  371. SQCollectable *nx = NULL;
  372. if(t) {
  373. t->_uiRef++;
  374. while(t) {
  375. t->Finalize();
  376. nx = t->_next;
  377. if(nx) nx->_uiRef++;
  378. if(--t->_uiRef == 0)
  379. t->Release();
  380. t = nx;
  381. n++;
  382. }
  383. }
  384. t = tchain;
  385. while(t) {
  386. t->UnMark();
  387. t = t->_next;
  388. }
  389. _gc_chain = tchain;
  390. return n;
  391. }
  392. #endif
  393. #ifndef NO_GARBAGE_COLLECTOR
  394. void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)
  395. {
  396. c->_prev = NULL;
  397. c->_next = *chain;
  398. if(*chain) (*chain)->_prev = c;
  399. *chain = c;
  400. }
  401. void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
  402. {
  403. if(c->_prev) c->_prev->_next = c->_next;
  404. else *chain = c->_next;
  405. if(c->_next)
  406. c->_next->_prev = c->_prev;
  407. c->_next = NULL;
  408. c->_prev = NULL;
  409. }
  410. #endif
  411. SQChar* SQSharedState::GetScratchPad(SQInteger size)
  412. {
  413. SQInteger newsize;
  414. if(size>0) {
  415. if(_scratchpadsize < size) {
  416. newsize = size + (size>>1);
  417. _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
  418. _scratchpadsize = newsize;
  419. }else if(_scratchpadsize >= (size<<5)) {
  420. newsize = _scratchpadsize >> 1;
  421. _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
  422. _scratchpadsize = newsize;
  423. }
  424. }
  425. return _scratchpad;
  426. }
  427. SQChar* SQSharedState::GetScratchStr(SQInteger size)
  428. {
  429. if(_scratchstr) return NULL; //only one at a time
  430. _scratchstr = _stringtable->NewStrBuf(size);
  431. return _scratchstr->_val;
  432. }
  433. SQString* SQSharedState::AddScratchStr()
  434. {
  435. if(!_scratchstr) return NULL;
  436. SQString *str = _stringtable->Add(_scratchstr);
  437. _scratchstr = NULL;
  438. return str;
  439. }
  440. SQBool SQSharedState::DelScratchStr(SQChar *s)
  441. {
  442. if(_scratchstr && _scratchstr->_val == s)
  443. {
  444. _stringtable->DeleteStrBuf(_scratchstr);
  445. _scratchstr = NULL;
  446. return SQTrue;
  447. }
  448. return SQFalse;
  449. }
  450. RefTable::RefTable()
  451. {
  452. AllocNodes(4);
  453. }
  454. void RefTable::Finalize()
  455. {
  456. RefNode *nodes = _nodes;
  457. for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
  458. nodes->obj.Null();
  459. nodes++;
  460. }
  461. }
  462. RefTable::~RefTable()
  463. {
  464. SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
  465. }
  466. #ifndef NO_GARBAGE_COLLECTOR
  467. void RefTable::Mark(SQCollectable **chain)
  468. {
  469. RefNode *nodes = (RefNode *)_nodes;
  470. for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
  471. if(sq_type(nodes->obj) != OT_NULL) {
  472. SQSharedState::MarkObject(nodes->obj,chain);
  473. }
  474. nodes++;
  475. }
  476. }
  477. #endif
  478. void RefTable::AddRef(SQObject &obj)
  479. {
  480. SQHash mainpos;
  481. RefNode *prev;
  482. RefNode *ref = Get(obj,mainpos,&prev,true);
  483. ref->refs++;
  484. }
  485. SQUnsignedInteger RefTable::GetRefCount(SQObject &obj)
  486. {
  487. SQHash mainpos;
  488. RefNode *prev;
  489. RefNode *ref = Get(obj,mainpos,&prev,true);
  490. return ref->refs;
  491. }
  492. SQBool RefTable::Release(SQObject &obj)
  493. {
  494. SQHash mainpos;
  495. RefNode *prev;
  496. RefNode *ref = Get(obj,mainpos,&prev,false);
  497. if(ref) {
  498. if(--ref->refs == 0) {
  499. SQObjectPtr o = ref->obj;
  500. if(prev) {
  501. prev->next = ref->next;
  502. }
  503. else {
  504. _buckets[mainpos] = ref->next;
  505. }
  506. ref->next = _freelist;
  507. _freelist = ref;
  508. _slotused--;
  509. ref->obj.Null();
  510. //<<FIXME>>test for shrink?
  511. return SQTrue;
  512. }
  513. }
  514. else {
  515. assert(0);
  516. }
  517. return SQFalse;
  518. }
  519. void RefTable::Resize(SQUnsignedInteger size)
  520. {
  521. RefNode **oldbucks = _buckets;
  522. RefNode *t = _nodes;
  523. SQUnsignedInteger oldnumofslots = _numofslots;
  524. AllocNodes(size);
  525. //rehash
  526. SQUnsignedInteger nfound = 0;
  527. for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
  528. if(sq_type(t->obj) != OT_NULL) {
  529. //add back;
  530. assert(t->refs != 0);
  531. RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
  532. nn->refs = t->refs;
  533. t->obj.Null();
  534. nfound++;
  535. }
  536. t++;
  537. }
  538. assert(nfound == oldnumofslots);
  539. SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
  540. }
  541. RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)
  542. {
  543. RefNode *t = _buckets[mainpos];
  544. RefNode *newnode = _freelist;
  545. newnode->obj = obj;
  546. _buckets[mainpos] = newnode;
  547. _freelist = _freelist->next;
  548. newnode->next = t;
  549. assert(newnode->refs == 0);
  550. _slotused++;
  551. return newnode;
  552. }
  553. RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)
  554. {
  555. RefNode *ref;
  556. mainpos = ::HashObj(obj)&(_numofslots-1);
  557. *prev = NULL;
  558. for (ref = _buckets[mainpos]; ref; ) {
  559. if(_rawval(ref->obj) == _rawval(obj) && sq_type(ref->obj) == sq_type(obj))
  560. break;
  561. *prev = ref;
  562. ref = ref->next;
  563. }
  564. if(ref == NULL && add) {
  565. if(_numofslots == _slotused) {
  566. assert(_freelist == 0);
  567. Resize(_numofslots*2);
  568. mainpos = ::HashObj(obj)&(_numofslots-1);
  569. }
  570. ref = Add(mainpos,obj);
  571. }
  572. return ref;
  573. }
  574. void RefTable::AllocNodes(SQUnsignedInteger size)
  575. {
  576. RefNode **bucks;
  577. RefNode *nodes;
  578. bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
  579. nodes = (RefNode *)&bucks[size];
  580. RefNode *temp = nodes;
  581. SQUnsignedInteger n;
  582. for(n = 0; n < size - 1; n++) {
  583. bucks[n] = NULL;
  584. temp->refs = 0;
  585. new (&temp->obj) SQObjectPtr;
  586. temp->next = temp+1;
  587. temp++;
  588. }
  589. bucks[n] = NULL;
  590. temp->refs = 0;
  591. new (&temp->obj) SQObjectPtr;
  592. temp->next = NULL;
  593. _freelist = nodes;
  594. _nodes = nodes;
  595. _buckets = bucks;
  596. _slotused = 0;
  597. _numofslots = size;
  598. }
  599. //////////////////////////////////////////////////////////////////////////
  600. //SQStringTable
  601. /*
  602. * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
  603. * http://www.lua.org/copyright.html#4
  604. * http://www.lua.org/source/4.0.1/src_lstring.c.html
  605. */
  606. SQStringTable::SQStringTable(SQSharedState *ss):_slotused(0), _sharedstate(ss)
  607. {
  608. AllocNodes(4);
  609. }
  610. SQStringTable::~SQStringTable()
  611. {
  612. SQ_FREE(_strings,sizeof(SQString*)*_numofslots);
  613. _strings = NULL;
  614. }
  615. void SQStringTable::AllocNodes(SQInteger size)
  616. {
  617. _numofslots = size;
  618. _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
  619. memset(_strings,0,sizeof(SQString*)*_numofslots);
  620. }
  621. SQString *SQStringTable::Contains(const SQChar *news, SQInteger &len, SQHash &newhash, SQHash &h)
  622. {
  623. if(len<0)
  624. len = (SQInteger)scstrlen(news);
  625. newhash = ::_hashstr(news,len);
  626. h = newhash&(_numofslots-1);
  627. SQString *s;
  628. SQInteger calculated_len = rsl(len);
  629. for (s = _strings[h]; s; s = s->_next){
  630. if(s->_len == len && (!memcmp(news,s->_val,calculated_len)))
  631. return s; //found
  632. }
  633. return 0;
  634. }
  635. SQString *SQStringTable::Add(const SQChar *news,SQInteger len)
  636. {
  637. SQHash newhash, h;
  638. SQString *t = Contains(news, len, newhash, h);
  639. if(t) return t;
  640. t = NewStrBuf(len);
  641. memcpy(t->_val,news,rsl(len));
  642. return Add(t, newhash, h);
  643. }
  644. SQString *SQStringTable::Add(SQString *strBuf)
  645. {
  646. SQHash newhash, h;
  647. #ifdef SQ_PACKED_STRUCT
  648. SQInteger blen = strBuf->_len;
  649. SQString *t = Contains(strBuf->_val, blen, newhash, h);
  650. #else
  651. SQString *t = Contains(strBuf->_val, strBuf->_len, newhash, h);
  652. #endif
  653. if(t) {
  654. SQ_FREE(strBuf,SQSTRING_CALCULATED_SIZE(rsl(strBuf->_len)));
  655. return t;
  656. }
  657. return Add(strBuf, newhash, h);
  658. }
  659. SQString *SQStringTable::Add(SQString *strBuf, SQHash newhash, SQHash h)
  660. {
  661. strBuf->_sharedstate = _sharedstate;
  662. strBuf->_val[strBuf->_len] = _SC('\0');
  663. strBuf->_hash = newhash;
  664. strBuf->_next = _strings[h];
  665. _strings[h] = strBuf;
  666. _slotused++;
  667. if (_slotused > _numofslots) /* too crowded? */
  668. Resize(_numofslots*2);
  669. return strBuf;
  670. }
  671. SQString *SQStringTable::NewStrBuf(SQInteger len)
  672. {
  673. //Take in account padding
  674. SQInteger calculated_size = SQSTRING_CALCULATED_SIZE(rsl(len));
  675. SQString *t = (SQString *)SQ_MALLOC(calculated_size);
  676. memset(t, 0, calculated_size);
  677. new (t) SQString;
  678. t->_len = len;
  679. return t;
  680. }
  681. void SQStringTable::DeleteStrBuf(SQString *sb)
  682. {
  683. SQ_FREE(sb,SQSTRING_CALCULATED_SIZE(rsl(sb->_len)));
  684. }
  685. void SQStringTable::Resize(SQInteger size)
  686. {
  687. SQInteger oldsize=_numofslots;
  688. SQString **oldtable=_strings;
  689. AllocNodes(size);
  690. for (SQInteger i=0; i<oldsize; i++){
  691. SQString *p = oldtable[i];
  692. while(p){
  693. SQString *next = p->_next;
  694. SQHash h = p->_hash&(_numofslots-1);
  695. p->_next = _strings[h];
  696. _strings[h] = p;
  697. p = next;
  698. }
  699. }
  700. SQ_FREE(oldtable,oldsize*sizeof(SQString*));
  701. }
  702. void SQStringTable::Remove(SQString *bs)
  703. {
  704. SQString *s;
  705. SQString *prev=NULL;
  706. SQHash h = bs->_hash&(_numofslots - 1);
  707. for (s = _strings[h]; s; ){
  708. if(s == bs){
  709. if(prev)
  710. prev->_next = s->_next;
  711. else
  712. _strings[h] = s->_next;
  713. _slotused--;
  714. SQInteger slen = s->_len;
  715. s->~SQString();
  716. //printf("Free str %p : %d : %.*s\n", s, (int)SQSTRING_CALCULATED_SIZE(rsl(slen))), (int)slen, s->_val);
  717. SQ_FREE(s,SQSTRING_CALCULATED_SIZE(rsl(slen)));
  718. return;
  719. }
  720. prev = s;
  721. s = s->_next;
  722. }
  723. assert(0);//if this fail something is wrong
  724. }