fixed warnings in squirrel
[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                 default: break;
80         }
81 }
82
83 SQFuncState::SQFuncState(SQSharedState *ss,SQFunctionProto *func,SQFuncState *parent)
84 {
85                 _nliterals = 0;
86                 _literals = 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 }
97
98 #ifdef _DEBUG_DUMP
99 void SQFuncState::Dump()
100 {
101         unsigned int n=0,i;
102         SQFunctionProto *func=_funcproto(_func);
103         scprintf(_SC("SQInstruction sizeof %d\n"),sizeof(SQInstruction));
104         scprintf(_SC("SQObject sizeof %d\n"),sizeof(SQObject));
105         scprintf(_SC("--------------------------------------------------------------------\n"));
106         scprintf(_SC("*****FUNCTION [%s]\n"),type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown"));
107         scprintf(_SC("-----LITERALS\n"));
108         SQObjectPtr refidx,key,val;
109         SQInteger idx;
110         SQObjectPtrVec templiterals;
111         templiterals.resize(_nliterals);
112         while((idx=_table(_literals)->Next(refidx,key,val))!=-1) {
113                 refidx=idx;
114                 templiterals[_integer(val)]=key;
115         }
116         for(i=0;i<templiterals.size();i++){
117                 scprintf(_SC("[%d] "),n);
118                 DumpLiteral(templiterals[i]);
119                 scprintf(_SC("\n"));
120                 n++;
121         }
122         scprintf(_SC("-----PARAMS\n"));
123         if(_varparams)
124                 scprintf(_SC("<<VARPARAMS>>\n"));
125         n=0;
126         for(i=0;i<_parameters.size();i++){
127                 scprintf(_SC("[%d] "),n);
128                 DumpLiteral(_parameters[i]);
129                 scprintf(_SC("\n"));
130                 n++;
131         }
132         scprintf(_SC("-----LOCALS\n"));
133         for(i=0;i<func->_localvarinfos.size();i++){
134                 SQLocalVarInfo lvi=func->_localvarinfos[i];
135                 scprintf(_SC("[%d] %s \t%d %d\n"),lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op);
136                 n++;
137         }
138         scprintf(_SC("-----LINE INFO\n"));
139         for(i=0;i<_lineinfos.size();i++){
140                 SQLineInfo li=_lineinfos[i];
141                 scprintf(_SC("op [%d] line [%d] \n"),li._op,li._line);
142                 n++;
143         }
144         scprintf(_SC("-----dump\n"));
145         n=0;
146         for(i=0;i<_instructions.size();i++){
147                 SQInstruction &inst=_instructions[i];
148                 if(inst.op==_OP_LOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){
149                         
150                         int lidx = inst._arg1;
151                         scprintf(_SC("[%03d] %15s %d "),n,g_InstrDesc[inst.op].name,inst._arg0);
152                         if(lidx >= 0xFFFFFFFF)
153                                 scprintf(_SC("null"));
154                         else {
155                                 int refidx;
156                                 SQObjectPtr val,key,refo;
157                                 while(((refidx=_table(_literals)->Next(refo,key,val))!= -1) && (_integer(val) != lidx)) {
158                                         refo = refidx;  
159                                 }
160                                 DumpLiteral(key);
161                         }
162                         scprintf(_SC(" %d %d \n"),inst._arg2,inst._arg3);
163                 }
164                 else if(inst.op==_OP_ARITH){
165                         scprintf(_SC("[%03d] %15s %d %d %d %c\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);
166                 }
167                 else 
168                         scprintf(_SC("[%03d] %15s %d %d %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);
169                 n++;
170         }
171         scprintf(_SC("-----\n"));
172         scprintf(_SC("stack size[%d]\n"),func->_stacksize);
173         scprintf(_SC("--------------------------------------------------------------------\n\n"));
174 }
175 #endif
176 int SQFuncState::GetStringConstant(const SQChar *cons)
177 {
178         return GetConstant(SQString::Create(_sharedstate,cons));
179 }
180
181 int SQFuncState::GetNumericConstant(const SQInteger cons)
182 {
183         return GetConstant(cons);
184 }
185
186 int SQFuncState::GetNumericConstant(const SQFloat cons)
187 {
188         return GetConstant(cons);
189 }
190
191 int SQFuncState::GetConstant(SQObjectPtr cons)
192 {
193         // int n=0;
194         SQObjectPtr val;
195         if(!_table(_literals)->Get(cons,val))
196         {
197                 val = _nliterals;
198                 _table(_literals)->NewSlot(cons,val);
199                 _nliterals++;
200                 if(_nliterals > MAX_LITERALS) throw ParserException(_SC("internal compiler error: too many literals"));
201         }
202         return _integer(val);
203 }
204
205 void SQFuncState::SetIntructionParams(int pos,int arg0,int arg1,int arg2,int arg3)
206 {
207         _instructions[pos]._arg0=*((unsigned int *)&arg0);
208         _instructions[pos]._arg1=*((unsigned int *)&arg1);
209         _instructions[pos]._arg2=*((unsigned int *)&arg2);
210         _instructions[pos]._arg3=*((unsigned int *)&arg3);
211 }
212
213 void SQFuncState::SetIntructionParam(int pos,int arg,int val)
214 {
215         switch(arg){
216                 case 0:_instructions[pos]._arg0=*((unsigned int *)&val);break;
217                 case 1:_instructions[pos]._arg1=*((unsigned int *)&val);break;
218                 case 2:_instructions[pos]._arg2=*((unsigned int *)&val);break;
219                 case 3:_instructions[pos]._arg3=*((unsigned int *)&val);break;
220                 case 4:_instructions[pos]._arg1=*((unsigned int *)&val);break;
221         };
222 }
223
224 int SQFuncState::AllocStackPos()
225 {
226         int npos=_vlocals.size();
227         _vlocals.push_back(SQLocalVarInfo());
228         if(_vlocals.size()>((unsigned int)_stacksize)) {
229                 if(_stacksize>MAX_FUNC_STACKSIZE) throw ParserException(_SC("internal compiler error: too many locals"));
230                 _stacksize=_vlocals.size();
231         }
232         return npos;
233 }
234
235 int SQFuncState::PushTarget(int n)
236 {
237         if(n!=-1){
238                 _targetstack.push_back(n);
239                 return n;
240         }
241         n=AllocStackPos();
242         _targetstack.push_back(n);
243         return n;
244 }
245
246 int SQFuncState::GetUpTarget(int n){
247         return _targetstack[((_targetstack.size()-1)-n)];
248 }
249
250 int SQFuncState::TopTarget(){
251         return _targetstack.back();
252 }
253 int SQFuncState::PopTarget()
254 {
255         int npos=_targetstack.back();
256         SQLocalVarInfo t=_vlocals[_targetstack.back()];
257         if(type(t._name)==OT_NULL){
258                 _vlocals.pop_back();
259         }
260         _targetstack.pop_back();
261         return npos;
262 }
263
264 int SQFuncState::GetStackSize()
265 {
266         return _vlocals.size();
267 }
268
269 void SQFuncState::SetStackSize(int n)
270 {
271         int size=_vlocals.size();
272         while(size>n){
273                 size--;
274                 SQLocalVarInfo lvi=_vlocals.back();
275                 if(type(lvi._name)!=OT_NULL){
276                         lvi._end_op=GetCurrentPos();
277                         _localvarinfos.push_back(lvi);
278                 }
279                 _vlocals.pop_back();
280         }
281 }
282
283 bool SQFuncState::IsLocal(unsigned int stkpos)
284 {
285         if(stkpos>=_vlocals.size())return false;
286         else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true;
287         return false;
288 }
289
290 int SQFuncState::PushLocalVariable(const SQObjectPtr &name)
291 {
292         int pos=_vlocals.size();
293         SQLocalVarInfo lvi;
294         lvi._name=name;
295         lvi._start_op=GetCurrentPos()+1;
296         lvi._pos=_vlocals.size();
297         _vlocals.push_back(lvi);
298         if(_vlocals.size()>((unsigned int)_stacksize))_stacksize=_vlocals.size();
299         
300         return pos;
301 }
302
303 int SQFuncState::GetLocalVariable(const SQObjectPtr &name)
304 {
305         int locals=_vlocals.size();
306         while(locals>=1){
307                 if(type(_vlocals[locals-1]._name)==OT_STRING && _string(_vlocals[locals-1]._name)==_string(name)){
308                         return locals-1;
309                 }
310                 locals--;
311         }
312         return -1;
313 }
314
315 int SQFuncState::GetOuterVariable(const SQObjectPtr &name)
316 {
317         int outers = _outervalues.size();
318         for(int i = 0; i<outers; i++) {
319                 if(_string(_outervalues[i]._name) == _string(name))
320                         return i;
321         }
322         return -1;
323 }
324
325 void SQFuncState::AddOuterValue(const SQObjectPtr &name)
326 {
327         //AddParameter(name);
328         int pos=-1;
329         if(_parent) { 
330                 pos = _parent->GetLocalVariable(name);
331                 if(pos == -1) {
332                         pos = _parent->GetOuterVariable(name);
333                         if(pos != -1) {
334                                 _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local
335                                 return;
336                         }
337                 }
338                 else {
339                         _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local
340                         return;
341                 }
342         }       
343         _outervalues.push_back(SQOuterVar(name,name,otSYMBOL)); //global
344 }
345
346 void SQFuncState::AddParameter(const SQObjectPtr &name)
347 {
348         PushLocalVariable(name);
349         _parameters.push_back(name);
350 }
351
352 void SQFuncState::AddLineInfos(int line,bool lineop,bool force)
353 {
354         if(_lastline!=line || force){
355                 SQLineInfo li;
356                 li._line=line;li._op=(GetCurrentPos()+1);
357                 if(lineop)AddInstruction(_OP_LINE,0,line);
358                 _lineinfos.push_back(li);
359                 _lastline=line;
360         }
361 }
362
363 void SQFuncState::AddInstruction(SQInstruction &i)
364 {
365         int size = _instructions.size();
366         if(size > 0 && _optimization){ //simple optimizer
367                 SQInstruction &pi = _instructions[size-1];//previous instruction
368                 switch(i.op) {
369                 case _OP_RETURN:
370                         if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) {
371                                 pi.op = _OP_TAILCALL;
372                         }
373                 break;
374                 case _OP_GET:
375                         if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){
376                                 pi._arg1 = pi._arg1;
377                                 pi._arg2 = (unsigned char)i._arg1;
378                                 pi.op = _OP_GETK;
379                                 pi._arg0 = i._arg0;
380                                 
381                                 return;
382                         }
383                 break;
384                 case _OP_PREPCALL:
385                         if( pi.op == _OP_LOAD  && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){
386                                 pi.op = _OP_PREPCALLK;
387                                 pi._arg0 = i._arg0;
388                                 pi._arg1 = pi._arg1;
389                                 pi._arg2 = i._arg2;
390                                 pi._arg3 = i._arg3;
391                                 return;
392                         }
393                         break;
394                 case _OP_APPENDARRAY:
395                         if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){
396                                 pi.op = _OP_APPENDARRAY;
397                                 pi._arg0 = i._arg0;
398                                 pi._arg1 = pi._arg1;
399                                 pi._arg2 = MAX_FUNC_STACKSIZE;
400                                 pi._arg3 = MAX_FUNC_STACKSIZE;
401                                 return;
402                         }
403                         break;
404                 case _OP_MOVE: 
405                         if((pi.op == _OP_GET || pi.op == _OP_ARITH || pi.op == _OP_BITW) && (pi._arg0 == i._arg1))
406                         {
407                                 pi._arg0 = i._arg0;
408                                 _optimization = false;
409                                 return;
410                         }
411
412                         if(pi.op == _OP_MOVE)
413                         {
414                                 pi.op = _OP_DMOVE;
415                                 pi._arg2 = i._arg0;
416                                 pi._arg3 = (unsigned char)i._arg1;
417                                 return;
418                         }
419                         break;
420
421                 case _OP_EQ:case _OP_NE:
422                         if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) ))
423                         {
424                                 pi.op = i.op;
425                                 pi._arg0 = i._arg0;
426                                 pi._arg1 = pi._arg1;
427                                 pi._arg2 = i._arg2;
428                                 pi._arg3 = MAX_FUNC_STACKSIZE;
429                                 return;
430                         }
431                         break;
432                 case _OP_LOADNULLS:
433                 //case _OP_LOADNULL:
434                         if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) {
435                                 
436                                 pi._arg1 = pi._arg1 + 1;
437                                 pi.op = _OP_LOADNULLS;
438                                 return;
439                         }
440             break;
441                 case _OP_LINE:
442                         if(pi.op == _OP_LINE) {
443                                 _instructions.pop_back();
444                                 _lineinfos.pop_back();
445                         }
446                         break;
447                 }
448         }
449         _optimization = true;
450         _instructions.push_back(i);
451 }
452
453 SQObject SQFuncState::CreateString(const SQChar *s)
454 {
455         SQObjectPtr ns(SQString::Create(_sharedstate,s));
456         _stringrefs.push_back(ns);
457         return ns;
458 }
459
460 void SQFuncState::Finalize()
461 {
462         SQFunctionProto *f=_funcproto(_func);
463         f->_literals.resize(_nliterals);
464         SQObjectPtr refidx,key,val;
465         SQInteger idx;
466         while((idx=_table(_literals)->Next(refidx,key,val))!=-1) {
467                 f->_literals[_integer(val)]=key;
468                 refidx=idx;
469         }
470         f->_functions.resize(_functions.size());
471         f->_functions.copy(_functions);
472         f->_parameters.resize(_parameters.size());
473         f->_parameters.copy(_parameters);
474         f->_outervalues.resize(_outervalues.size());
475         f->_outervalues.copy(_outervalues);
476         f->_instructions.resize(_instructions.size());
477         f->_instructions.copy(_instructions);
478         f->_localvarinfos.resize(_localvarinfos.size());
479         f->_localvarinfos.copy(_localvarinfos);
480         f->_lineinfos.resize(_lineinfos.size());
481         f->_lineinfos.copy(_lineinfos);
482         f->_varparams = _varparams;
483 }