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