1 /*
2 	see copyright notice in squirrel.h
3 */
4 #include "sqpcheader.h"
5 #include "sqcompiler.h"
6 #include "sqfuncproto.h"
7 #include "sqstring.h"
8 #include "sqtable.h"
9 #include "sqopcodes.h"
10 #include "sqfuncstate.h"
11 
12 #ifdef _DEBUG_DUMP
13 SQInstructionDesc g_InstrDesc[]={
14 	{_SC("_OP_LINE")},
15 	{_SC("_OP_LOAD")},
16 	{_SC("_OP_LOADINT")},
17 	{_SC("_OP_LOADFLOAT")},
18 	{_SC("_OP_DLOAD")},
19 	{_SC("_OP_TAILCALL")},
20 	{_SC("_OP_CALL")},
21 	{_SC("_OP_PREPCALL")},
22 	{_SC("_OP_PREPCALLK")},
23 	{_SC("_OP_GETK")},
24 	{_SC("_OP_MOVE")},
25 	{_SC("_OP_NEWSLOT")},
26 	{_SC("_OP_DELETE")},
27 	{_SC("_OP_SET")},
28 	{_SC("_OP_GET")},
29 	{_SC("_OP_EQ")},
30 	{_SC("_OP_NE")},
31 	{_SC("_OP_ARITH")},
32 	{_SC("_OP_BITW")},
33 	{_SC("_OP_RETURN")},
34 	{_SC("_OP_LOADNULLS")},
35 	{_SC("_OP_LOADROOTTABLE")},
36 	{_SC("_OP_LOADBOOL")},
37 	{_SC("_OP_DMOVE")},
38 	{_SC("_OP_JMP")},
39 	{_SC("_OP_JNZ")},
40 	{_SC("_OP_JZ")},
41 	{_SC("_OP_LOADFREEVAR")},
42 	{_SC("_OP_VARGC")},
43 	{_SC("_OP_GETVARGV")},
44 	{_SC("_OP_NEWTABLE")},
45 	{_SC("_OP_NEWARRAY")},
46 	{_SC("_OP_APPENDARRAY")},
47 	{_SC("_OP_GETPARENT")},
48 	{_SC("_OP_COMPARITH")},
49 	{_SC("_OP_COMPARITHL")},
50 	{_SC("_OP_INC")},
51 	{_SC("_OP_INCL")},
52 	{_SC("_OP_PINC")},
53 	{_SC("_OP_PINCL")},
54 	{_SC("_OP_CMP")},
55 	{_SC("_OP_EXISTS")},
56 	{_SC("_OP_INSTANCEOF")},
57 	{_SC("_OP_AND")},
58 	{_SC("_OP_OR")},
59 	{_SC("_OP_NEG")},
60 	{_SC("_OP_NOT")},
61 	{_SC("_OP_BWNOT")},
62 	{_SC("_OP_CLOSURE")},
63 	{_SC("_OP_YIELD")},
64 	{_SC("_OP_RESUME")},
65 	{_SC("_OP_FOREACH")},
66 	{_SC("_OP_POSTFOREACH")},
67 	{_SC("_OP_DELEGATE")},
68 	{_SC("_OP_CLONE")},
69 	{_SC("_OP_TYPEOF")},
70 	{_SC("_OP_PUSHTRAP")},
71 	{_SC("_OP_POPTRAP")},
72 	{_SC("_OP_THROW")},
73 	{_SC("_OP_CLASS")},
74 	{_SC("_OP_NEWSLOTA")}
75 };
76 #endif
DumpLiteral(SQObjectPtr & o)77 void DumpLiteral(SQObjectPtr &o)
78 {
79 	switch(type(o)){
80 		case OT_STRING:	scprintf(_SC("\"%s\""),_stringval(o));break;
81 		case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break;
82 		case OT_INTEGER:
83 			// C::B patch: Support for Windows 64 bit
84             #if defined(_WIN64)
85             scprintf(_SC("{%I64d}"),_integer(o));
86 			// C::B patch: Support for Linux 64 bit
87             #elif defined(_SQ64)
88             scprintf(_SC("{%ld}"),_integer(o));
89             #else
90             scprintf(_SC("{%d}"),_integer(o));
91             #endif
92             break;
93 		case OT_BOOL: scprintf(_SC("%s"),_integer(o)?_SC("true"):_SC("false"));break;
94 		// C::B patch: Eliminate compiler warnings
95 		default: scprintf(_SC("(%s %p)"),GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler
96 	}
97 }
98 
SQFuncState(SQSharedState * ss,SQFuncState * parent,CompilerErrorFunc efunc,void * ed)99 SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed)
100 {
101 		_nliterals = 0;
102 		_literals = SQTable::Create(ss,0);
103 		_strings =  SQTable::Create(ss,0);
104 		_sharedstate = ss;
105 		_lastline = 0;
106 		_optimization = true;
107 		_parent = parent;
108 		_stacksize = 0;
109 		_traps = 0;
110 		_returnexp = 0;
111 		_varparams = false;
112 		_errfunc = efunc;
113 		_errtarget = ed;
114 		_bgenerator = false;
115 
116 }
117 
Error(const SQChar * err)118 void SQFuncState::Error(const SQChar *err)
119 {
120 	_errfunc(_errtarget,err);
121 }
122 
123 #ifdef _DEBUG_DUMP
Dump(SQFunctionProto * func)124 void SQFuncState::Dump(SQFunctionProto *func)
125 {
126 	SQUnsignedInteger n=0,i;
127 	SQInteger si;
128 	scprintf(_SC("SQInstruction sizeof %d\n"),sizeof(SQInstruction));
129 	scprintf(_SC("SQObject sizeof %d\n"),sizeof(SQObject));
130 	scprintf(_SC("--------------------------------------------------------------------\n"));
131 	scprintf(_SC("*****FUNCTION [%s]\n"),type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown"));
132 	scprintf(_SC("-----LITERALS\n"));
133 	SQObjectPtr refidx,key,val;
134 	SQInteger idx;
135 	SQObjectPtrVec templiterals;
136 	templiterals.resize(_nliterals);
137 	while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {
138 		refidx=idx;
139 		templiterals[_integer(val)]=key;
140 	}
141 	for(i=0;i<templiterals.size();i++){
142 		scprintf(_SC("[%d] "),n);
143 		DumpLiteral(templiterals[i]);
144 		scprintf(_SC("\n"));
145 		n++;
146 	}
147 	scprintf(_SC("-----PARAMS\n"));
148 	if(_varparams)
149 		scprintf(_SC("<<VARPARAMS>>\n"));
150 	n=0;
151 	for(i=0;i<_parameters.size();i++){
152 		scprintf(_SC("[%d] "),n);
153 		DumpLiteral(_parameters[i]);
154 		scprintf(_SC("\n"));
155 		n++;
156 	}
157 	scprintf(_SC("-----LOCALS\n"));
158 	for(si=0;si<func->_nlocalvarinfos;si++){
159 		SQLocalVarInfo lvi=func->_localvarinfos[si];
160 		scprintf(_SC("[%d] %s \t%d %d\n"),lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op);
161 		n++;
162 	}
163 	scprintf(_SC("-----LINE INFO\n"));
164 	for(i=0;i<_lineinfos.size();i++){
165 		SQLineInfo li=_lineinfos[i];
166 		scprintf(_SC("op [%d] line [%d] \n"),li._op,li._line);
167 		n++;
168 	}
169 	scprintf(_SC("-----dump\n"));
170 	n=0;
171 	for(i=0;i<_instructions.size();i++){
172 		SQInstruction &inst=_instructions[i];
173 		if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){
174 
175 			SQInteger lidx = inst._arg1;
176 			scprintf(_SC("[%03d] %15s %d "),n,g_InstrDesc[inst.op].name,inst._arg0);
177 			if(lidx >= 0xFFFFFFFF)
178 				scprintf(_SC("null"));
179 			else {
180 				SQInteger refidx;
181 				SQObjectPtr val,key,refo;
182 				while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) {
183 					refo = refidx;
184 				}
185 				DumpLiteral(key);
186 			}
187 			if(inst.op != _OP_DLOAD) {
188 				scprintf(_SC(" %d %d \n"),inst._arg2,inst._arg3);
189 			}
190 			else {
191 				scprintf(_SC(" %d "),inst._arg2);
192 				lidx = inst._arg3;
193 				if(lidx >= 0xFFFFFFFF)
194 					scprintf(_SC("null"));
195 				else {
196 					SQInteger refidx;
197 					SQObjectPtr val,key,refo;
198 					while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) {
199 						refo = refidx;
200 				}
201 				DumpLiteral(key);
202 				scprintf(_SC("\n"));
203 			}
204 			}
205 		}
206 		else if(inst.op==_OP_LOADFLOAT) {
207 			scprintf(_SC("[%03d] %15s %d %f %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,*((SQFloat*)&inst._arg1),inst._arg2,inst._arg3);
208 		}
209 		else if(inst.op==_OP_ARITH){
210 			scprintf(_SC("[%03d] %15s %d %d %d %c\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);
211 		}
212 		else
213 			scprintf(_SC("[%03d] %15s %d %d %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);
214 		n++;
215 	}
216 	scprintf(_SC("-----\n"));
217 	scprintf(_SC("stack size[%d]\n"),func->_stacksize);
218 	scprintf(_SC("--------------------------------------------------------------------\n\n"));
219 }
220 #endif
221 
GetNumericConstant(const SQInteger cons)222 SQInteger SQFuncState::GetNumericConstant(const SQInteger cons)
223 {
224 	return GetConstant(SQObjectPtr(cons));
225 }
226 
GetNumericConstant(const SQFloat cons)227 SQInteger SQFuncState::GetNumericConstant(const SQFloat cons)
228 {
229 	return GetConstant(SQObjectPtr(cons));
230 }
231 
GetConstant(const SQObject & cons)232 SQInteger SQFuncState::GetConstant(const SQObject &cons)
233 {
234 	SQObjectPtr val;
235 	if(!_table(_literals)->Get(cons,val))
236 	{
237 		val = _nliterals;
238 		_table(_literals)->NewSlot(cons,val);
239 		_nliterals++;
240 		if(_nliterals > MAX_LITERALS) {
241 			val.Null();
242 			Error(_SC("internal compiler error: too many literals"));
243 		}
244 	}
245 	return _integer(val);
246 }
247 
SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)248 void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)
249 {
250 	_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0);
251 	_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1);
252 	_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2);
253 	_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3);
254 }
255 
SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val)256 void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val)
257 {
258 	switch(arg){
259 		case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break;
260 		case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break;
261 		case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break;
262 		case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break;
263 	};
264 }
265 
AllocStackPos()266 SQInteger SQFuncState::AllocStackPos()
267 {
268 	SQInteger npos=_vlocals.size();
269 	_vlocals.push_back(SQLocalVarInfo());
270 	if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) {
271 		if(_stacksize>MAX_FUNC_STACKSIZE) Error(_SC("internal compiler error: too many locals"));
272 		_stacksize=_vlocals.size();
273 	}
274 	return npos;
275 }
276 
PushTarget(SQInteger n)277 SQInteger SQFuncState::PushTarget(SQInteger n)
278 {
279 	if(n!=-1){
280 		_targetstack.push_back(n);
281 		return n;
282 	}
283 	n=AllocStackPos();
284 	_targetstack.push_back(n);
285 	return n;
286 }
287 
GetUpTarget(SQInteger n)288 SQInteger SQFuncState::GetUpTarget(SQInteger n){
289 	return _targetstack[((_targetstack.size()-1)-n)];
290 }
291 
TopTarget()292 SQInteger SQFuncState::TopTarget(){
293 	return _targetstack.back();
294 }
PopTarget()295 SQInteger SQFuncState::PopTarget()
296 {
297 	SQInteger npos=_targetstack.back();
298 	SQLocalVarInfo t=_vlocals[_targetstack.back()];
299 	if(type(t._name)==OT_NULL){
300 		_vlocals.pop_back();
301 	}
302 	_targetstack.pop_back();
303 	return npos;
304 }
305 
GetStackSize()306 SQInteger SQFuncState::GetStackSize()
307 {
308 	return _vlocals.size();
309 }
310 
SetStackSize(SQInteger n)311 void SQFuncState::SetStackSize(SQInteger n)
312 {
313 	SQInteger size=_vlocals.size();
314 	while(size>n){
315 		size--;
316 		SQLocalVarInfo lvi=_vlocals.back();
317 		if(type(lvi._name)!=OT_NULL){
318 			lvi._end_op=GetCurrentPos();
319 			_localvarinfos.push_back(lvi);
320 		}
321 		_vlocals.pop_back();
322 	}
323 }
324 
IsConstant(const SQObject & name,SQObject & e)325 bool SQFuncState::IsConstant(const SQObject &name,SQObject &e)
326 {
327 	SQObjectPtr val;
328 	if(_table(_sharedstate->_consts)->Get(name,val)) {
329 		e = val;
330 		return true;
331 	}
332 	return false;
333 }
334 
IsLocal(SQUnsignedInteger stkpos)335 bool SQFuncState::IsLocal(SQUnsignedInteger stkpos)
336 {
337 	if(stkpos>=_vlocals.size())return false;
338 	else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true;
339 	return false;
340 }
341 
PushLocalVariable(const SQObject & name)342 SQInteger SQFuncState::PushLocalVariable(const SQObject &name)
343 {
344 	SQInteger pos=_vlocals.size();
345 	SQLocalVarInfo lvi;
346 	lvi._name=name;
347 	lvi._start_op=GetCurrentPos()+1;
348 	lvi._pos=_vlocals.size();
349 	_vlocals.push_back(lvi);
350 	if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size();
351 
352 	return pos;
353 }
354 
GetLocalVariable(const SQObject & name)355 SQInteger SQFuncState::GetLocalVariable(const SQObject &name)
356 {
357 	SQInteger locals=_vlocals.size();
358 	while(locals>=1){
359 		if(type(_vlocals[locals-1]._name)==OT_STRING && _string(_vlocals[locals-1]._name)==_string(name)){
360 			return locals-1;
361 		}
362 		locals--;
363 	}
364 	return -1;
365 }
366 
GetOuterVariable(const SQObject & name)367 SQInteger SQFuncState::GetOuterVariable(const SQObject &name)
368 {
369 	SQInteger outers = _outervalues.size();
370 	for(SQInteger i = 0; i<outers; i++) {
371 		if(_string(_outervalues[i]._name) == _string(name))
372 			return i;
373 	}
374 	return -1;
375 }
376 
AddOuterValue(const SQObject & name)377 void SQFuncState::AddOuterValue(const SQObject &name)
378 {
379 	SQInteger pos=-1;
380 	if(_parent) {
381 		pos = _parent->GetLocalVariable(name);
382 		if(pos == -1) {
383 			pos = _parent->GetOuterVariable(name);
384 			if(pos != -1) {
385 				_outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local
386 				return;
387 			}
388 		}
389 		else {
390 			_outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local
391 			return;
392 		}
393 	}
394 	_outervalues.push_back(SQOuterVar(name,name,otSYMBOL)); //global
395 }
396 
AddParameter(const SQObject & name)397 void SQFuncState::AddParameter(const SQObject &name)
398 {
399 	PushLocalVariable(name);
400 	_parameters.push_back(name);
401 }
402 
AddLineInfos(SQInteger line,bool lineop,bool force)403 void SQFuncState::AddLineInfos(SQInteger line,bool lineop,bool force)
404 {
405 	if(_lastline!=line || force){
406 		SQLineInfo li;
407 		li._line=line;li._op=(GetCurrentPos()+1);
408 		if(lineop)AddInstruction(_OP_LINE,0,line);
409 		_lineinfos.push_back(li);
410 		_lastline=line;
411 	}
412 }
413 
AddInstruction(SQInstruction & i)414 void SQFuncState::AddInstruction(SQInstruction &i)
415 {
416 	SQInteger size = _instructions.size();
417 	if(size > 0 && _optimization){ //simple optimizer
418 		SQInstruction &pi = _instructions[size-1];//previous instruction
419 		switch(i.op) {
420 		case _OP_RETURN:
421 			if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) {
422 				pi.op = _OP_TAILCALL;
423 			}
424 		break;
425 		case _OP_GET:
426 			if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){
427 				pi._arg1 = pi._arg1;
428 				pi._arg2 = (unsigned char)i._arg1;
429 				pi.op = _OP_GETK;
430 				pi._arg0 = i._arg0;
431 
432 				return;
433 			}
434 		break;
435 		case _OP_PREPCALL:
436 			if( pi.op == _OP_LOAD  && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){
437 				pi.op = _OP_PREPCALLK;
438 				pi._arg0 = i._arg0;
439 				pi._arg1 = pi._arg1;
440 				pi._arg2 = i._arg2;
441 				pi._arg3 = i._arg3;
442 				return;
443 			}
444 			break;
445 		case _OP_APPENDARRAY:
446 			if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){
447 				pi.op = _OP_APPENDARRAY;
448 				pi._arg0 = i._arg0;
449 				pi._arg1 = pi._arg1;
450 				pi._arg2 = MAX_FUNC_STACKSIZE;
451 				pi._arg3 = MAX_FUNC_STACKSIZE;
452 				return;
453 			}
454 			break;
455 		case _OP_MOVE:
456 			if((pi.op == _OP_GET || pi.op == _OP_ARITH || pi.op == _OP_BITW) && (pi._arg0 == i._arg1))
457 			{
458 				pi._arg0 = i._arg0;
459 				_optimization = false;
460 				return;
461 			}
462 
463 			if(pi.op == _OP_MOVE)
464 			{
465 				pi.op = _OP_DMOVE;
466 				pi._arg2 = i._arg0;
467 				pi._arg3 = (unsigned char)i._arg1;
468 				return;
469 			}
470 			break;
471 		case _OP_LOAD:
472 			if(pi.op == _OP_LOAD && i._arg1 < 256) {
473 				pi.op = _OP_DLOAD;
474 				pi._arg2 = i._arg0;
475 				pi._arg3 = (unsigned char)i._arg1;
476 				return;
477 			}
478 			break;
479 		case _OP_EQ:case _OP_NE:
480 			if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) ))
481 			{
482 				pi.op = i.op;
483 				pi._arg0 = i._arg0;
484 				pi._arg1 = pi._arg1;
485 				pi._arg2 = i._arg2;
486 				pi._arg3 = MAX_FUNC_STACKSIZE;
487 				return;
488 			}
489 			break;
490 		case _OP_LOADNULLS:
491 			if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) {
492 
493 				pi._arg1 = pi._arg1 + 1;
494 				pi.op = _OP_LOADNULLS;
495 				return;
496 			}
497             break;
498 		case _OP_LINE:
499 			if(pi.op == _OP_LINE) {
500 				_instructions.pop_back();
501 				_lineinfos.pop_back();
502 			}
503 			break;
504 		}
505 	}
506 	_optimization = true;
507 	_instructions.push_back(i);
508 }
509 
CreateString(const SQChar * s,SQInteger len)510 SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len)
511 {
512 	SQObjectPtr ns(SQString::Create(_sharedstate,s,len));
513 	_table(_strings)->NewSlot(ns,(SQInteger)1);
514 	return ns;
515 }
516 
CreateTable()517 SQObject SQFuncState::CreateTable()
518 {
519 	SQObjectPtr nt(SQTable::Create(_sharedstate,0));
520 	_table(_strings)->NewSlot(nt,(SQInteger)1);
521 	return nt;
522 }
523 
BuildProto()524 SQFunctionProto *SQFuncState::BuildProto()
525 {
526 	SQFunctionProto *f=SQFunctionProto::Create(_instructions.size(),
527 		_nliterals,_parameters.size(),_functions.size(),_outervalues.size(),
528 		_lineinfos.size(),_localvarinfos.size(),_defaultparams.size());
529 
530 	SQObjectPtr refidx,key,val;
531 	SQInteger idx;
532 
533 	f->_stacksize = _stacksize;
534 	f->_sourcename = _sourcename;
535 	f->_bgenerator = _bgenerator;
536 	f->_name = _name;
537 
538 	while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {
539 		f->_literals[_integer(val)]=key;
540 		refidx=idx;
541 	}
542 
543 	for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf];
544 	for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np];
545 	for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no];
546 	for(SQUnsignedInteger no = 0; no < _localvarinfos.size(); no++) f->_localvarinfos[no] = _localvarinfos[no];
547 	for(SQUnsignedInteger no = 0; no < _lineinfos.size(); no++) f->_lineinfos[no] = _lineinfos[no];
548 	for(SQUnsignedInteger no = 0; no < _defaultparams.size(); no++) f->_defaultparams[no] = _defaultparams[no];
549 
550 	memcpy(f->_instructions,&_instructions[0],_instructions.size()*sizeof(SQInstruction));
551 
552 	f->_varparams = _varparams;
553 
554 	return f;
555 }
556 
PushChildState(SQSharedState * ss)557 SQFuncState *SQFuncState::PushChildState(SQSharedState *ss)
558 {
559 	SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState));
560 	new (child) SQFuncState(ss,this,_errfunc,_errtarget);
561 	_childstates.push_back(child);
562 	return child;
563 }
564 
PopChildState()565 void SQFuncState::PopChildState()
566 {
567 	SQFuncState *child = _childstates.back();
568 	sq_delete(child,SQFuncState);
569 	_childstates.pop_back();
570 }
571 
~SQFuncState()572 SQFuncState::~SQFuncState()
573 {
574 	while(_childstates.size() > 0)
575 	{
576 		PopChildState();
577 	}
578 }
579