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