1 /*
2  see copyright notice in squirrel.h
3 */
4 #include "sqpcheader.h"
5 #include <math.h>
6 #include <stdlib.h>
7 #include "sqopcodes.h"
8 #include "sqfuncproto.h"
9 #include "sqvm.h"
10 #include "sqclosure.h"
11 #include "sqstring.h"
12 #include "sqtable.h"
13 #include "squserdata.h"
14 #include "sqarray.h"
15 #include "sqclass.h"
16 
17 #define TOP() (_stack[_top-1])
18 
BW_OP(SQUnsignedInteger op,SQObjectPtr & trg,const SQObjectPtr & o1,const SQObjectPtr & o2)19 bool SQVM::BW_OP( SQUnsignedInteger op, SQObjectPtr &trg, const SQObjectPtr &o1, const SQObjectPtr &o2 ) {
20 	SQInteger res;
21 	SQInteger i1 = _integer( o1 ), i2 = _integer( o2 );
22 	if ( ( squirrel_type( o1 ) == OT_INTEGER ) && ( squirrel_type( o2 ) == OT_INTEGER ) ) {
23 		switch ( op ) {
24 		case BW_AND: res = i1 & i2; break;
25 		case BW_OR:  res = i1 | i2; break;
26 		case BW_XOR: res = i1 ^ i2; break;
27 		case BW_SHIFTL: res = i1 << i2; break;
28 		case BW_SHIFTR: res = i1 >> i2; break;
29 		case BW_USHIFTR: res = ( SQInteger )( *( ( SQUnsignedInteger* ) & i1 ) >> i2 ); break;
30 		default: {
31 				Raise_Error( _SC( "internal vm error bitwise op failed" ) ); return false;
32 			}
33 		}
34 	} else {
35 		Raise_Error( _SC( "bitwise op between '%s' and '%s'" ), GetTypeName( o1 ), GetTypeName( o2 ) ); return false;
36 	}
37 	trg = res;
38 	return true;
39 }
40 
ARITH_OP(SQUnsignedInteger op,SQObjectPtr & trg,const SQObjectPtr & o1,const SQObjectPtr & o2)41 bool SQVM::ARITH_OP( SQUnsignedInteger op, SQObjectPtr &trg, const SQObjectPtr &o1, const SQObjectPtr &o2 ) {
42 	if ( sq_isnumeric( o1 ) && sq_isnumeric( o2 ) ) {
43 		if ( ( squirrel_type( o1 ) == OT_INTEGER ) && ( squirrel_type( o2 ) == OT_INTEGER ) ) {
44 			switch ( op ) {
45 			case '+': trg = _integer( o1 ) + _integer( o2 ); break;
46 			case '-': trg = _integer( o1 ) - _integer( o2 ); break;
47 			case '/': if ( _integer( o2 ) == 0 ) {
48 					Raise_Error( _SC( "division by zero" ) ); return false;
49 				}
50 				trg = _integer( o1 ) / _integer( o2 );
51 				break;
52 			case '*': trg = _integer( o1 ) * _integer( o2 ); break;
53 			case '%': trg = _integer( o1 ) % _integer( o2 ); break;
54 			}
55 		} else {
56 			switch ( op ) {
57 			case '+': trg = tofloat( o1 ) + tofloat( o2 ); break;
58 			case '-': trg = tofloat( o1 ) - tofloat( o2 ); break;
59 			case '/': trg = tofloat( o1 ) / tofloat( o2 ); break;
60 			case '*': trg = tofloat( o1 ) * tofloat( o2 ); break;
61 			case '%': trg = SQFloat( fmod( static_cast<double>( tofloat( o1 ) ), static_cast<double>( tofloat( o2 ) ) ) ); break;
62 			}
63 		}
64 	} else {
65 		if ( op == '+' && ( squirrel_type( o1 ) == OT_STRING || squirrel_type( o2 ) == OT_STRING ) ) {
66 			if ( !StringCat( o1, o2, trg ) ) return false;
67 		} else if ( !ArithMetaMethod( op, o1, o2, trg ) ) {
68 			Raise_Error( _SC( "arith op %c on between '%s' and '%s'" ), op, GetTypeName( o1 ), GetTypeName( o2 ) ); return false;
69 		}
70 	}
71 	return true;
72 }
73 
SQVM(SQSharedState * ss)74 SQVM::SQVM( SQSharedState *ss ) {
75 	_sharedstate = ss;
76 	_suspended = SQFalse;
77 	_suspended_target = -1;
78 	_suspended_root = SQFalse;
79 	_suspended_traps = -1;
80 	_foreignptr = NULL;
81 	_nnativecalls = 0;
82 	_lasterror = _null_;
83 	_errorhandler = _null_;
84 	_debughook = _null_;
85 	INIT_CHAIN();ADD_TO_CHAIN( &_ss( this )->_gc_chain, this );
86 }
87 
Finalize()88 void SQVM::Finalize() {
89 	_roottable = _null_;
90 	_lasterror = _null_;
91 	_errorhandler = _null_;
92 	_debughook = _null_;
93 	temp_reg = _null_;
94 	SQInteger size = _stack.size();
95 	for ( SQInteger i = 0;i < size;i++ )
96 		_stack[i] = _null_;
97 }
98 
~SQVM()99 SQVM::~SQVM() {
100 	Finalize();
101 	REMOVE_FROM_CHAIN( &_ss( this )->_gc_chain, this );
102 }
103 
ArithMetaMethod(SQInteger op,const SQObjectPtr & o1,const SQObjectPtr & o2,SQObjectPtr & dest)104 bool SQVM::ArithMetaMethod( SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest ) {
105 	SQMetaMethod mm;
106 	switch ( op ) {
107 	case _SC( '+' ): mm = MT_ADD; break;
108 	case _SC( '-' ): mm = MT_SUB; break;
109 	case _SC( '/' ): mm = MT_DIV; break;
110 	case _SC( '*' ): mm = MT_MUL; break;
111 	case _SC( '%' ): mm = MT_MODULO; break;
112 	}
113 	if ( is_delegable( o1 ) && _delegable( o1 )->_delegate ) {
114 		Push( o1 );Push( o2 );
115 		return CallMetaMethod( _delegable( o1 ), mm, 2, dest );
116 	}
117 	return false;
118 }
119 
NEG_OP(SQObjectPtr & trg,const SQObjectPtr & o)120 bool SQVM::NEG_OP( SQObjectPtr &trg, const SQObjectPtr &o ) {
121 
122 	switch ( squirrel_type( o ) ) {
123 	case OT_INTEGER:
124 		trg = -_integer( o );
125 		return true;
126 	case OT_FLOAT:
127 		trg = -_float( o );
128 		return true;
129 	case OT_TABLE:
130 	case OT_USERDATA:
131 	case OT_INSTANCE:
132 		if ( _delegable( o )->_delegate ) {
133 			Push( o );
134 			if ( CallMetaMethod( _delegable( o ), MT_UNM, 1, temp_reg ) ) {
135 				trg = temp_reg;
136 				return true;
137 			}
138 		}
139 		return true;
140 
141 	}
142 	Raise_Error( _SC( "attempt to negate a %s" ), GetTypeName( o ) );
143 	return false;
144 }
145 
146 #define _RET_SUCCEED(exp) { result = (exp); return true; }
ObjCmp(const SQObjectPtr & o1,const SQObjectPtr & o2,SQInteger & result)147 bool SQVM::ObjCmp( const SQObjectPtr &o1, const SQObjectPtr &o2, SQInteger &result ) {
148 	if ( squirrel_type( o1 ) == squirrel_type( o2 ) ) {
149 		if ( _userpointer( o1 ) == _userpointer( o2 ) )_RET_SUCCEED( 0 );
150 		SQObjectPtr res;
151 		switch ( squirrel_type( o1 ) ) {
152 		case OT_STRING:
153 			_RET_SUCCEED( scstrcmp( _stringval( o1 ), _stringval( o2 ) ) );
154 		case OT_INTEGER:
155 			_RET_SUCCEED( _integer( o1 ) - _integer( o2 ) );
156 		case OT_FLOAT:
157 			_RET_SUCCEED( ( _float( o1 ) < _float( o2 ) ) ? -1 : 1 );
158 		case OT_TABLE:
159 		case OT_USERDATA:
160 		case OT_INSTANCE:
161 			Push( o1 );Push( o2 );
162 			if ( _delegable( o1 )->_delegate )CallMetaMethod( _delegable( o1 ), MT_CMP, 2, res );
163 			break;
164 		}
165 		if ( squirrel_type( res ) != OT_INTEGER ) {
166 			Raise_CompareError( o1, o2 ); return false;
167 		}
168 		_RET_SUCCEED( _integer( res ) );
169 	} else {
170 		if ( sq_isnumeric( o1 ) && sq_isnumeric( o2 ) ) {
171 			if ( ( squirrel_type( o1 ) == OT_INTEGER ) && ( squirrel_type( o2 ) == OT_FLOAT ) ) {
172 				if ( _integer( o1 ) == _float( o2 ) ) {
173 					_RET_SUCCEED( 0 );
174 				} else if ( _integer( o1 ) < _float( o2 ) ) {
175 					_RET_SUCCEED( -1 );
176 				}
177 				_RET_SUCCEED( 1 );
178 			} else {
179 				if ( _float( o1 ) == _integer( o2 ) ) {
180 					_RET_SUCCEED( 0 );
181 				} else if ( _float( o1 ) < _integer( o2 ) ) {
182 					_RET_SUCCEED( -1 );
183 				}
184 				_RET_SUCCEED( 1 );
185 			}
186 		} else if ( squirrel_type( o1 ) == OT_NULL ) {
187 			_RET_SUCCEED( -1 );
188 		} else if ( squirrel_type( o2 ) == OT_NULL ) {
189 			_RET_SUCCEED( 1 );
190 		} else {
191 			Raise_CompareError( o1, o2 ); return false;
192 		}
193 
194 	}
195 	assert( 0 );
196 	_RET_SUCCEED( 0 ); //cannot happen
197 }
198 
CMP_OP(CmpOP op,const SQObjectPtr & o1,const SQObjectPtr & o2,SQObjectPtr & res)199 bool SQVM::CMP_OP( CmpOP op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &res ) {
200 	SQInteger r;
201 	if ( ObjCmp( o1, o2, r ) ) {
202 		switch ( op ) {
203 		case CMP_G: res = ( r > 0 ) ? _true_ : _false_; return true;
204 		case CMP_GE: res = ( r >= 0 ) ? _true_ : _false_; return true;
205 		case CMP_L: res = ( r < 0 ) ? _true_ : _false_; return true;
206 		case CMP_LE: res = ( r <= 0 ) ? _true_ : _false_; return true;
207 
208 		}
209 		assert( 0 );
210 	}
211 	return false;
212 }
213 
ToString(const SQObjectPtr & o,SQObjectPtr & res)214 void SQVM::ToString( const SQObjectPtr &o, SQObjectPtr &res ) {
215 	switch ( squirrel_type( o ) ) {
216 	case OT_STRING:
217 		res = o;
218 		return;
219 	case OT_FLOAT:
220 		scsprintf( _sp( rsl( NUMBER_MAX_CHAR + 1 ) ), _SC( "%g" ), _float( o ) );
221 		break;
222 	case OT_INTEGER:
223 		scsprintf( _sp( rsl( NUMBER_MAX_CHAR + 1 ) ), _SC( "%d" ), _integer( o ) );
224 		break;
225 	case OT_BOOL:
226 		scsprintf( _sp( rsl( 6 ) ), _integer( o ) ? _SC( "true" ) : _SC( "false" ) );
227 		break;
228 	case OT_TABLE:
229 	case OT_USERDATA:
230 	case OT_INSTANCE:
231 		if ( _delegable( o )->_delegate ) {
232 			Push( o );
233 			if ( CallMetaMethod( _delegable( o ), MT_TOSTRING, 1, res ) ) {
234 				if ( squirrel_type( res ) == OT_STRING )
235 					return;
236 				//else keeps going to the default
237 			}
238 		}
239 	default:
240 		scsprintf( _sp( rsl( sizeof( void* ) + 20 ) ), _SC( "(%s : 0x%p)" ), GetTypeName( o ), _rawval( o ) );
241 	}
242 	res = SQString::Create( _ss( this ), _spval );
243 	return;
244 }
245 
246 
StringCat(const SQObjectPtr & str,const SQObjectPtr & obj,SQObjectPtr & dest)247 bool SQVM::StringCat( const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest ) {
248 	switch ( squirrel_type( obj ) ) {
249 	case OT_STRING:
250 		switch ( squirrel_type( str ) ) {
251 		case OT_STRING: {
252 				SQInteger l = _string( str )->_len, ol = _string( obj )->_len;
253 				SQChar *s = _sp( rsl( l + ol + 1 ) );
254 				memcpy( s, _stringval( str ), rsl( l ) );memcpy( s + l, _stringval( obj ), rsl( ol ) );s[l+ol] = _SC( '\0' );
255 				break;
256 			}
257 		case OT_FLOAT:
258 			scsprintf( _sp( rsl( NUMBER_MAX_CHAR + _string( obj )->_len + 1 ) ), _SC( "%g%s" ), _float( str ), _stringval( obj ) );
259 			break;
260 		case OT_INTEGER:
261 			scsprintf( _sp( rsl( NUMBER_MAX_CHAR + _string( obj )->_len + 1 ) ), _SC( "%d%s" ), _integer( str ), _stringval( obj ) );
262 			break;
263 		default:
264 			Raise_Error( _SC( "string concatenation between '%s' and '%s'" ), GetTypeName( str ), GetTypeName( obj ) );
265 			return false;
266 		}
267 		dest = SQString::Create( _ss( this ), _spval );
268 		break;
269 	case OT_FLOAT:
270 		scsprintf( _sp( rsl( NUMBER_MAX_CHAR + _string( str )->_len + 1 ) ), _SC( "%s%g" ), _stringval( str ), _float( obj ) );
271 		dest = SQString::Create( _ss( this ), _spval );
272 		break;
273 	case OT_INTEGER:
274 		scsprintf( _sp( rsl( NUMBER_MAX_CHAR + _string( str )->_len + 1 ) ), _SC( "%s%d" ), _stringval( str ), _integer( obj ) );
275 		dest = SQString::Create( _ss( this ), _spval );
276 		break;
277 	default:
278 		Raise_Error( _SC( "string concatenation between '%s' and '%s'" ), GetTypeName( str ), GetTypeName( obj ) );
279 		return false;
280 	}
281 	return true;
282 }
283 
IdType2Name(SQObjectType type)284 const SQChar *IdType2Name( SQObjectType type ) {
285 	switch ( _RAW_TYPE( type ) ) {
286 	case _RT_NULL: return _SC( "null" );
287 	case _RT_INTEGER: return _SC( "integer" );
288 	case _RT_FLOAT: return _SC( "float" );
289 	case _RT_BOOL: return _SC( "bool" );
290 	case _RT_STRING: return _SC( "string" );
291 	case _RT_TABLE: return _SC( "table" );
292 	case _RT_ARRAY: return _SC( "array" );
293 	case _RT_GENERATOR: return _SC( "generator" );
294 	case _RT_CLOSURE:
295 	case _RT_NATIVECLOSURE:
296 		return _SC( "function" );
297 	case _RT_USERDATA:
298 	case _RT_USERPOINTER:
299 		return _SC( "userdata" );
300 	case _RT_THREAD: return _SC( "thread" );
301 	case _RT_FUNCPROTO: return _SC( "function" );
302 	case _RT_CLASS: return _SC( "class" );
303 	case _RT_INSTANCE: return _SC( "instance" );
304 	case _RT_WEAKREF: return _SC( "weakref" );
305 	default:
306 		return NULL;
307 	}
308 }
309 
GetTypeName(const SQObjectPtr & obj1)310 const SQChar *GetTypeName( const SQObjectPtr &obj1 ) {
311 	return IdType2Name( squirrel_type( obj1 ) );
312 }
313 
TypeOf(const SQObjectPtr & obj1,SQObjectPtr & dest)314 void SQVM::TypeOf( const SQObjectPtr &obj1, SQObjectPtr &dest ) {
315 	if ( is_delegable( obj1 ) && _delegable( obj1 )->_delegate ) {
316 		Push( obj1 );
317 		if ( CallMetaMethod( _delegable( obj1 ), MT_TYPEOF, 1, dest ) )
318 			return;
319 	}
320 	dest = SQString::Create( _ss( this ), GetTypeName( obj1 ) );
321 }
322 
Init(SQVM * friendvm,SQInteger stacksize)323 bool SQVM::Init( SQVM *friendvm, SQInteger stacksize ) {
324 	_stack.resize( stacksize );
325 	_callsstack.reserve( 4 );
326 	_stackbase = 0;
327 	_top = 0;
328 	if ( !friendvm )
329 		_roottable = SQTable::Create( _ss( this ), 0 );
330 	else {
331 		_roottable = friendvm->_roottable;
332 		_errorhandler = friendvm->_errorhandler;
333 		_debughook = friendvm->_debughook;
334 	}
335 
336 	sq_base_register( this );
337 	return true;
338 }
339 
340 extern SQInstructionDesc g_InstrDesc[];
341 
StartCall(SQClosure * closure,SQInteger target,SQInteger nargs,SQInteger stackbase,bool tailcall)342 bool SQVM::StartCall( SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall ) {
343 	SQFunctionProto *func = _funcproto( closure->_function );
344 	//const SQInteger outerssize = func->_outervalues.size();
345 
346 	const SQInteger paramssize = func->_parameters.size();
347 	const SQInteger oldtop = _top;
348 	const SQInteger newtop = stackbase + func->_stacksize;
349 
350 
351 	if ( paramssize != nargs ) {
352 		if ( func->_varparams ) {
353 			if ( nargs < paramssize ) {
354 				Raise_Error( _SC( "wrong number of parameters" ) );
355 				return false;
356 			}
357 			for ( SQInteger n = 0; n < nargs - paramssize; n++ ) {
358 				_vargsstack.push_back( _stack[stackbase+paramssize+n] );
359 				_stack[stackbase+paramssize+n] = _null_;
360 			}
361 		} else {
362 			Raise_Error( _SC( "wrong number of parameters" ) );
363 			return false;
364 		}
365 	}
366 
367 	if ( !tailcall ) {
368 		PUSH_CALLINFO( this, CallInfo() );
369 		ci->_etraps = 0;
370 		ci->_prevstkbase = stackbase - _stackbase;
371 		ci->_target = target;
372 		ci->_prevtop = _top - _stackbase;
373 		ci->_ncalls = 1;
374 		ci->_root = SQFalse;
375 	} else {
376 		ci->_ncalls++;
377 	}
378 	ci->_vargs.size = ( nargs - paramssize );
379 	ci->_vargs.base = _vargsstack.size() - ( nargs - paramssize );
380 	ci->_closure._unVal.pClosure = closure;
381 	ci->_closure._type = OT_CLOSURE;
382 	ci->_iv = &func->_instructions;
383 	ci->_literals = &func->_literals;
384 	//grows the stack if needed
385 	if ( ( ( SQUnsignedInteger )newtop + ( func->_stacksize << 1 ) ) > _stack.size() ) {
386 		_stack.resize( _stack.size() + ( func->_stacksize << 1 ) );
387 	}
388 
389 	_top = newtop;
390 	_stackbase = stackbase;
391 	ci->_ip = ci->_iv->_vals;
392 	return true;
393 }
394 
Return(SQInteger _arg0,SQInteger _arg1,SQObjectPtr & retval)395 bool SQVM::Return( SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval ) {
396 	if ( squirrel_type( _debughook ) != OT_NULL && _rawval( _debughook ) != _rawval( ci->_closure ) )
397 		for ( SQInteger i = 0;i < ci->_ncalls;i++ )
398 			CallDebugHook( _SC( 'r' ) );
399 
400 	SQBool broot = ci->_root;
401 	SQInteger last_top = _top;
402 	SQInteger target = ci->_target;
403 	SQInteger oldstackbase = _stackbase;
404 	_stackbase -= ci->_prevstkbase;
405 	_top = _stackbase + ci->_prevtop;
406 	if ( ci->_vargs.size ) PopVarArgs( ci->_vargs );
407 	POP_CALLINFO( this );
408 	if ( broot ) {
409 		if ( _arg0 != MAX_FUNC_STACKSIZE ) retval = _stack[oldstackbase+_arg1];
410 		else retval = _null_;
411 	} else {
412 		if ( _arg0 != MAX_FUNC_STACKSIZE )
413 			STK( target ) = _stack[oldstackbase+_arg1];
414 		else
415 			STK( target ) = _null_;
416 	}
417 
418 	while ( last_top >= _top ) _stack[last_top--].Null();
419 	assert( oldstackbase >= _stackbase );
420 	return broot ? true : false;
421 }
422 
423 #define _RET_ON_FAIL(exp) { if(!exp) return false; }
424 
LOCAL_INC(SQInteger op,SQObjectPtr & target,SQObjectPtr & a,SQObjectPtr & incr)425 bool SQVM::LOCAL_INC( SQInteger op, SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr ) {
426 	_RET_ON_FAIL( ARITH_OP( op , target, a, incr ) );
427 	a = target;
428 	return true;
429 }
430 
PLOCAL_INC(SQInteger op,SQObjectPtr & target,SQObjectPtr & a,SQObjectPtr & incr)431 bool SQVM::PLOCAL_INC( SQInteger op, SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr ) {
432 	SQObjectPtr trg;
433 	_RET_ON_FAIL( ARITH_OP( op , trg, a, incr ) );
434 	target = a;
435 	a = trg;
436 	return true;
437 }
438 
DerefInc(SQInteger op,SQObjectPtr & target,SQObjectPtr & self,SQObjectPtr & key,SQObjectPtr & incr,bool postfix)439 bool SQVM::DerefInc( SQInteger op, SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix ) {
440 	SQObjectPtr tmp, tself = self, tkey = key;
441 	if ( !Get( tself, tkey, tmp, false, true ) ) {
442 		Raise_IdxError( tkey ); return false;
443 	}
444 	_RET_ON_FAIL( ARITH_OP( op , target, tmp, incr ) )
445 	Set( tself, tkey, target, true );
446 	if ( postfix ) target = tmp;
447 	return true;
448 }
449 
450 #define arg0 (_i_._arg0)
451 #define arg1 (_i_._arg1)
452 #define sarg1 (*((SQInteger *)&_i_._arg1))
453 #define arg2 (_i_._arg2)
454 #define arg3 (_i_._arg3)
455 #define sarg3 (*((char *)&_i_._arg3))
456 
Suspend()457 SQRESULT SQVM::Suspend() {
458 	if ( _suspended )
459 		return sq_throwerror( this, _SC( "cannot suspend an already suspended vm" ) );
460 	if ( _nnativecalls != 2 )
461 		return sq_throwerror( this, _SC( "cannot suspend through native calls/metamethods" ) );
462 	return SQ_SUSPEND_FLAG;
463 }
464 
PopVarArgs(VarArgs & vargs)465 void SQVM::PopVarArgs( VarArgs &vargs ) {
466 	for ( SQInteger n = 0; n < vargs.size; n++ )
467 		_vargsstack.pop_back();
468 }
469 
470 #define _FINISH(stoploop) {finished = stoploop; return true; }
FOREACH_OP(SQObjectPtr & o1,SQObjectPtr & o2,SQObjectPtr & o3,SQObjectPtr & o4,SQInteger arg_2,bool & finished)471 bool SQVM::FOREACH_OP( SQObjectPtr &o1, SQObjectPtr &o2, SQObjectPtr
472                        &o3, SQObjectPtr &o4, SQInteger arg_2, bool &finished ) {
473 	SQInteger nrefidx;
474 	switch ( squirrel_type( o1 ) ) {
475 	case OT_TABLE:
476 		if ( ( nrefidx = _table( o1 )->Next( false, o4, o2, o3 ) ) == -1 ) _FINISH( true );
477 		o4 = ( SQInteger )nrefidx; _FINISH( false );
478 	case OT_ARRAY:
479 		if ( ( nrefidx = _array( o1 )->Next( o4, o2, o3 ) ) == -1 ) _FINISH( true );
480 		o4 = ( SQInteger ) nrefidx; _FINISH( false );
481 	case OT_STRING:
482 		if ( ( nrefidx = _string( o1 )->Next( o4, o2, o3 ) ) == -1 )_FINISH( true );
483 		o4 = ( SQInteger )nrefidx; _FINISH( false );
484 	case OT_CLASS:
485 		if ( ( nrefidx = _class( o1 )->Next( o4, o2, o3 ) ) == -1 )_FINISH( true );
486 		o4 = ( SQInteger )nrefidx; _FINISH( false );
487 	case OT_USERDATA:
488 	case OT_INSTANCE:
489 		if ( _delegable( o1 )->_delegate ) {
490 			SQObjectPtr itr;
491 			Push( o1 );
492 			Push( o4 );
493 			if ( CallMetaMethod( _delegable( o1 ), MT_NEXTI, 2, itr ) ) {
494 				o4 = o2 = itr;
495 				if ( squirrel_type( itr ) == OT_NULL ) _FINISH( true );
496 				if ( !Get( o1, itr, o3, false, false ) ) {
497 					Raise_Error( _SC( "_nexti returned an invalid idx" ) );
498 					return false;
499 				}
500 				_FINISH( false );
501 			}
502 			Raise_Error( _SC( "_nexti failed" ) );
503 			return false;
504 		}
505 		break;
506 	case OT_GENERATOR:
507 		if ( _generator( o1 )->_state == SQGenerator::eDead ) _FINISH( true );
508 		if ( _generator( o1 )->_state == SQGenerator::eSuspended ) {
509 			SQInteger idx = 0;
510 			if ( squirrel_type( o4 ) == OT_INTEGER ) {
511 				idx = _integer( o4 ) + 1;
512 			}
513 			o2 = idx;
514 			o4 = idx;
515 			_generator( o1 )->Resume( this, arg_2 + 1 );
516 			_FINISH( false );
517 		}
518 	}
519 	Raise_Error( _SC( "cannot iterate %s" ), GetTypeName( o1 ) );
520 	return false; //cannot be hit(just to avoid warnings)
521 }
522 
DELEGATE_OP(SQObjectPtr & trg,SQObjectPtr & o1,SQObjectPtr & o2)523 bool SQVM::DELEGATE_OP( SQObjectPtr &trg, SQObjectPtr &o1, SQObjectPtr &o2 ) {
524 	if ( squirrel_type( o1 ) != OT_TABLE ) {
525 		Raise_Error( _SC( "delegating a '%s'" ), GetTypeName( o1 ) ); return false;
526 	}
527 	switch ( squirrel_type( o2 ) ) {
528 	case OT_TABLE:
529 		if ( !_table( o1 )->SetDelegate( _table( o2 ) ) ) {
530 			Raise_Error( _SC( "delegate cycle detected" ) );
531 			return false;
532 		}
533 		break;
534 	case OT_NULL:
535 		_table( o1 )->SetDelegate( NULL );
536 		break;
537 	default:
538 		Raise_Error( _SC( "using '%s' as delegate" ), GetTypeName( o2 ) );
539 		return false;
540 		break;
541 	}
542 	trg = o1;
543 	return true;
544 }
545 #define COND_LITERAL (arg3!=0?(*ci->_literals)[arg1]:STK(arg1))
546 
547 #define _GUARD(exp) { if(!exp) { Raise_Error(_lasterror); SQ_THROW();} }
548 
549 #define SQ_THROW() { goto exception_trap; }
550 
CLOSURE_OP(SQObjectPtr & target,SQFunctionProto * func)551 bool SQVM::CLOSURE_OP( SQObjectPtr &target, SQFunctionProto *func ) {
552 	SQInteger nouters;
553 	SQClosure *closure = SQClosure::Create( _ss( this ), func );
554 	if ( nouters = func->_outervalues.size() ) {
555 		closure->_outervalues.reserve( nouters );
556 		for ( SQInteger i = 0; i < nouters; i++ ) {
557 			SQOuterVar &v = func->_outervalues[i];
558 			switch ( v._type ) {
559 			case otSYMBOL:
560 				closure->_outervalues.push_back( _null_ );
561 				if ( !Get( _stack._vals[_stackbase]/*STK(0)*/, v._src, closure->_outervalues.top(), false, true ) ) {
562 					Raise_IdxError( v._src ); return false;
563 				}
564 				break;
565 			case otLOCAL:
566 				closure->_outervalues.push_back( _stack._vals[_stackbase+_integer( v._src )] );
567 				break;
568 			case otOUTER:
569 				closure->_outervalues.push_back( _closure( ci->_closure )->_outervalues[_integer( v._src )] );
570 				break;
571 			}
572 		}
573 	}
574 	target = closure;
575 	return true;
576 
577 }
578 
GETVARGV_OP(SQObjectPtr & target,SQObjectPtr & index,CallInfo * ci)579 bool SQVM::GETVARGV_OP( SQObjectPtr &target, SQObjectPtr &index, CallInfo *ci ) {
580 	if ( ci->_vargs.size == 0 ) {
581 		Raise_Error( _SC( "the function doesn't have var args" ) );
582 		return false;
583 	}
584 	if ( !sq_isnumeric( index ) ) {
585 		Raise_Error( _SC( "indexing 'vargv' with %s" ), GetTypeName( index ) );
586 		return false;
587 	}
588 	SQInteger idx = tointeger( index );
589 	if ( idx < 0 || idx >= ci->_vargs.size ) {
590 		Raise_Error( _SC( "vargv index out of range" ) ); return false;
591 	}
592 	target = _vargsstack[ci->_vargs.base+idx];
593 	return true;
594 }
595 
CLASS_OP(SQObjectPtr & target,SQInteger baseclass,SQInteger attributes)596 bool SQVM::CLASS_OP( SQObjectPtr &target, SQInteger baseclass, SQInteger attributes ) {
597 	SQClass *base = NULL;
598 	SQObjectPtr attrs;
599 	if ( baseclass != MAX_LITERALS ) {
600 		if ( squirrel_type( _stack._vals[_stackbase+baseclass] ) != OT_CLASS ) {
601 			Raise_Error( _SC( "trying to inherit from a %s" ), GetTypeName( _stack._vals[_stackbase+baseclass] ) ); return false;
602 		}
603 		base = _class( _stack._vals[_stackbase + baseclass] );
604 	}
605 	if ( attributes != MAX_FUNC_STACKSIZE ) {
606 		attrs = _stack._vals[_stackbase+attributes];
607 	}
608 	target = SQClass::Create( _ss( this ), base );
609 	_class( target )->_attributes = attrs;
610 	return true;
611 }
612 
613 
614 
IsEqual(SQObjectPtr & o1,SQObjectPtr & o2,bool & res)615 bool SQVM::IsEqual( SQObjectPtr &o1, SQObjectPtr &o2, bool &res ) {
616 	if ( squirrel_type( o1 ) == squirrel_type( o2 ) ) {
617 		res = ( ( _userpointer( o1 ) == _userpointer( o2 ) ? true : false ) );
618 	} else {
619 		if ( sq_isnumeric( o1 ) && sq_isnumeric( o2 ) ) {
620 			SQInteger cmpres;
621 			if ( !ObjCmp( o1, o2, cmpres ) ) return false;
622 			res = ( cmpres == 0 );
623 		} else {
624 			res = false;
625 		}
626 	}
627 	return true;
628 }
629 
Execute(SQObjectPtr & closure,SQInteger target,SQInteger nargs,SQInteger stackbase,SQObjectPtr & outres,ExecutionType et)630 bool SQVM::Execute( SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, ExecutionType et ) {
631 	if ( ( _nnativecalls + 1 ) > MAX_NATIVE_CALLS ) {
632 		Raise_Error( _SC( "Native stack overflow" ) ); return false;
633 	}
634 	_nnativecalls++;
635 	AutoDec ad( &_nnativecalls );
636 	SQInteger traps = 0;
637 	//temp_reg vars for OP_CALL
638 	SQInteger ct_target;
639 	bool ct_tailcall;
640 
641 	switch ( et ) {
642 	case ET_CALL:
643 		if ( !StartCall( _closure( closure ), _top - nargs, nargs, stackbase, false ) ) {
644 			//call the handler if there are no calls in the stack, if not relies on the previous node
645 			if ( ci == NULL ) CallErrorHandler( _lasterror );
646 			return false;
647 		}
648 		ci->_root = SQTrue;
649 		break;
650 	case ET_RESUME_GENERATOR: _generator( closure )->Resume( this, target ); ci->_root = SQTrue; traps += ci->_etraps; break;
651 	case ET_RESUME_VM:
652 		traps = _suspended_traps;
653 		ci->_root = _suspended_root;
654 		_suspended = SQFalse;
655 		break;
656 	}
657 
658 exception_restore:
659 	//
660 	{
661 		for ( ;; ) {
662 			const SQInstruction &_i_ = *ci->_ip++;
663 			//dumpstack(_stackbase);
664 			//scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-ci->_iv->_vals,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);
665 			switch ( _i_.op ) {
666 			case _OP_LINE:
667 				if ( squirrel_type( _debughook ) != OT_NULL && _rawval( _debughook ) != _rawval( ci->_closure ) )
668 					CallDebugHook( _SC( 'l' ), arg1 );
669 				continue;
670 			case _OP_LOAD: TARGET = ( *ci->_literals )[arg1]; continue;
671 			case _OP_DLOAD: TARGET = ( *ci->_literals )[arg1]; STK( arg2 ) = ( *ci->_literals )[arg3];continue;
672 			case _OP_TAILCALL:
673 				temp_reg = STK( arg1 );
674 				if ( squirrel_type( temp_reg ) == OT_CLOSURE ) {
675 					ct_tailcall = true;
676 					if ( ci->_vargs.size ) PopVarArgs( ci->_vargs );
677 					for ( SQInteger i = 0; i < arg3; i++ ) STK( i ) = STK( arg2 + i );
678 					ct_target = ci->_target;
679 					goto common_call;
680 				}
681 			case _OP_CALL: {
682 					ct_tailcall = false;
683 					ct_target = arg0;
684 					temp_reg = STK( arg1 );
685 common_call:
686 					SQInteger last_top = _top;
687 					switch ( squirrel_type( temp_reg ) ) {
688 					case OT_CLOSURE: {
689 							_GUARD( StartCall( _closure( temp_reg ), ct_target, arg3, ct_tailcall ? _stackbase : _stackbase + arg2, ct_tailcall ) );
690 							if ( _funcproto( _closure( temp_reg )->_function )->_bgenerator ) {
691 								SQGenerator *gen = SQGenerator::Create( _ss( this ), _closure( temp_reg ) );
692 								_GUARD( gen->Yield( this ) );
693 								Return( 1, ct_target, temp_reg );
694 								STK( ct_target ) = gen;
695 								while ( last_top >= _top ) _stack[last_top--].Null();
696 								continue;
697 							}
698 							if ( squirrel_type( _debughook ) != OT_NULL && _rawval( _debughook ) != _rawval( ci->_closure ) )
699 								CallDebugHook( _SC( 'c' ) );
700 						}
701 						break;
702 					case OT_NATIVECLOSURE: {
703 							bool suspend;
704 							_GUARD( CallNative( _nativeclosure( temp_reg ), arg3, _stackbase + arg2, ct_tailcall, temp_reg, suspend ) );
705 							if ( suspend ) {
706 								_suspended = SQTrue;
707 								_suspended_target = ct_target;
708 								_suspended_root = ci->_root;
709 								_suspended_traps = traps;
710 								outres = temp_reg;
711 								return true;
712 							}
713 							STK( ct_target ) = temp_reg;
714 						}
715 						break;
716 					case OT_CLASS: {
717 							_GUARD( CreateClassInstance( _class( temp_reg ), arg3, _stackbase + arg2, STK( ct_target ) ) );
718 						}
719 						break;
720 					case OT_TABLE:
721 					case OT_USERDATA:
722 					case OT_INSTANCE: {
723 							Push( temp_reg );
724 							for ( SQInteger i = 0; i < arg3; i++ ) Push( STK( arg2 + i ) );
725 							if ( _delegable( temp_reg ) && CallMetaMethod( _delegable( temp_reg ), MT_CALL, arg3 + 1, temp_reg ) ) {
726 								STK( ct_target ) = temp_reg;
727 								break;
728 							}
729 							Raise_Error( _SC( "attempt to call '%s'" ), GetTypeName( temp_reg ) );
730 							SQ_THROW();
731 						}
732 					default:
733 						Raise_Error( _SC( "attempt to call '%s'" ), GetTypeName( temp_reg ) );
734 						SQ_THROW();
735 					}
736 				}
737 				continue;
738 			case _OP_PREPCALL:
739 				if ( !Get( STK( arg2 ), STK( arg1 ), temp_reg, false, true ) ) {
740 					Raise_IdxError( STK( arg1 ) ); SQ_THROW();
741 				}
742 				goto common_prepcall;
743 			case _OP_PREPCALLK:
744 				if ( !Get( STK( arg2 ), ( *ci->_literals )[arg1], temp_reg, false, true ) ) {
745 					if ( squirrel_type( STK( arg2 ) ) == OT_CLASS ) { //hack?
746 						if ( _class_ddel->Get( ( *ci->_literals )[arg1], temp_reg ) ) {
747 							STK( arg3 ) = STK( arg2 );
748 							TARGET = temp_reg;
749 							continue;
750 						}
751 					}
752 					{
753 						Raise_IdxError( ( *ci->_literals )[arg1] ); SQ_THROW();
754 					}
755 				}
756 common_prepcall:
757 				if ( squirrel_type( STK( arg2 ) ) == OT_CLASS ) {
758 					STK( arg3 ) = STK( 0 ); // this
759 				} else {
760 					STK( arg3 ) = STK( arg2 );
761 				}
762 				TARGET = temp_reg;
763 				continue;
764 			case _OP_GETK:
765 				if ( !Get( STK( arg2 ), ( *ci->_literals )[arg1], temp_reg, false, true ) ) {
766 					Raise_IdxError( ( *ci->_literals )[arg1] ); SQ_THROW();
767 				}
768 				TARGET = temp_reg;
769 				continue;
770 			case _OP_MOVE: TARGET = STK( arg1 ); continue;
771 			case _OP_NEWSLOT:
772 				_GUARD( NewSlot( STK( arg1 ), STK( arg2 ), STK( arg3 ) ) );
773 				if ( arg0 != arg3 ) TARGET = STK( arg3 );
774 				continue;
775 			case _OP_DELETE: _GUARD( DeleteSlot( STK( arg1 ), STK( arg2 ), TARGET ) ); continue;
776 			case _OP_SET:
777 				if ( !Set( STK( arg1 ), STK( arg2 ), STK( arg3 ), true ) ) {
778 					Raise_IdxError( STK( arg2 ) ); SQ_THROW();
779 				}
780 				if ( arg0 != arg3 ) TARGET = STK( arg3 );
781 				continue;
782 			case _OP_GET:
783 				if ( !Get( STK( arg1 ), STK( arg2 ), temp_reg, false, true ) ) {
784 					Raise_IdxError( STK( arg2 ) ); SQ_THROW();
785 				}
786 				TARGET = temp_reg;
787 				continue;
788 			case _OP_EQ: {
789 					bool res;
790 					if ( !IsEqual( STK( arg2 ), COND_LITERAL, res ) ) {
791 						SQ_THROW();
792 					}
793 					TARGET = res ? _true_ : _false_;
794 				}
795 				continue;
796 			case _OP_NE: {
797 					bool res;
798 					if ( !IsEqual( STK( arg2 ), COND_LITERAL, res ) ) {
799 						SQ_THROW();
800 					}
801 					TARGET = ( !res ) ? _true_ : _false_;
802 				}
803 				continue;
804 			case _OP_ARITH: _GUARD( ARITH_OP( arg3 , temp_reg, STK( arg2 ), STK( arg1 ) ) ); TARGET = temp_reg; continue;
805 			case _OP_BITW: _GUARD( BW_OP( arg3, TARGET, STK( arg2 ), STK( arg1 ) ) ); continue;
806 			case _OP_RETURN:
807 				if ( squirrel_type( ( ci )->_generator ) == OT_GENERATOR ) {
808 					_generator( ( ci )->_generator )->Kill();
809 				}
810 				if ( Return( arg0, arg1, temp_reg ) ) {
811 					assert( traps == 0 );
812 					outres = temp_reg;
813 					return true;
814 				}
815 				continue;
816 			case _OP_LOADNULLS: {
817 					for ( SQInt32 n = 0; n < arg1; n++ ) STK( arg0 + n ) = _null_;
818 				}
819 				continue;
820 			case _OP_LOADROOTTABLE: TARGET = _roottable; continue;
821 			case _OP_LOADBOOL: TARGET = arg1 ? _true_ : _false_; continue;
822 			case _OP_DMOVE: STK( arg0 ) = STK( arg1 ); STK( arg2 ) = STK( arg3 ); continue;
823 			case _OP_JMP: ci->_ip += ( sarg1 ); continue;
824 			case _OP_JNZ: if ( !IsFalse( STK( arg0 ) ) ) ci->_ip += ( sarg1 ); continue;
825 			case _OP_JZ: if ( IsFalse( STK( arg0 ) ) ) ci->_ip += ( sarg1 ); continue;
826 			case _OP_LOADFREEVAR: TARGET = _closure( ci->_closure )->_outervalues[arg1]; continue;
827 			case _OP_VARGC: TARGET = SQInteger( ci->_vargs.size ); continue;
828 			case _OP_GETVARGV:
829 				if ( !GETVARGV_OP( TARGET, STK( arg1 ), ci ) ) {
830 					SQ_THROW();
831 				}
832 				continue;
833 			case _OP_NEWTABLE: TARGET = SQTable::Create( _ss( this ), arg1 ); continue;
834 			case _OP_NEWARRAY: TARGET = SQArray::Create( _ss( this ), 0 ); _array( TARGET )->Reserve( arg1 ); continue;
835 			case _OP_APPENDARRAY: _array( STK( arg0 ) )->Append( COND_LITERAL ); continue;
836 			case _OP_GETPARENT:
837 				switch ( squirrel_type( STK( arg1 ) ) ) {
838 				case OT_TABLE:
839 					TARGET = _table( STK( arg1 ) )->_delegate ? SQObjectPtr( _table( STK( arg1 ) )->_delegate ) : _null_;
840 					continue;
841 				case OT_CLASS: TARGET = _class( STK( arg1 ) )->_base ? _class( STK( arg1 ) )->_base : _null_;
842 					continue;
843 				}
844 				Raise_Error( _SC( "the %s type doesn't have a parent slot" ), GetTypeName( STK( arg1 ) ) );
845 				SQ_THROW();
846 				continue;
847 			case _OP_COMPARITH: _GUARD( DerefInc( arg3, TARGET, STK( ( ( ( SQUnsignedInteger )arg1&0xFFFF0000 ) >> 16 ) ), STK( arg2 ), STK( arg1&0x0000FFFF ), false ) ); continue;
848 			case _OP_COMPARITHL: _GUARD( LOCAL_INC( arg3, TARGET, STK( arg1 ), STK( arg2 ) ) ); continue;
849 			case _OP_INC: {
850 					SQObjectPtr o( sarg3 ); _GUARD( DerefInc( '+', TARGET, STK( arg1 ), STK( arg2 ), o, false ) );
851 				}
852 				continue;
853 			case _OP_INCL: {
854 					SQObjectPtr o( sarg3 ); _GUARD( LOCAL_INC( '+', TARGET, STK( arg1 ), o ) );
855 				}
856 				continue;
857 			case _OP_PINC: {
858 					SQObjectPtr o( sarg3 ); _GUARD( DerefInc( '+', TARGET, STK( arg1 ), STK( arg2 ), o, true ) );
859 				}
860 				continue;
861 			case _OP_PINCL: {
862 					SQObjectPtr o( sarg3 ); _GUARD( PLOCAL_INC( '+', TARGET, STK( arg1 ), o ) );
863 				}
864 				continue;
865 			case _OP_CMP: _GUARD( CMP_OP( ( CmpOP )arg3, STK( arg2 ), STK( arg1 ), TARGET ) ) continue;
866 			case _OP_EXISTS: TARGET = Get( STK( arg1 ), STK( arg2 ), temp_reg, true, false ) ? _true_ : _false_;continue;
867 			case _OP_INSTANCEOF:
868 				if ( squirrel_type( STK( arg1 ) ) != OT_CLASS || squirrel_type( STK( arg2 ) ) != OT_INSTANCE ) {
869 					Raise_Error( _SC( "cannot apply instanceof between a %s and a %s" ), GetTypeName( STK( arg1 ) ), GetTypeName( STK( arg2 ) ) ); SQ_THROW();
870 				}
871 				TARGET = _instance( STK( arg2 ) )->InstanceOf( _class( STK( arg1 ) ) ) ? _true_ : _false_;
872 				continue;
873 			case _OP_AND:
874 				if ( IsFalse( STK( arg2 ) ) ) {
875 					TARGET = STK( arg2 );
876 					ci->_ip += ( sarg1 );
877 				}
878 				continue;
879 			case _OP_OR:
880 				if ( !IsFalse( STK( arg2 ) ) ) {
881 					TARGET = STK( arg2 );
882 					ci->_ip += ( sarg1 );
883 				}
884 				continue;
885 			case _OP_NEG: _GUARD( NEG_OP( TARGET, STK( arg1 ) ) ); continue;
886 			case _OP_NOT: TARGET = ( IsFalse( STK( arg1 ) ) ? _true_ : _false_ ); continue;
887 			case _OP_BWNOT:
888 				if ( squirrel_type( STK( arg1 ) ) == OT_INTEGER ) {
889 					TARGET = SQInteger( ~_integer( STK( arg1 ) ) );
890 					continue;
891 				}
892 				Raise_Error( _SC( "attempt to perform a bitwise op on a %s" ), GetTypeName( STK( arg1 ) ) );
893 				SQ_THROW();
894 			case _OP_CLOSURE: {
895 					SQClosure *c = ci->_closure._unVal.pClosure;
896 					SQFunctionProto *fp = c->_function._unVal.pFunctionProto;
897 					if ( !CLOSURE_OP( TARGET, fp->_functions[arg1]._unVal.pFunctionProto ) ) {
898 						SQ_THROW();
899 					}
900 					continue;
901 				}
902 			case _OP_YIELD: {
903 					if ( squirrel_type( ci->_generator ) == OT_GENERATOR ) {
904 						if ( sarg1 != MAX_FUNC_STACKSIZE ) temp_reg = STK( arg1 );
905 						_GUARD( _generator( ci->_generator )->Yield( this ) );
906 						traps -= ci->_etraps;
907 						if ( sarg1 != MAX_FUNC_STACKSIZE ) STK( arg1 ) = temp_reg;
908 					} else {
909 						Raise_Error( _SC( "trying to yield a '%s',only genenerator can be yielded" ), GetTypeName( ci->_generator ) ); SQ_THROW();
910 					}
911 					if ( Return( arg0, arg1, temp_reg ) ) {
912 						assert( traps == 0 );
913 						outres = temp_reg;
914 						return true;
915 					}
916 
917 				}
918 				continue;
919 			case _OP_RESUME:
920 				if ( squirrel_type( STK( arg1 ) ) != OT_GENERATOR ) {
921 					Raise_Error( _SC( "trying to resume a '%s',only genenerator can be resumed" ), GetTypeName( STK( arg1 ) ) ); SQ_THROW();
922 				}
923 				_GUARD( _generator( STK( arg1 ) )->Resume( this, arg0 ) );
924 				traps += ci->_etraps;
925 				continue;
926 			case _OP_FOREACH: {
927 					bool finished;
928 					_GUARD( FOREACH_OP( STK( arg0 ), STK( arg2 ), STK( arg2 + 1 ), STK( arg2 + 2 ), arg2, finished ) );
929 					if ( finished ) ci->_ip += sarg1;
930 				}
931 				continue;
932 			case _OP_DELEGATE: _GUARD( DELEGATE_OP( TARGET, STK( arg1 ), STK( arg2 ) ) ); continue;
933 			case _OP_CLONE:
934 				if ( !Clone( STK( arg1 ), TARGET ) ) {
935 					Raise_Error( _SC( "cloning a %s" ), GetTypeName( STK( arg1 ) ) ); SQ_THROW();
936 				}
937 				continue;
938 			case _OP_TYPEOF: TypeOf( STK( arg1 ), TARGET ); continue;
939 			case _OP_PUSHTRAP:
940 				_etraps.push_back( SQExceptionTrap( _top, _stackbase, &ci->_iv->_vals[( ci->_ip-ci->_iv->_vals )+arg1], arg0 ) ); traps++;
941 				ci->_etraps++;
942 				continue;
943 			case _OP_POPTRAP: {
944 					for ( SQInteger i = 0; i < arg0; i++ ) {
945 						_etraps.pop_back(); traps--;
946 						ci->_etraps--;
947 					}
948 				}
949 				continue;
950 			case _OP_THROW: Raise_Error( TARGET ); SQ_THROW(); continue;
951 			case _OP_CLASS: _GUARD( CLASS_OP( TARGET, arg1, arg2 ) ); continue;
952 			case _OP_NEWSLOTA:
953 				_GUARD( NewSlot( STK( arg1 ), STK( arg2 ), STK( arg3 ) ) );
954 				_class( STK( arg1 ) )->SetAttributes( STK( arg2 ), STK( arg2 - 1 ) );
955 				if ( arg0 != arg3 ) TARGET = STK( arg3 );
956 				continue;
957 			}
958 
959 		}
960 	}
961 exception_trap: {
962 		SQObjectPtr currerror = _lasterror;
963 //  dumpstack(_stackbase);
964 		SQInteger n = 0;
965 		SQInteger last_top = _top;
966 		if ( ci ) {
967 			if ( traps ) {
968 				do {
969 					if ( ci->_etraps > 0 ) {
970 						SQExceptionTrap &et = _etraps.top();
971 						ci->_ip = et._ip;
972 						_top = et._stacksize;
973 						_stackbase = et._stackbase;
974 						_stack[_stackbase+et._extarget] = currerror;
975 						_etraps.pop_back(); traps--; ci->_etraps--;
976 						while ( last_top >= _top ) _stack[last_top--].Null();
977 						goto exception_restore;
978 					}
979 					//if is a native closure
980 					if ( squirrel_type( ci->_closure ) != OT_CLOSURE && n )
981 						break;
982 					if ( squirrel_type( ci->_generator ) == OT_GENERATOR ) _generator( ci->_generator )->Kill();
983 					PopVarArgs( ci->_vargs );
984 					POP_CALLINFO( this );
985 					n++;
986 				} while ( !_callsstack.empty() );
987 			}
988 			//call the hook
989 			CallErrorHandler( currerror );
990 			//remove call stack until a C function is found or the cstack is empty
991 			if ( ci ) do {
992 					SQBool exitafterthisone = ci->_root;
993 					if ( squirrel_type( ci->_generator ) == OT_GENERATOR ) _generator( ci->_generator )->Kill();
994 					_stackbase -= ci->_prevstkbase;
995 					_top = _stackbase + ci->_prevtop;
996 					PopVarArgs( ci->_vargs );
997 					POP_CALLINFO( this );
998 					if ( ( ci && squirrel_type( ci->_closure ) != OT_CLOSURE ) || exitafterthisone ) break;
999 				} while ( !_callsstack.empty() );
1000 
1001 			while ( last_top >= _top ) _stack[last_top--].Null();
1002 		}
1003 		_lasterror = currerror;
1004 		return false;
1005 	}
1006 	assert( 0 );
1007 }
1008 
CreateClassInstance(SQClass * theclass,SQInteger nargs,SQInteger stackbase,SQObjectPtr & retval)1009 bool SQVM::CreateClassInstance( SQClass *theclass, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval ) {
1010 	SQObjectPtr constr;
1011 	SQObjectPtr inst = theclass->CreateInstance();
1012 	_stack[stackbase] = inst;
1013 	if ( theclass->Get( _ss( this )->_constructoridx, constr ) ) {
1014 		if ( !Call( constr, nargs, stackbase, constr ) )
1015 			return false;
1016 	}
1017 	retval = inst;
1018 	return true;
1019 }
1020 
CallErrorHandler(SQObjectPtr & error)1021 void SQVM::CallErrorHandler( SQObjectPtr &error ) {
1022 	if ( squirrel_type( _errorhandler ) != OT_NULL ) {
1023 		SQObjectPtr out;
1024 		Push( _roottable ); Push( error );
1025 		Call( _errorhandler, 2, _top - 2, out );
1026 		Pop( 2 );
1027 	}
1028 }
1029 
CallDebugHook(SQInteger type,SQInteger forcedline)1030 void SQVM::CallDebugHook( SQInteger type, SQInteger forcedline ) {
1031 	SQObjectPtr temp_reg;
1032 	SQInteger nparams = 5;
1033 	SQFunctionProto *func = _funcproto( _closure( ci->_closure )->_function );
1034 	Push( _roottable ); Push( type ); Push( func->_sourcename ); Push( forcedline ? forcedline : func->GetLine( ci->_ip ) ); Push( func->_name );
1035 	Call( _debughook, nparams, _top - nparams, temp_reg );
1036 	Pop( nparams );
1037 }
1038 
CallNative(SQNativeClosure * nclosure,SQInteger nargs,SQInteger stackbase,bool tailcall,SQObjectPtr & retval,bool & suspend)1039 bool SQVM::CallNative( SQNativeClosure *nclosure, SQInteger nargs, SQInteger stackbase, bool tailcall, SQObjectPtr &retval, bool &suspend ) {
1040 	if ( _nnativecalls + 1 > MAX_NATIVE_CALLS ) {
1041 		Raise_Error( _SC( "Native stack overflow" ) ); return false;
1042 	}
1043 	SQInteger nparamscheck = nclosure->_nparamscheck;
1044 	if ( ( ( nparamscheck > 0 ) && ( nparamscheck != nargs ) )
1045 	        || ( ( nparamscheck < 0 ) && ( nargs < ( -nparamscheck ) ) ) ) {
1046 		Raise_Error( _SC( "wrong number of parameters" ) );
1047 		return false;
1048 	}
1049 
1050 	SQInteger tcs;
1051 	if ( tcs = nclosure->_typecheck.size() ) {
1052 		for ( SQInteger i = 0; i < nargs && i < tcs; i++ )
1053 			if ( ( nclosure->_typecheck[i] != -1 ) && !( squirrel_type( _stack[stackbase+i] ) & nclosure->_typecheck[i] ) ) {
1054 				Raise_ParamTypeError( i, nclosure->_typecheck[i], squirrel_type( _stack[stackbase+i] ) );
1055 				return false;
1056 			}
1057 	}
1058 	_nnativecalls++;
1059 	if ( ( _top + MIN_STACK_OVERHEAD ) > ( SQInteger )_stack.size() ) {
1060 		_stack.resize( _stack.size() + ( MIN_STACK_OVERHEAD << 1 ) );
1061 	}
1062 	SQInteger oldtop = _top;
1063 	SQInteger oldstackbase = _stackbase;
1064 	_top = stackbase + nargs;
1065 	PUSH_CALLINFO( this, CallInfo() );
1066 	ci->_etraps = 0;
1067 	ci->_closure._unVal.pNativeClosure = nclosure;
1068 	ci->_closure._type = OT_NATIVECLOSURE;
1069 	ci->_prevstkbase = stackbase - _stackbase;
1070 	ci->_ncalls = 1;
1071 	_stackbase = stackbase;
1072 	//push free variables
1073 	SQInteger outers = nclosure->_outervalues.size();
1074 	for ( SQInteger i = 0; i < outers; i++ ) {
1075 		Push( nclosure->_outervalues[i] );
1076 	}
1077 	ci->_prevtop = ( oldtop - oldstackbase );
1078 	SQInteger ret = ( nclosure->_function )( this );
1079 	_nnativecalls--;
1080 	suspend = false;
1081 	if ( ret == SQ_SUSPEND_FLAG ) suspend = true;
1082 	else if ( ret < 0 ) {
1083 		_stackbase = oldstackbase;
1084 		_top = oldtop;
1085 		POP_CALLINFO( this );
1086 		Raise_Error( _lasterror );
1087 		return false;
1088 	}
1089 
1090 	if ( ret != 0 ) {
1091 		retval = TOP();
1092 	} else {
1093 		retval = _null_;
1094 	}
1095 	_stackbase = oldstackbase;
1096 	_top = oldtop;
1097 	POP_CALLINFO( this );
1098 	return true;
1099 }
1100 
Get(const SQObjectPtr & self,const SQObjectPtr & key,SQObjectPtr & dest,bool raw,bool fetchroot)1101 bool SQVM::Get( const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, bool fetchroot ) {
1102 	switch ( squirrel_type( self ) ) {
1103 	case OT_TABLE:
1104 		if ( _table( self )->Get( key, dest ) )return true;
1105 		break;
1106 	case OT_ARRAY:
1107 		if ( sq_isnumeric( key ) ) {
1108 			return _array( self )->Get( tointeger( key ), dest );
1109 		}
1110 		break;
1111 	case OT_INSTANCE:
1112 		if ( _instance( self )->Get( key, dest ) ) return true;
1113 		break;
1114 	}
1115 	if ( FallBackGet( self, key, dest, raw ) ) return true;
1116 
1117 	if ( fetchroot ) {
1118 		if ( _rawval( STK( 0 ) ) == _rawval( self ) &&
1119 		        squirrel_type( STK( 0 ) ) == squirrel_type( self ) ) {
1120 			return _table( _roottable )->Get( key, dest );
1121 		}
1122 	}
1123 	return false;
1124 }
1125 
FallBackGet(const SQObjectPtr & self,const SQObjectPtr & key,SQObjectPtr & dest,bool raw)1126 bool SQVM::FallBackGet( const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw ) {
1127 	switch ( squirrel_type( self ) ) {
1128 	case OT_CLASS:
1129 		return _class( self )->Get( key, dest );
1130 		break;
1131 	case OT_TABLE:
1132 	case OT_USERDATA:
1133 		//delegation
1134 		if ( _delegable( self )->_delegate ) {
1135 			if ( Get( SQObjectPtr( _delegable( self )->_delegate ), key, dest, raw, false ) )
1136 				return true;
1137 			if ( raw )return false;
1138 			Push( self );Push( key );
1139 			if ( CallMetaMethod( _delegable( self ), MT_GET, 2, dest ) )
1140 				return true;
1141 		}
1142 		if ( squirrel_type( self ) == OT_TABLE ) {
1143 			if ( raw ) return false;
1144 			return _table_ddel->Get( key, dest );
1145 		}
1146 		return false;
1147 		break;
1148 	case OT_ARRAY:
1149 		if ( raw )return false;
1150 		return _array_ddel->Get( key, dest );
1151 	case OT_STRING:
1152 		if ( sq_isnumeric( key ) ) {
1153 			SQInteger n = tointeger( key );
1154 			if ( abs( n ) < _string( self )->_len ) {
1155 				if ( n < 0 )n = _string( self )->_len - n;
1156 				dest = SQInteger( _stringval( self )[n] );
1157 				return true;
1158 			}
1159 			return false;
1160 		} else {
1161 			if ( raw )return false;
1162 			return _string_ddel->Get( key, dest );
1163 		}
1164 		break;
1165 	case OT_INSTANCE:
1166 		if ( raw )return false;
1167 		Push( self );Push( key );
1168 		if ( !CallMetaMethod( _delegable( self ), MT_GET, 2, dest ) ) {
1169 			return _instance_ddel->Get( key, dest );
1170 		}
1171 		return true;
1172 case OT_INTEGER: case OT_FLOAT: case OT_BOOL:
1173 		if ( raw )return false;
1174 		return _number_ddel->Get( key, dest );
1175 	case OT_GENERATOR:
1176 		if ( raw )return false;
1177 		return _generator_ddel->Get( key, dest );
1178 case OT_CLOSURE: case OT_NATIVECLOSURE:
1179 		if ( raw )return false;
1180 		return _closure_ddel->Get( key, dest );
1181 	case OT_THREAD:
1182 		if ( raw )return false;
1183 		return  _thread_ddel->Get( key, dest );
1184 	case OT_WEAKREF:
1185 		if ( raw )return false;
1186 		return  _weakref_ddel->Get( key, dest );
1187 	default: return false;
1188 	}
1189 	return false;
1190 }
1191 
Set(const SQObjectPtr & self,const SQObjectPtr & key,const SQObjectPtr & val,bool fetchroot)1192 bool SQVM::Set( const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, bool fetchroot ) {
1193 	switch ( squirrel_type( self ) ) {
1194 	case OT_TABLE:
1195 		if ( _table( self )->Set( key, val ) )
1196 			return true;
1197 		if ( _table( self )->_delegate ) {
1198 			if ( Set( _table( self )->_delegate, key, val, false ) ) {
1199 				return true;
1200 			}
1201 		}
1202 		//keeps going
1203 	case OT_USERDATA:
1204 		if ( _delegable( self )->_delegate ) {
1205 			SQObjectPtr t;
1206 			Push( self );Push( key );Push( val );
1207 			if ( CallMetaMethod( _delegable( self ), MT_SET, 3, t ) ) return true;
1208 		}
1209 		break;
1210 	case OT_INSTANCE: {
1211 			if ( _instance( self )->Set( key, val ) )
1212 				return true;
1213 			SQObjectPtr t;
1214 			Push( self );Push( key );Push( val );
1215 			if ( CallMetaMethod( _delegable( self ), MT_SET, 3, t ) ) return true;
1216 		}
1217 		break;
1218 	case OT_ARRAY:
1219 		if ( !sq_isnumeric( key ) ) {
1220 			Raise_Error( _SC( "indexing %s with %s" ), GetTypeName( self ), GetTypeName( key ) ); return false;
1221 		}
1222 		return _array( self )->Set( tointeger( key ), val );
1223 	default:
1224 		Raise_Error( _SC( "trying to set '%s'" ), GetTypeName( self ) );
1225 		return false;
1226 	}
1227 	if ( fetchroot ) {
1228 		if ( _rawval( STK( 0 ) ) == _rawval( self ) &&
1229 		        squirrel_type( STK( 0 ) ) == squirrel_type( self ) ) {
1230 			return _table( _roottable )->Set( key, val );
1231 		}
1232 	}
1233 	return false;
1234 }
1235 
Clone(const SQObjectPtr & self,SQObjectPtr & target)1236 bool SQVM::Clone( const SQObjectPtr &self, SQObjectPtr &target ) {
1237 	SQObjectPtr temp_reg;
1238 	switch ( squirrel_type( self ) ) {
1239 	case OT_TABLE:
1240 		target = _table( self )->Clone();
1241 		goto cloned_mt;
1242 	case OT_INSTANCE:
1243 		target = _instance( self )->Clone( _ss( this ) );
1244 cloned_mt:
1245 		if ( _delegable( target )->_delegate ) {
1246 			Push( target );
1247 			Push( self );
1248 			CallMetaMethod( _delegable( target ), MT_CLONED, 2, temp_reg );
1249 		}
1250 		return true;
1251 	case OT_ARRAY:
1252 		target = _array( self )->Clone();
1253 		return true;
1254 	default: return false;
1255 	}
1256 }
1257 
NewSlot(const SQObjectPtr & self,const SQObjectPtr & key,const SQObjectPtr & val)1258 bool SQVM::NewSlot( const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val ) {
1259 	if ( squirrel_type( key ) == OT_NULL ) {
1260 		Raise_Error( _SC( "null cannot be used as index" ) ); return false;
1261 	}
1262 	switch ( squirrel_type( self ) ) {
1263 	case OT_TABLE: {
1264 			bool rawcall = true;
1265 			if ( _table( self )->_delegate ) {
1266 				SQObjectPtr res;
1267 				if ( !_table( self )->Get( key, res ) ) {
1268 					Push( self );Push( key );Push( val );
1269 					rawcall = !CallMetaMethod( _table( self ), MT_NEWSLOT, 3, res );
1270 				}
1271 			}
1272 			if ( rawcall ) _table( self )->NewSlot( key, val ); //cannot fail
1273 
1274 			break;
1275 		}
1276 	case OT_CLASS:
1277 		if ( !_class( self )->NewSlot( key, val ) ) {
1278 			if ( _class( self )->_locked ) {
1279 				Raise_Error( _SC( "trying to modify a class that has already been instantiated" ) );
1280 				return false;
1281 			} else {
1282 				SQObjectPtr oval = PrintObjVal( key );
1283 				Raise_Error( _SC( "the property '%s' already exists" ), _stringval( oval ) );
1284 				return false;
1285 			}
1286 		}
1287 		break;
1288 	default:
1289 		Raise_Error( _SC( "indexing %s with %s" ), GetTypeName( self ), GetTypeName( key ) );
1290 		return false;
1291 		break;
1292 	}
1293 	return true;
1294 }
1295 
DeleteSlot(const SQObjectPtr & self,const SQObjectPtr & key,SQObjectPtr & res)1296 bool SQVM::DeleteSlot( const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res ) {
1297 	switch ( squirrel_type( self ) ) {
1298 	case OT_TABLE:
1299 	case OT_INSTANCE:
1300 	case OT_USERDATA: {
1301 			SQObjectPtr t;
1302 			bool handled = false;
1303 			if ( _delegable( self )->_delegate ) {
1304 				Push( self );Push( key );
1305 				handled = CallMetaMethod( _delegable( self ), MT_DELSLOT, 2, t );
1306 			}
1307 
1308 			if ( !handled ) {
1309 				if ( squirrel_type( self ) == OT_TABLE ) {
1310 					if ( _table( self )->Get( key, t ) ) {
1311 						_table( self )->Remove( key );
1312 					} else {
1313 						Raise_IdxError( ( SQObject & )key );
1314 						return false;
1315 					}
1316 				} else {
1317 					Raise_Error( _SC( "cannot delete a slot from %s" ), GetTypeName( self ) );
1318 					return false;
1319 				}
1320 			}
1321 			res = t;
1322 		}
1323 		break;
1324 	default:
1325 		Raise_Error( _SC( "attempt to delete a slot from a %s" ), GetTypeName( self ) );
1326 		return false;
1327 	}
1328 	return true;
1329 }
1330 
Call(SQObjectPtr & closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr & outres)1331 bool SQVM::Call( SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres ) {
1332 #ifdef _DEBUG
1333 	SQInteger prevstackbase = _stackbase;
1334 #endif
1335 	switch ( squirrel_type( closure ) ) {
1336 	case OT_CLOSURE:
1337 		return Execute( closure, _top - nparams, nparams, stackbase, outres );
1338 		break;
1339 	case OT_NATIVECLOSURE: {
1340 			bool suspend;
1341 			return CallNative( _nativeclosure( closure ), nparams, stackbase, false, outres, suspend );
1342 
1343 		}
1344 		break;
1345 	case OT_CLASS:
1346 		return CreateClassInstance( _class( closure ), nparams, stackbase, outres );
1347 		break;
1348 	default:
1349 		return false;
1350 	}
1351 #ifdef _DEBUG
1352 	if ( !_suspended ) {
1353 		assert( _stackbase == prevstackbase );
1354 	}
1355 #endif
1356 	return true;
1357 }
1358 
CallMetaMethod(SQDelegable * del,SQMetaMethod mm,SQInteger nparams,SQObjectPtr & outres)1359 bool SQVM::CallMetaMethod( SQDelegable *del, SQMetaMethod mm, SQInteger nparams, SQObjectPtr &outres ) {
1360 	SQObjectPtr closure;
1361 	if ( del->GetMetaMethod( mm, closure ) ) {
1362 		if ( Call( closure, nparams, _top - nparams, outres ) ) {
1363 			Pop( nparams );
1364 			return true;
1365 		}
1366 	}
1367 	Pop( nparams );
1368 	return false;
1369 }
1370 
Remove(SQInteger n)1371 void SQVM::Remove( SQInteger n ) {
1372 	n = ( n >= 0 ) ? n + _stackbase - 1 : _top + n;
1373 	for ( SQInteger i = n; i < _top; i++ ) {
1374 		_stack[i] = _stack[i+1];
1375 	}
1376 	_stack[_top] = _null_;
1377 	_top--;
1378 }
1379 
1380 
1381 #ifdef _DEBUG_DUMP
dumpstack(SQInteger stackbase,bool dumpall)1382 void SQVM::dumpstack( SQInteger stackbase, bool dumpall ) {
1383 	SQInteger size = dumpall ? _stack.size() : _top;
1384 	SQInteger n = 0;
1385 	scprintf( _SC( "\n>>>>stack dump<<<<\n" ) );
1386 	CallInfo &ci = _callsstack.back();
1387 	scprintf( _SC( "IP: %d\n" ), ci._ip );
1388 	scprintf( _SC( "prev stack base: %d\n" ), ci._prevstkbase );
1389 	scprintf( _SC( "prev top: %d\n" ), ci._prevtop );
1390 	for ( SQInteger i = 0;i < size;i++ ) {
1391 		SQObjectPtr &obj = _stack[i];
1392 		if ( stackbase == i )scprintf( _SC( ">" ) );else scprintf( _SC( " " ) );
1393 		scprintf( _SC( "[%d]:" ), n );
1394 		switch ( squirrel_type( obj ) ) {
1395 		case OT_FLOAT:   scprintf( _SC( "FLOAT %.3f" ), _float( obj ) );break;
1396 		case OT_INTEGER:  scprintf( _SC( "INTEGER %d" ), _integer( obj ) );break;
1397 		case OT_BOOL:   scprintf( _SC( "BOOL %s" ), _integer( obj ) ? "true" : "false" );break;
1398 		case OT_STRING:   scprintf( _SC( "STRING %s" ), _stringval( obj ) );break;
1399 		case OT_NULL:   scprintf( _SC( "NULL" ) ); break;
1400 		case OT_TABLE:   scprintf( _SC( "TABLE %p[%p]" ), _table( obj ), _table( obj )->_delegate );break;
1401 		case OT_ARRAY:   scprintf( _SC( "ARRAY %p" ), _array( obj ) );break;
1402 		case OT_CLOSURE:  scprintf( _SC( "CLOSURE [%p]" ), _closure( obj ) );break;
1403 		case OT_NATIVECLOSURE: scprintf( _SC( "NATIVECLOSURE" ) );break;
1404 		case OT_USERDATA:  scprintf( _SC( "USERDATA %p[%p]" ), _userdataval( obj ), _userdata( obj )->_delegate );break;
1405 		case OT_GENERATOR:  scprintf( _SC( "GENERATOR" ) );break;
1406 		case OT_THREAD:   scprintf( _SC( "THREAD [%p]" ), _thread( obj ) );break;
1407 		case OT_USERPOINTER: scprintf( _SC( "USERPOINTER %p" ), _userpointer( obj ) );break;
1408 		case OT_CLASS:   scprintf( _SC( "CLASS %p" ), _class( obj ) );break;
1409 		case OT_INSTANCE:  scprintf( _SC( "INSTANCE %p" ), _instance( obj ) );break;
1410 		case OT_WEAKREF:  scprintf( _SC( "WEAKERF %p" ), _weakref( obj ) );break;
1411 		default:
1412 			assert( 0 );
1413 			break;
1414 		};
1415 		scprintf( _SC( "\n" ) );
1416 		++n;
1417 	}
1418 }
1419 
1420 #endif
1421