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