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