Back to home page

Enduro/X

 
 

    


0001 /*

0002     see copyright notice in pscript.h

0003 */
0004 #include "pspcheader.h"
0005 #include "psopcodes.h"
0006 #include "psvm.h"
0007 #include "psfuncproto.h"
0008 #include "psclosure.h"
0009 #include "psstring.h"
0010 #include "pstable.h"
0011 #include "psarray.h"
0012 #include "psuserdata.h"
0013 #include "psclass.h"
0014 
0015 //PSObjectPtr _null_;

0016 //PSObjectPtr _true_(true);

0017 //PSObjectPtr _false_(false);

0018 //PSObjectPtr _one_((PSInteger)1);

0019 //PSObjectPtr _minusone_((PSInteger)-1);

0020 
0021 PSSharedState::PSSharedState()
0022 {
0023     _compilererrorhandler = NULL;
0024     _printfunc = NULL;
0025     _errorfunc = NULL;
0026     _debuginfo = false;
0027     _notifyallexceptions = false;
0028     _foreignptr = NULL;
0029     _releasehook = NULL;
0030 }
0031 
0032 #define newsysstring(s) {   \
0033     _systemstrings->push_back(PSString::Create(this,s));    \
0034     }
0035 
0036 #define newmetamethod(s) {  \
0037     _metamethods->push_back(PSString::Create(this,s));  \
0038     _table(_metamethodsmap)->NewSlot(_metamethods->back(),(PSInteger)(_metamethods->size()-1)); \
0039     }
0040 
0041 bool CompileTypemask(PSIntVec &res,const PSChar *typemask)
0042 {
0043     PSInteger i = 0;
0044 
0045     PSInteger mask = 0;
0046     while(typemask[i] != 0) {
0047 
0048         switch(typemask[i]){
0049                 case 'o': mask |= _RT_NULL; break;
0050                 case 'i': mask |= _RT_INTEGER; break;
0051                 case 'f': mask |= _RT_FLOAT; break;
0052                 case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;
0053                 case 's': mask |= _RT_STRING; break;
0054                 case 't': mask |= _RT_TABLE; break;
0055                 case 'a': mask |= _RT_ARRAY; break;
0056                 case 'u': mask |= _RT_USERDATA; break;
0057                 case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;
0058                 case 'b': mask |= _RT_BOOL; break;
0059                 case 'g': mask |= _RT_GENERATOR; break;
0060                 case 'p': mask |= _RT_USERPOINTER; break;
0061                 case 'v': mask |= _RT_THREAD; break;
0062                 case 'x': mask |= _RT_INSTANCE; break;
0063                 case 'y': mask |= _RT_CLASS; break;
0064                 case 'r': mask |= _RT_WEAKREF; break;
0065                 case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
0066                 case ' ': i++; continue; //ignores spaces

0067                 default:
0068                     return false;
0069         }
0070         i++;
0071         if(typemask[i] == '|') {
0072             i++;
0073             if(typemask[i] == 0)
0074                 return false;
0075             continue;
0076         }
0077         res.push_back(mask);
0078         mask = 0;
0079 
0080     }
0081     return true;
0082 }
0083 
0084 PSTable *CreateDefaultDelegate(PSSharedState *ss,const PSRegFunction *funcz)
0085 {
0086     PSInteger i=0;
0087     PSTable *t=PSTable::Create(ss,0);
0088     while(funcz[i].name!=0){
0089         PSNativeClosure *nc = PSNativeClosure::Create(ss,funcz[i].f,0);
0090         nc->_nparamscheck = funcz[i].nparamscheck;
0091         nc->_name = PSString::Create(ss,funcz[i].name);
0092         if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))
0093             return NULL;
0094         t->NewSlot(PSString::Create(ss,funcz[i].name),nc);
0095         i++;
0096     }
0097     return t;
0098 }
0099 
0100 void PSSharedState::Init()
0101 {
0102     _scratchpad=NULL;
0103     _scratchpadsize=0;
0104 #ifndef NO_GARBAGE_COLLECTOR
0105     _gc_chain=NULL;
0106 #endif
0107     _stringtable = (PSStringTable*)PS_MALLOC(sizeof(PSStringTable));
0108     new (_stringtable) PSStringTable(this);
0109     ps_new(_metamethods,PSObjectPtrVec);
0110     ps_new(_systemstrings,PSObjectPtrVec);
0111     ps_new(_types,PSObjectPtrVec);
0112     _metamethodsmap = PSTable::Create(this,MT_LAST-1);
0113     //adding type strings to avoid memory trashing

0114     //types names

0115     newsysstring(_SC("null"));
0116     newsysstring(_SC("table"));
0117     newsysstring(_SC("array"));
0118     newsysstring(_SC("closure"));
0119     newsysstring(_SC("string"));
0120     newsysstring(_SC("userdata"));
0121     newsysstring(_SC("integer"));
0122     newsysstring(_SC("float"));
0123     newsysstring(_SC("userpointer"));
0124     newsysstring(_SC("function"));
0125     newsysstring(_SC("generator"));
0126     newsysstring(_SC("thread"));
0127     newsysstring(_SC("class"));
0128     newsysstring(_SC("instance"));
0129     newsysstring(_SC("bool"));
0130     //meta methods

0131     newmetamethod(MM_ADD);
0132     newmetamethod(MM_SUB);
0133     newmetamethod(MM_MUL);
0134     newmetamethod(MM_DIV);
0135     newmetamethod(MM_UNM);
0136     newmetamethod(MM_MODULO);
0137     newmetamethod(MM_SET);
0138     newmetamethod(MM_GET);
0139     newmetamethod(MM_TYPEOF);
0140     newmetamethod(MM_NEXTI);
0141     newmetamethod(MM_CMP);
0142     newmetamethod(MM_CALL);
0143     newmetamethod(MM_CLONED);
0144     newmetamethod(MM_NEWSLOT);
0145     newmetamethod(MM_DELSLOT);
0146     newmetamethod(MM_TOSTRING);
0147     newmetamethod(MM_NEWMEMBER);
0148     newmetamethod(MM_INHERITED);
0149 
0150     _constructoridx = PSString::Create(this,_SC("constructor"));
0151     _registry = PSTable::Create(this,0);
0152     _consts = PSTable::Create(this,0);
0153     _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);
0154     _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);
0155     _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);
0156     _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);
0157     _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);
0158     _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);
0159     _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);
0160     _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);
0161     _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);
0162     _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
0163 
0164 }
0165 
0166 PSSharedState::~PSSharedState()
0167 {
0168     if(_releasehook) { _releasehook(_foreignptr,0); _releasehook = NULL; }
0169     _constructoridx.Null();
0170     _table(_registry)->Finalize();
0171     _table(_consts)->Finalize();
0172     _table(_metamethodsmap)->Finalize();
0173     _registry.Null();
0174     _consts.Null();
0175     _metamethodsmap.Null();
0176     while(!_systemstrings->empty()) {
0177         _systemstrings->back().Null();
0178         _systemstrings->pop_back();
0179     }
0180     _thread(_root_vm)->Finalize();
0181     _root_vm.Null();
0182     _table_default_delegate.Null();
0183     _array_default_delegate.Null();
0184     _string_default_delegate.Null();
0185     _number_default_delegate.Null();
0186     _closure_default_delegate.Null();
0187     _generator_default_delegate.Null();
0188     _thread_default_delegate.Null();
0189     _class_default_delegate.Null();
0190     _instance_default_delegate.Null();
0191     _weakref_default_delegate.Null();
0192     _refs_table.Finalize();
0193 #ifndef NO_GARBAGE_COLLECTOR
0194     PSCollectable *t = _gc_chain;
0195     PSCollectable *nx = NULL;
0196     if(t) {
0197         t->_uiRef++;
0198         while(t) {
0199             t->Finalize();
0200             nx = t->_next;
0201             if(nx) nx->_uiRef++;
0202             if(--t->_uiRef == 0)
0203                 t->Release();
0204             t = nx;
0205         }
0206     }
0207     assert(_gc_chain==NULL); //just to proove a theory

0208     while(_gc_chain){
0209         _gc_chain->_uiRef++;
0210         _gc_chain->Release();
0211     }
0212 #endif
0213 
0214     ps_delete(_types,PSObjectPtrVec);
0215     ps_delete(_systemstrings,PSObjectPtrVec);
0216     ps_delete(_metamethods,PSObjectPtrVec);
0217     ps_delete(_stringtable,PSStringTable);
0218     if(_scratchpad)PS_FREE(_scratchpad,_scratchpadsize);
0219 }
0220 
0221 
0222 PSInteger PSSharedState::GetMetaMethodIdxByName(const PSObjectPtr &name)
0223 {
0224     if(type(name) != OT_STRING)
0225         return -1;
0226     PSObjectPtr ret;
0227     if(_table(_metamethodsmap)->Get(name,ret)) {
0228         return _integer(ret);
0229     }
0230     return -1;
0231 }
0232 
0233 #ifndef NO_GARBAGE_COLLECTOR
0234 
0235 void PSSharedState::MarkObject(PSObjectPtr &o,PSCollectable **chain)
0236 {
0237     switch(type(o)){
0238     case OT_TABLE:_table(o)->Mark(chain);break;
0239     case OT_ARRAY:_array(o)->Mark(chain);break;
0240     case OT_USERDATA:_userdata(o)->Mark(chain);break;
0241     case OT_CLOSURE:_closure(o)->Mark(chain);break;
0242     case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
0243     case OT_GENERATOR:_generator(o)->Mark(chain);break;
0244     case OT_THREAD:_thread(o)->Mark(chain);break;
0245     case OT_CLASS:_class(o)->Mark(chain);break;
0246     case OT_INSTANCE:_instance(o)->Mark(chain);break;
0247     case OT_OUTER:_outer(o)->Mark(chain);break;
0248     case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break;
0249     default: break; //shutup compiler

0250     }
0251 }
0252 
0253 void PSSharedState::RunMark(PSVM PS_UNUSED_ARG(*vm),PSCollectable **tchain)
0254 {
0255     PSVM *vms = _thread(_root_vm);
0256 
0257     vms->Mark(tchain);
0258 
0259     _refs_table.Mark(tchain);
0260     MarkObject(_registry,tchain);
0261     MarkObject(_consts,tchain);
0262     MarkObject(_metamethodsmap,tchain);
0263     MarkObject(_table_default_delegate,tchain);
0264     MarkObject(_array_default_delegate,tchain);
0265     MarkObject(_string_default_delegate,tchain);
0266     MarkObject(_number_default_delegate,tchain);
0267     MarkObject(_generator_default_delegate,tchain);
0268     MarkObject(_thread_default_delegate,tchain);
0269     MarkObject(_closure_default_delegate,tchain);
0270     MarkObject(_class_default_delegate,tchain);
0271     MarkObject(_instance_default_delegate,tchain);
0272     MarkObject(_weakref_default_delegate,tchain);
0273 
0274 }
0275 
0276 PSInteger PSSharedState::ResurrectUnreachable(PSVM *vm)
0277 {
0278     PSInteger n=0;
0279     PSCollectable *tchain=NULL;
0280 
0281     RunMark(vm,&tchain);
0282 
0283     PSCollectable *resurrected = _gc_chain;
0284     PSCollectable *t = resurrected;
0285     //PSCollectable *nx = NULL;

0286 
0287     _gc_chain = tchain;
0288 
0289     PSArray *ret = NULL;
0290     if(resurrected) {
0291         ret = PSArray::Create(this,0);
0292         PSCollectable *rlast = NULL;
0293         while(t) {
0294             rlast = t;
0295             PSObjectType type = t->GetType();
0296             if(type != OT_FUNCPROTO && type != OT_OUTER) {
0297                 PSObject pso;
0298                 pso._type = type;
0299                 pso._unVal.pRefCounted = t;
0300                 ret->Append(pso);
0301             }
0302             t = t->_next;
0303             n++;
0304         }
0305 
0306         assert(rlast->_next == NULL);
0307         rlast->_next = _gc_chain;
0308         if(_gc_chain)
0309         {
0310             _gc_chain->_prev = rlast;
0311         }
0312         _gc_chain = resurrected;
0313     }
0314 
0315     t = _gc_chain;
0316     while(t) {
0317         t->UnMark();
0318         t = t->_next;
0319     }
0320 
0321     if(ret) {
0322         PSObjectPtr temp = ret;
0323         vm->Push(temp);
0324     }
0325     else {
0326         vm->PushNull();
0327     }
0328     return n;
0329 }
0330 
0331 PSInteger PSSharedState::CollectGarbage(PSVM *vm)
0332 {
0333     PSInteger n = 0;
0334     PSCollectable *tchain = NULL;
0335 
0336     RunMark(vm,&tchain);
0337 
0338     PSCollectable *t = _gc_chain;
0339     PSCollectable *nx = NULL;
0340     if(t) {
0341         t->_uiRef++;
0342         while(t) {
0343             t->Finalize();
0344             nx = t->_next;
0345             if(nx) nx->_uiRef++;
0346             if(--t->_uiRef == 0)
0347                 t->Release();
0348             t = nx;
0349             n++;
0350         }
0351     }
0352 
0353     t = tchain;
0354     while(t) {
0355         t->UnMark();
0356         t = t->_next;
0357     }
0358     _gc_chain = tchain;
0359 
0360     return n;
0361 }
0362 #endif
0363 
0364 #ifndef NO_GARBAGE_COLLECTOR
0365 void PSCollectable::AddToChain(PSCollectable **chain,PSCollectable *c)
0366 {
0367     c->_prev = NULL;
0368     c->_next = *chain;
0369     if(*chain) (*chain)->_prev = c;
0370     *chain = c;
0371 }
0372 
0373 void PSCollectable::RemoveFromChain(PSCollectable **chain,PSCollectable *c)
0374 {
0375     if(c->_prev) c->_prev->_next = c->_next;
0376     else *chain = c->_next;
0377     if(c->_next)
0378         c->_next->_prev = c->_prev;
0379     c->_next = NULL;
0380     c->_prev = NULL;
0381 }
0382 #endif
0383 
0384 PSChar* PSSharedState::GetScratchPad(PSInteger size)
0385 {
0386     PSInteger newsize;
0387     if(size>0) {
0388         if(_scratchpadsize < size) {
0389             newsize = size + (size>>1);
0390             _scratchpad = (PSChar *)PS_REALLOC(_scratchpad,_scratchpadsize,newsize);
0391             _scratchpadsize = newsize;
0392 
0393         }else if(_scratchpadsize >= (size<<5)) {
0394             newsize = _scratchpadsize >> 1;
0395             _scratchpad = (PSChar *)PS_REALLOC(_scratchpad,_scratchpadsize,newsize);
0396             _scratchpadsize = newsize;
0397         }
0398     }
0399     return _scratchpad;
0400 }
0401 
0402 RefTable::RefTable()
0403 {
0404     AllocNodes(4);
0405 }
0406 
0407 void RefTable::Finalize()
0408 {
0409     RefNode *nodes = _nodes;
0410     for(PSUnsignedInteger n = 0; n < _numofslots; n++) {
0411         nodes->obj.Null();
0412         nodes++;
0413     }
0414 }
0415 
0416 RefTable::~RefTable()
0417 {
0418     PS_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
0419 }
0420 
0421 #ifndef NO_GARBAGE_COLLECTOR
0422 void RefTable::Mark(PSCollectable **chain)
0423 {
0424     RefNode *nodes = (RefNode *)_nodes;
0425     for(PSUnsignedInteger n = 0; n < _numofslots; n++) {
0426         if(type(nodes->obj) != OT_NULL) {
0427             PSSharedState::MarkObject(nodes->obj,chain);
0428         }
0429         nodes++;
0430     }
0431 }
0432 #endif
0433 
0434 void RefTable::AddRef(PSObject &obj)
0435 {
0436     PSHash mainpos;
0437     RefNode *prev;
0438     RefNode *ref = Get(obj,mainpos,&prev,true);
0439     ref->refs++;
0440 }
0441 
0442 PSUnsignedInteger RefTable::GetRefCount(PSObject &obj)
0443 {
0444      PSHash mainpos;
0445      RefNode *prev;
0446      RefNode *ref = Get(obj,mainpos,&prev,true);
0447      return ref->refs;
0448 }
0449 
0450 
0451 PSBool RefTable::Release(PSObject &obj)
0452 {
0453     PSHash mainpos;
0454     RefNode *prev;
0455     RefNode *ref = Get(obj,mainpos,&prev,false);
0456     if(ref) {
0457         if(--ref->refs == 0) {
0458             PSObjectPtr o = ref->obj;
0459             if(prev) {
0460                 prev->next = ref->next;
0461             }
0462             else {
0463                 _buckets[mainpos] = ref->next;
0464             }
0465             ref->next = _freelist;
0466             _freelist = ref;
0467             _slotused--;
0468             ref->obj.Null();
0469             //<<FIXME>>test for shrink?

0470             return PSTrue;
0471         }
0472     }
0473     else {
0474         assert(0);
0475     }
0476     return PSFalse;
0477 }
0478 
0479 void RefTable::Resize(PSUnsignedInteger size)
0480 {
0481     RefNode **oldbucks = _buckets;
0482     RefNode *t = _nodes;
0483     PSUnsignedInteger oldnumofslots = _numofslots;
0484     AllocNodes(size);
0485     //rehash

0486     PSUnsignedInteger nfound = 0;
0487     for(PSUnsignedInteger n = 0; n < oldnumofslots; n++) {
0488         if(type(t->obj) != OT_NULL) {
0489             //add back;

0490             assert(t->refs != 0);
0491             RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
0492             nn->refs = t->refs;
0493             t->obj.Null();
0494             nfound++;
0495         }
0496         t++;
0497     }
0498     assert(nfound == oldnumofslots);
0499     PS_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
0500 }
0501 
0502 RefTable::RefNode *RefTable::Add(PSHash mainpos,PSObject &obj)
0503 {
0504     RefNode *t = _buckets[mainpos];
0505     RefNode *newnode = _freelist;
0506     newnode->obj = obj;
0507     _buckets[mainpos] = newnode;
0508     _freelist = _freelist->next;
0509     newnode->next = t;
0510     assert(newnode->refs == 0);
0511     _slotused++;
0512     return newnode;
0513 }
0514 
0515 RefTable::RefNode *RefTable::Get(PSObject &obj,PSHash &mainpos,RefNode **prev,bool add)
0516 {
0517     RefNode *ref;
0518     mainpos = ::HashObj(obj)&(_numofslots-1);
0519     *prev = NULL;
0520     for (ref = _buckets[mainpos]; ref; ) {
0521         if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))
0522             break;
0523         *prev = ref;
0524         ref = ref->next;
0525     }
0526     if(ref == NULL && add) {
0527         if(_numofslots == _slotused) {
0528             assert(_freelist == 0);
0529             Resize(_numofslots*2);
0530             mainpos = ::HashObj(obj)&(_numofslots-1);
0531         }
0532         ref = Add(mainpos,obj);
0533     }
0534     return ref;
0535 }
0536 
0537 void RefTable::AllocNodes(PSUnsignedInteger size)
0538 {
0539     RefNode **bucks;
0540     RefNode *nodes;
0541     bucks = (RefNode **)PS_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
0542     nodes = (RefNode *)&bucks[size];
0543     RefNode *temp = nodes;
0544     PSUnsignedInteger n;
0545     for(n = 0; n < size - 1; n++) {
0546         bucks[n] = NULL;
0547         temp->refs = 0;
0548         new (&temp->obj) PSObjectPtr;
0549         temp->next = temp+1;
0550         temp++;
0551     }
0552     bucks[n] = NULL;
0553     temp->refs = 0;
0554     new (&temp->obj) PSObjectPtr;
0555     temp->next = NULL;
0556     _freelist = nodes;
0557     _nodes = nodes;
0558     _buckets = bucks;
0559     _slotused = 0;
0560     _numofslots = size;
0561 }
0562 //////////////////////////////////////////////////////////////////////////

