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