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