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
DumpLiteral(SQObjectPtr & o)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
SQFuncState(SQSharedState * ss,SQFuncState * parent,CompilerErrorFunc efunc,void * ed)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
Error(const SQChar * err)118 void SQFuncState::Error(const SQChar *err)
119 {
120 _errfunc(_errtarget,err);
121 }
122
123 #ifdef _DEBUG_DUMP
Dump(SQFunctionProto * func)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
GetNumericConstant(const SQInteger cons)222 SQInteger SQFuncState::GetNumericConstant(const SQInteger cons)
223 {
224 return GetConstant(SQObjectPtr(cons));
225 }
226
GetNumericConstant(const SQFloat cons)227 SQInteger SQFuncState::GetNumericConstant(const SQFloat cons)
228 {
229 return GetConstant(SQObjectPtr(cons));
230 }
231
GetConstant(const SQObject & cons)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
SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)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
SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val)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
AllocStackPos()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
PushTarget(SQInteger n)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
GetUpTarget(SQInteger n)288 SQInteger SQFuncState::GetUpTarget(SQInteger n){
289 return _targetstack[((_targetstack.size()-1)-n)];
290 }
291
TopTarget()292 SQInteger SQFuncState::TopTarget(){
293 return _targetstack.back();
294 }
PopTarget()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
GetStackSize()306 SQInteger SQFuncState::GetStackSize()
307 {
308 return _vlocals.size();
309 }
310
SetStackSize(SQInteger n)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
IsConstant(const SQObject & name,SQObject & e)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
IsLocal(SQUnsignedInteger stkpos)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
PushLocalVariable(const SQObject & name)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
GetLocalVariable(const SQObject & name)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
GetOuterVariable(const SQObject & name)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
AddOuterValue(const SQObject & name)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
AddParameter(const SQObject & name)397 void SQFuncState::AddParameter(const SQObject &name)
398 {
399 PushLocalVariable(name);
400 _parameters.push_back(name);
401 }
402
AddLineInfos(SQInteger line,bool lineop,bool force)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
AddInstruction(SQInstruction & i)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
CreateString(const SQChar * s,SQInteger len)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
CreateTable()517 SQObject SQFuncState::CreateTable()
518 {
519 SQObjectPtr nt(SQTable::Create(_sharedstate,0));
520 _table(_strings)->NewSlot(nt,(SQInteger)1);
521 return nt;
522 }
523
BuildProto()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
PushChildState(SQSharedState * ss)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
PopChildState()565 void SQFuncState::PopChildState()
566 {
567 SQFuncState *child = _childstates.back();
568 sq_delete(child,SQFuncState);
569 _childstates.pop_back();
570 }
571
~SQFuncState()572 SQFuncState::~SQFuncState()
573 {
574 while(_childstates.size() > 0)
575 {
576 PopChildState();
577 }
578 }
579