0563 //PSStringTable

0564 /*

0565 * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)

0566 * http://www.lua.org/copyright.html#4

0567 * http://www.lua.org/source/4.0.1/src_lstring.c.html

0568 */
0569 
0570 PSStringTable::PSStringTable(PSSharedState *ss)
0571 {
0572     _sharedstate = ss;
0573     AllocNodes(4);
0574     _slotused = 0;
0575 }
0576 
0577 PSStringTable::~PSStringTable()
0578 {
0579     PS_FREE(_strings,sizeof(PSString*)*_numofslots);
0580     _strings = NULL;
0581 }
0582 
0583 void PSStringTable::AllocNodes(PSInteger size)
0584 {
0585     _numofslots = size;
0586     _strings = (PSString**)PS_MALLOC(sizeof(PSString*)*_numofslots);
0587     memset(_strings,0,sizeof(PSString*)*_numofslots);
0588 }
0589 
0590 PSString *PSStringTable::Add(const PSChar *news,PSInteger len)
0591 {
0592     if(len<0)
0593         len = (PSInteger)scstrlen(news);
0594     PSHash newhash = ::_hashstr(news,len);
0595     PSHash h = newhash&(_numofslots-1);
0596     PSString *s;
0597     for (s = _strings[h]; s; s = s->_next){
0598         if(s->_len == len && (!memcmp(news,s->_val,ps_rsl(len))))
0599             return s; //found

0600     }
0601 
0602     PSString *t = (PSString *)PS_MALLOC(ps_rsl(len)+sizeof(PSString));
0603     new (t) PSString;
0604     t->_sharedstate = _sharedstate;
0605     memcpy(t->_val,news,ps_rsl(len));
0606     t->_val[len] = _SC('\0');
0607     t->_len = len;
0608     t->_hash = newhash;
0609     t->_next = _strings[h];
0610     _strings[h] = t;
0611     _slotused++;
0612     if (_slotused > _numofslots)  /* too crowded? */
0613         Resize(_numofslots*2);
0614     return t;
0615 }
0616 
0617 void PSStringTable::Resize(PSInteger size)
0618 {
0619     PSInteger oldsize=_numofslots;
0620     PSString **oldtable=_strings;
0621     AllocNodes(size);
0622     for (PSInteger i=0; i<oldsize; i++){
0623         PSString *p = oldtable[i];
0624         while(p){
0625             PSString *next = p->_next;
0626             PSHash h = p->_hash&(_numofslots-1);
0627             p->_next = _strings[h];
0628             _strings[h] = p;
0629             p = next;
0630         }
0631     }
0632     PS_FREE(oldtable,oldsize*sizeof(PSString*));
0633 }
0634 
0635 void PSStringTable::Remove(PSString *bs)
0636 {
0637     PSString *s;
0638     PSString *prev=NULL;
0639     PSHash h = bs->_hash&(_numofslots - 1);
0640 
0641     for (s = _strings[h]; s; ){
0642         if(s == bs){
0643             if(prev)
0644                 prev->_next = s->_next;
0645             else
0646                 _strings[h] = s->_next;
0647             _slotused--;
0648             PSInteger slen = s->_len;
0649             s->~PSString();
0650             PS_FREE(s,sizeof(PSString) + ps_rsl(slen));
0651             return;
0652         }
0653         prev = s;
0654         s = s->_next;
0655     }
0656     assert(0);//if this fail something is wrong

0657 }