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