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