2 see copyright notice in squirrel.h
\r
4 #include "sqpcheader.h"
\r
6 #include "sqcompiler.h"
\r
7 #include "sqstring.h"
\r
8 #include "sqfuncproto.h"
\r
10 #include "sqopcodes.h"
\r
11 #include "sqfuncstate.h"
\r
14 SQInstructionDesc g_InstrDesc[]={
\r
17 {_SC("_OP_LOADINT")},
\r
18 {_SC("_OP_LOADFLOAT")},
\r
20 {_SC("_OP_TAILCALL")},
\r
22 {_SC("_OP_PREPCALL")},
\r
23 {_SC("_OP_PREPCALLK")},
\r
26 {_SC("_OP_NEWSLOT")},
\r
27 {_SC("_OP_DELETE")},
\r
38 {_SC("_OP_RETURN")},
\r
39 {_SC("_OP_LOADNULLS")},
\r
40 {_SC("_OP_LOADROOT")},
\r
41 {_SC("_OP_LOADBOOL")},
\r
46 {_SC("_OP_SETOUTER")},
\r
47 {_SC("_OP_GETOUTER")},
\r
48 {_SC("_OP_NEWOBJ")},
\r
49 {_SC("_OP_APPENDARRAY")},
\r
50 {_SC("_OP_COMPARITH")},
\r
56 {_SC("_OP_EXISTS")},
\r
57 {_SC("_OP_INSTANCEOF")},
\r
63 {_SC("_OP_CLOSURE")},
\r
65 {_SC("_OP_RESUME")},
\r
66 {_SC("_OP_FOREACH")},
\r
67 {_SC("_OP_POSTFOREACH")},
\r
69 {_SC("_OP_TYPEOF")},
\r
70 {_SC("_OP_PUSHTRAP")},
\r
71 {_SC("_OP_POPTRAP")},
\r
73 {_SC("_OP_NEWSLOTA")},
\r
74 {_SC("_OP_GETBASE")},
\r
79 void DumpLiteral(SQObjectPtr &o)
\r
82 case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break;
\r
83 case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break;
\r
84 case OT_INTEGER: scprintf(_SC("{") _PRINT_INT_FMT _SC("}"),_integer(o));break;
\r
85 case OT_BOOL: scprintf(_SC("%s"),_integer(o)?_SC("true"):_SC("false"));break;
\r
86 default: scprintf(_SC("(%s %p)"),GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler
\r
90 SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed)
\r
93 _literals = SQTable::Create(ss,0);
\r
94 _strings = SQTable::Create(ss,0);
\r
97 _optimization = true;
\r
102 _varparams = false;
\r
105 _bgenerator = false;
\r
111 void SQFuncState::Error(const SQChar *err)
\r
113 _errfunc(_errtarget,err);
\r
117 void SQFuncState::Dump(SQFunctionProto *func)
\r
119 SQUnsignedInteger n=0,i;
\r
121 scprintf(_SC("SQInstruction sizeof %d\n"),sizeof(SQInstruction));
\r
122 scprintf(_SC("SQObject sizeof %d\n"),sizeof(SQObject));
\r
123 scprintf(_SC("--------------------------------------------------------------------\n"));
\r
124 scprintf(_SC("*****FUNCTION [%s]\n"),type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown"));
\r
125 scprintf(_SC("-----LITERALS\n"));
\r
126 SQObjectPtr refidx,key,val;
\r
128 SQObjectPtrVec templiterals;
\r
129 templiterals.resize(_nliterals);
\r
130 while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {
\r
132 templiterals[_integer(val)]=key;
\r
134 for(i=0;i<templiterals.size();i++){
\r
135 scprintf(_SC("[%d] "),n);
\r
136 DumpLiteral(templiterals[i]);
\r
137 scprintf(_SC("\n"));
\r
140 scprintf(_SC("-----PARAMS\n"));
\r
142 scprintf(_SC("<<VARPARAMS>>\n"));
\r
144 for(i=0;i<_parameters.size();i++){
\r
145 scprintf(_SC("[%d] "),n);
\r
146 DumpLiteral(_parameters[i]);
\r
147 scprintf(_SC("\n"));
\r
150 scprintf(_SC("-----LOCALS\n"));
\r
151 for(si=0;si<func->_nlocalvarinfos;si++){
\r
152 SQLocalVarInfo lvi=func->_localvarinfos[si];
\r
153 scprintf(_SC("[%d] %s \t%d %d\n"),lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op);
\r
156 scprintf(_SC("-----LINE INFO\n"));
\r
157 for(i=0;i<_lineinfos.size();i++){
\r
158 SQLineInfo li=_lineinfos[i];
\r
159 scprintf(_SC("op [%d] line [%d] \n"),li._op,li._line);
\r
162 scprintf(_SC("-----dump\n"));
\r
164 for(i=0;i<_instructions.size();i++){
\r
165 SQInstruction &inst=_instructions[i];
\r
166 if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){
\r
168 SQInteger lidx = inst._arg1;
\r
169 scprintf(_SC("[%03d] %15s %d "),n,g_InstrDesc[inst.op].name,inst._arg0);
\r
170 if(lidx >= 0xFFFFFFFF)
\r
171 scprintf(_SC("null"));
\r
174 SQObjectPtr val,key,refo;
\r
175 while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) {
\r
180 if(inst.op != _OP_DLOAD) {
\r
181 scprintf(_SC(" %d %d \n"),inst._arg2,inst._arg3);
\r
184 scprintf(_SC(" %d "),inst._arg2);
\r
186 if(lidx >= 0xFFFFFFFF)
\r
187 scprintf(_SC("null"));
\r
190 SQObjectPtr val,key,refo;
\r
191 while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) {
\r
195 scprintf(_SC("\n"));
\r
199 else if(inst.op==_OP_LOADFLOAT) {
\r
200 scprintf(_SC("[%03d] %15s %d %f %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,*((SQFloat*)&inst._arg1),inst._arg2,inst._arg3);
\r
202 /* else if(inst.op==_OP_ARITH){
\r
203 scprintf(_SC("[%03d] %15s %d %d %d %c\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);
\r
206 scprintf(_SC("[%03d] %15s %d %d %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);
\r
210 scprintf(_SC("-----\n"));
\r
211 scprintf(_SC("stack size[%d]\n"),func->_stacksize);
\r
212 scprintf(_SC("--------------------------------------------------------------------\n\n"));
\r
216 SQInteger SQFuncState::GetNumericConstant(const SQInteger cons)
\r
218 return GetConstant(SQObjectPtr(cons));
\r
221 SQInteger SQFuncState::GetNumericConstant(const SQFloat cons)
\r
223 return GetConstant(SQObjectPtr(cons));
\r
226 SQInteger SQFuncState::GetConstant(const SQObject &cons)
\r
229 if(!_table(_literals)->Get(cons,val))
\r
232 _table(_literals)->NewSlot(cons,val);
\r
234 if(_nliterals > MAX_LITERALS) {
\r
236 Error(_SC("internal compiler error: too many literals"));
\r
239 return _integer(val);
\r
242 void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)
\r
244 _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0);
\r
245 _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1);
\r
246 _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2);
\r
247 _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3);
\r
250 void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val)
\r
253 case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break;
\r
254 case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break;
\r
255 case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break;
\r
256 case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break;
\r
260 SQInteger SQFuncState::AllocStackPos()
\r
262 SQInteger npos=_vlocals.size();
\r
263 _vlocals.push_back(SQLocalVarInfo());
\r
264 if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) {
\r
265 if(_stacksize>MAX_FUNC_STACKSIZE) Error(_SC("internal compiler error: too many locals"));
\r
266 _stacksize=_vlocals.size();
\r
271 SQInteger SQFuncState::PushTarget(SQInteger n)
\r
274 _targetstack.push_back(n);
\r
278 _targetstack.push_back(n);
\r
282 SQInteger SQFuncState::GetUpTarget(SQInteger n){
\r
283 return _targetstack[((_targetstack.size()-1)-n)];
\r
286 SQInteger SQFuncState::TopTarget(){
\r
287 return _targetstack.back();
\r
289 SQInteger SQFuncState::PopTarget()
\r
291 SQUnsignedInteger npos=_targetstack.back();
\r
292 assert(npos < _vlocals.size());
\r
293 SQLocalVarInfo &t = _vlocals[npos];
\r
294 if(type(t._name)==OT_NULL){
\r
295 _vlocals.pop_back();
\r
297 _targetstack.pop_back();
\r
301 SQInteger SQFuncState::GetStackSize()
\r
303 return _vlocals.size();
\r
306 SQInteger SQFuncState::CountOuters(SQInteger stacksize)
\r
308 SQInteger outers = 0;
\r
309 SQInteger k = _vlocals.size() - 1;
\r
310 while(k >= stacksize) {
\r
311 SQLocalVarInfo &lvi = _vlocals[k];
\r
313 if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer
\r
320 void SQFuncState::SetStackSize(SQInteger n)
\r
322 SQInteger size=_vlocals.size();
\r
325 SQLocalVarInfo lvi = _vlocals.back();
\r
326 if(type(lvi._name)!=OT_NULL){
\r
327 if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer
\r
330 lvi._end_op = GetCurrentPos();
\r
331 _localvarinfos.push_back(lvi);
\r
333 _vlocals.pop_back();
\r
337 bool SQFuncState::IsConstant(const SQObject &name,SQObject &e)
\r
340 if(_table(_sharedstate->_consts)->Get(name,val)) {
\r
347 bool SQFuncState::IsLocal(SQUnsignedInteger stkpos)
\r
349 if(stkpos>=_vlocals.size())return false;
\r
350 else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true;
\r
354 SQInteger SQFuncState::PushLocalVariable(const SQObject &name)
\r
356 SQInteger pos=_vlocals.size();
\r
357 SQLocalVarInfo lvi;
\r
359 lvi._start_op=GetCurrentPos()+1;
\r
360 lvi._pos=_vlocals.size();
\r
361 _vlocals.push_back(lvi);
\r
362 if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size();
\r
368 SQInteger SQFuncState::GetLocalVariable(const SQObject &name)
\r
370 SQInteger locals=_vlocals.size();
\r
372 SQLocalVarInfo &lvi = _vlocals[locals-1];
\r
373 if(type(lvi._name)==OT_STRING && _string(lvi._name)==_string(name)){
\r
381 void SQFuncState::MarkLocalAsOuter(SQInteger pos)
\r
383 SQLocalVarInfo &lvi = _vlocals[pos];
\r
384 lvi._end_op = UINT_MINUS_ONE;
\r
388 SQInteger SQFuncState::GetOuterVariable(const SQObject &name)
\r
390 SQInteger outers = _outervalues.size();
\r
391 for(SQInteger i = 0; i<outers; i++) {
\r
392 if(_string(_outervalues[i]._name) == _string(name))
\r
397 pos = _parent->GetLocalVariable(name);
\r
399 pos = _parent->GetOuterVariable(name);
\r
401 _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local
\r
402 return _outervalues.size() - 1;
\r
406 _parent->MarkLocalAsOuter(pos);
\r
407 _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local
\r
408 return _outervalues.size() - 1;
\r
416 void SQFuncState::AddParameter(const SQObject &name)
\r
418 PushLocalVariable(name);
\r
419 _parameters.push_back(name);
\r
422 void SQFuncState::AddLineInfos(SQInteger line,bool lineop,bool force)
\r
424 if(_lastline!=line || force){
\r
426 li._line=line;li._op=(GetCurrentPos()+1);
\r
427 if(lineop)AddInstruction(_OP_LINE,0,line);
\r
428 if(_lastline!=line) {
\r
429 _lineinfos.push_back(li);
\r
435 void SQFuncState::DiscardTarget()
\r
437 SQInteger discardedtarget = PopTarget();
\r
438 SQInteger size = _instructions.size();
\r
439 if(size > 0 && _optimization){
\r
440 SQInstruction &pi = _instructions[size-1];//previous instruction
\r
442 case _OP_SET:case _OP_NEWSLOT:case _OP_SETOUTER:case _OP_CALL:
\r
443 if(pi._arg0 == discardedtarget) {
\r
450 void SQFuncState::AddInstruction(SQInstruction &i)
\r
452 SQInteger size = _instructions.size();
\r
453 if(size > 0 && _optimization){ //simple optimizer
\r
454 SQInstruction &pi = _instructions[size-1];//previous instruction
\r
457 if( pi.op == _OP_CMP && pi._arg1 < 0xFF) {
\r
459 pi._arg0 = (unsigned char)pi._arg1;
\r
460 pi._arg1 = i._arg1;
\r
465 if(i._arg0 == i._arg3) {
\r
470 if(i._arg0 == i._arg2) {
\r
475 if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) {
\r
476 pi.op = _OP_TAILCALL;
\r
477 } else if(pi.op == _OP_CLOSE){
\r
483 if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){
\r
484 pi._arg1 = pi._arg1;
\r
485 pi._arg2 = (unsigned char)i._arg1;
\r
487 pi._arg0 = i._arg0;
\r
493 if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){
\r
494 pi.op = _OP_PREPCALLK;
\r
495 pi._arg0 = i._arg0;
\r
496 pi._arg1 = pi._arg1;
\r
497 pi._arg2 = i._arg2;
\r
498 pi._arg3 = i._arg3;
\r
502 case _OP_APPENDARRAY: {
\r
503 SQInteger aat = -1;
\r
505 case _OP_LOAD: aat = AAT_LITERAL; break;
\r
506 case _OP_LOADINT: aat = AAT_INT; break;
\r
507 case _OP_LOADBOOL: aat = AAT_BOOL; break;
\r
508 case _OP_LOADFLOAT: aat = AAT_FLOAT; break;
\r
511 if(aat != -1 && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){
\r
512 pi.op = _OP_APPENDARRAY;
\r
513 pi._arg0 = i._arg0;
\r
514 pi._arg1 = pi._arg1;
\r
515 pi._arg2 = (unsigned char)aat;
\r
516 pi._arg3 = MAX_FUNC_STACKSIZE;
\r
523 case _OP_GET: case _OP_ADD: case _OP_SUB: case _OP_MUL: case _OP_DIV: case _OP_MOD: case _OP_BITW:
\r
524 case _OP_LOADINT: case _OP_LOADFLOAT: case _OP_LOADBOOL: case _OP_LOAD:
\r
526 if(pi._arg0 == i._arg1)
\r
528 pi._arg0 = i._arg0;
\r
529 _optimization = false;
\r
530 //_result_elimination = false;
\r
535 if(pi.op == _OP_MOVE)
\r
538 pi._arg2 = i._arg0;
\r
539 pi._arg3 = (unsigned char)i._arg1;
\r
544 if(pi.op == _OP_LOAD && i._arg1 < 256) {
\r
546 pi._arg2 = i._arg0;
\r
547 pi._arg3 = (unsigned char)i._arg1;
\r
551 case _OP_EQ:case _OP_NE:
\r
552 if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) ))
\r
555 pi._arg0 = i._arg0;
\r
556 pi._arg1 = pi._arg1;
\r
557 pi._arg2 = i._arg2;
\r
558 pi._arg3 = MAX_FUNC_STACKSIZE;
\r
562 case _OP_LOADNULLS:
\r
563 if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) {
\r
565 pi._arg1 = pi._arg1 + 1;
\r
566 pi.op = _OP_LOADNULLS;
\r
571 if(pi.op == _OP_LINE) {
\r
572 _instructions.pop_back();
\r
573 _lineinfos.pop_back();
\r
578 _optimization = true;
\r
579 _instructions.push_back(i);
\r
582 SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len)
\r
584 SQObjectPtr ns(SQString::Create(_sharedstate,s,len));
\r
585 _table(_strings)->NewSlot(ns,(SQInteger)1);
\r
589 SQObject SQFuncState::CreateTable()
\r
591 SQObjectPtr nt(SQTable::Create(_sharedstate,0));
\r
592 _table(_strings)->NewSlot(nt,(SQInteger)1);
\r
596 SQFunctionProto *SQFuncState::BuildProto()
\r
599 SQFunctionProto *f=SQFunctionProto::Create(_ss,_instructions.size(),
\r
600 _nliterals,_parameters.size(),_functions.size(),_outervalues.size(),
\r
601 _lineinfos.size(),_localvarinfos.size(),_defaultparams.size());
\r
603 SQObjectPtr refidx,key,val;
\r
606 f->_stacksize = _stacksize;
\r
607 f->_sourcename = _sourcename;
\r
608 f->_bgenerator = _bgenerator;
\r
611 while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {
\r
612 f->_literals[_integer(val)]=key;
\r
616 for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf];
\r
617 for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np];
\r
618 for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no];
\r
619 for(SQUnsignedInteger nl = 0; nl < _localvarinfos.size(); nl++) f->_localvarinfos[nl] = _localvarinfos[nl];
\r
620 for(SQUnsignedInteger ni = 0; ni < _lineinfos.size(); ni++) f->_lineinfos[ni] = _lineinfos[ni];
\r
621 for(SQUnsignedInteger nd = 0; nd < _defaultparams.size(); nd++) f->_defaultparams[nd] = _defaultparams[nd];
\r
623 memcpy(f->_instructions,&_instructions[0],_instructions.size()*sizeof(SQInstruction));
\r
625 f->_varparams = _varparams;
\r
630 SQFuncState *SQFuncState::PushChildState(SQSharedState *ss)
\r
632 SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState));
\r
633 new (child) SQFuncState(ss,this,_errfunc,_errtarget);
\r
634 _childstates.push_back(child);
\r
638 void SQFuncState::PopChildState()
\r
640 SQFuncState *child = _childstates.back();
\r
641 sq_delete(child,SQFuncState);
\r
642 _childstates.pop_back();
\r
645 SQFuncState::~SQFuncState()
\r
647 while(_childstates.size() > 0)
\r