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