# sqfuncstate.cpp

    00001 /*
    00002   see copyright notice in squirrel.h
    00003 */
    00004 #include "sqpcheader.h"
    00005 #include "sqcompiler.h"
    00006 #include "sqfuncproto.h"
    00007 #include "sqstring.h"
    00008 #include "sqtable.h"
    00009 #include "sqopcodes.h"
    00010 #include "sqfuncstate.h"
    00011
    00012 #ifdef _DEBUG_DUMP
    00013 SQInstructionDesc g_InstrDesc[]={
    00014   {_SC("_OP_LINE")},
    00015   {_SC("_OP_LOAD")},
    00016   {_SC("_OP_LOADINT")},
    00017   {_SC("_OP_LOADFLOAT")},
    00018   {_SC("_OP_DLOAD")},
    00019   {_SC("_OP_TAILCALL")},
    00020   {_SC("_OP_CALL")},
    00021   {_SC("_OP_PREPCALL")},
    00022   {_SC("_OP_PREPCALLK")},
    00023   {_SC("_OP_GETK")},
    00024   {_SC("_OP_MOVE")},
    00025   {_SC("_OP_NEWSLOT")},
    00026   {_SC("_OP_DELETE")},
    00027   {_SC("_OP_SET")},
    00028   {_SC("_OP_GET")},
    00029   {_SC("_OP_EQ")},
    00030   {_SC("_OP_NE")},
    00031   {_SC("_OP_ARITH")},
    00032   {_SC("_OP_BITW")},
    00033   {_SC("_OP_RETURN")},
    00034   {_SC("_OP_LOADNULLS")},
    00035   {_SC("_OP_LOADROOTTABLE")},
    00036   {_SC("_OP_LOADBOOL")},
    00037   {_SC("_OP_DMOVE")},
    00038   {_SC("_OP_JMP")},
    00039   {_SC("_OP_JNZ")},
    00040   {_SC("_OP_JZ")},
    00041   {_SC("_OP_LOADFREEVAR")},
    00042   {_SC("_OP_VARGC")},
    00043   {_SC("_OP_GETVARGV")},
    00044   {_SC("_OP_NEWTABLE")},
    00045   {_SC("_OP_NEWARRAY")},
    00046   {_SC("_OP_APPENDARRAY")},
    00047   {_SC("_OP_GETPARENT")},
    00048   {_SC("_OP_COMPARITH")},
    00049   {_SC("_OP_COMPARITHL")},
    00050   {_SC("_OP_INC")},
    00051   {_SC("_OP_INCL")},
    00052   {_SC("_OP_PINC")},
    00053   {_SC("_OP_PINCL")},
    00054   {_SC("_OP_CMP")},
    00055   {_SC("_OP_EXISTS")},
    00056   {_SC("_OP_INSTANCEOF")},
    00057   {_SC("_OP_AND")},
    00058   {_SC("_OP_OR")},
    00059   {_SC("_OP_NEG")},
    00060   {_SC("_OP_NOT")},
    00061   {_SC("_OP_BWNOT")},
    00062   {_SC("_OP_CLOSURE")},
    00063   {_SC("_OP_YIELD")},
    00064   {_SC("_OP_RESUME")},
    00065   {_SC("_OP_FOREACH")},
    00066   {_SC("_OP_POSTFOREACH")},
    00067   {_SC("_OP_DELEGATE")},
    00068   {_SC("_OP_CLONE")},
    00069   {_SC("_OP_TYPEOF")},
    00070   {_SC("_OP_PUSHTRAP")},
    00071   {_SC("_OP_POPTRAP")},
    00072   {_SC("_OP_THROW")},
    00073   {_SC("_OP_CLASS")},
    00074   {_SC("_OP_NEWSLOTA")},
    00075   {_SC("_OP_SCOPE_END")}
    00076 };
    00077 #endif
    00078 void DumpLiteral(SQObjectPtr &o)
    00079 {
    00080   switch(type(o)){
    00081     case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break;
    00082     case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break;
    00083 #if defined(_SQ64)
    00084     case OT_INTEGER: scprintf(_SC("{%ld}"),_integer(o));break;
    00085 #else
    00086     case OT_INTEGER: scprintf(_SC("{%d}"),_integer(o));break;
    00087 #endif
    00088     case OT_BOOL: scprintf(_SC("%s"),_integer(o)?_SC("true"):_SC("false"));break;
    00089     default: scprintf(_SC("(%s %p)"),GetTypeName(o),_rawval(o));break; break; //shut up compiler
    00090   }
    00091 }
    00092
    00093 SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed)
    00094 {
    00095     _nliterals = 0;
    00096     _literals = SQTable::Create(ss,0);
    00097     _strings =  SQTable::Create(ss,0);
    00098     _sharedstate = ss;
    00099     _lastline = 0;
    00100     _optimization = true;
    00101     _parent = parent;
    00102     _stacksize = 0;
    00103     _traps = 0;
    00104     _returnexp = 0;
    00105     _varparams = false;
    00106     _errfunc = efunc;
    00107     _errtarget = ed;
    00108     _bgenerator = false;
    00109
    00110 }
    00111
    00112 void SQFuncState::Error(const SQChar *err)
    00113 {
    00114   _errfunc(_errtarget,err);
    00115 }
    00116
    00117 #ifdef _DEBUG_DUMP
    00118 void SQFuncState::Dump(SQFunctionProto *func)
    00119 {
    00120   SQUnsignedInteger n=0,i;
    00121   SQInteger si;
    00122   scprintf(_SC("SQInstruction sizeof %d\n"),sizeof(SQInstruction));
    00123   scprintf(_SC("SQObject sizeof %d\n"),sizeof(SQObject));
    00124   scprintf(_SC("--------------------------------------------------------------------\n"));
    00125   scprintf(_SC("*****FUNCTION [%s]\n"),type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown"));
    00126   scprintf(_SC("-----LITERALS\n"));
    00127   SQObjectPtr refidx,key,val;
    00128   SQInteger idx;
    00129   SQObjectPtrVec templiterals;
    00130   templiterals.resize(_nliterals);
    00131   while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {
    00132     refidx=idx;
    00133     templiterals[_integer(val)]=key;
    00134   }
    00135   for(i=0;i<templiterals.size();i++){
    00136     scprintf(_SC("[%d] "),n);
    00137     DumpLiteral(templiterals[i]);
    00138     scprintf(_SC("\n"));
    00139     n++;
    00140   }
    00141   scprintf(_SC("-----PARAMS\n"));
    00142   if(_varparams)
    00143     scprintf(_SC("<<VARPARAMS>>\n"));
    00144   n=0;
    00145   for(i=0;i<_parameters.size();i++){
    00146     scprintf(_SC("[%d] "),n);
    00147     DumpLiteral(_parameters[i]);
    00148     scprintf(_SC("\n"));
    00149     n++;
    00150   }
    00151   scprintf(_SC("-----LOCALS\n"));
    00152   for(si=0;si<func->_nlocalvarinfos;si++){
    00153     SQLocalVarInfo lvi=func->_localvarinfos[si];
    00154     scprintf(_SC("[%d] %s \t%d %d\n"),lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op);
    00155     n++;
    00156   }
    00157   scprintf(_SC("-----LINE INFO\n"));
    00158   for(i=0;i<_lineinfos.size();i++){
    00159     SQLineInfo li=_lineinfos[i];
    00160     scprintf(_SC("op [%d] line [%d] \n"),li._op,li._line);
    00161     n++;
    00162   }
    00163   scprintf(_SC("-----dump\n"));
    00164   n=0;
    00165   for(i=0;i<_instructions.size();i++){
    00166     SQInstruction &inst=_instructions[i];
    00167     if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){
    00168
    00169       SQInteger lidx = inst._arg1;
    00170       scprintf(_SC("[%03d] %15s %d "),n,g_InstrDesc[inst.op].name,inst._arg0);
    00171       if(lidx >= 0xFFFFFFFF)
    00172         scprintf(_SC("null"));
    00173       else {
    00174         SQInteger refidx;
    00175         SQObjectPtr val,key,refo;
    00176         while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) {
    00177           refo = refidx;
    00178         }
    00179         DumpLiteral(key);
    00180       }
    00181       if(inst.op != _OP_DLOAD) {
    00182         scprintf(_SC(" %d %d \n"),inst._arg2,inst._arg3);
    00183       }
    00184       else {
    00185         scprintf(_SC(" %d "),inst._arg2);
    00186         lidx = inst._arg3;
    00187         if(lidx >= 0xFFFFFFFF)
    00188           scprintf(_SC("null"));
    00189         else {
    00190           SQInteger refidx;
    00191           SQObjectPtr val,key,refo;
    00192           while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) {
    00193             refo = refidx;
    00194         }
    00195         DumpLiteral(key);
    00196         scprintf(_SC("\n"));
    00197       }
    00198       }
    00199     }
    00200     else if(inst.op==_OP_LOADFLOAT) {
    00201       scprintf(_SC("[%03d] %15s %d %f %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,*((SQFloat*)&inst._arg1),inst._arg2,inst._arg3);
    00202     }
    00203     else if(inst.op==_OP_ARITH){
    00204       scprintf(_SC("[%03d] %15s %d %d %d %c\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);
    00205     }
    00206     else
    00207       scprintf(_SC("[%03d] %15s %d %d %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);
    00208     n++;
    00209   }
    00210   scprintf(_SC("-----\n"));
    00211   scprintf(_SC("stack size[%d]\n"),func->_stacksize);
    00212   scprintf(_SC("--------------------------------------------------------------------\n\n"));
    00213 }
    00214 #endif
    00215
    00216 SQInteger SQFuncState::GetNumericConstant(const SQInteger cons)
    00217 {
    00218   return GetConstant(SQObjectPtr(cons));
    00219 }
    00220
    00221 SQInteger SQFuncState::GetNumericConstant(const SQFloat cons)
    00222 {
    00223   return GetConstant(SQObjectPtr(cons));
    00224 }
    00225
    00226 SQInteger SQFuncState::GetConstant(const SQObject &cons)
    00227 {
    00228   SQObjectPtr val;
    00229   if(!_table(_literals)->Get(cons,val))
    00230   {
    00231     val = _nliterals;
    00232     _table(_literals)->NewSlot(cons,val);
    00233     _nliterals++;
    00234     if(_nliterals > MAX_LITERALS) {
    00235       val.Null();
    00236       Error(_SC("internal compiler error: too many literals"));
    00237     }
    00238   }
    00239   return _integer(val);
    00240 }
    00241
    00242 void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)
    00243 {
    00244   _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0);
    00245   _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1);
    00246   _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2);
    00247   _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3);
    00248 }
    00249
    00250 void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val)
    00251 {
    00252   switch(arg){
    00253     case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break;
    00254     case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break;
    00255     case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break;
    00256     case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break;
    00257   };
    00258 }
    00259
    00260 SQInteger SQFuncState::AllocStackPos()
    00261 {
    00262   SQInteger npos=_vlocals.size();
    00263   _vlocals.push_back(SQLocalVarInfo());
    00264   if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) {
    00265     if(_stacksize>MAX_FUNC_STACKSIZE) Error(_SC("internal compiler error: too many locals"));
    00266     _stacksize=_vlocals.size();
    00267   }
    00268   return npos;
    00269 }
    00270
    00271 SQInteger SQFuncState::PushTarget(SQInteger n)
    00272 {
    00273   if(n!=-1){
    00274     _targetstack.push_back(n);
    00275     return n;
    00276   }
    00277   n=AllocStackPos();
    00278   _targetstack.push_back(n);
    00279   return n;
    00280 }
    00281
    00282 SQInteger SQFuncState::GetUpTarget(SQInteger n){
    00283   return _targetstack[((_targetstack.size()-1)-n)];
    00284 }
    00285
    00286 SQInteger SQFuncState::TopTarget(){
    00287   return _targetstack.back();
    00288 }
    00289 SQInteger SQFuncState::PopTarget()
    00290 {
    00291   SQInteger npos=_targetstack.back();
    00292   SQLocalVarInfo t=_vlocals[_targetstack.back()];
    00293   if(type(t._name)==OT_NULL){
    00294     _vlocals.pop_back();
    00295   }
    00296   _targetstack.pop_back();
    00297   return npos;
    00298 }
    00299
    00300 SQInteger SQFuncState::GetStackSize()
    00301 {
    00302   return _vlocals.size();
    00303 }
    00304
    00305 void SQFuncState::SetStackSize(SQInteger n)
    00306 {
    00307   SQInteger size=_vlocals.size();
    00308   while(size>n){
    00309     size--;
    00310     SQLocalVarInfo lvi=_vlocals.back();
    00311     if(type(lvi._name)!=OT_NULL){
    00312       lvi._end_op=GetCurrentPos();
    00313       _localvarinfos.push_back(lvi);
    00314     }
    00315     _vlocals.pop_back();
    00316   }
    00317 }
    00318
    00319 bool SQFuncState::IsConstant(const SQObject &name,SQObject &e)
    00320 {
    00321   SQObjectPtr val;
    00322   if(_table(_sharedstate->_consts)->Get(name,val)) {
    00323     e = val;
    00324     return true;
    00325   }
    00326   return false;
    00327 }
    00328
    00329 bool SQFuncState::IsLocal(SQUnsignedInteger stkpos)
    00330 {
    00331   if(stkpos>=_vlocals.size())return false;
    00332   else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true;
    00333   return false;
    00334 }
    00335
    00336 SQInteger SQFuncState::PushLocalVariable(const SQObject &name)
    00337 {
    00338   SQInteger pos=_vlocals.size();
    00339   SQLocalVarInfo lvi;
    00340   lvi._name=name;
    00341   lvi._start_op=GetCurrentPos()+1;
    00342   lvi._pos=_vlocals.size();
    00343   _vlocals.push_back(lvi);
    00344   if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size();
    00345
    00346   return pos;
    00347 }
    00348
    00349 SQInteger SQFuncState::GetLocalVariable(const SQObject &name)
    00350 {
    00351   SQInteger locals=_vlocals.size();
    00352   while(locals>=1){
    00353     if(type(_vlocals[locals-1]._name)==OT_STRING && _string(_vlocals[locals-1]._name)==_string(name)){
    00354       return locals-1;
    00355     }
    00356     locals--;
    00357   }
    00358   return -1;
    00359 }
    00360
    00361 SQInteger SQFuncState::GetOuterVariable(const SQObject &name)
    00362 {
    00363   SQInteger outers = _outervalues.size();
    00364   for(SQInteger i = 0; i<outers; i++) {
    00365     if(_string(_outervalues[i]._name) == _string(name))
    00366       return i;
    00367   }
    00368   return -1;
    00369 }
    00370
    00371 void SQFuncState::AddOuterValue(const SQObject &name)
    00372 {
    00373   SQInteger pos=-1;
    00374   if(_parent) {
    00375     pos = _parent->GetLocalVariable(name);
    00376     if(pos == -1) {
    00377       pos = _parent->GetOuterVariable(name);
    00378       if(pos != -1) {
    00379         _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local
    00380         return;
    00381       }
    00382     }
    00383     else {
    00384       _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local
    00385       return;
    00386     }
    00387   }
    00388   _outervalues.push_back(SQOuterVar(name,name,otSYMBOL)); //global
    00389 }
    00390
    00391 void SQFuncState::AddParameter(const SQObject &name)
    00392 {
    00393   PushLocalVariable(name);
    00394   _parameters.push_back(name);
    00395 }
    00396
    00397 void SQFuncState::AddLineInfos(SQInteger line,bool lineop,bool force)
    00398 {
    00399   if(_lastline!=line || force){
    00400     SQLineInfo li;
    00401     li._line=line;li._op=(GetCurrentPos()+1);
    00402     if(lineop)AddInstruction(_OP_LINE,0,line);
    00403     _lineinfos.push_back(li);
    00404     _lastline=line;
    00405   }
    00406 }
    00407
    00408 void SQFuncState::AddInstruction(SQInstruction &i)
    00409 {
    00410   SQInteger size = _instructions.size();
    00411   if(size > 0 && _optimization){ //simple optimizer
    00412     SQInstruction &pi = _instructions[size-1];//previous instruction
    00413     switch(i.op) {
    00414     case _OP_RETURN:
    00415       if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) {
    00416         pi.op = _OP_TAILCALL;
    00417       }
    00418     break;
    00419     case _OP_GET:
    00420       if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){
    00421         pi._arg1 = pi._arg1;
    00422         pi._arg2 = (unsigned char)i._arg1;
    00423         pi.op = _OP_GETK;
    00424         pi._arg0 = i._arg0;
    00425
    00426         return;
    00427       }
    00428     break;
    00429     case _OP_PREPCALL:
    00430       if( pi.op == _OP_LOAD  && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){
    00431         pi.op = _OP_PREPCALLK;
    00432         pi._arg0 = i._arg0;
    00433         pi._arg1 = pi._arg1;
    00434         pi._arg2 = i._arg2;
    00435         pi._arg3 = i._arg3;
    00436         return;
    00437       }
    00438       break;
    00439     case _OP_APPENDARRAY:
    00440       if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){
    00441         pi.op = _OP_APPENDARRAY;
    00442         pi._arg0 = i._arg0;
    00443         pi._arg1 = pi._arg1;
    00444         pi._arg2 = MAX_FUNC_STACKSIZE;
    00445         pi._arg3 = MAX_FUNC_STACKSIZE;
    00446         return;
    00447       }
    00448       break;
    00449     case _OP_MOVE:
    00450       if((pi.op == _OP_GET || pi.op == _OP_ARITH || pi.op == _OP_BITW) && (pi._arg0 == i._arg1))
    00451       {
    00452         pi._arg0 = i._arg0;
    00453         _optimization = false;
    00454         return;
    00455       }
    00456
    00457       if(pi.op == _OP_MOVE)
    00458       {
    00459         pi.op = _OP_DMOVE;
    00460         pi._arg2 = i._arg0;
    00461         pi._arg3 = (unsigned char)i._arg1;
    00462         return;
    00463       }
    00464       break;
    00465     case _OP_LOAD:
    00466       if(pi.op == _OP_LOAD && i._arg1 < 256) {
    00467         pi.op = _OP_DLOAD;
    00468         pi._arg2 = i._arg0;
    00469         pi._arg3 = (unsigned char)i._arg1;
    00470         return;
    00471       }
    00472       break;
    00473     case _OP_EQ:case _OP_NE:
    00474       if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) ))
    00475       {
    00476         pi.op = i.op;
    00477         pi._arg0 = i._arg0;
    00478         pi._arg1 = pi._arg1;
    00479         pi._arg2 = i._arg2;
    00480         pi._arg3 = MAX_FUNC_STACKSIZE;
    00481         return;
    00482       }
    00483       break;
    00484     case _OP_LOADNULLS:
    00485       if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) {
    00486
    00487         pi._arg1 = pi._arg1 + 1;
    00488         pi.op = _OP_LOADNULLS;
    00489         return;
    00490       }
    00491             break;
    00492     case _OP_LINE:
    00493       if(pi.op == _OP_LINE) {
    00494         _instructions.pop_back();
    00495         _lineinfos.pop_back();
    00496       }
    00497       break;
    00498     }
    00499   }
    00500   _optimization = true;
    00501   _instructions.push_back(i);
    00502 }
    00503
    00504 SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len)
    00505 {
    00506   SQObjectPtr ns(SQString::Create(_sharedstate,s,len));
    00507   _table(_strings)->NewSlot(ns,(SQInteger)1);
    00508   return ns;
    00509 }
    00510
    00511 SQObject SQFuncState::CreateTable()
    00512 {
    00513   SQObjectPtr nt(SQTable::Create(_sharedstate,0));
    00514   _table(_strings)->NewSlot(nt,(SQInteger)1);
    00515   return nt;
    00516 }
    00517
    00518 SQFunctionProto *SQFuncState::BuildProto()
    00519 {
    00520   SQFunctionProto *f=SQFunctionProto::Create(_instructions.size(),
    00521     _nliterals,_parameters.size(),_functions.size(),_outervalues.size(),
    00522     _lineinfos.size(),_localvarinfos.size(),_defaultparams.size());
    00523
    00524   SQObjectPtr refidx,key,val;
    00525   SQInteger idx;
    00526
    00527   f->_stacksize = _stacksize;
    00528   f->_sourcename = _sourcename;
    00529   f->_bgenerator = _bgenerator;
    00530   f->_name = _name;
    00531
    00532   while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {
    00533     f->_literals[_integer(val)]=key;
    00534     refidx=idx;
    00535   }
    00536
    00537   for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf];
    00538   for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np];
    00539   for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no];
    00540   for(SQUnsignedInteger no = 0; no < _localvarinfos.size(); no++) f->_localvarinfos[no] = _localvarinfos[no];
    00541   for(SQUnsignedInteger no = 0; no < _lineinfos.size(); no++) f->_lineinfos[no] = _lineinfos[no];
    00542   for(SQUnsignedInteger no = 0; no < _defaultparams.size(); no++) f->_defaultparams[no] = _defaultparams[no];
    00543
    00544   memcpy(f->_instructions,&_instructions[0],_instructions.size()*sizeof(SQInstruction));
    00545
    00546   f->_varparams = _varparams;
    00547
    00548   return f;
    00549 }
    00550
    00551 SQFuncState *SQFuncState::PushChildState(SQSharedState *ss)
    00552 {
    00553   SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState));
    00554   new (child) SQFuncState(ss,this,_errfunc,_errtarget);
    00555   _childstates.push_back(child);
    00556   return child;
    00557 }
    00558
    00559 void SQFuncState::PopChildState()
    00560 {
    00561   SQFuncState *child = _childstates.back();
    00562   sq_delete(child,SQFuncState);
    00563   _childstates.pop_back();
    00564 }
    00565
    00566 SQFuncState::~SQFuncState()
    00567 {
    00568   while(_childstates.size() > 0)
    00569   {
    00570     PopChildState();
    00571   }
    00572 }