1 /*
2    AngelCode Scripting Library
3    Copyright (c) 2003-2017 Andreas Jonsson
4 
5    This software is provided 'as-is', without any express or implied
6    warranty. In no event will the authors be held liable for any
7    damages arising from the use of this software.
8 
9    Permission is granted to anyone to use this software for any
10    purpose, including commercial applications, and to alter it and
11    redistribute it freely, subject to the following restrictions:
12 
13    1. The origin of this software must not be misrepresented; you
14       must not claim that you wrote the original software. If you use
15       this software in a product, an acknowledgment in the product
16       documentation would be appreciated but is not required.
17 
18    2. Altered source versions must be plainly marked as such, and
19       must not be misrepresented as being the original software.
20 
21    3. This notice may not be removed or altered from any source
22       distribution.
23 
24    The original version of this library can be located at:
25    http://www.angelcode.com/angelscript/
26 
27    Andreas Jonsson
28    andreas@angelcode.com
29 */
30 
31 
32 //
33 // as_context.cpp
34 //
35 // This class handles the execution of the byte code
36 //
37 
38 #include <math.h> // fmodf() pow()
39 
40 #include "as_config.h"
41 #include "as_context.h"
42 #include "as_scriptengine.h"
43 #include "as_tokendef.h"
44 #include "as_texts.h"
45 #include "as_callfunc.h"
46 #include "as_generic.h"
47 #include "as_debug.h" // mkdir()
48 #include "as_bytecode.h"
49 #include "as_scriptobject.h"
50 
51 #ifdef _MSC_VER
52 #pragma warning(disable:4702) // unreachable code
53 #endif
54 
55 BEGIN_AS_NAMESPACE
56 
57 // We need at least 2 PTRs reserved for exception handling
58 // We need at least 1 PTR reserved for calling system functions
59 const int RESERVE_STACK = 2*AS_PTR_SIZE;
60 
61 // For each script function call we push 9 PTRs on the call stack
62 const int CALLSTACK_FRAME_SIZE = 9;
63 
64 #if defined(AS_DEBUG)
65 
66 class asCDebugStats
67 {
68 public:
asCDebugStats()69 	asCDebugStats()
70 	{
71 		memset(instrCount, 0, sizeof(instrCount));
72 		memset(instrCount2, 0, sizeof(instrCount2));
73 		lastBC = 255;
74 	}
75 
~asCDebugStats()76 	~asCDebugStats()
77 	{
78 		// This code writes out some statistics for the VM.
79 		// It's useful for determining what needs to be optimized.
80 
81 		_mkdir("AS_DEBUG");
82 		#if _MSC_VER >= 1500 && !defined(AS_MARMALADE)
83 			FILE *f;
84 			fopen_s(&f, "AS_DEBUG/stats.txt", "wt");
85 		#else
86 			FILE *f = fopen("AS_DEBUG/stats.txt", "wt");
87 		#endif
88 		if( f )
89 		{
90 			// Output instruction statistics
91 			fprintf(f, "\nTotal count\n");
92 			int n;
93 			for( n = 0; n < asBC_MAXBYTECODE; n++ )
94 			{
95 				if( asBCInfo[n].name && instrCount[n] > 0 )
96 					fprintf(f, "%-10.10s : %.0f\n", asBCInfo[n].name, instrCount[n]);
97 			}
98 
99 			fprintf(f, "\nNever executed\n");
100 			for( n = 0; n < asBC_MAXBYTECODE; n++ )
101 			{
102 				if( asBCInfo[n].name && instrCount[n] == 0 )
103 					fprintf(f, "%-10.10s\n", asBCInfo[n].name);
104 			}
105 
106 			fprintf(f, "\nSequences\n");
107 			for( n = 0; n < 256; n++ )
108 			{
109 				if( asBCInfo[n].name )
110 				{
111 					for( int m = 0; m < 256; m++ )
112 					{
113 						if( instrCount2[n][m] )
114 							fprintf(f, "%-10.10s, %-10.10s : %.0f\n", asBCInfo[n].name, asBCInfo[m].name, instrCount2[n][m]);
115 					}
116 				}
117 			}
118 			fclose(f);
119 		}
120 	}
121 
Instr(asBYTE bc)122 	void Instr(asBYTE bc)
123 	{
124 		++instrCount[bc];
125 		++instrCount2[lastBC][bc];
126 		lastBC = bc;
127 	}
128 
129 	// Instruction statistics
130 	double instrCount[256];
131 	double instrCount2[256][256];
132 	int lastBC;
133 } stats;
134 
135 #endif
136 
137 // interface
asGetActiveContext()138 AS_API asIScriptContext *asGetActiveContext()
139 {
140 	asCThreadLocalData *tld = asCThreadManager::GetLocalData();
141 
142 	// tld can be 0 if asGetActiveContext is called before any engine has been created.
143 
144 	// Observe! I've seen a case where an application linked with the library twice
145 	// and thus ended up with two separate instances of the code and global variables.
146 	// The application somehow mixed the two instances so that a function called from
147 	// a script ended up calling asGetActiveContext from the other instance that had
148 	// never been initialized.
149 
150 	if( tld == 0 || tld->activeContexts.GetLength() == 0 )
151 		return 0;
152 	return tld->activeContexts[tld->activeContexts.GetLength()-1];
153 }
154 
155 // internal
asPushActiveContext(asIScriptContext * ctx)156 asCThreadLocalData *asPushActiveContext(asIScriptContext *ctx)
157 {
158 	asCThreadLocalData *tld = asCThreadManager::GetLocalData();
159 	asASSERT( tld );
160 	if( tld == 0 )
161 		return 0;
162 	tld->activeContexts.PushLast(ctx);
163 	return tld;
164 }
165 
166 // internal
asPopActiveContext(asCThreadLocalData * tld,asIScriptContext * ctx)167 void asPopActiveContext(asCThreadLocalData *tld, asIScriptContext *ctx)
168 {
169 	UNUSED_VAR(ctx);
170 	asASSERT(tld && tld->activeContexts[tld->activeContexts.GetLength() - 1] == ctx);
171 	if (tld)
172 		tld->activeContexts.PopLast();
173 }
174 
asCContext(asCScriptEngine * engine,bool holdRef)175 asCContext::asCContext(asCScriptEngine *engine, bool holdRef)
176 {
177 	m_refCount.set(1);
178 
179 	m_holdEngineRef = holdRef;
180 	if( holdRef )
181 		engine->AddRef();
182 
183 	m_engine                    = engine;
184 	m_status                    = asEXECUTION_UNINITIALIZED;
185 	m_stackBlockSize            = 0;
186 	m_originalStackPointer      = 0;
187 	m_inExceptionHandler        = false;
188 	m_isStackMemoryNotAllocated = false;
189 	m_needToCleanupArgs         = false;
190 	m_currentFunction           = 0;
191 	m_callingSystemFunction     = 0;
192 	m_regs.objectRegister       = 0;
193 	m_initialFunction           = 0;
194 	m_lineCallback              = false;
195 	m_exceptionCallback         = false;
196 	m_regs.doProcessSuspend     = false;
197 	m_doSuspend                 = false;
198 	m_userData                  = 0;
199 	m_regs.ctx                  = this;
200 }
201 
~asCContext()202 asCContext::~asCContext()
203 {
204 	DetachEngine();
205 }
206 
207 // interface
IsNested(asUINT * nestCount) const208 bool asCContext::IsNested(asUINT *nestCount) const
209 {
210 	if( nestCount )
211 		*nestCount = 0;
212 
213 	asUINT c = GetCallstackSize();
214 	if( c == 0 )
215 		return false;
216 
217 	// Search for a marker on the call stack
218 	// This loop starts at 2 because the 0th entry is not stored in m_callStack,
219 	// and then we need to subtract one more to get the base of each frame
220 	for( asUINT n = 2; n <= c; n++ )
221 	{
222 		const asPWORD *s = m_callStack.AddressOf() + (c - n)*CALLSTACK_FRAME_SIZE;
223 		if( s && s[0] == 0 )
224 		{
225 			if( nestCount )
226 				(*nestCount)++;
227 			else
228 				return true;
229 		}
230 	}
231 
232 	if( nestCount && *nestCount > 0 )
233 		return true;
234 
235 	return false;
236 }
237 
238 // interface
AddRef() const239 int asCContext::AddRef() const
240 {
241 	return m_refCount.atomicInc();
242 }
243 
244 // interface
Release() const245 int asCContext::Release() const
246 {
247 	int r = m_refCount.atomicDec();
248 
249 	if( r == 0 )
250 	{
251 		asDELETE(const_cast<asCContext*>(this),asCContext);
252 		return 0;
253 	}
254 
255 	return r;
256 }
257 
258 // internal
DetachEngine()259 void asCContext::DetachEngine()
260 {
261 	if( m_engine == 0 ) return;
262 
263 	// Clean up all calls, included nested ones
264 	do
265 	{
266 		// Abort any execution
267 		Abort();
268 
269 		// Free all resources
270 		Unprepare();
271 	}
272 	while( IsNested() );
273 
274 	// Free the stack blocks
275 	for( asUINT n = 0; n < m_stackBlocks.GetLength(); n++ )
276 	{
277 		if( m_stackBlocks[n] )
278 		{
279 #ifndef WIP_16BYTE_ALIGN
280 			asDELETEARRAY(m_stackBlocks[n]);
281 #else
282 			asDELETEARRAYALIGNED(m_stackBlocks[n]);
283 #endif
284 		}
285 	}
286 	m_stackBlocks.SetLength(0);
287 	m_stackBlockSize = 0;
288 
289 	// Clean the user data
290 	for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
291 	{
292 		if( m_userData[n+1] )
293 		{
294 			for( asUINT c = 0; c < m_engine->cleanContextFuncs.GetLength(); c++ )
295 				if( m_engine->cleanContextFuncs[c].type == m_userData[n] )
296 					m_engine->cleanContextFuncs[c].cleanFunc(this);
297 		}
298 	}
299 	m_userData.SetLength(0);
300 
301 	// Clear engine pointer
302 	if( m_holdEngineRef )
303 		m_engine->Release();
304 	m_engine = 0;
305 }
306 
307 // interface
GetEngine() const308 asIScriptEngine *asCContext::GetEngine() const
309 {
310 	return m_engine;
311 }
312 
313 // interface
SetUserData(void * data,asPWORD type)314 void *asCContext::SetUserData(void *data, asPWORD type)
315 {
316 	// As a thread might add a new new user data at the same time as another
317 	// it is necessary to protect both read and write access to the userData member
318 	ACQUIREEXCLUSIVE(m_engine->engineRWLock);
319 
320 	// It is not intended to store a lot of different types of userdata,
321 	// so a more complex structure like a associative map would just have
322 	// more overhead than a simple array.
323 	for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
324 	{
325 		if( m_userData[n] == type )
326 		{
327 			void *oldData = reinterpret_cast<void*>(m_userData[n+1]);
328 			m_userData[n+1] = reinterpret_cast<asPWORD>(data);
329 
330 			RELEASEEXCLUSIVE(m_engine->engineRWLock);
331 
332 			return oldData;
333 		}
334 	}
335 
336 	m_userData.PushLast(type);
337 	m_userData.PushLast(reinterpret_cast<asPWORD>(data));
338 
339 	RELEASEEXCLUSIVE(m_engine->engineRWLock);
340 
341 	return 0;
342 }
343 
344 // interface
GetUserData(asPWORD type) const345 void *asCContext::GetUserData(asPWORD type) const
346 {
347 	// There may be multiple threads reading, but when
348 	// setting the user data nobody must be reading.
349 	ACQUIRESHARED(m_engine->engineRWLock);
350 
351 	for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
352 	{
353 		if( m_userData[n] == type )
354 		{
355 			RELEASESHARED(m_engine->engineRWLock);
356 			return reinterpret_cast<void*>(m_userData[n+1]);
357 		}
358 	}
359 
360 	RELEASESHARED(m_engine->engineRWLock);
361 
362 	return 0;
363 }
364 
365 // interface
GetSystemFunction()366 asIScriptFunction *asCContext::GetSystemFunction()
367 {
368 	return m_callingSystemFunction;
369 }
370 
371 // interface
Prepare(asIScriptFunction * func)372 int asCContext::Prepare(asIScriptFunction *func)
373 {
374 	if( func == 0 )
375 	{
376 		asCString str;
377 		str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_d, "Prepare", "null", asNO_FUNCTION);
378 		m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
379 		return asNO_FUNCTION;
380 	}
381 
382 	if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED )
383 	{
384 		asCString str;
385 		str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_d, "Prepare", func->GetDeclaration(true, true), asCONTEXT_ACTIVE);
386 		m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
387 		return asCONTEXT_ACTIVE;
388 	}
389 
390 	// Clean the stack if not done before
391 	if( m_status != asEXECUTION_FINISHED && m_status != asEXECUTION_UNINITIALIZED )
392 		CleanStack();
393 
394 	// Release the returned object (if any)
395 	CleanReturnObject();
396 
397 	// Release the object if it is a script object
398 	if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) )
399 	{
400 		asCScriptObject *obj = *(asCScriptObject**)&m_regs.stackFramePointer[0];
401 		if( obj )
402 			obj->Release();
403 
404 		*(asPWORD*)&m_regs.stackFramePointer[0] = 0;
405 	}
406 
407 	if( m_initialFunction && m_initialFunction == func )
408 	{
409 		// If the same function is executed again, we can skip a lot of the setup
410 		m_currentFunction = m_initialFunction;
411 
412 		// Reset stack pointer
413 		m_regs.stackPointer = m_originalStackPointer;
414 
415 		// Make sure the stack pointer is pointing to the original position,
416 		// otherwise something is wrong with the way it is being updated
417 		asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
418 	}
419 	else
420 	{
421 		asASSERT( m_engine );
422 
423 		// Make sure the function is from the same engine as the context to avoid mixups
424 		if( m_engine != func->GetEngine() )
425 		{
426 			asCString str;
427 			str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_d, "Prepare", func->GetDeclaration(true, true), asINVALID_ARG);
428 			m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
429 			return asINVALID_ARG;
430 		}
431 
432 		if( m_initialFunction )
433 		{
434 			m_initialFunction->Release();
435 
436 			// Reset stack pointer
437 			m_regs.stackPointer = m_originalStackPointer;
438 
439 			// Make sure the stack pointer is pointing to the original position,
440 			// otherwise something is wrong with the way it is being updated
441 			asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
442 		}
443 
444 		// We trust the application not to pass anything else but a asCScriptFunction
445 		m_initialFunction = reinterpret_cast<asCScriptFunction *>(func);
446 		m_initialFunction->AddRef();
447 		m_currentFunction = m_initialFunction;
448 
449 		// TODO: runtime optimize: GetSpaceNeededForArguments() should be precomputed
450 		m_argumentsSize = m_currentFunction->GetSpaceNeededForArguments() + (m_currentFunction->objectType ? AS_PTR_SIZE : 0);
451 
452 		// Reserve space for the arguments and return value
453 		if( m_currentFunction->DoesReturnOnStack() )
454 		{
455 			m_returnValueSize = m_currentFunction->returnType.GetSizeInMemoryDWords();
456 			m_argumentsSize += AS_PTR_SIZE;
457 		}
458 		else
459 			m_returnValueSize = 0;
460 
461 		// Determine the minimum stack size needed
462 		int stackSize = m_argumentsSize + m_returnValueSize;
463 		if( m_currentFunction->scriptData )
464 			stackSize += m_currentFunction->scriptData->stackNeeded;
465 
466 		// Make sure there is enough space on the stack for the arguments and return value
467 		if( !ReserveStackSpace(stackSize) )
468 			return asOUT_OF_MEMORY;
469 	}
470 
471 	// Reset state
472 	// Most of the time the previous state will be asEXECUTION_FINISHED, in which case the values are already initialized
473 	if( m_status != asEXECUTION_FINISHED )
474 	{
475 		m_exceptionLine           = -1;
476 		m_exceptionFunction       = 0;
477 		m_doAbort                 = false;
478 		m_doSuspend               = false;
479 		m_regs.doProcessSuspend   = m_lineCallback;
480 		m_externalSuspendRequest  = false;
481 	}
482 	m_status = asEXECUTION_PREPARED;
483 	m_regs.programPointer = 0;
484 
485 	// Reserve space for the arguments and return value
486 	m_regs.stackFramePointer = m_regs.stackPointer - m_argumentsSize - m_returnValueSize;
487 	m_originalStackPointer   = m_regs.stackPointer;
488 	m_regs.stackPointer      = m_regs.stackFramePointer;
489 
490 	// Set arguments to 0
491 	memset(m_regs.stackPointer, 0, 4*m_argumentsSize);
492 
493 	if( m_returnValueSize )
494 	{
495 		// Set the address of the location where the return value should be put
496 		asDWORD *ptr = m_regs.stackFramePointer;
497 		if( m_currentFunction->objectType )
498 			ptr += AS_PTR_SIZE;
499 
500 		*(void**)ptr = (void*)(m_regs.stackFramePointer + m_argumentsSize);
501 	}
502 
503 	return asSUCCESS;
504 }
505 
506 // Free all resources
Unprepare()507 int asCContext::Unprepare()
508 {
509 	if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED )
510 		return asCONTEXT_ACTIVE;
511 
512 	// Set the context as active so that any clean up code can use access it if desired
513 	asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this);
514 	asDWORD count = m_refCount.get();
515 	UNUSED_VAR(count);
516 
517 	// Only clean the stack if the context was prepared but not executed until the end
518 	if( m_status != asEXECUTION_UNINITIALIZED &&
519 		m_status != asEXECUTION_FINISHED )
520 		CleanStack();
521 
522 	asASSERT( m_needToCleanupArgs == false );
523 
524 	// Release the returned object (if any)
525 	CleanReturnObject();
526 
527 	// TODO: Unprepare is called during destruction, so nobody
528 	//       must be allowed to keep an extra reference
529 	asASSERT(m_refCount.get() == count);
530 	asPopActiveContext(tld, this);
531 
532 	// Release the object if it is a script object
533 	if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) )
534 	{
535 		asCScriptObject *obj = *(asCScriptObject**)&m_regs.stackFramePointer[0];
536 		if( obj )
537 			obj->Release();
538 	}
539 
540 	// Release the initial function
541 	if( m_initialFunction )
542 	{
543 		m_initialFunction->Release();
544 
545 		// Reset stack pointer
546 		m_regs.stackPointer = m_originalStackPointer;
547 
548 		// Make sure the stack pointer is pointing to the original position,
549 		// otherwise something is wrong with the way it is being updated
550 		asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) );
551 	}
552 
553 	// Clear function pointers
554 	m_initialFunction = 0;
555 	m_currentFunction = 0;
556 	m_exceptionFunction = 0;
557 	m_regs.programPointer = 0;
558 
559 	// Reset status
560 	m_status = asEXECUTION_UNINITIALIZED;
561 
562 	m_regs.stackFramePointer = 0;
563 
564 	return 0;
565 }
566 
GetReturnByte()567 asBYTE asCContext::GetReturnByte()
568 {
569 	if( m_status != asEXECUTION_FINISHED ) return 0;
570 
571 	asCDataType *dt = &m_initialFunction->returnType;
572 
573 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
574 
575 	return *(asBYTE*)&m_regs.valueRegister;
576 }
577 
GetReturnWord()578 asWORD asCContext::GetReturnWord()
579 {
580 	if( m_status != asEXECUTION_FINISHED ) return 0;
581 
582 	asCDataType *dt = &m_initialFunction->returnType;
583 
584 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
585 
586 	return *(asWORD*)&m_regs.valueRegister;
587 }
588 
GetReturnDWord()589 asDWORD asCContext::GetReturnDWord()
590 {
591 	if( m_status != asEXECUTION_FINISHED ) return 0;
592 
593 	asCDataType *dt = &m_initialFunction->returnType;
594 
595 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
596 
597 	return *(asDWORD*)&m_regs.valueRegister;
598 }
599 
GetReturnQWord()600 asQWORD asCContext::GetReturnQWord()
601 {
602 	if( m_status != asEXECUTION_FINISHED ) return 0;
603 
604 	asCDataType *dt = &m_initialFunction->returnType;
605 
606 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
607 
608 	return m_regs.valueRegister;
609 }
610 
GetReturnFloat()611 float asCContext::GetReturnFloat()
612 {
613 	if( m_status != asEXECUTION_FINISHED ) return 0;
614 
615 	asCDataType *dt = &m_initialFunction->returnType;
616 
617 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
618 
619 	return *(float*)&m_regs.valueRegister;
620 }
621 
GetReturnDouble()622 double asCContext::GetReturnDouble()
623 {
624 	if( m_status != asEXECUTION_FINISHED ) return 0;
625 
626 	asCDataType *dt = &m_initialFunction->returnType;
627 
628 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0;
629 
630 	return *(double*)&m_regs.valueRegister;
631 }
632 
GetReturnAddress()633 void *asCContext::GetReturnAddress()
634 {
635 	if( m_status != asEXECUTION_FINISHED ) return 0;
636 
637 	asCDataType *dt = &m_initialFunction->returnType;
638 
639 	if( dt->IsReference() )
640 		return *(void**)&m_regs.valueRegister;
641 	else if( dt->IsObject() || dt->IsFuncdef() )
642 	{
643 		if( m_initialFunction->DoesReturnOnStack() )
644 		{
645 			// The address of the return value was passed as the first argument, after the object pointer
646 			int offset = 0;
647 			if( m_initialFunction->objectType )
648 				offset += AS_PTR_SIZE;
649 
650 			return *(void**)(&m_regs.stackFramePointer[offset]);
651 		}
652 
653 		return m_regs.objectRegister;
654 	}
655 
656 	return 0;
657 }
658 
GetReturnObject()659 void *asCContext::GetReturnObject()
660 {
661 	if( m_status != asEXECUTION_FINISHED ) return 0;
662 
663 	asCDataType *dt = &m_initialFunction->returnType;
664 
665 	if( !dt->IsObject() && !dt->IsFuncdef() ) return 0;
666 
667 	if( dt->IsReference() )
668 		return *(void**)(asPWORD)m_regs.valueRegister;
669 	else
670 	{
671 		if( m_initialFunction->DoesReturnOnStack() )
672 		{
673 			// The address of the return value was passed as the first argument, after the object pointer
674 			int offset = 0;
675 			if( m_initialFunction->objectType )
676 				offset += AS_PTR_SIZE;
677 
678 			return *(void**)(&m_regs.stackFramePointer[offset]);
679 		}
680 
681 		return m_regs.objectRegister;
682 	}
683 }
684 
GetAddressOfReturnValue()685 void *asCContext::GetAddressOfReturnValue()
686 {
687 	if( m_status != asEXECUTION_FINISHED ) return 0;
688 
689 	asCDataType *dt = &m_initialFunction->returnType;
690 
691 	// An object is stored in the objectRegister
692 	if( !dt->IsReference() && (dt->IsObject() || dt->IsFuncdef()) )
693 	{
694 		// Need to dereference objects
695 		if( !dt->IsObjectHandle() )
696 		{
697 			if( m_initialFunction->DoesReturnOnStack() )
698 			{
699 				// The address of the return value was passed as the first argument, after the object pointer
700 				int offset = 0;
701 				if( m_initialFunction->objectType )
702 					offset += AS_PTR_SIZE;
703 
704 				return *(void**)(&m_regs.stackFramePointer[offset]);
705 			}
706 
707 			return *(void**)&m_regs.objectRegister;
708 		}
709 		return &m_regs.objectRegister;
710 	}
711 
712 	// Primitives and references are stored in valueRegister
713 	return &m_regs.valueRegister;
714 }
715 
SetObject(void * obj)716 int asCContext::SetObject(void *obj)
717 {
718 	if( m_status != asEXECUTION_PREPARED )
719 		return asCONTEXT_NOT_PREPARED;
720 
721 	if( !m_initialFunction->objectType )
722 	{
723 		m_status = asEXECUTION_ERROR;
724 		return asERROR;
725 	}
726 
727 	asASSERT( *(asPWORD*)&m_regs.stackFramePointer[0] == 0 );
728 
729 	*(asPWORD*)&m_regs.stackFramePointer[0] = (asPWORD)obj;
730 
731 	// TODO: This should be optional by having a flag where the application can chose whether it should be done or not
732 	//       The flag could be named something like takeOwnership and have default value of true
733 	if( obj && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) )
734 		reinterpret_cast<asCScriptObject*>(obj)->AddRef();
735 
736 	return 0;
737 }
738 
SetArgByte(asUINT arg,asBYTE value)739 int asCContext::SetArgByte(asUINT arg, asBYTE value)
740 {
741 	if( m_status != asEXECUTION_PREPARED )
742 		return asCONTEXT_NOT_PREPARED;
743 
744 	if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
745 	{
746 		m_status = asEXECUTION_ERROR;
747 		return asINVALID_ARG;
748 	}
749 
750 	// Verify the type of the argument
751 	asCDataType *dt = &m_initialFunction->parameterTypes[arg];
752 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
753 	{
754 		m_status = asEXECUTION_ERROR;
755 		return asINVALID_TYPE;
756 	}
757 
758 	if( dt->GetSizeInMemoryBytes() != 1 )
759 	{
760 		m_status = asEXECUTION_ERROR;
761 		return asINVALID_TYPE;
762 	}
763 
764 	// Determine the position of the argument
765 	int offset = 0;
766 	if( m_initialFunction->objectType )
767 		offset += AS_PTR_SIZE;
768 
769 	// If function returns object by value an extra pointer is pushed on the stack
770 	if( m_returnValueSize )
771 		offset += AS_PTR_SIZE;
772 
773 	for( asUINT n = 0; n < arg; n++ )
774 		offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
775 
776 	// Set the value
777 	*(asBYTE*)&m_regs.stackFramePointer[offset] = value;
778 
779 	return 0;
780 }
781 
SetArgWord(asUINT arg,asWORD value)782 int asCContext::SetArgWord(asUINT arg, asWORD value)
783 {
784 	if( m_status != asEXECUTION_PREPARED )
785 		return asCONTEXT_NOT_PREPARED;
786 
787 	if( arg >= m_initialFunction->parameterTypes.GetLength() )
788 	{
789 		m_status = asEXECUTION_ERROR;
790 		return asINVALID_ARG;
791 	}
792 
793 	// Verify the type of the argument
794 	asCDataType *dt = &m_initialFunction->parameterTypes[arg];
795 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
796 	{
797 		m_status = asEXECUTION_ERROR;
798 		return asINVALID_TYPE;
799 	}
800 
801 	if( dt->GetSizeInMemoryBytes() != 2 )
802 	{
803 		m_status = asEXECUTION_ERROR;
804 		return asINVALID_TYPE;
805 	}
806 
807 	// Determine the position of the argument
808 	int offset = 0;
809 	if( m_initialFunction->objectType )
810 		offset += AS_PTR_SIZE;
811 
812 	// If function returns object by value an extra pointer is pushed on the stack
813 	if( m_returnValueSize )
814 		offset += AS_PTR_SIZE;
815 
816 	for( asUINT n = 0; n < arg; n++ )
817 		offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
818 
819 	// Set the value
820 	*(asWORD*)&m_regs.stackFramePointer[offset] = value;
821 
822 	return 0;
823 }
824 
SetArgDWord(asUINT arg,asDWORD value)825 int asCContext::SetArgDWord(asUINT arg, asDWORD value)
826 {
827 	if( m_status != asEXECUTION_PREPARED )
828 		return asCONTEXT_NOT_PREPARED;
829 
830 	if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
831 	{
832 		m_status = asEXECUTION_ERROR;
833 		return asINVALID_ARG;
834 	}
835 
836 	// Verify the type of the argument
837 	asCDataType *dt = &m_initialFunction->parameterTypes[arg];
838 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
839 	{
840 		m_status = asEXECUTION_ERROR;
841 		return asINVALID_TYPE;
842 	}
843 
844 	if( dt->GetSizeInMemoryBytes() != 4 )
845 	{
846 		m_status = asEXECUTION_ERROR;
847 		return asINVALID_TYPE;
848 	}
849 
850 	// Determine the position of the argument
851 	int offset = 0;
852 	if( m_initialFunction->objectType )
853 		offset += AS_PTR_SIZE;
854 
855 	// If function returns object by value an extra pointer is pushed on the stack
856 	if( m_returnValueSize )
857 		offset += AS_PTR_SIZE;
858 
859 	for( asUINT n = 0; n < arg; n++ )
860 		offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
861 
862 	// Set the value
863 	*(asDWORD*)&m_regs.stackFramePointer[offset] = value;
864 
865 	return 0;
866 }
867 
SetArgQWord(asUINT arg,asQWORD value)868 int asCContext::SetArgQWord(asUINT arg, asQWORD value)
869 {
870 	if( m_status != asEXECUTION_PREPARED )
871 		return asCONTEXT_NOT_PREPARED;
872 
873 	if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
874 	{
875 		m_status = asEXECUTION_ERROR;
876 		return asINVALID_ARG;
877 	}
878 
879 	// Verify the type of the argument
880 	asCDataType *dt = &m_initialFunction->parameterTypes[arg];
881 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
882 	{
883 		m_status = asEXECUTION_ERROR;
884 		return asINVALID_TYPE;
885 	}
886 
887 	if( dt->GetSizeOnStackDWords() != 2 )
888 	{
889 		m_status = asEXECUTION_ERROR;
890 		return asINVALID_TYPE;
891 	}
892 
893 	// Determine the position of the argument
894 	int offset = 0;
895 	if( m_initialFunction->objectType )
896 		offset += AS_PTR_SIZE;
897 
898 	// If function returns object by value an extra pointer is pushed on the stack
899 	if( m_returnValueSize )
900 		offset += AS_PTR_SIZE;
901 
902 	for( asUINT n = 0; n < arg; n++ )
903 		offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
904 
905 	// Set the value
906 	*(asQWORD*)(&m_regs.stackFramePointer[offset]) = value;
907 
908 	return 0;
909 }
910 
SetArgFloat(asUINT arg,float value)911 int asCContext::SetArgFloat(asUINT arg, float value)
912 {
913 	if( m_status != asEXECUTION_PREPARED )
914 		return asCONTEXT_NOT_PREPARED;
915 
916 	if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
917 	{
918 		m_status = asEXECUTION_ERROR;
919 		return asINVALID_ARG;
920 	}
921 
922 	// Verify the type of the argument
923 	asCDataType *dt = &m_initialFunction->parameterTypes[arg];
924 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
925 	{
926 		m_status = asEXECUTION_ERROR;
927 		return asINVALID_TYPE;
928 	}
929 
930 	if( dt->GetSizeOnStackDWords() != 1 )
931 	{
932 		m_status = asEXECUTION_ERROR;
933 		return asINVALID_TYPE;
934 	}
935 
936 	// Determine the position of the argument
937 	int offset = 0;
938 	if( m_initialFunction->objectType )
939 		offset += AS_PTR_SIZE;
940 
941 	// If function returns object by value an extra pointer is pushed on the stack
942 	if( m_returnValueSize )
943 		offset += AS_PTR_SIZE;
944 
945 	for( asUINT n = 0; n < arg; n++ )
946 		offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
947 
948 	// Set the value
949 	*(float*)(&m_regs.stackFramePointer[offset]) = value;
950 
951 	return 0;
952 }
953 
SetArgDouble(asUINT arg,double value)954 int asCContext::SetArgDouble(asUINT arg, double value)
955 {
956 	if( m_status != asEXECUTION_PREPARED )
957 		return asCONTEXT_NOT_PREPARED;
958 
959 	if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
960 	{
961 		m_status = asEXECUTION_ERROR;
962 		return asINVALID_ARG;
963 	}
964 
965 	// Verify the type of the argument
966 	asCDataType *dt = &m_initialFunction->parameterTypes[arg];
967 	if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() )
968 	{
969 		m_status = asEXECUTION_ERROR;
970 		return asINVALID_TYPE;
971 	}
972 
973 	if( dt->GetSizeOnStackDWords() != 2 )
974 	{
975 		m_status = asEXECUTION_ERROR;
976 		return asINVALID_TYPE;
977 	}
978 
979 	// Determine the position of the argument
980 	int offset = 0;
981 	if( m_initialFunction->objectType )
982 		offset += AS_PTR_SIZE;
983 
984 	// If function returns object by value an extra pointer is pushed on the stack
985 	if( m_returnValueSize )
986 		offset += AS_PTR_SIZE;
987 
988 	for( asUINT n = 0; n < arg; n++ )
989 		offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
990 
991 	// Set the value
992 	*(double*)(&m_regs.stackFramePointer[offset]) = value;
993 
994 	return 0;
995 }
996 
SetArgAddress(asUINT arg,void * value)997 int asCContext::SetArgAddress(asUINT arg, void *value)
998 {
999 	if( m_status != asEXECUTION_PREPARED )
1000 		return asCONTEXT_NOT_PREPARED;
1001 
1002 	if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
1003 	{
1004 		m_status = asEXECUTION_ERROR;
1005 		return asINVALID_ARG;
1006 	}
1007 
1008 	// Verify the type of the argument
1009 	asCDataType *dt = &m_initialFunction->parameterTypes[arg];
1010 	if( !dt->IsReference() && !dt->IsObjectHandle() )
1011 	{
1012 		m_status = asEXECUTION_ERROR;
1013 		return asINVALID_TYPE;
1014 	}
1015 
1016 	// Determine the position of the argument
1017 	int offset = 0;
1018 	if( m_initialFunction->objectType )
1019 		offset += AS_PTR_SIZE;
1020 
1021 	// If function returns object by value an extra pointer is pushed on the stack
1022 	if( m_returnValueSize )
1023 		offset += AS_PTR_SIZE;
1024 
1025 	for( asUINT n = 0; n < arg; n++ )
1026 		offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
1027 
1028 	// Set the value
1029 	*(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)value;
1030 
1031 	return 0;
1032 }
1033 
SetArgObject(asUINT arg,void * obj)1034 int asCContext::SetArgObject(asUINT arg, void *obj)
1035 {
1036 	if( m_status != asEXECUTION_PREPARED )
1037 		return asCONTEXT_NOT_PREPARED;
1038 
1039 	if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
1040 	{
1041 		m_status = asEXECUTION_ERROR;
1042 		return asINVALID_ARG;
1043 	}
1044 
1045 	// Verify the type of the argument
1046 	asCDataType *dt = &m_initialFunction->parameterTypes[arg];
1047 	if( !dt->IsObject() && !dt->IsFuncdef() )
1048 	{
1049 		m_status = asEXECUTION_ERROR;
1050 		return asINVALID_TYPE;
1051 	}
1052 
1053 	// If the object should be sent by value we must make a copy of it
1054 	if( !dt->IsReference() )
1055 	{
1056 		if( dt->IsObjectHandle() )
1057 		{
1058 			// Increase the reference counter
1059 			if (obj && dt->IsFuncdef())
1060 				((asIScriptFunction*)obj)->AddRef();
1061 			else
1062 			{
1063 				asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh;
1064 				if (obj && beh->addref)
1065 					m_engine->CallObjectMethod(obj, beh->addref);
1066 			}
1067 		}
1068 		else
1069 		{
1070 			obj = m_engine->CreateScriptObjectCopy(obj, dt->GetTypeInfo());
1071 		}
1072 	}
1073 
1074 	// Determine the position of the argument
1075 	int offset = 0;
1076 	if( m_initialFunction->objectType )
1077 		offset += AS_PTR_SIZE;
1078 
1079 	// If function returns object by value an extra pointer is pushed on the stack
1080 	if( m_returnValueSize )
1081 		offset += AS_PTR_SIZE;
1082 
1083 	for( asUINT n = 0; n < arg; n++ )
1084 		offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
1085 
1086 	// Set the value
1087 	*(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)obj;
1088 
1089 	return 0;
1090 }
1091 
SetArgVarType(asUINT arg,void * ptr,int typeId)1092 int asCContext::SetArgVarType(asUINT arg, void *ptr, int typeId)
1093 {
1094 	if( m_status != asEXECUTION_PREPARED )
1095 		return asCONTEXT_NOT_PREPARED;
1096 
1097 	if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
1098 	{
1099 		m_status = asEXECUTION_ERROR;
1100 		return asINVALID_ARG;
1101 	}
1102 
1103 	// Verify the type of the argument
1104 	asCDataType *dt = &m_initialFunction->parameterTypes[arg];
1105 	if( dt->GetTokenType() != ttQuestion )
1106 	{
1107 		m_status = asEXECUTION_ERROR;
1108 		return asINVALID_TYPE;
1109 	}
1110 
1111 	// Determine the position of the argument
1112 	int offset = 0;
1113 	if( m_initialFunction->objectType )
1114 		offset += AS_PTR_SIZE;
1115 
1116 	// If function returns object by value an extra pointer is pushed on the stack
1117 	if( m_returnValueSize )
1118 		offset += AS_PTR_SIZE;
1119 
1120 	for( asUINT n = 0; n < arg; n++ )
1121 		offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
1122 
1123 	// Set the typeId and pointer
1124 	*(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)ptr;
1125 	offset += AS_PTR_SIZE;
1126 	*(int*)(&m_regs.stackFramePointer[offset]) = typeId;
1127 
1128 	return 0;
1129 }
1130 
1131 // TODO: Instead of GetAddressOfArg, maybe we need a SetArgValue(int arg, void *value, bool takeOwnership) instead.
1132 
1133 // interface
GetAddressOfArg(asUINT arg)1134 void *asCContext::GetAddressOfArg(asUINT arg)
1135 {
1136 	if( m_status != asEXECUTION_PREPARED )
1137 		return 0;
1138 
1139 	if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() )
1140 		return 0;
1141 
1142 	// Determine the position of the argument
1143 	int offset = 0;
1144 	if( m_initialFunction->objectType )
1145 		offset += AS_PTR_SIZE;
1146 
1147 	// If function returns object by value an extra pointer is pushed on the stack
1148 	if( m_returnValueSize )
1149 		offset += AS_PTR_SIZE;
1150 
1151 	for( asUINT n = 0; n < arg; n++ )
1152 		offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords();
1153 
1154 	// We should return the address of the location where the argument value will be placed
1155 
1156 	// All registered types are always sent by reference, even if
1157 	// the function is declared to receive the argument by value.
1158 	return &m_regs.stackFramePointer[offset];
1159 }
1160 
1161 
Abort()1162 int asCContext::Abort()
1163 {
1164 	if( m_engine == 0 ) return asERROR;
1165 
1166 	// TODO: multithread: Make thread safe. There is a chance that the status
1167 	//                    changes to something else after being set to ABORTED here.
1168 	if( m_status == asEXECUTION_SUSPENDED )
1169 		m_status = asEXECUTION_ABORTED;
1170 
1171 	m_doSuspend = true;
1172 	m_regs.doProcessSuspend = true;
1173 	m_externalSuspendRequest = true;
1174 	m_doAbort = true;
1175 
1176 	return 0;
1177 }
1178 
1179 // interface
Suspend()1180 int asCContext::Suspend()
1181 {
1182 	// This function just sets some internal flags and is safe
1183 	// to call from a secondary thread, even if the library has
1184 	// been built without multi-thread support.
1185 
1186 	if( m_engine == 0 ) return asERROR;
1187 
1188 	m_doSuspend = true;
1189 	m_externalSuspendRequest = true;
1190 	m_regs.doProcessSuspend = true;
1191 
1192 	return 0;
1193 }
1194 
1195 // interface
Execute()1196 int asCContext::Execute()
1197 {
1198 	asASSERT( m_engine != 0 );
1199 
1200 	if( m_status != asEXECUTION_SUSPENDED && m_status != asEXECUTION_PREPARED )
1201 	{
1202 		asCString str;
1203 		str.Format(TXT_FAILED_IN_FUNC_s_d, "Execute", asCONTEXT_NOT_PREPARED);
1204 		m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
1205 		return asCONTEXT_NOT_PREPARED;
1206 	}
1207 
1208 	m_status = asEXECUTION_ACTIVE;
1209 
1210 	asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this);
1211 
1212 	// Make sure there are not too many nested calls, as it could crash the application
1213 	// by filling up the thread call stack
1214 	if (tld->activeContexts.GetLength() > m_engine->ep.maxNestedCalls)
1215 		SetInternalException(TXT_TOO_MANY_NESTED_CALLS);
1216 	else if( m_regs.programPointer == 0 )
1217 	{
1218 		if( m_currentFunction->funcType == asFUNC_DELEGATE )
1219 		{
1220 			// Push the object pointer onto the stack
1221 			asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] );
1222 			m_regs.stackPointer -= AS_PTR_SIZE;
1223 			m_regs.stackFramePointer -= AS_PTR_SIZE;
1224 			*(asPWORD*)m_regs.stackPointer = asPWORD(m_currentFunction->objForDelegate);
1225 
1226 			// Make the call to the delegated object method
1227 			m_currentFunction = m_currentFunction->funcForDelegate;
1228 		}
1229 
1230 		if( m_currentFunction->funcType == asFUNC_VIRTUAL ||
1231 			m_currentFunction->funcType == asFUNC_INTERFACE )
1232 		{
1233 			// The currentFunction is a virtual method
1234 
1235 			// Determine the true function from the object
1236 			asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackFramePointer;
1237 			if( obj == 0 )
1238 			{
1239 				SetInternalException(TXT_NULL_POINTER_ACCESS);
1240 			}
1241 			else
1242 			{
1243 				asCObjectType *objType = obj->objType;
1244 				asCScriptFunction *realFunc = 0;
1245 
1246 				if( m_currentFunction->funcType == asFUNC_VIRTUAL )
1247 				{
1248 					if( objType->virtualFunctionTable.GetLength() > (asUINT)m_currentFunction->vfTableIdx )
1249 					{
1250 						realFunc = objType->virtualFunctionTable[m_currentFunction->vfTableIdx];
1251 					}
1252 				}
1253 				else
1254 				{
1255 					// Search the object type for a function that matches the interface function
1256 					for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
1257 					{
1258 						asCScriptFunction *f2 = m_engine->scriptFunctions[objType->methods[n]];
1259 						if( f2->signatureId == m_currentFunction->signatureId )
1260 						{
1261 							if( f2->funcType == asFUNC_VIRTUAL )
1262 								realFunc = objType->virtualFunctionTable[f2->vfTableIdx];
1263 							else
1264 								realFunc = f2;
1265 							break;
1266 						}
1267 					}
1268 				}
1269 
1270 				if( realFunc && realFunc->signatureId == m_currentFunction->signatureId )
1271 					m_currentFunction = realFunc;
1272 				else
1273 					SetInternalException(TXT_NULL_POINTER_ACCESS);
1274 			}
1275 		}
1276 		else if( m_currentFunction->funcType == asFUNC_IMPORTED )
1277 		{
1278 			int funcId = m_engine->importedFunctions[m_currentFunction->id & ~FUNC_IMPORTED]->boundFunctionId;
1279 			if( funcId > 0 )
1280 				m_currentFunction = m_engine->scriptFunctions[funcId];
1281 			else
1282 				SetInternalException(TXT_UNBOUND_FUNCTION);
1283 		}
1284 
1285 		if( m_currentFunction->funcType == asFUNC_SCRIPT )
1286 		{
1287 			m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf();
1288 
1289 			// Set up the internal registers for executing the script function
1290 			PrepareScriptFunction();
1291 		}
1292 		else if( m_currentFunction->funcType == asFUNC_SYSTEM )
1293 		{
1294 			// The current function is an application registered function
1295 
1296 			// Call the function directly
1297 			CallSystemFunction(m_currentFunction->id, this);
1298 
1299 			// Was the call successful?
1300 			if( m_status == asEXECUTION_ACTIVE )
1301 			{
1302 				m_status = asEXECUTION_FINISHED;
1303 			}
1304 		}
1305 		else
1306 		{
1307 			// This shouldn't happen unless there was an error in which
1308 			// case an exception should have been raised already
1309 			asASSERT( m_status == asEXECUTION_EXCEPTION );
1310 		}
1311 	}
1312 
1313 	asUINT gcPreObjects = 0;
1314 	if( m_engine->ep.autoGarbageCollect )
1315 		m_engine->gc.GetStatistics(&gcPreObjects, 0, 0, 0, 0);
1316 
1317 	while( m_status == asEXECUTION_ACTIVE )
1318 		ExecuteNext();
1319 
1320 	if( m_lineCallback )
1321 	{
1322 		// Call the line callback one last time before leaving
1323 		// so anyone listening can catch the state change
1324 		CallLineCallback();
1325 		m_regs.doProcessSuspend = true;
1326 	}
1327 	else
1328 		m_regs.doProcessSuspend = false;
1329 
1330 	m_doSuspend = false;
1331 
1332 	if( m_engine->ep.autoGarbageCollect )
1333 	{
1334 		asUINT gcPosObjects = 0;
1335 		m_engine->gc.GetStatistics(&gcPosObjects, 0, 0, 0, 0);
1336 		if( gcPosObjects > gcPreObjects )
1337 		{
1338 			// Execute as many steps as there were new objects created
1339 			m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE, gcPosObjects - gcPreObjects);
1340 		}
1341 		else if( gcPosObjects > 0 )
1342 		{
1343 			// Execute at least one step, even if no new objects were created
1344 			m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE, 1);
1345 		}
1346 	}
1347 
1348 	// Pop the active context
1349 	asPopActiveContext(tld, this);
1350 
1351 	if( m_status == asEXECUTION_FINISHED )
1352 	{
1353 		m_regs.objectType = m_initialFunction->returnType.GetTypeInfo();
1354 		return asEXECUTION_FINISHED;
1355 	}
1356 
1357 	if( m_doAbort )
1358 	{
1359 		m_doAbort = false;
1360 
1361 		m_status = asEXECUTION_ABORTED;
1362 		return asEXECUTION_ABORTED;
1363 	}
1364 
1365 	if( m_status == asEXECUTION_SUSPENDED )
1366 		return asEXECUTION_SUSPENDED;
1367 
1368 	if( m_status == asEXECUTION_EXCEPTION )
1369 		return asEXECUTION_EXCEPTION;
1370 
1371 	return asERROR;
1372 }
1373 
PushState()1374 int asCContext::PushState()
1375 {
1376 	// Only allow the state to be pushed when active
1377 	// TODO: Can we support a suspended state too? So the reuse of
1378 	//       the context can be done outside the Execute() call?
1379 	if( m_status != asEXECUTION_ACTIVE )
1380 	{
1381 		// TODO: Write message. Wrong usage
1382 		return asERROR;
1383 	}
1384 
1385 	// Push the current script function that is calling the system function
1386 	PushCallState();
1387 
1388 	// Push the system function too, which will serve both as a marker and
1389 	// informing which system function that created the nested call
1390 	if( m_callStack.GetLength() == m_callStack.GetCapacity() )
1391 	{
1392 		// Allocate space for 10 call states at a time to save time
1393 		m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true);
1394 	}
1395 	m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE);
1396 
1397 	// Need to push m_initialFunction as it must be restored later
1398 	asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
1399 	tmp[0] = 0;
1400 	tmp[1] = (asPWORD)m_callingSystemFunction;
1401 	tmp[2] = (asPWORD)m_initialFunction;
1402 	tmp[3] = (asPWORD)m_originalStackPointer;
1403 	tmp[4] = (asPWORD)m_argumentsSize;
1404 
1405 	// Need to push the value of registers so they can be restored
1406 	tmp[5] = (asPWORD)asDWORD(m_regs.valueRegister);
1407 	tmp[6] = (asPWORD)asDWORD(m_regs.valueRegister>>32);
1408 	tmp[7] = (asPWORD)m_regs.objectRegister;
1409 	tmp[8] = (asPWORD)m_regs.objectType;
1410 
1411 	// Decrease stackpointer to prevent the top value from being overwritten
1412 	m_regs.stackPointer -= 2;
1413 
1414 	// Clear the initial function so that Prepare() knows it must do all validations
1415 	m_initialFunction = 0;
1416 
1417 	// After this the state should appear as if uninitialized
1418 	m_callingSystemFunction = 0;
1419 
1420 	m_regs.objectRegister = 0;
1421 	m_regs.objectType = 0;
1422 
1423 	// Set the status to uninitialized as application
1424 	// should call Prepare() after this to reuse the context
1425 	m_status = asEXECUTION_UNINITIALIZED;
1426 
1427 	return asSUCCESS;
1428 }
1429 
PopState()1430 int asCContext::PopState()
1431 {
1432 	if( !IsNested() )
1433 		return asERROR;
1434 
1435 	// Clean up the current execution
1436 	Unprepare();
1437 
1438 	// The topmost state must be a marker for nested call
1439 	asASSERT( m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE] == 0 );
1440 
1441 	// Restore the previous state
1442 	asPWORD *tmp = &m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE];
1443 	m_callingSystemFunction = reinterpret_cast<asCScriptFunction*>(tmp[1]);
1444 	m_callStack.SetLength(m_callStack.GetLength() - CALLSTACK_FRAME_SIZE);
1445 
1446 	// Restore the previous initial function and the associated values
1447 	m_initialFunction      = reinterpret_cast<asCScriptFunction*>(tmp[2]);
1448 	m_originalStackPointer = (asDWORD*)tmp[3];
1449 	m_argumentsSize        = (int)tmp[4];
1450 
1451 	m_regs.valueRegister   = asQWORD(asDWORD(tmp[5]));
1452 	m_regs.valueRegister  |= asQWORD(tmp[6])<<32;
1453 	m_regs.objectRegister  = (void*)tmp[7];
1454 	m_regs.objectType      = (asITypeInfo*)tmp[8];
1455 
1456 	// Calculate the returnValueSize
1457 	if( m_initialFunction->DoesReturnOnStack() )
1458 		m_returnValueSize = m_initialFunction->returnType.GetSizeInMemoryDWords();
1459 	else
1460 		m_returnValueSize = 0;
1461 
1462 	// Pop the current script function. This will also restore the previous stack pointer
1463 	PopCallState();
1464 
1465 	m_status = asEXECUTION_ACTIVE;
1466 
1467 	return asSUCCESS;
1468 }
1469 
PushCallState()1470 void asCContext::PushCallState()
1471 {
1472 	if( m_callStack.GetLength() == m_callStack.GetCapacity() )
1473 	{
1474 		// Allocate space for 10 call states at a time to save time
1475 		m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true);
1476 	}
1477 	m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE);
1478 
1479     // Separating the loads and stores limits data cache trash, and with a smart compiler
1480     // could turn into SIMD style loading/storing if available.
1481     // The compiler can't do this itself due to potential pointer aliasing between the pointers,
1482     // ie writing to tmp could overwrite the data contained in registers.stackFramePointer for example
1483     // for all the compiler knows. So introducing the local variable s, which is never referred to by
1484     // its address we avoid this issue.
1485 
1486 	asPWORD s[5];
1487 	s[0] = (asPWORD)m_regs.stackFramePointer;
1488 	s[1] = (asPWORD)m_currentFunction;
1489 	s[2] = (asPWORD)m_regs.programPointer;
1490 	s[3] = (asPWORD)m_regs.stackPointer;
1491 	s[4] = m_stackIndex;
1492 
1493 	asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
1494 	tmp[0] = s[0];
1495 	tmp[1] = s[1];
1496 	tmp[2] = s[2];
1497 	tmp[3] = s[3];
1498 	tmp[4] = s[4];
1499 }
1500 
PopCallState()1501 void asCContext::PopCallState()
1502 {
1503 	// See comments in PushCallState about pointer aliasing and data cache trashing
1504 	asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
1505 	asPWORD s[5];
1506 	s[0] = tmp[0];
1507 	s[1] = tmp[1];
1508 	s[2] = tmp[2];
1509 	s[3] = tmp[3];
1510 	s[4] = tmp[4];
1511 
1512 	m_regs.stackFramePointer = (asDWORD*)s[0];
1513 	m_currentFunction        = (asCScriptFunction*)s[1];
1514 	m_regs.programPointer    = (asDWORD*)s[2];
1515 	m_regs.stackPointer      = (asDWORD*)s[3];
1516 	m_stackIndex             = (int)s[4];
1517 
1518 	m_callStack.SetLength(m_callStack.GetLength() - CALLSTACK_FRAME_SIZE);
1519 }
1520 
1521 // interface
GetCallstackSize() const1522 asUINT asCContext::GetCallstackSize() const
1523 {
1524 	if( m_currentFunction == 0 ) return 0;
1525 
1526 	// The current function is accessed at stackLevel 0
1527 	return asUINT(1 + m_callStack.GetLength() / CALLSTACK_FRAME_SIZE);
1528 }
1529 
1530 // interface
GetFunction(asUINT stackLevel)1531 asIScriptFunction *asCContext::GetFunction(asUINT stackLevel)
1532 {
1533 	if( stackLevel >= GetCallstackSize() ) return 0;
1534 
1535 	if( stackLevel == 0 ) return m_currentFunction;
1536 
1537 	asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize() - stackLevel - 1)*CALLSTACK_FRAME_SIZE;
1538 	asCScriptFunction *func = (asCScriptFunction*)s[1];
1539 
1540 	return func;
1541 }
1542 
1543 // interface
GetLineNumber(asUINT stackLevel,int * column,const char ** sectionName)1544 int asCContext::GetLineNumber(asUINT stackLevel, int *column, const char **sectionName)
1545 {
1546 	if( stackLevel >= GetCallstackSize() ) return asINVALID_ARG;
1547 
1548 	asCScriptFunction *func;
1549 	asDWORD *bytePos;
1550 	if( stackLevel == 0 )
1551 	{
1552 		func = m_currentFunction;
1553 		if( func->scriptData == 0 ) return 0;
1554 		bytePos = m_regs.programPointer;
1555 	}
1556 	else
1557 	{
1558 		asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
1559 		func = (asCScriptFunction*)s[1];
1560 		if( func->scriptData == 0 ) return 0;
1561 		bytePos = (asDWORD*)s[2];
1562 
1563 		// Subract 1 from the bytePos, because we want the line where
1564 		// the call was made, and not the instruction after the call
1565 		bytePos -= 1;
1566 	}
1567 
1568 	// For nested calls it is possible that func is null
1569 	if( func == 0 )
1570 	{
1571 		if( column ) *column = 0;
1572 		if( sectionName ) *sectionName = 0;
1573 		return 0;
1574 	}
1575 
1576 	int sectionIdx;
1577 	asDWORD line = func->GetLineNumber(int(bytePos - func->scriptData->byteCode.AddressOf()), &sectionIdx);
1578 	if( column ) *column = (line >> 20);
1579 	if( sectionName )
1580 	{
1581 		asASSERT( sectionIdx < int(m_engine->scriptSectionNames.GetLength()) );
1582 		if( sectionIdx >= 0 && asUINT(sectionIdx) < m_engine->scriptSectionNames.GetLength() )
1583 			*sectionName = m_engine->scriptSectionNames[sectionIdx]->AddressOf();
1584 		else
1585 			*sectionName = 0;
1586 	}
1587 	return (line & 0xFFFFF);
1588 }
1589 
1590 // internal
ReserveStackSpace(asUINT size)1591 bool asCContext::ReserveStackSpace(asUINT size)
1592 {
1593 #ifdef WIP_16BYTE_ALIGN
1594 	// Pad size to a multiple of MAX_TYPE_ALIGNMENT.
1595 	const asUINT remainder = size % MAX_TYPE_ALIGNMENT;
1596 	if(remainder != 0)
1597 	{
1598 		size = size + (MAX_TYPE_ALIGNMENT - (size % MAX_TYPE_ALIGNMENT));
1599 	}
1600 #endif
1601 
1602 	// Make sure the first stack block is allocated
1603 	if( m_stackBlocks.GetLength() == 0 )
1604 	{
1605 		m_stackBlockSize = m_engine->initialContextStackSize;
1606 		asASSERT( m_stackBlockSize > 0 );
1607 
1608 #ifndef WIP_16BYTE_ALIGN
1609 		asDWORD *stack = asNEWARRAY(asDWORD,m_stackBlockSize);
1610 #else
1611 		asDWORD *stack = asNEWARRAYALIGNED(asDWORD, m_stackBlockSize, MAX_TYPE_ALIGNMENT);
1612 #endif
1613 		if( stack == 0 )
1614 		{
1615 			// Out of memory
1616 			return false;
1617 		}
1618 
1619 #ifdef WIP_16BYTE_ALIGN
1620 		asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) );
1621 #endif
1622 
1623 		m_stackBlocks.PushLast(stack);
1624 		m_stackIndex = 0;
1625 		m_regs.stackPointer = m_stackBlocks[0] + m_stackBlockSize;
1626 
1627 #ifdef WIP_16BYTE_ALIGN
1628 		// Align the stack pointer. This is necessary as the m_stackBlockSize is not necessarily evenly divisable with the max alignment
1629 		((asPWORD&)m_regs.stackPointer) &= ~(MAX_TYPE_ALIGNMENT-1);
1630 
1631 		asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) );
1632 #endif
1633 	}
1634 
1635 	// Check if there is enough space on the current stack block, otherwise move
1636 	// to the next one. New and larger blocks will be allocated as necessary
1637 	while( m_regs.stackPointer - (size + RESERVE_STACK) < m_stackBlocks[m_stackIndex] )
1638 	{
1639 		// Make sure we don't allocate more space than allowed
1640 		if( m_engine->ep.maximumContextStackSize )
1641 		{
1642 			// This test will only stop growth once it has already crossed the limit
1643 			if( m_stackBlockSize * ((1 << (m_stackIndex+1)) - 1) > m_engine->ep.maximumContextStackSize )
1644 			{
1645 				m_isStackMemoryNotAllocated = true;
1646 
1647 				// Set the stackFramePointer, even though the stackPointer wasn't updated
1648 				m_regs.stackFramePointer = m_regs.stackPointer;
1649 
1650 				SetInternalException(TXT_STACK_OVERFLOW);
1651 				return false;
1652 			}
1653 		}
1654 
1655 		m_stackIndex++;
1656 		if( m_stackBlocks.GetLength() == m_stackIndex )
1657 		{
1658 			// Allocate the new stack block, with twice the size of the previous
1659 #ifndef WIP_16BYTE_ALIGN
1660 			asDWORD *stack = asNEWARRAY(asDWORD, (m_stackBlockSize << m_stackIndex));
1661 #else
1662 			asDWORD *stack = asNEWARRAYALIGNED(asDWORD, (m_stackBlockSize << m_stackIndex), MAX_TYPE_ALIGNMENT);
1663 #endif
1664 			if( stack == 0 )
1665 			{
1666 				// Out of memory
1667 				m_isStackMemoryNotAllocated = true;
1668 
1669 				// Set the stackFramePointer, even though the stackPointer wasn't updated
1670 				m_regs.stackFramePointer = m_regs.stackPointer;
1671 
1672 				SetInternalException(TXT_STACK_OVERFLOW);
1673 				return false;
1674 			}
1675 
1676 #ifdef WIP_16BYTE_ALIGN
1677 			asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) );
1678 #endif
1679 
1680 			m_stackBlocks.PushLast(stack);
1681 		}
1682 
1683 		// Update the stack pointer to point to the new block.
1684 		// Leave enough room above the stackpointer to copy the arguments from the previous stackblock
1685 		m_regs.stackPointer = m_stackBlocks[m_stackIndex] +
1686 			                  (m_stackBlockSize<<m_stackIndex) -
1687 			                  m_currentFunction->GetSpaceNeededForArguments() -
1688 			                  (m_currentFunction->objectType ? AS_PTR_SIZE : 0) -
1689 			                  (m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0);
1690 
1691 #ifdef WIP_16BYTE_ALIGN
1692 		// Align the stack pointer
1693 		(asPWORD&)m_regs.stackPointer &= ~(MAX_TYPE_ALIGNMENT-1);
1694 
1695 		asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) );
1696 #endif
1697 	}
1698 
1699 	return true;
1700 }
1701 
1702 // internal
CallScriptFunction(asCScriptFunction * func)1703 void asCContext::CallScriptFunction(asCScriptFunction *func)
1704 {
1705 	asASSERT( func->scriptData );
1706 
1707 	// Push the framepointer, function id and programCounter on the stack
1708 	PushCallState();
1709 
1710 	// Update the current function and program position before increasing the stack
1711 	// so the exception handler will know what to do if there is a stack overflow
1712 	m_currentFunction = func;
1713 	m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf();
1714 
1715 	PrepareScriptFunction();
1716 }
1717 
PrepareScriptFunction()1718 void asCContext::PrepareScriptFunction()
1719 {
1720 	asASSERT( m_currentFunction->scriptData );
1721 
1722 	// Make sure there is space on the stack to execute the function
1723 	asDWORD *oldStackPointer = m_regs.stackPointer;
1724 	if( !ReserveStackSpace(m_currentFunction->scriptData->stackNeeded) )
1725 		return;
1726 
1727 	// If a new stack block was allocated then we'll need to move
1728 	// over the function arguments to the new block.
1729 	if( m_regs.stackPointer != oldStackPointer )
1730 	{
1731 		int numDwords = m_currentFunction->GetSpaceNeededForArguments() +
1732 		                (m_currentFunction->objectType ? AS_PTR_SIZE : 0) +
1733 		                (m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0);
1734 		memcpy(m_regs.stackPointer, oldStackPointer, sizeof(asDWORD)*numDwords);
1735 	}
1736 
1737 	// Update framepointer
1738 	m_regs.stackFramePointer = m_regs.stackPointer;
1739 
1740 	// Set all object variables to 0 to guarantee that they are null before they are used
1741 	// Only variables on the heap should be cleared. The rest will be cleared by calling the constructor
1742 	asUINT n = m_currentFunction->scriptData->objVariablesOnHeap;
1743 	while( n-- > 0 )
1744 	{
1745 		int pos = m_currentFunction->scriptData->objVariablePos[n];
1746 		*(asPWORD*)&m_regs.stackFramePointer[-pos] = 0;
1747 	}
1748 
1749 	// Initialize the stack pointer with the space needed for local variables
1750 	m_regs.stackPointer -= m_currentFunction->scriptData->variableSpace;
1751 
1752 	// Call the line callback for each script function, to guarantee that infinitely recursive scripts can
1753 	// be interrupted, even if the scripts have been compiled with asEP_BUILD_WITHOUT_LINE_CUES
1754 	if( m_regs.doProcessSuspend )
1755 	{
1756 		if( m_lineCallback )
1757 			CallLineCallback();
1758 		if( m_doSuspend )
1759 			m_status = asEXECUTION_SUSPENDED;
1760 	}
1761 }
1762 
CallInterfaceMethod(asCScriptFunction * func)1763 void asCContext::CallInterfaceMethod(asCScriptFunction *func)
1764 {
1765 	// Resolve the interface method using the current script type
1766 	asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackPointer;
1767 	if( obj == 0 )
1768 	{
1769 		// Tell the exception handler to clean up the arguments to this method
1770 		m_needToCleanupArgs = true;
1771 		SetInternalException(TXT_NULL_POINTER_ACCESS);
1772 		return;
1773 	}
1774 
1775 	asCObjectType *objType = obj->objType;
1776 
1777 	// Search the object type for a function that matches the interface function
1778 	asCScriptFunction *realFunc = 0;
1779 	if( func->funcType == asFUNC_INTERFACE )
1780 	{
1781 		// Find the offset for the interface's virtual function table chunk
1782 		asUINT offset = 0;
1783 		bool found = false;
1784 		asCObjectType *findInterface = func->objectType;
1785 
1786 		// TODO: runtime optimize: The list of interfaces should be ordered by the address
1787 		//                         Then a binary search pattern can be used.
1788 		asUINT intfCount = asUINT(objType->interfaces.GetLength());
1789 		for( asUINT n = 0; n < intfCount; n++ )
1790 		{
1791 			if( objType->interfaces[n] == findInterface )
1792 			{
1793 				offset = objType->interfaceVFTOffsets[n];
1794 				found = true;
1795 				break;
1796 			}
1797 		}
1798 
1799 		if( !found )
1800 		{
1801 			// Tell the exception handler to clean up the arguments to this method
1802 			m_needToCleanupArgs = true;
1803 			SetInternalException(TXT_NULL_POINTER_ACCESS);
1804 			return;
1805 		}
1806 
1807 		// Find the real function in the virtual table chunk with the found offset
1808 		realFunc = objType->virtualFunctionTable[func->vfTableIdx + offset];
1809 
1810 		// Since the interface was implemented by the class, it shouldn't
1811 		// be possible that the real function isn't found
1812 		asASSERT( realFunc );
1813 
1814 		asASSERT( realFunc->signatureId == func->signatureId );
1815 	}
1816 	else // if( func->funcType == asFUNC_VIRTUAL )
1817 	{
1818 		realFunc = objType->virtualFunctionTable[func->vfTableIdx];
1819 	}
1820 
1821 	// Then call the true script function
1822 	CallScriptFunction(realFunc);
1823 }
1824 
ExecuteNext()1825 void asCContext::ExecuteNext()
1826 {
1827 	asDWORD *l_bc = m_regs.programPointer;
1828 	asDWORD *l_sp = m_regs.stackPointer;
1829 	asDWORD *l_fp = m_regs.stackFramePointer;
1830 
1831 	for(;;)
1832 	{
1833 
1834 #ifdef AS_DEBUG
1835 	// Gather statistics on executed bytecode
1836 	stats.Instr(*(asBYTE*)l_bc);
1837 
1838 	// Used to verify that the size of the instructions are correct
1839 	asDWORD *old = l_bc;
1840 #endif
1841 
1842 
1843 	// Remember to keep the cases in order and without
1844 	// gaps, because that will make the switch faster.
1845 	// It will be faster since only one lookup will be
1846 	// made to find the correct jump destination. If not
1847 	// in order, the switch will make two lookups.
1848 	switch( *(asBYTE*)l_bc )
1849 	{
1850 //--------------
1851 // memory access functions
1852 
1853 	case asBC_PopPtr:
1854 		// Pop a pointer from the stack
1855 		l_sp += AS_PTR_SIZE;
1856 		l_bc++;
1857 		break;
1858 
1859 	case asBC_PshGPtr:
1860 		// Replaces PGA + RDSPtr
1861 		l_sp -= AS_PTR_SIZE;
1862 		*(asPWORD*)l_sp = *(asPWORD*)asBC_PTRARG(l_bc);
1863 		l_bc += 1 + AS_PTR_SIZE;
1864 		break;
1865 
1866 	// Push a dword value on the stack
1867 	case asBC_PshC4:
1868 		--l_sp;
1869 		*l_sp = asBC_DWORDARG(l_bc);
1870 		l_bc += 2;
1871 		break;
1872 
1873 	// Push the dword value of a variable on the stack
1874 	case asBC_PshV4:
1875 		--l_sp;
1876 		*l_sp = *(l_fp - asBC_SWORDARG0(l_bc));
1877 		l_bc++;
1878 		break;
1879 
1880 	// Push the address of a variable on the stack
1881 	case asBC_PSF:
1882 		l_sp -= AS_PTR_SIZE;
1883 		*(asPWORD*)l_sp = asPWORD(l_fp - asBC_SWORDARG0(l_bc));
1884 		l_bc++;
1885 		break;
1886 
1887 	// Swap the top 2 pointers on the stack
1888 	case asBC_SwapPtr:
1889 		{
1890 			asPWORD p = *(asPWORD*)l_sp;
1891 			*(asPWORD*)l_sp = *(asPWORD*)(l_sp+AS_PTR_SIZE);
1892 			*(asPWORD*)(l_sp+AS_PTR_SIZE) = p;
1893 			l_bc++;
1894 		}
1895 		break;
1896 
1897 	// Do a boolean not operation, modifying the value of the variable
1898 	case asBC_NOT:
1899 #if AS_SIZEOF_BOOL == 1
1900 		{
1901 			// Set the value to true if it is equal to 0
1902 
1903 			// We need to use volatile here to tell the compiler it cannot
1904 			// change the order of read and write operations on the pointer.
1905 
1906 			volatile asBYTE *ptr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
1907 			asBYTE val = (ptr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
1908 			ptr[0] = val; // The result is stored in the lower byte
1909 			ptr[1] = 0;   // Make sure the rest of the DWORD is 0
1910 			ptr[2] = 0;
1911 			ptr[3] = 0;
1912 		}
1913 #else
1914 		*(l_fp - asBC_SWORDARG0(l_bc)) = (*(l_fp - asBC_SWORDARG0(l_bc)) == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
1915 #endif
1916 		l_bc++;
1917 		break;
1918 
1919 	// Push the dword value of a global variable on the stack
1920 	case asBC_PshG4:
1921 		--l_sp;
1922 		*l_sp = *(asDWORD*)asBC_PTRARG(l_bc);
1923 		l_bc += 1 + AS_PTR_SIZE;
1924 		break;
1925 
1926 	// Load the address of a global variable in the register, then
1927 	// copy the value of the global variable into a local variable
1928 	case asBC_LdGRdR4:
1929 		*(void**)&m_regs.valueRegister = (void*)asBC_PTRARG(l_bc);
1930 		*(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&m_regs.valueRegister;
1931 		l_bc += 1+AS_PTR_SIZE;
1932 		break;
1933 
1934 //----------------
1935 // path control instructions
1936 
1937 	// Begin execution of a script function
1938 	case asBC_CALL:
1939 		{
1940 			int i = asBC_INTARG(l_bc);
1941 			l_bc += 2;
1942 
1943 			asASSERT( i >= 0 );
1944 			asASSERT( (i & FUNC_IMPORTED) == 0 );
1945 
1946 			// Need to move the values back to the context
1947 			m_regs.programPointer = l_bc;
1948 			m_regs.stackPointer = l_sp;
1949 			m_regs.stackFramePointer = l_fp;
1950 
1951 			CallScriptFunction(m_engine->scriptFunctions[i]);
1952 
1953 			// Extract the values from the context again
1954 			l_bc = m_regs.programPointer;
1955 			l_sp = m_regs.stackPointer;
1956 			l_fp = m_regs.stackFramePointer;
1957 
1958 			// If status isn't active anymore then we must stop
1959 			if( m_status != asEXECUTION_ACTIVE )
1960 				return;
1961 		}
1962 		break;
1963 
1964 	// Return to the caller, and remove the arguments from the stack
1965 	case asBC_RET:
1966 		{
1967 			// Return if this was the first function, or a nested execution
1968 			if( m_callStack.GetLength() == 0 ||
1969 				m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE] == 0 )
1970 			{
1971 				m_status = asEXECUTION_FINISHED;
1972 				return;
1973 			}
1974 
1975 			asWORD w = asBC_WORDARG0(l_bc);
1976 
1977 			// Read the old framepointer, functionid, and programCounter from the call stack
1978 			PopCallState();
1979 
1980 			// Extract the values from the context again
1981 			l_bc = m_regs.programPointer;
1982 			l_sp = m_regs.stackPointer;
1983 			l_fp = m_regs.stackFramePointer;
1984 
1985 			// Pop arguments from stack
1986 			l_sp += w;
1987 		}
1988 		break;
1989 
1990 	// Jump to a relative position
1991 	case asBC_JMP:
1992 		l_bc += 2 + asBC_INTARG(l_bc);
1993 		break;
1994 
1995 //----------------
1996 // Conditional jumps
1997 
1998 	// Jump to a relative position if the value in the register is 0
1999 	case asBC_JZ:
2000 		if( *(int*)&m_regs.valueRegister == 0 )
2001 			l_bc += asBC_INTARG(l_bc) + 2;
2002 		else
2003 			l_bc += 2;
2004 		break;
2005 
2006 	// Jump to a relative position if the value in the register is not 0
2007 	case asBC_JNZ:
2008 		if( *(int*)&m_regs.valueRegister != 0 )
2009 			l_bc += asBC_INTARG(l_bc) + 2;
2010 		else
2011 			l_bc += 2;
2012 		break;
2013 
2014 	// Jump to a relative position if the value in the register is negative
2015 	case asBC_JS:
2016 		if( *(int*)&m_regs.valueRegister < 0 )
2017 			l_bc += asBC_INTARG(l_bc) + 2;
2018 		else
2019 			l_bc += 2;
2020 		break;
2021 
2022 	// Jump to a relative position if the value in the register it not negative
2023 	case asBC_JNS:
2024 		if( *(int*)&m_regs.valueRegister >= 0 )
2025 			l_bc += asBC_INTARG(l_bc) + 2;
2026 		else
2027 			l_bc += 2;
2028 		break;
2029 
2030 	// Jump to a relative position if the value in the register is greater than 0
2031 	case asBC_JP:
2032 		if( *(int*)&m_regs.valueRegister > 0 )
2033 			l_bc += asBC_INTARG(l_bc) + 2;
2034 		else
2035 			l_bc += 2;
2036 		break;
2037 
2038 	// Jump to a relative position if the value in the register is not greater than 0
2039 	case asBC_JNP:
2040 		if( *(int*)&m_regs.valueRegister <= 0 )
2041 			l_bc += asBC_INTARG(l_bc) + 2;
2042 		else
2043 			l_bc += 2;
2044 		break;
2045 //--------------------
2046 // test instructions
2047 
2048 	// If the value in the register is 0, then set the register to 1, else to 0
2049 	case asBC_TZ:
2050 #if AS_SIZEOF_BOOL == 1
2051 		{
2052 			// Set the value to true if it is equal to 0
2053 
2054 			// We need to use volatile here to tell the compiler it cannot
2055 			// change the order of read and write operations on valueRegister.
2056 
2057 			volatile int    *regPtr  = (int*)&m_regs.valueRegister;
2058 			volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
2059 			asBYTE val = (regPtr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
2060 			regBptr[0] = val; // The result is stored in the lower byte
2061 			regBptr[1] = 0;   // Make sure the rest of the register is 0
2062 			regBptr[2] = 0;
2063 			regBptr[3] = 0;
2064 			regBptr[4] = 0;
2065 			regBptr[5] = 0;
2066 			regBptr[6] = 0;
2067 			regBptr[7] = 0;
2068 		}
2069 #else
2070 		*(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
2071 #endif
2072 		l_bc++;
2073 		break;
2074 
2075 	// If the value in the register is not 0, then set the register to 1, else to 0
2076 	case asBC_TNZ:
2077 #if AS_SIZEOF_BOOL == 1
2078 		{
2079 			// Set the value to true if it is not equal to 0
2080 
2081 			// We need to use volatile here to tell the compiler it cannot
2082 			// change the order of read and write operations on valueRegister.
2083 
2084 			volatile int    *regPtr  = (int*)&m_regs.valueRegister;
2085 			volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
2086 			asBYTE val = (regPtr[0] == 0) ? 0 : VALUE_OF_BOOLEAN_TRUE;
2087 			regBptr[0] = val; // The result is stored in the lower byte
2088 			regBptr[1] = 0;   // Make sure the rest of the register is 0
2089 			regBptr[2] = 0;
2090 			regBptr[3] = 0;
2091 			regBptr[4] = 0;
2092 			regBptr[5] = 0;
2093 			regBptr[6] = 0;
2094 			regBptr[7] = 0;
2095 		}
2096 #else
2097 		*(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
2098 #endif
2099 		l_bc++;
2100 		break;
2101 
2102 	// If the value in the register is negative, then set the register to 1, else to 0
2103 	case asBC_TS:
2104 #if AS_SIZEOF_BOOL == 1
2105 		{
2106 			// Set the value to true if it is less than 0
2107 
2108 			// We need to use volatile here to tell the compiler it cannot
2109 			// change the order of read and write operations on valueRegister.
2110 
2111 			volatile int    *regPtr  = (int*)&m_regs.valueRegister;
2112 			volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
2113 			asBYTE val = (regPtr[0] < 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
2114 			regBptr[0] = val; // The result is stored in the lower byte
2115 			regBptr[1] = 0;   // Make sure the rest of the register is 0
2116 			regBptr[2] = 0;
2117 			regBptr[3] = 0;
2118 			regBptr[4] = 0;
2119 			regBptr[5] = 0;
2120 			regBptr[6] = 0;
2121 			regBptr[7] = 0;
2122 		}
2123 #else
2124 		*(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
2125 #endif
2126 		l_bc++;
2127 		break;
2128 
2129 	// If the value in the register is not negative, then set the register to 1, else to 0
2130 	case asBC_TNS:
2131 #if AS_SIZEOF_BOOL == 1
2132 		{
2133 			// Set the value to true if it is not less than 0
2134 
2135 			// We need to use volatile here to tell the compiler it cannot
2136 			// change the order of read and write operations on valueRegister.
2137 
2138 			volatile int    *regPtr  = (int*)&m_regs.valueRegister;
2139 			volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
2140 			asBYTE val = (regPtr[0] >= 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
2141 			regBptr[0] = val; // The result is stored in the lower byte
2142 			regBptr[1] = 0;   // Make sure the rest of the register is 0
2143 			regBptr[2] = 0;
2144 			regBptr[3] = 0;
2145 			regBptr[4] = 0;
2146 			regBptr[5] = 0;
2147 			regBptr[6] = 0;
2148 			regBptr[7] = 0;
2149 		}
2150 #else
2151 		*(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
2152 #endif
2153 		l_bc++;
2154 		break;
2155 
2156 	// If the value in the register is greater than 0, then set the register to 1, else to 0
2157 	case asBC_TP:
2158 #if AS_SIZEOF_BOOL == 1
2159 		{
2160 			// Set the value to true if it is greater than 0
2161 
2162 			// We need to use volatile here to tell the compiler it cannot
2163 			// change the order of read and write operations on valueRegister.
2164 
2165 			volatile int    *regPtr  = (int*)&m_regs.valueRegister;
2166 			volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
2167 			asBYTE val = (regPtr[0] > 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
2168 			regBptr[0] = val; // The result is stored in the lower byte
2169 			regBptr[1] = 0;   // Make sure the rest of the register is 0
2170 			regBptr[2] = 0;
2171 			regBptr[3] = 0;
2172 			regBptr[4] = 0;
2173 			regBptr[5] = 0;
2174 			regBptr[6] = 0;
2175 			regBptr[7] = 0;
2176 		}
2177 #else
2178 		*(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
2179 #endif
2180 		l_bc++;
2181 		break;
2182 
2183 	// If the value in the register is not greater than 0, then set the register to 1, else to 0
2184 	case asBC_TNP:
2185 #if AS_SIZEOF_BOOL == 1
2186 		{
2187 			// Set the value to true if it is not greater than 0
2188 
2189 			// We need to use volatile here to tell the compiler it cannot
2190 			// change the order of read and write operations on valueRegister.
2191 
2192 			volatile int    *regPtr  = (int*)&m_regs.valueRegister;
2193 			volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister;
2194 			asBYTE val = (regPtr[0] <= 0) ? VALUE_OF_BOOLEAN_TRUE : 0;
2195 			regBptr[0] = val; // The result is stored in the lower byte
2196 			regBptr[1] = 0;   // Make sure the rest of the register is 0
2197 			regBptr[2] = 0;
2198 			regBptr[3] = 0;
2199 			regBptr[4] = 0;
2200 			regBptr[5] = 0;
2201 			regBptr[6] = 0;
2202 			regBptr[7] = 0;
2203 		}
2204 #else
2205 		*(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? 0 : VALUE_OF_BOOLEAN_TRUE);
2206 #endif
2207 		l_bc++;
2208 		break;
2209 
2210 //--------------------
2211 // negate value
2212 
2213 	// Negate the integer value in the variable
2214 	case asBC_NEGi:
2215 		*(l_fp - asBC_SWORDARG0(l_bc)) = asDWORD(-int(*(l_fp - asBC_SWORDARG0(l_bc))));
2216 		l_bc++;
2217 		break;
2218 
2219 	// Negate the float value in the variable
2220 	case asBC_NEGf:
2221 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(float*)(l_fp - asBC_SWORDARG0(l_bc));
2222 		l_bc++;
2223 		break;
2224 
2225 	// Negate the double value in the variable
2226 	case asBC_NEGd:
2227 		*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(double*)(l_fp - asBC_SWORDARG0(l_bc));
2228 		l_bc++;
2229 		break;
2230 
2231 //-------------------------
2232 // Increment value pointed to by address in register
2233 
2234 	// Increment the short value pointed to by the register
2235 	case asBC_INCi16:
2236 		(**(short**)&m_regs.valueRegister)++;
2237 		l_bc++;
2238 		break;
2239 
2240 	// Increment the byte value pointed to by the register
2241 	case asBC_INCi8:
2242 		(**(char**)&m_regs.valueRegister)++;
2243 		l_bc++;
2244 		break;
2245 
2246 	// Decrement the short value pointed to by the register
2247 	case asBC_DECi16:
2248 		(**(short**)&m_regs.valueRegister)--;
2249 		l_bc++;
2250 		break;
2251 
2252 	// Decrement the byte value pointed to by the register
2253 	case asBC_DECi8:
2254 		(**(char**)&m_regs.valueRegister)--;
2255 		l_bc++;
2256 		break;
2257 
2258 	// Increment the integer value pointed to by the register
2259 	case asBC_INCi:
2260 		++(**(int**)&m_regs.valueRegister);
2261 		l_bc++;
2262 		break;
2263 
2264 	// Decrement the integer value pointed to by the register
2265 	case asBC_DECi:
2266 		--(**(int**)&m_regs.valueRegister);
2267 		l_bc++;
2268 		break;
2269 
2270 	// Increment the float value pointed to by the register
2271 	case asBC_INCf:
2272 		++(**(float**)&m_regs.valueRegister);
2273 		l_bc++;
2274 		break;
2275 
2276 	// Decrement the float value pointed to by the register
2277 	case asBC_DECf:
2278 		--(**(float**)&m_regs.valueRegister);
2279 		l_bc++;
2280 		break;
2281 
2282 	// Increment the double value pointed to by the register
2283 	case asBC_INCd:
2284 		++(**(double**)&m_regs.valueRegister);
2285 		l_bc++;
2286 		break;
2287 
2288 	// Decrement the double value pointed to by the register
2289 	case asBC_DECd:
2290 		--(**(double**)&m_regs.valueRegister);
2291 		l_bc++;
2292 		break;
2293 
2294 	// Increment the local integer variable
2295 	case asBC_IncVi:
2296 		(*(int*)(l_fp - asBC_SWORDARG0(l_bc)))++;
2297 		l_bc++;
2298 		break;
2299 
2300 	// Decrement the local integer variable
2301 	case asBC_DecVi:
2302 		(*(int*)(l_fp - asBC_SWORDARG0(l_bc)))--;
2303 		l_bc++;
2304 		break;
2305 
2306 //--------------------
2307 // bits instructions
2308 
2309 	// Do a bitwise not on the value in the variable
2310 	case asBC_BNOT:
2311 		*(l_fp - asBC_SWORDARG0(l_bc)) = ~*(l_fp - asBC_SWORDARG0(l_bc));
2312 		l_bc++;
2313 		break;
2314 
2315 	// Do a bitwise and of two variables and store the result in a third variable
2316 	case asBC_BAND:
2317 		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) & *(l_fp - asBC_SWORDARG2(l_bc));
2318 		l_bc += 2;
2319 		break;
2320 
2321 	// Do a bitwise or of two variables and store the result in a third variable
2322 	case asBC_BOR:
2323 		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) | *(l_fp - asBC_SWORDARG2(l_bc));
2324 		l_bc += 2;
2325 		break;
2326 
2327 	// Do a bitwise xor of two variables and store the result in a third variable
2328 	case asBC_BXOR:
2329 		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) ^ *(l_fp - asBC_SWORDARG2(l_bc));
2330 		l_bc += 2;
2331 		break;
2332 
2333 	// Do a logical shift left of two variables and store the result in a third variable
2334 	case asBC_BSLL:
2335 		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc));
2336 		l_bc += 2;
2337 		break;
2338 
2339 	// Do a logical shift right of two variables and store the result in a third variable
2340 	case asBC_BSRL:
2341 		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
2342 		l_bc += 2;
2343 		break;
2344 
2345 	// Do an arithmetic shift right of two variables and store the result in a third variable
2346 	case asBC_BSRA:
2347 		*(l_fp - asBC_SWORDARG0(l_bc)) = int(*(l_fp - asBC_SWORDARG1(l_bc))) >> *(l_fp - asBC_SWORDARG2(l_bc));
2348 		l_bc += 2;
2349 		break;
2350 
2351 	case asBC_COPY:
2352 		{
2353 			void *d = (void*)*(asPWORD*)l_sp; l_sp += AS_PTR_SIZE;
2354 			void *s = (void*)*(asPWORD*)l_sp;
2355 			if( s == 0 || d == 0 )
2356 			{
2357 				// Need to move the values back to the context
2358 				m_regs.programPointer    = l_bc;
2359 				m_regs.stackPointer      = l_sp;
2360 				m_regs.stackFramePointer = l_fp;
2361 
2362 				// Raise exception
2363 				SetInternalException(TXT_NULL_POINTER_ACCESS);
2364 				return;
2365 			}
2366 			memcpy(d, s, asBC_WORDARG0(l_bc)*4);
2367 
2368 			// replace the pointer on the stack with the lvalue
2369 			*(asPWORD**)l_sp = (asPWORD*)d;
2370 		}
2371 		l_bc += 2;
2372 		break;
2373 
2374 	case asBC_PshC8:
2375 		l_sp -= 2;
2376 		*(asQWORD*)l_sp = asBC_QWORDARG(l_bc);
2377 		l_bc += 3;
2378 		break;
2379 
2380 	case asBC_PshVPtr:
2381 		l_sp -= AS_PTR_SIZE;
2382 		*(asPWORD*)l_sp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
2383 		l_bc++;
2384 		break;
2385 
2386 	case asBC_RDSPtr:
2387 		{
2388 			// The pointer must not be null
2389 			asPWORD a = *(asPWORD*)l_sp;
2390 			if( a == 0 )
2391 			{
2392 				m_regs.programPointer    = l_bc;
2393 				m_regs.stackPointer      = l_sp;
2394 				m_regs.stackFramePointer = l_fp;
2395 
2396 				SetInternalException(TXT_NULL_POINTER_ACCESS);
2397 				return;
2398 			}
2399 			// Pop an address from the stack, read a pointer from that address and push it on the stack
2400 			*(asPWORD*)l_sp = *(asPWORD*)a;
2401 		}
2402 		l_bc++;
2403 		break;
2404 
2405 	//----------------------------
2406 	// Comparisons
2407 	case asBC_CMPd:
2408 		{
2409 			// Do a comparison of the values, rather than a subtraction
2410 			// in order to get proper behaviour for infinity values.
2411 			double dbl1 = *(double*)(l_fp - asBC_SWORDARG0(l_bc));
2412 			double dbl2 = *(double*)(l_fp - asBC_SWORDARG1(l_bc));
2413 			if( dbl1 == dbl2 )     *(int*)&m_regs.valueRegister =  0;
2414 			else if( dbl1 < dbl2 ) *(int*)&m_regs.valueRegister = -1;
2415 			else                   *(int*)&m_regs.valueRegister =  1;
2416 			l_bc += 2;
2417 		}
2418 		break;
2419 
2420 	case asBC_CMPu:
2421 		{
2422 			asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
2423 			asDWORD d2 = *(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc));
2424 			if( d1 == d2 )     *(int*)&m_regs.valueRegister =  0;
2425 			else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1;
2426 			else               *(int*)&m_regs.valueRegister =  1;
2427 			l_bc += 2;
2428 		}
2429 		break;
2430 
2431 	case asBC_CMPf:
2432 		{
2433 			// Do a comparison of the values, rather than a subtraction
2434 			// in order to get proper behaviour for infinity values.
2435 			float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc));
2436 			float f2 = *(float*)(l_fp - asBC_SWORDARG1(l_bc));
2437 			if( f1 == f2 )     *(int*)&m_regs.valueRegister =  0;
2438 			else if( f1 < f2 ) *(int*)&m_regs.valueRegister = -1;
2439 			else               *(int*)&m_regs.valueRegister =  1;
2440 			l_bc += 2;
2441 		}
2442 		break;
2443 
2444 	case asBC_CMPi:
2445 		{
2446 			int i1 = *(int*)(l_fp - asBC_SWORDARG0(l_bc));
2447 			int i2 = *(int*)(l_fp - asBC_SWORDARG1(l_bc));
2448 			if( i1 == i2 )     *(int*)&m_regs.valueRegister =  0;
2449 			else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1;
2450 			else               *(int*)&m_regs.valueRegister =  1;
2451 			l_bc += 2;
2452 		}
2453 		break;
2454 
2455 	//----------------------------
2456 	// Comparisons with constant value
2457 	case asBC_CMPIi:
2458 		{
2459 			int i1 = *(int*)(l_fp - asBC_SWORDARG0(l_bc));
2460 			int i2 = asBC_INTARG(l_bc);
2461 			if( i1 == i2 )     *(int*)&m_regs.valueRegister =  0;
2462 			else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1;
2463 			else               *(int*)&m_regs.valueRegister =  1;
2464 			l_bc += 2;
2465 		}
2466 		break;
2467 
2468 	case asBC_CMPIf:
2469 		{
2470 			// Do a comparison of the values, rather than a subtraction
2471 			// in order to get proper behaviour for infinity values.
2472 			float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc));
2473 			float f2 = asBC_FLOATARG(l_bc);
2474 			if( f1 == f2 )     *(int*)&m_regs.valueRegister =  0;
2475 			else if( f1 < f2 ) *(int*)&m_regs.valueRegister = -1;
2476 			else               *(int*)&m_regs.valueRegister =  1;
2477 			l_bc += 2;
2478 		}
2479 		break;
2480 
2481 	case asBC_CMPIu:
2482 		{
2483 			asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
2484 			asDWORD d2 = asBC_DWORDARG(l_bc);
2485 			if( d1 == d2 )     *(int*)&m_regs.valueRegister =  0;
2486 			else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1;
2487 			else               *(int*)&m_regs.valueRegister =  1;
2488 			l_bc += 2;
2489 		}
2490 		break;
2491 
2492 	case asBC_JMPP:
2493 		l_bc += 1 + (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))*2;
2494 		break;
2495 
2496 	case asBC_PopRPtr:
2497 		*(asPWORD*)&m_regs.valueRegister = *(asPWORD*)l_sp;
2498 		l_sp += AS_PTR_SIZE;
2499 		l_bc++;
2500 		break;
2501 
2502 	case asBC_PshRPtr:
2503 		l_sp -= AS_PTR_SIZE;
2504 		*(asPWORD*)l_sp = *(asPWORD*)&m_regs.valueRegister;
2505 		l_bc++;
2506 		break;
2507 
2508 	case asBC_STR:
2509 		// TODO: NEWSTRING: Deprecate this instruction
2510 		asASSERT(false);
2511 		l_bc++;
2512 		break;
2513 
2514 	case asBC_CALLSYS:
2515 		{
2516 			// Get function ID from the argument
2517 			int i = asBC_INTARG(l_bc);
2518 
2519 			// Need to move the values back to the context as the called functions
2520 			// may use the debug interface to inspect the registers
2521 			m_regs.programPointer    = l_bc;
2522 			m_regs.stackPointer      = l_sp;
2523 			m_regs.stackFramePointer = l_fp;
2524 
2525 			l_sp += CallSystemFunction(i, this);
2526 
2527 			// Update the program position after the call so that line number is correct
2528 			l_bc += 2;
2529 
2530 			if( m_regs.doProcessSuspend )
2531 			{
2532 				// Should the execution be suspended?
2533 				if( m_doSuspend )
2534 				{
2535 					m_regs.programPointer    = l_bc;
2536 					m_regs.stackPointer      = l_sp;
2537 					m_regs.stackFramePointer = l_fp;
2538 
2539 					m_status = asEXECUTION_SUSPENDED;
2540 					return;
2541 				}
2542 				// An exception might have been raised
2543 				if( m_status != asEXECUTION_ACTIVE )
2544 				{
2545 					m_regs.programPointer    = l_bc;
2546 					m_regs.stackPointer      = l_sp;
2547 					m_regs.stackFramePointer = l_fp;
2548 
2549 					return;
2550 				}
2551 			}
2552 		}
2553 		break;
2554 
2555 	case asBC_CALLBND:
2556 		{
2557 			// TODO: Clean-up: This code is very similar to asBC_CallPtr. Create a shared method for them
2558 			// Get the function ID from the stack
2559 			int i = asBC_INTARG(l_bc);
2560 
2561 			asASSERT( i >= 0 );
2562 			asASSERT( i & FUNC_IMPORTED );
2563 
2564 			// Need to move the values back to the context
2565 			m_regs.programPointer    = l_bc;
2566 			m_regs.stackPointer      = l_sp;
2567 			m_regs.stackFramePointer = l_fp;
2568 
2569 			int funcId = m_engine->importedFunctions[i & ~FUNC_IMPORTED]->boundFunctionId;
2570 			if( funcId == -1 )
2571 			{
2572 				// Need to update the program pointer for the exception handler
2573 				m_regs.programPointer += 2;
2574 
2575 				// Tell the exception handler to clean up the arguments to this function
2576 				m_needToCleanupArgs = true;
2577 				SetInternalException(TXT_UNBOUND_FUNCTION);
2578 				return;
2579 			}
2580 			else
2581 			{
2582 				asCScriptFunction *func = m_engine->GetScriptFunction(funcId);
2583 				if( func->funcType == asFUNC_SCRIPT )
2584 				{
2585 					m_regs.programPointer += 2;
2586 					CallScriptFunction(func);
2587 				}
2588 				else if( func->funcType == asFUNC_DELEGATE )
2589 				{
2590 					// Push the object pointer on the stack. There is always a reserved space for this so
2591 					// we don't don't need to worry about overflowing the allocated memory buffer
2592 					asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] );
2593 					m_regs.stackPointer -= AS_PTR_SIZE;
2594 					*(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate);
2595 
2596 					// Call the delegated method
2597 					if( func->funcForDelegate->funcType == asFUNC_SYSTEM )
2598 					{
2599 						m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this);
2600 
2601 						// Update program position after the call so the line number
2602 						// is correct in case the system function queries it
2603 						m_regs.programPointer += 2;
2604 					}
2605 					else
2606 					{
2607 						m_regs.programPointer += 2;
2608 
2609 						// TODO: run-time optimize: The true method could be figured out when creating the delegate
2610 						CallInterfaceMethod(func->funcForDelegate);
2611 					}
2612 				}
2613 				else
2614 				{
2615 					asASSERT( func->funcType == asFUNC_SYSTEM );
2616 
2617 					m_regs.stackPointer += CallSystemFunction(func->id, this);
2618 
2619 					// Update program position after the call so the line number
2620 					// is correct in case the system function queries it
2621 					m_regs.programPointer += 2;
2622 				}
2623 			}
2624 
2625 			// Extract the values from the context again
2626 			l_bc = m_regs.programPointer;
2627 			l_sp = m_regs.stackPointer;
2628 			l_fp = m_regs.stackFramePointer;
2629 
2630 			// If status isn't active anymore then we must stop
2631 			if( m_status != asEXECUTION_ACTIVE )
2632 				return;
2633 		}
2634 		break;
2635 
2636 	case asBC_SUSPEND:
2637 		if( m_regs.doProcessSuspend )
2638 		{
2639 			if( m_lineCallback )
2640 			{
2641 				m_regs.programPointer    = l_bc;
2642 				m_regs.stackPointer      = l_sp;
2643 				m_regs.stackFramePointer = l_fp;
2644 
2645 				CallLineCallback();
2646 			}
2647 			if( m_doSuspend )
2648 			{
2649 				l_bc++;
2650 
2651 				// Need to move the values back to the context
2652 				m_regs.programPointer    = l_bc;
2653 				m_regs.stackPointer      = l_sp;
2654 				m_regs.stackFramePointer = l_fp;
2655 
2656 				m_status = asEXECUTION_SUSPENDED;
2657 				return;
2658 			}
2659 		}
2660 
2661 		l_bc++;
2662 		break;
2663 
2664 	case asBC_ALLOC:
2665 		{
2666 			asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
2667 			int func = asBC_INTARG(l_bc+AS_PTR_SIZE);
2668 
2669 			if( objType->flags & asOBJ_SCRIPT_OBJECT )
2670 			{
2671 				// Need to move the values back to the context as the construction
2672 				// of the script object may reuse the context for nested calls.
2673 				m_regs.programPointer    = l_bc;
2674 				m_regs.stackPointer      = l_sp;
2675 				m_regs.stackFramePointer = l_fp;
2676 
2677 				// Pre-allocate the memory
2678 				asDWORD *mem = (asDWORD*)m_engine->CallAlloc(objType);
2679 
2680 				// Pre-initialize the memory by calling the constructor for asCScriptObject
2681 				ScriptObject_Construct(objType, (asCScriptObject*)mem);
2682 
2683 				// Call the constructor to initalize the memory
2684 				asCScriptFunction *f = m_engine->scriptFunctions[func];
2685 
2686 				asDWORD **a = (asDWORD**)*(asPWORD*)(m_regs.stackPointer + f->GetSpaceNeededForArguments());
2687 				if( a ) *a = mem;
2688 
2689 				// Push the object pointer on the stack
2690 				m_regs.stackPointer -= AS_PTR_SIZE;
2691 				*(asPWORD*)m_regs.stackPointer = (asPWORD)mem;
2692 
2693 				m_regs.programPointer += 2+AS_PTR_SIZE;
2694 
2695 				CallScriptFunction(f);
2696 
2697 				// Extract the values from the context again
2698 				l_bc = m_regs.programPointer;
2699 				l_sp = m_regs.stackPointer;
2700 				l_fp = m_regs.stackFramePointer;
2701 
2702 				// If status isn't active anymore then we must stop
2703 				if( m_status != asEXECUTION_ACTIVE )
2704 					return;
2705 			}
2706 			else
2707 			{
2708 				// Pre-allocate the memory
2709 				asDWORD *mem = (asDWORD*)m_engine->CallAlloc(objType);
2710 
2711 				if( func )
2712 				{
2713 					// Push the object pointer on the stack (it will be popped by the function)
2714 					l_sp -= AS_PTR_SIZE;
2715 					*(asPWORD*)l_sp = (asPWORD)mem;
2716 
2717 					// Need to move the values back to the context as the called functions
2718 					// may use the debug interface to inspect the registers
2719 					m_regs.programPointer    = l_bc;
2720 					m_regs.stackPointer      = l_sp;
2721 					m_regs.stackFramePointer = l_fp;
2722 
2723 					l_sp += CallSystemFunction(func, this);
2724 				}
2725 
2726 				// Pop the variable address from the stack
2727 				asDWORD **a = (asDWORD**)*(asPWORD*)l_sp;
2728 				l_sp += AS_PTR_SIZE;
2729 				if( a ) *a = mem;
2730 
2731 				l_bc += 2+AS_PTR_SIZE;
2732 
2733 				if( m_regs.doProcessSuspend )
2734 				{
2735 					// Should the execution be suspended?
2736 					if( m_doSuspend )
2737 					{
2738 						m_regs.programPointer    = l_bc;
2739 						m_regs.stackPointer      = l_sp;
2740 						m_regs.stackFramePointer = l_fp;
2741 
2742 						m_status = asEXECUTION_SUSPENDED;
2743 						return;
2744 					}
2745 					// An exception might have been raised
2746 					if( m_status != asEXECUTION_ACTIVE )
2747 					{
2748 						m_regs.programPointer    = l_bc;
2749 						m_regs.stackPointer      = l_sp;
2750 						m_regs.stackFramePointer = l_fp;
2751 
2752 						m_engine->CallFree(mem);
2753 						*a = 0;
2754 
2755 						return;
2756 					}
2757 				}
2758 			}
2759 		}
2760 		break;
2761 
2762 	case asBC_FREE:
2763 		{
2764 			// Get the variable that holds the object handle/reference
2765 			asPWORD *a = (asPWORD*)asPWORD(l_fp - asBC_SWORDARG0(l_bc));
2766 			if( *a )
2767 			{
2768 				asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
2769 				asSTypeBehaviour *beh = &objType->beh;
2770 
2771 				// Need to move the values back to the context as the called functions
2772 				// may use the debug interface to inspect the registers
2773 				m_regs.programPointer    = l_bc;
2774 				m_regs.stackPointer      = l_sp;
2775 				m_regs.stackFramePointer = l_fp;
2776 
2777 				if( objType->flags & asOBJ_REF )
2778 				{
2779 					asASSERT( (objType->flags & asOBJ_NOCOUNT) || beh->release );
2780 					if( beh->release )
2781 						m_engine->CallObjectMethod((void*)(asPWORD)*a, beh->release);
2782 				}
2783 				else
2784 				{
2785 					if( beh->destruct )
2786 						m_engine->CallObjectMethod((void*)(asPWORD)*a, beh->destruct);
2787 					else if( objType->flags & asOBJ_LIST_PATTERN )
2788 						m_engine->DestroyList((asBYTE*)(asPWORD)*a, objType);
2789 
2790 					m_engine->CallFree((void*)(asPWORD)*a);
2791 				}
2792 
2793 				// Clear the variable
2794 				*a = 0;
2795 			}
2796 		}
2797 		l_bc += 1+AS_PTR_SIZE;
2798 		break;
2799 
2800 	case asBC_LOADOBJ:
2801 		{
2802 			// Move the object pointer from the object variable into the object register
2803 			void **a = (void**)(l_fp - asBC_SWORDARG0(l_bc));
2804 			m_regs.objectType = 0;
2805 			m_regs.objectRegister = *a;
2806 			*a = 0;
2807 		}
2808 		l_bc++;
2809 		break;
2810 
2811 	case asBC_STOREOBJ:
2812 		// Move the object pointer from the object register to the object variable
2813 		*(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asPWORD(m_regs.objectRegister);
2814 		m_regs.objectRegister = 0;
2815 		l_bc++;
2816 		break;
2817 
2818 	case asBC_GETOBJ:
2819 		{
2820 			// Read variable index from location on stack
2821 			asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
2822 			asPWORD offset = *a;
2823 			// Move pointer from variable to the same location on the stack
2824 			asPWORD *v = (asPWORD*)(l_fp - offset);
2825 			*a = *v;
2826 			// Clear variable
2827 			*v = 0;
2828 		}
2829 		l_bc++;
2830 		break;
2831 
2832 	case asBC_REFCPY:
2833 		{
2834 			asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
2835 			asSTypeBehaviour *beh = &objType->beh;
2836 
2837 			// Pop address of destination pointer from the stack
2838 			void **d = (void**)*(asPWORD*)l_sp;
2839 			l_sp += AS_PTR_SIZE;
2840 
2841 			// Read wanted pointer from the stack
2842 			void *s = (void*)*(asPWORD*)l_sp;
2843 
2844 			// Need to move the values back to the context as the called functions
2845 			// may use the debug interface to inspect the registers
2846 			m_regs.programPointer    = l_bc;
2847 			m_regs.stackPointer      = l_sp;
2848 			m_regs.stackFramePointer = l_fp;
2849 
2850 			if( !(objType->flags & asOBJ_NOCOUNT) )
2851 			{
2852 				// Release previous object held by destination pointer
2853 				if( *d != 0 )
2854 					m_engine->CallObjectMethod(*d, beh->release);
2855 				// Increase ref counter of wanted object
2856 				if( s != 0 )
2857 					m_engine->CallObjectMethod(s, beh->addref);
2858 			}
2859 
2860 			// Set the new object in the destination
2861 			*d = s;
2862 		}
2863 		l_bc += 1+AS_PTR_SIZE;
2864 		break;
2865 
2866 	case asBC_CHKREF:
2867 		{
2868 			// Verify if the pointer on the stack is null
2869 			// This is used when validating a pointer that an operator will work on
2870 			asPWORD a = *(asPWORD*)l_sp;
2871 			if( a == 0 )
2872 			{
2873 				m_regs.programPointer    = l_bc;
2874 				m_regs.stackPointer      = l_sp;
2875 				m_regs.stackFramePointer = l_fp;
2876 
2877 				SetInternalException(TXT_NULL_POINTER_ACCESS);
2878 				return;
2879 			}
2880 		}
2881 		l_bc++;
2882 		break;
2883 
2884 	case asBC_GETOBJREF:
2885 		{
2886 			// Get the location on the stack where the reference will be placed
2887 			asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
2888 
2889 			// Replace the variable index with the object handle held in the variable
2890 			*(asPWORD**)a = *(asPWORD**)(l_fp - *a);
2891 		}
2892 		l_bc++;
2893 		break;
2894 
2895 	case asBC_GETREF:
2896 		{
2897 			// Get the location on the stack where the reference will be placed
2898 			asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
2899 
2900 			// Replace the variable index with the address of the variable
2901 			*(asPWORD**)a = (asPWORD*)(l_fp - (int)*a);
2902 		}
2903 		l_bc++;
2904 		break;
2905 
2906 	case asBC_PshNull:
2907 		// Push a null pointer on the stack
2908 		l_sp -= AS_PTR_SIZE;
2909 		*(asPWORD*)l_sp = 0;
2910 		l_bc++;
2911 		break;
2912 
2913 	case asBC_ClrVPtr:
2914 		// TODO: runtime optimize: Is this instruction really necessary?
2915 		//                         CallScriptFunction() can clear the null handles upon entry, just as is done for
2916 		//                         all other object variables
2917 		// Clear pointer variable
2918 		*(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = 0;
2919 		l_bc++;
2920 		break;
2921 
2922 	case asBC_OBJTYPE:
2923 		// Push the object type on the stack
2924 		l_sp -= AS_PTR_SIZE;
2925 		*(asPWORD*)l_sp = asBC_PTRARG(l_bc);
2926 		l_bc += 1+AS_PTR_SIZE;
2927 		break;
2928 
2929 	case asBC_TYPEID:
2930 		// Equivalent to PshC4, but kept as separate instruction for bytecode serialization
2931 		--l_sp;
2932 		*l_sp = asBC_DWORDARG(l_bc);
2933 		l_bc += 2;
2934 		break;
2935 
2936 	case asBC_SetV4:
2937 		*(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
2938 		l_bc += 2;
2939 		break;
2940 
2941 	case asBC_SetV8:
2942 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asBC_QWORDARG(l_bc);
2943 		l_bc += 3;
2944 		break;
2945 
2946 	case asBC_ADDSi:
2947 		{
2948 			// The pointer must not be null
2949 			asPWORD a = *(asPWORD*)l_sp;
2950 			if( a == 0 )
2951 			{
2952 				m_regs.programPointer    = l_bc;
2953 				m_regs.stackPointer      = l_sp;
2954 				m_regs.stackFramePointer = l_fp;
2955 
2956 				SetInternalException(TXT_NULL_POINTER_ACCESS);
2957 				return;
2958 			}
2959 			// Add an offset to the pointer
2960 			*(asPWORD*)l_sp = a + asBC_SWORDARG0(l_bc);
2961 		}
2962 		l_bc += 2;
2963 		break;
2964 
2965 	case asBC_CpyVtoV4:
2966 		*(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc));
2967 		l_bc += 2;
2968 		break;
2969 
2970 	case asBC_CpyVtoV8:
2971 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc));
2972 		l_bc += 2;
2973 		break;
2974 
2975 	case asBC_CpyVtoR4:
2976 		*(asDWORD*)&m_regs.valueRegister = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
2977 		l_bc++;
2978 		break;
2979 
2980 	case asBC_CpyVtoR8:
2981 		*(asQWORD*)&m_regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
2982 		l_bc++;
2983 		break;
2984 
2985 	case asBC_CpyVtoG4:
2986 		*(asDWORD*)asBC_PTRARG(l_bc) = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc));
2987 		l_bc += 1 + AS_PTR_SIZE;
2988 		break;
2989 
2990 	case asBC_CpyRtoV4:
2991 		*(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)&m_regs.valueRegister;
2992 		l_bc++;
2993 		break;
2994 
2995 	case asBC_CpyRtoV8:
2996 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = m_regs.valueRegister;
2997 		l_bc++;
2998 		break;
2999 
3000 	case asBC_CpyGtoV4:
3001 		*(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)asBC_PTRARG(l_bc);
3002 		l_bc += 1 + AS_PTR_SIZE;
3003 		break;
3004 
3005 	case asBC_WRTV1:
3006 		// The pointer in the register points to a byte, and *(l_fp - offset) too
3007 		**(asBYTE**)&m_regs.valueRegister = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
3008 		l_bc++;
3009 		break;
3010 
3011 	case asBC_WRTV2:
3012 		// The pointer in the register points to a word, and *(l_fp - offset) too
3013 		**(asWORD**)&m_regs.valueRegister = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
3014 		l_bc++;
3015 		break;
3016 
3017 	case asBC_WRTV4:
3018 		**(asDWORD**)&m_regs.valueRegister = *(l_fp - asBC_SWORDARG0(l_bc));
3019 		l_bc++;
3020 		break;
3021 
3022 	case asBC_WRTV8:
3023 		**(asQWORD**)&m_regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
3024 		l_bc++;
3025 		break;
3026 
3027 	case asBC_RDR1:
3028 		{
3029 			// The pointer in the register points to a byte, and *(l_fp - offset) will also point to a byte
3030 			asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
3031 			bPtr[0] = **(asBYTE**)&m_regs.valueRegister; // read the byte
3032 			bPtr[1] = 0;                      // 0 the rest of the DWORD
3033 			bPtr[2] = 0;
3034 			bPtr[3] = 0;
3035 		}
3036 		l_bc++;
3037 		break;
3038 
3039 	case asBC_RDR2:
3040 		{
3041 			// The pointer in the register points to a word, and *(l_fp - offset) will also point to a word
3042 			asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
3043 			wPtr[0] = **(asWORD**)&m_regs.valueRegister; // read the word
3044 			wPtr[1] = 0;                      // 0 the rest of the DWORD
3045 		}
3046 		l_bc++;
3047 		break;
3048 
3049 	case asBC_RDR4:
3050 		*(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&m_regs.valueRegister;
3051 		l_bc++;
3052 		break;
3053 
3054 	case asBC_RDR8:
3055 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asQWORD**)&m_regs.valueRegister;
3056 		l_bc++;
3057 		break;
3058 
3059 	case asBC_LDG:
3060 		*(asPWORD*)&m_regs.valueRegister = asBC_PTRARG(l_bc);
3061 		l_bc += 1+AS_PTR_SIZE;
3062 		break;
3063 
3064 	case asBC_LDV:
3065 		*(asDWORD**)&m_regs.valueRegister = (l_fp - asBC_SWORDARG0(l_bc));
3066 		l_bc++;
3067 		break;
3068 
3069 	case asBC_PGA:
3070 		l_sp -= AS_PTR_SIZE;
3071 		*(asPWORD*)l_sp = asBC_PTRARG(l_bc);
3072 		l_bc += 1+AS_PTR_SIZE;
3073 		break;
3074 
3075 	case asBC_CmpPtr:
3076 		{
3077 			// TODO: runtime optimize: This instruction should really just be an equals, and return true or false.
3078 			//                         The instruction is only used for is and !is tests anyway.
3079 			asPWORD p1 = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
3080 			asPWORD p2 = *(asPWORD*)(l_fp - asBC_SWORDARG1(l_bc));
3081 			if( p1 == p2 )     *(int*)&m_regs.valueRegister =  0;
3082 			else if( p1 < p2 ) *(int*)&m_regs.valueRegister = -1;
3083 			else               *(int*)&m_regs.valueRegister =  1;
3084 			l_bc += 2;
3085 		}
3086 		break;
3087 
3088 	case asBC_VAR:
3089 		l_sp -= AS_PTR_SIZE;
3090 		*(asPWORD*)l_sp = (asPWORD)asBC_SWORDARG0(l_bc);
3091 		l_bc++;
3092 		break;
3093 
3094 	//----------------------------
3095 	// Type conversions
3096 	case asBC_iTOf:
3097 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(int*)(l_fp - asBC_SWORDARG0(l_bc)));
3098 		l_bc++;
3099 		break;
3100 
3101 	case asBC_fTOi:
3102 		*(l_fp - asBC_SWORDARG0(l_bc)) = int(*(float*)(l_fp - asBC_SWORDARG0(l_bc)));
3103 		l_bc++;
3104 		break;
3105 
3106 	case asBC_uTOf:
3107 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(l_fp - asBC_SWORDARG0(l_bc)));
3108 		l_bc++;
3109 		break;
3110 
3111 	case asBC_fTOu:
3112 		// We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0
3113 		*(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(float*)(l_fp - asBC_SWORDARG0(l_bc))));
3114 		l_bc++;
3115 		break;
3116 
3117 	case asBC_sbTOi:
3118 		// *(l_fp - offset) points to a char, and will point to an int afterwards
3119 		*(l_fp - asBC_SWORDARG0(l_bc)) = *(signed char*)(l_fp - asBC_SWORDARG0(l_bc));
3120 		l_bc++;
3121 		break;
3122 
3123 	case asBC_swTOi:
3124 		// *(l_fp - offset) points to a short, and will point to an int afterwards
3125 		*(l_fp - asBC_SWORDARG0(l_bc)) = *(short*)(l_fp - asBC_SWORDARG0(l_bc));
3126 		l_bc++;
3127 		break;
3128 
3129 	case asBC_ubTOi:
3130 		// (l_fp - offset) points to a byte, and will point to an int afterwards
3131 		*(l_fp - asBC_SWORDARG0(l_bc)) = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
3132 		l_bc++;
3133 		break;
3134 
3135 	case asBC_uwTOi:
3136 		// *(l_fp - offset) points to a word, and will point to an int afterwards
3137 		*(l_fp - asBC_SWORDARG0(l_bc)) = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
3138 		l_bc++;
3139 		break;
3140 
3141 	case asBC_dTOi:
3142 		*(l_fp - asBC_SWORDARG0(l_bc)) = int(*(double*)(l_fp - asBC_SWORDARG1(l_bc)));
3143 		l_bc += 2;
3144 		break;
3145 
3146 	case asBC_dTOu:
3147 		// We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0
3148 		*(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(double*)(l_fp - asBC_SWORDARG1(l_bc))));
3149 		l_bc += 2;
3150 		break;
3151 
3152 	case asBC_dTOf:
3153 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(double*)(l_fp - asBC_SWORDARG1(l_bc)));
3154 		l_bc += 2;
3155 		break;
3156 
3157 	case asBC_iTOd:
3158 		*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(int*)(l_fp - asBC_SWORDARG1(l_bc)));
3159 		l_bc += 2;
3160 		break;
3161 
3162 	case asBC_uTOd:
3163 		*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)));
3164 		l_bc += 2;
3165 		break;
3166 
3167 	case asBC_fTOd:
3168 		*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(float*)(l_fp - asBC_SWORDARG1(l_bc)));
3169 		l_bc += 2;
3170 		break;
3171 
3172 	//------------------------------
3173 	// Math operations
3174 	case asBC_ADDi:
3175 		*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + *(int*)(l_fp - asBC_SWORDARG2(l_bc));
3176 		l_bc += 2;
3177 		break;
3178 
3179 	case asBC_SUBi:
3180 		*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - *(int*)(l_fp - asBC_SWORDARG2(l_bc));
3181 		l_bc += 2;
3182 		break;
3183 
3184 	case asBC_MULi:
3185 		*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * *(int*)(l_fp - asBC_SWORDARG2(l_bc));
3186 		l_bc += 2;
3187 		break;
3188 
3189 	case asBC_DIVi:
3190 		{
3191 			int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc));
3192 			if( divider == 0 )
3193 			{
3194 				// Need to move the values back to the context
3195 				m_regs.programPointer    = l_bc;
3196 				m_regs.stackPointer      = l_sp;
3197 				m_regs.stackFramePointer = l_fp;
3198 
3199 				// Raise exception
3200 				SetInternalException(TXT_DIVIDE_BY_ZERO);
3201 				return;
3202 			}
3203 			else if( divider == -1 )
3204 			{
3205 				// Need to check if the value that is divided is 0x80000000
3206 				// as dividing it with -1 will cause an overflow exception
3207 				if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) )
3208 				{
3209 					// Need to move the values back to the context
3210 					m_regs.programPointer    = l_bc;
3211 					m_regs.stackPointer      = l_sp;
3212 					m_regs.stackFramePointer = l_fp;
3213 
3214 					// Raise exception
3215 					SetInternalException(TXT_DIVIDE_OVERFLOW);
3216 					return;
3217 				}
3218 			}
3219 			*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
3220 		}
3221 		l_bc += 2;
3222 		break;
3223 
3224 	case asBC_MODi:
3225 		{
3226 			int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc));
3227 			if( divider == 0 )
3228 			{
3229 				// Need to move the values back to the context
3230 				m_regs.programPointer    = l_bc;
3231 				m_regs.stackPointer      = l_sp;
3232 				m_regs.stackFramePointer = l_fp;
3233 
3234 				// Raise exception
3235 				SetInternalException(TXT_DIVIDE_BY_ZERO);
3236 				return;
3237 			}
3238 			else if( divider == -1 )
3239 			{
3240 				// Need to check if the value that is divided is 0x80000000
3241 				// as dividing it with -1 will cause an overflow exception
3242 				if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) )
3243 				{
3244 					// Need to move the values back to the context
3245 					m_regs.programPointer    = l_bc;
3246 					m_regs.stackPointer      = l_sp;
3247 					m_regs.stackFramePointer = l_fp;
3248 
3249 					// Raise exception
3250 					SetInternalException(TXT_DIVIDE_OVERFLOW);
3251 					return;
3252 				}
3253 			}
3254 			*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
3255 		}
3256 		l_bc += 2;
3257 		break;
3258 
3259 	case asBC_ADDf:
3260 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + *(float*)(l_fp - asBC_SWORDARG2(l_bc));
3261 		l_bc += 2;
3262 		break;
3263 
3264 	case asBC_SUBf:
3265 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - *(float*)(l_fp - asBC_SWORDARG2(l_bc));
3266 		l_bc += 2;
3267 		break;
3268 
3269 	case asBC_MULf:
3270 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * *(float*)(l_fp - asBC_SWORDARG2(l_bc));
3271 		l_bc += 2;
3272 		break;
3273 
3274 	case asBC_DIVf:
3275 		{
3276 			float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc));
3277 			if( divider == 0 )
3278 			{
3279 				// Need to move the values back to the context
3280 				m_regs.programPointer    = l_bc;
3281 				m_regs.stackPointer      = l_sp;
3282 				m_regs.stackFramePointer = l_fp;
3283 
3284 				// Raise exception
3285 				SetInternalException(TXT_DIVIDE_BY_ZERO);
3286 				return;
3287 			}
3288 			*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
3289 		}
3290 		l_bc += 2;
3291 		break;
3292 
3293 	case asBC_MODf:
3294 		{
3295 			float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc));
3296 			if( divider == 0 )
3297 			{
3298 				// Need to move the values back to the context
3299 				m_regs.programPointer    = l_bc;
3300 				m_regs.stackPointer      = l_sp;
3301 				m_regs.stackFramePointer = l_fp;
3302 
3303 				// Raise exception
3304 				SetInternalException(TXT_DIVIDE_BY_ZERO);
3305 				return;
3306 			}
3307 			*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = fmodf(*(float*)(l_fp - asBC_SWORDARG1(l_bc)), divider);
3308 		}
3309 		l_bc += 2;
3310 		break;
3311 
3312 	case asBC_ADDd:
3313 		*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) + *(double*)(l_fp - asBC_SWORDARG2(l_bc));
3314 		l_bc += 2;
3315 		break;
3316 
3317 	case asBC_SUBd:
3318 		*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) - *(double*)(l_fp - asBC_SWORDARG2(l_bc));
3319 		l_bc += 2;
3320 		break;
3321 
3322 	case asBC_MULd:
3323 		*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) * *(double*)(l_fp - asBC_SWORDARG2(l_bc));
3324 		l_bc += 2;
3325 		break;
3326 
3327 	case asBC_DIVd:
3328 		{
3329 			double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc));
3330 			if( divider == 0 )
3331 			{
3332 				// Need to move the values back to the context
3333 				m_regs.programPointer    = l_bc;
3334 				m_regs.stackPointer      = l_sp;
3335 				m_regs.stackFramePointer = l_fp;
3336 
3337 				// Raise exception
3338 				SetInternalException(TXT_DIVIDE_BY_ZERO);
3339 				return;
3340 			}
3341 
3342 			*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
3343 			l_bc += 2;
3344 		}
3345 		break;
3346 
3347 	case asBC_MODd:
3348 		{
3349 			double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc));
3350 			if( divider == 0 )
3351 			{
3352 				// Need to move the values back to the context
3353 				m_regs.programPointer    = l_bc;
3354 				m_regs.stackPointer      = l_sp;
3355 				m_regs.stackFramePointer = l_fp;
3356 
3357 				// Raise exception
3358 				SetInternalException(TXT_DIVIDE_BY_ZERO);
3359 				return;
3360 			}
3361 
3362 			*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = fmod(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), divider);
3363 			l_bc += 2;
3364 		}
3365 		break;
3366 
3367 	//------------------------------
3368 	// Math operations with constant value
3369 	case asBC_ADDIi:
3370 		*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_INTARG(l_bc+1);
3371 		l_bc += 3;
3372 		break;
3373 
3374 	case asBC_SUBIi:
3375 		*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_INTARG(l_bc+1);
3376 		l_bc += 3;
3377 		break;
3378 
3379 	case asBC_MULIi:
3380 		*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_INTARG(l_bc+1);
3381 		l_bc += 3;
3382 		break;
3383 
3384 	case asBC_ADDIf:
3385 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_FLOATARG(l_bc+1);
3386 		l_bc += 3;
3387 		break;
3388 
3389 	case asBC_SUBIf:
3390 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_FLOATARG(l_bc+1);
3391 		l_bc += 3;
3392 		break;
3393 
3394 	case asBC_MULIf:
3395 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_FLOATARG(l_bc+1);
3396 		l_bc += 3;
3397 		break;
3398 
3399 	//-----------------------------------
3400 	case asBC_SetG4:
3401 		*(asDWORD*)asBC_PTRARG(l_bc) = asBC_DWORDARG(l_bc+AS_PTR_SIZE);
3402 		l_bc += 2 + AS_PTR_SIZE;
3403 		break;
3404 
3405 	case asBC_ChkRefS:
3406 		{
3407 			// Verify if the pointer on the stack refers to a non-null value
3408 			// This is used to validate a reference to a handle
3409 			asPWORD *a = (asPWORD*)*(asPWORD*)l_sp;
3410 			if( *a == 0 )
3411 			{
3412 				m_regs.programPointer    = l_bc;
3413 				m_regs.stackPointer      = l_sp;
3414 				m_regs.stackFramePointer = l_fp;
3415 
3416 				SetInternalException(TXT_NULL_POINTER_ACCESS);
3417 				return;
3418 			}
3419 		}
3420 		l_bc++;
3421 		break;
3422 
3423 	case asBC_ChkNullV:
3424 		{
3425 			// Verify if variable (on the stack) is not null
3426 			asDWORD *a = *(asDWORD**)(l_fp - asBC_SWORDARG0(l_bc));
3427 			if( a == 0 )
3428 			{
3429 				m_regs.programPointer    = l_bc;
3430 				m_regs.stackPointer      = l_sp;
3431 				m_regs.stackFramePointer = l_fp;
3432 
3433 				SetInternalException(TXT_NULL_POINTER_ACCESS);
3434 				return;
3435 			}
3436 		}
3437 		l_bc++;
3438 		break;
3439 
3440 	case asBC_CALLINTF:
3441 		{
3442 			int i = asBC_INTARG(l_bc);
3443 			l_bc += 2;
3444 
3445 			asASSERT( i >= 0 );
3446 			asASSERT( (i & FUNC_IMPORTED) == 0 );
3447 
3448 			// Need to move the values back to the context
3449 			m_regs.programPointer    = l_bc;
3450 			m_regs.stackPointer      = l_sp;
3451 			m_regs.stackFramePointer = l_fp;
3452 
3453 			CallInterfaceMethod(m_engine->GetScriptFunction(i));
3454 
3455 			// Extract the values from the context again
3456 			l_bc = m_regs.programPointer;
3457 			l_sp = m_regs.stackPointer;
3458 			l_fp = m_regs.stackFramePointer;
3459 
3460 			// If status isn't active anymore then we must stop
3461 			if( m_status != asEXECUTION_ACTIVE )
3462 				return;
3463 		}
3464 		break;
3465 
3466 	case asBC_iTOb:
3467 		{
3468 			// *(l_fp - offset) points to an int, and will point to a byte afterwards
3469 
3470 			// We need to use volatile here to tell the compiler not to rearrange
3471 			// read and write operations during optimizations.
3472 			volatile asDWORD val  = *(l_fp - asBC_SWORDARG0(l_bc));
3473 			volatile asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc));
3474 			bPtr[0] = (asBYTE)val; // write the byte
3475 			bPtr[1] = 0;           // 0 the rest of the DWORD
3476 			bPtr[2] = 0;
3477 			bPtr[3] = 0;
3478 		}
3479 		l_bc++;
3480 		break;
3481 
3482 	case asBC_iTOw:
3483 		{
3484 			// *(l_fp - offset) points to an int, and will point to word afterwards
3485 
3486 			// We need to use volatile here to tell the compiler not to rearrange
3487 			// read and write operations during optimizations.
3488 			volatile asDWORD val  = *(l_fp - asBC_SWORDARG0(l_bc));
3489 			volatile asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc));
3490 			wPtr[0] = (asWORD)val; // write the word
3491 			wPtr[1] = 0;           // 0 the rest of the DWORD
3492 		}
3493 		l_bc++;
3494 		break;
3495 
3496 	case asBC_SetV1:
3497 		// TODO: This is exactly the same as SetV4. This is a left over from the time
3498 		//       when the bytecode instructions were more tightly packed. It can now
3499 		//       be removed. When removing it, make sure the value is correctly converted
3500 		//       on big-endian CPUs.
3501 
3502 		// The byte is already stored correctly in the argument
3503 		*(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
3504 		l_bc += 2;
3505 		break;
3506 
3507 	case asBC_SetV2:
3508 		// TODO: This is exactly the same as SetV4. This is a left over from the time
3509 		//       when the bytecode instructions were more tightly packed. It can now
3510 		//       be removed. When removing it, make sure the value is correctly converted
3511 		//       on big-endian CPUs.
3512 
3513 		// The word is already stored correctly in the argument
3514 		*(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc);
3515 		l_bc += 2;
3516 		break;
3517 
3518 	case asBC_Cast:
3519 		// Cast the handle at the top of the stack to the type in the argument
3520 		{
3521 			asDWORD **a = (asDWORD**)*(asPWORD*)l_sp;
3522 			if( a && *a )
3523 			{
3524 				asDWORD typeId = asBC_DWORDARG(l_bc);
3525 
3526 				asCScriptObject *obj = (asCScriptObject *)* a;
3527 				asCObjectType *objType = obj->objType;
3528 				asCObjectType *to = m_engine->GetObjectTypeFromTypeId(typeId);
3529 
3530 				// This instruction can only be used with script classes and interfaces
3531 				asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT );
3532 				asASSERT( to->flags & asOBJ_SCRIPT_OBJECT );
3533 
3534 				if( objType->Implements(to) || objType->DerivesFrom(to) )
3535 				{
3536 					m_regs.objectType = 0;
3537 					m_regs.objectRegister = obj;
3538 					obj->AddRef();
3539 				}
3540 				else
3541 				{
3542 					// The object register should already be null, so there
3543 					// is no need to clear it if the cast is unsuccessful
3544 					asASSERT( m_regs.objectRegister == 0 );
3545 				}
3546 			}
3547 			l_sp += AS_PTR_SIZE;
3548 		}
3549 		l_bc += 2;
3550 		break;
3551 
3552 	case asBC_i64TOi:
3553 		*(l_fp - asBC_SWORDARG0(l_bc)) = int(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)));
3554 		l_bc += 2;
3555 		break;
3556 
3557 	case asBC_uTOi64:
3558 		*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)));
3559 		l_bc += 2;
3560 		break;
3561 
3562 	case asBC_iTOi64:
3563 		*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(int*)(l_fp - asBC_SWORDARG1(l_bc)));
3564 		l_bc += 2;
3565 		break;
3566 
3567 	case asBC_fTOi64:
3568 		*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc)));
3569 		l_bc += 2;
3570 		break;
3571 
3572 	case asBC_dTOi64:
3573 		*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc)));
3574 		l_bc++;
3575 		break;
3576 
3577 	case asBC_fTOu64:
3578 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc))));
3579 		l_bc += 2;
3580 		break;
3581 
3582 	case asBC_dTOu64:
3583 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc))));
3584 		l_bc++;
3585 		break;
3586 
3587 	case asBC_i64TOf:
3588 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)));
3589 		l_bc += 2;
3590 		break;
3591 
3592 	case asBC_u64TOf:
3593 #if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC6
3594 		{
3595 			// MSVC6 doesn't permit UINT64 to double
3596 			asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc));
3597 			if( v < 0 )
3598 				*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0f+float(v);
3599 			else
3600 				*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(v);
3601 		}
3602 #else
3603 		*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)));
3604 #endif
3605 		l_bc += 2;
3606 		break;
3607 
3608 	case asBC_i64TOd:
3609 		*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)));
3610 		l_bc++;
3611 		break;
3612 
3613 	case asBC_u64TOd:
3614 #if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC6
3615 		{
3616 			// MSVC6 doesn't permit UINT64 to double
3617 			asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
3618 			if( v < 0 )
3619 				*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0+double(v);
3620 			else
3621 				*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(v);
3622 		}
3623 #else
3624 		*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)));
3625 #endif
3626 		l_bc++;
3627 		break;
3628 
3629 	case asBC_NEGi64:
3630 		*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
3631 		l_bc++;
3632 		break;
3633 
3634 	case asBC_INCi64:
3635 		++(**(asQWORD**)&m_regs.valueRegister);
3636 		l_bc++;
3637 		break;
3638 
3639 	case asBC_DECi64:
3640 		--(**(asQWORD**)&m_regs.valueRegister);
3641 		l_bc++;
3642 		break;
3643 
3644 	case asBC_BNOT64:
3645 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = ~*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
3646 		l_bc++;
3647 		break;
3648 
3649 	case asBC_ADDi64:
3650 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) + *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
3651 		l_bc += 2;
3652 		break;
3653 
3654 	case asBC_SUBi64:
3655 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) - *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
3656 		l_bc += 2;
3657 		break;
3658 
3659 	case asBC_MULi64:
3660 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) * *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
3661 		l_bc += 2;
3662 		break;
3663 
3664 	case asBC_DIVi64:
3665 		{
3666 			asINT64 divider = *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc));
3667 			if( divider == 0 )
3668 			{
3669 				// Need to move the values back to the context
3670 				m_regs.programPointer    = l_bc;
3671 				m_regs.stackPointer      = l_sp;
3672 				m_regs.stackFramePointer = l_fp;
3673 
3674 				// Raise exception
3675 				SetInternalException(TXT_DIVIDE_BY_ZERO);
3676 				return;
3677 			}
3678 			else if( divider == -1 )
3679 			{
3680 				// Need to check if the value that is divided is 1<<63
3681 				// as dividing it with -1 will cause an overflow exception
3682 				if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) )
3683 				{
3684 					// Need to move the values back to the context
3685 					m_regs.programPointer    = l_bc;
3686 					m_regs.stackPointer      = l_sp;
3687 					m_regs.stackFramePointer = l_fp;
3688 
3689 					// Raise exception
3690 					SetInternalException(TXT_DIVIDE_OVERFLOW);
3691 					return;
3692 				}
3693 			}
3694 
3695 			*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
3696 		}
3697 		l_bc += 2;
3698 		break;
3699 
3700 	case asBC_MODi64:
3701 		{
3702 			asINT64 divider = *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc));
3703 			if( divider == 0 )
3704 			{
3705 				// Need to move the values back to the context
3706 				m_regs.programPointer    = l_bc;
3707 				m_regs.stackPointer      = l_sp;
3708 				m_regs.stackFramePointer = l_fp;
3709 
3710 				// Raise exception
3711 				SetInternalException(TXT_DIVIDE_BY_ZERO);
3712 				return;
3713 			}
3714 			else if( divider == -1 )
3715 			{
3716 				// Need to check if the value that is divided is 1<<63
3717 				// as dividing it with -1 will cause an overflow exception
3718 				if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) )
3719 				{
3720 					// Need to move the values back to the context
3721 					m_regs.programPointer    = l_bc;
3722 					m_regs.stackPointer      = l_sp;
3723 					m_regs.stackFramePointer = l_fp;
3724 
3725 					// Raise exception
3726 					SetInternalException(TXT_DIVIDE_OVERFLOW);
3727 					return;
3728 				}
3729 			}
3730 			*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
3731 		}
3732 		l_bc += 2;
3733 		break;
3734 
3735 	case asBC_BAND64:
3736 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) & *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
3737 		l_bc += 2;
3738 		break;
3739 
3740 	case asBC_BOR64:
3741 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) | *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
3742 		l_bc += 2;
3743 		break;
3744 
3745 	case asBC_BXOR64:
3746 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) ^ *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
3747 		l_bc += 2;
3748 		break;
3749 
3750 	case asBC_BSLL64:
3751 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc));
3752 		l_bc += 2;
3753 		break;
3754 
3755 	case asBC_BSRL64:
3756 		*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
3757 		l_bc += 2;
3758 		break;
3759 
3760 	case asBC_BSRA64:
3761 		*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc));
3762 		l_bc += 2;
3763 		break;
3764 
3765 	case asBC_CMPi64:
3766 		{
3767 			asINT64 i1 = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc));
3768 			asINT64 i2 = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc));
3769 			if( i1 == i2 )     *(int*)&m_regs.valueRegister =  0;
3770 			else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1;
3771 			else               *(int*)&m_regs.valueRegister =  1;
3772 			l_bc += 2;
3773 		}
3774 		break;
3775 
3776 	case asBC_CMPu64:
3777 		{
3778 			asQWORD d1 = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
3779 			asQWORD d2 = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc));
3780 			if( d1 == d2 )     *(int*)&m_regs.valueRegister =  0;
3781 			else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1;
3782 			else               *(int*)&m_regs.valueRegister =  1;
3783 			l_bc += 2;
3784 		}
3785 		break;
3786 
3787 	case asBC_ChkNullS:
3788 		{
3789 			// Verify if the pointer on the stack is null
3790 			// This is used for example when validating handles passed as function arguments
3791 			asPWORD a = *(asPWORD*)(l_sp + asBC_WORDARG0(l_bc));
3792 			if( a == 0 )
3793 			{
3794 				m_regs.programPointer    = l_bc;
3795 				m_regs.stackPointer      = l_sp;
3796 				m_regs.stackFramePointer = l_fp;
3797 
3798 				SetInternalException(TXT_NULL_POINTER_ACCESS);
3799 				return;
3800 			}
3801 		}
3802 		l_bc++;
3803 		break;
3804 
3805 	case asBC_ClrHi:
3806 #if AS_SIZEOF_BOOL == 1
3807 		{
3808 			// Clear the upper bytes, so that trash data don't interfere with boolean operations
3809 
3810 			// We need to use volatile here to tell the compiler it cannot
3811 			// change the order of read and write operations on the pointer.
3812 
3813 			volatile asBYTE *ptr = (asBYTE*)&m_regs.valueRegister;
3814 			ptr[1] = 0;   // The boolean value is stored in the lower byte, so we clear the rest
3815 			ptr[2] = 0;
3816 			ptr[3] = 0;
3817 		}
3818 #else
3819 		// We don't have anything to do here
3820 #endif
3821 		l_bc++;
3822 		break;
3823 
3824 	case asBC_JitEntry:
3825 		{
3826 			if( m_currentFunction->scriptData->jitFunction )
3827 			{
3828 				asPWORD jitArg = asBC_PTRARG(l_bc);
3829 
3830 				if( jitArg )
3831 				{
3832 					// Resume JIT operation
3833 					m_regs.programPointer    = l_bc;
3834 					m_regs.stackPointer      = l_sp;
3835 					m_regs.stackFramePointer = l_fp;
3836 
3837 					(m_currentFunction->scriptData->jitFunction)(&m_regs, jitArg);
3838 
3839 					l_bc = m_regs.programPointer;
3840 					l_sp = m_regs.stackPointer;
3841 					l_fp = m_regs.stackFramePointer;
3842 
3843 					// If status isn't active anymore then we must stop
3844 					if( m_status != asEXECUTION_ACTIVE )
3845 						return;
3846 
3847 					break;
3848 				}
3849 			}
3850 
3851 			// Not a JIT resume point, treat as nop
3852 			l_bc += 1+AS_PTR_SIZE;
3853 		}
3854 		break;
3855 
3856 	case asBC_CallPtr:
3857 		{
3858 			// Get the function pointer from the local variable
3859 			asCScriptFunction *func = *(asCScriptFunction**)(l_fp - asBC_SWORDARG0(l_bc));
3860 
3861 			// Need to move the values back to the context
3862 			m_regs.programPointer    = l_bc;
3863 			m_regs.stackPointer      = l_sp;
3864 			m_regs.stackFramePointer = l_fp;
3865 
3866 			if( func == 0 )
3867 			{
3868 				// Need to update the program pointer anyway for the exception handler
3869 				m_regs.programPointer++;
3870 
3871 				// Tell the exception handler to clean up the arguments to this method
3872 				m_needToCleanupArgs = true;
3873 
3874 				// TODO: funcdef: Should we have a different exception string?
3875 				SetInternalException(TXT_UNBOUND_FUNCTION);
3876 				return;
3877 			}
3878 			else
3879 			{
3880 				if( func->funcType == asFUNC_SCRIPT )
3881 				{
3882 					m_regs.programPointer++;
3883 					CallScriptFunction(func);
3884 				}
3885 				else if( func->funcType == asFUNC_DELEGATE )
3886 				{
3887 					// Push the object pointer on the stack. There is always a reserved space for this so
3888 					// we don't don't need to worry about overflowing the allocated memory buffer
3889 					asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] );
3890 					m_regs.stackPointer -= AS_PTR_SIZE;
3891 					*(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate);
3892 
3893 					// Call the delegated method
3894 					if( func->funcForDelegate->funcType == asFUNC_SYSTEM )
3895 					{
3896 						m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this);
3897 
3898 						// Update program position after the call so the line number
3899 						// is correct in case the system function queries it
3900 						m_regs.programPointer++;
3901 					}
3902 					else
3903 					{
3904 						m_regs.programPointer++;
3905 
3906 						// TODO: run-time optimize: The true method could be figured out when creating the delegate
3907 						CallInterfaceMethod(func->funcForDelegate);
3908 					}
3909 				}
3910 				else
3911 				{
3912 					asASSERT( func->funcType == asFUNC_SYSTEM );
3913 
3914 					m_regs.stackPointer += CallSystemFunction(func->id, this);
3915 
3916 					// Update program position after the call so the line number
3917 					// is correct in case the system function queries it
3918 					m_regs.programPointer++;
3919 				}
3920 			}
3921 
3922 			// Extract the values from the context again
3923 			l_bc = m_regs.programPointer;
3924 			l_sp = m_regs.stackPointer;
3925 			l_fp = m_regs.stackFramePointer;
3926 
3927 			// If status isn't active anymore then we must stop
3928 			if( m_status != asEXECUTION_ACTIVE )
3929 				return;
3930 		}
3931 		break;
3932 
3933 	case asBC_FuncPtr:
3934 		// Push the function pointer on the stack. The pointer is in the argument
3935 		l_sp -= AS_PTR_SIZE;
3936 		*(asPWORD*)l_sp = asBC_PTRARG(l_bc);
3937 		l_bc += 1+AS_PTR_SIZE;
3938 		break;
3939 
3940 	case asBC_LoadThisR:
3941 		{
3942 			// PshVPtr 0
3943 			asPWORD tmp = *(asPWORD*)l_fp;
3944 
3945 			// Make sure the pointer is not null
3946 			if( tmp == 0 )
3947 			{
3948 				// Need to move the values back to the context
3949 				m_regs.programPointer    = l_bc;
3950 				m_regs.stackPointer      = l_sp;
3951 				m_regs.stackFramePointer = l_fp;
3952 
3953 				// Raise exception
3954 				SetInternalException(TXT_NULL_POINTER_ACCESS);
3955 				return;
3956 			}
3957 
3958 			// ADDSi
3959 			tmp = tmp + asBC_SWORDARG0(l_bc);
3960 
3961 			// PopRPtr
3962 			*(asPWORD*)&m_regs.valueRegister = tmp;
3963 			l_bc += 2;
3964 		}
3965 		break;
3966 
3967 	// Push the qword value of a variable on the stack
3968 	case asBC_PshV8:
3969 		l_sp -= 2;
3970 		*(asQWORD*)l_sp = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc));
3971 		l_bc++;
3972 		break;
3973 
3974 	case asBC_DIVu:
3975 		{
3976 			asUINT divider = *(asUINT*)(l_fp - asBC_SWORDARG2(l_bc));
3977 			if( divider == 0 )
3978 			{
3979 				// Need to move the values back to the context
3980 				m_regs.programPointer    = l_bc;
3981 				m_regs.stackPointer      = l_sp;
3982 				m_regs.stackFramePointer = l_fp;
3983 
3984 				// Raise exception
3985 				SetInternalException(TXT_DIVIDE_BY_ZERO);
3986 				return;
3987 			}
3988 			*(asUINT*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
3989 		}
3990 		l_bc += 2;
3991 		break;
3992 
3993 	case asBC_MODu:
3994 		{
3995 			asUINT divider = *(asUINT*)(l_fp - asBC_SWORDARG2(l_bc));
3996 			if( divider == 0 )
3997 			{
3998 				// Need to move the values back to the context
3999 				m_regs.programPointer    = l_bc;
4000 				m_regs.stackPointer      = l_sp;
4001 				m_regs.stackFramePointer = l_fp;
4002 
4003 				// Raise exception
4004 				SetInternalException(TXT_DIVIDE_BY_ZERO);
4005 				return;
4006 			}
4007 			*(asUINT*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
4008 		}
4009 		l_bc += 2;
4010 		break;
4011 
4012 	case asBC_DIVu64:
4013 		{
4014 			asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
4015 			if( divider == 0 )
4016 			{
4017 				// Need to move the values back to the context
4018 				m_regs.programPointer    = l_bc;
4019 				m_regs.stackPointer      = l_sp;
4020 				m_regs.stackFramePointer = l_fp;
4021 
4022 				// Raise exception
4023 				SetInternalException(TXT_DIVIDE_BY_ZERO);
4024 				return;
4025 			}
4026 			*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) / divider;
4027 		}
4028 		l_bc += 2;
4029 		break;
4030 
4031 	case asBC_MODu64:
4032 		{
4033 			asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc));
4034 			if( divider == 0 )
4035 			{
4036 				// Need to move the values back to the context
4037 				m_regs.programPointer    = l_bc;
4038 				m_regs.stackPointer      = l_sp;
4039 				m_regs.stackFramePointer = l_fp;
4040 
4041 				// Raise exception
4042 				SetInternalException(TXT_DIVIDE_BY_ZERO);
4043 				return;
4044 			}
4045 			*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) % divider;
4046 		}
4047 		l_bc += 2;
4048 		break;
4049 
4050 	case asBC_LoadRObjR:
4051 		{
4052 			// PshVPtr x
4053 			asPWORD tmp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
4054 
4055 			// Make sure the pointer is not null
4056 			if( tmp == 0 )
4057 			{
4058 				// Need to move the values back to the context
4059 				m_regs.programPointer    = l_bc;
4060 				m_regs.stackPointer      = l_sp;
4061 				m_regs.stackFramePointer = l_fp;
4062 
4063 				// Raise exception
4064 				SetInternalException(TXT_NULL_POINTER_ACCESS);
4065 				return;
4066 			}
4067 
4068 			// ADDSi y
4069 			tmp = tmp + asBC_SWORDARG1(l_bc);
4070 
4071 			// PopRPtr
4072 			*(asPWORD*)&m_regs.valueRegister = tmp;
4073 			l_bc += 3;
4074 		}
4075 		break;
4076 
4077 	case asBC_LoadVObjR:
4078 		{
4079 			// PSF x
4080 			asPWORD tmp = (asPWORD)(l_fp - asBC_SWORDARG0(l_bc));
4081 
4082 			// ADDSi y
4083 			tmp = tmp + asBC_SWORDARG1(l_bc);
4084 
4085 			// PopRPtr
4086 			*(asPWORD*)&m_regs.valueRegister = tmp;
4087 			l_bc += 3;
4088 		}
4089 		break;
4090 
4091 	case asBC_RefCpyV:
4092 		// Same as PSF v, REFCPY
4093 		{
4094 			asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
4095 			asSTypeBehaviour *beh = &objType->beh;
4096 
4097 			// Determine destination from argument
4098 			void **d = (void**)asPWORD(l_fp - asBC_SWORDARG0(l_bc));
4099 
4100 			// Read wanted pointer from the stack
4101 			void *s = (void*)*(asPWORD*)l_sp;
4102 
4103 			// Need to move the values back to the context as the called functions
4104 			// may use the debug interface to inspect the registers
4105 			m_regs.programPointer    = l_bc;
4106 			m_regs.stackPointer      = l_sp;
4107 			m_regs.stackFramePointer = l_fp;
4108 
4109 			if( !(objType->flags & asOBJ_NOCOUNT) )
4110 			{
4111 				// Release previous object held by destination pointer
4112 				if( *d != 0 )
4113 					m_engine->CallObjectMethod(*d, beh->release);
4114 				// Increase ref counter of wanted object
4115 				if( s != 0 )
4116 					m_engine->CallObjectMethod(s, beh->addref);
4117 			}
4118 
4119 			// Set the new object in the destination
4120 			*d = s;
4121 		}
4122 		l_bc += 1+AS_PTR_SIZE;
4123 		break;
4124 
4125 	case asBC_JLowZ:
4126 		if( *(asBYTE*)&m_regs.valueRegister == 0 )
4127 			l_bc += asBC_INTARG(l_bc) + 2;
4128 		else
4129 			l_bc += 2;
4130 		break;
4131 
4132 	case asBC_JLowNZ:
4133 		if( *(asBYTE*)&m_regs.valueRegister != 0 )
4134 			l_bc += asBC_INTARG(l_bc) + 2;
4135 		else
4136 			l_bc += 2;
4137 		break;
4138 
4139 	case asBC_AllocMem:
4140 		// Allocate a buffer and store the pointer in the local variable
4141 		{
4142 			// TODO: runtime optimize: As the list buffers are going to be short lived, it may be interesting
4143 			//                         to use a memory pool to avoid reallocating the memory all the time
4144 
4145 			asUINT size = asBC_DWORDARG(l_bc);
4146 			asBYTE **var = (asBYTE**)(l_fp - asBC_SWORDARG0(l_bc));
4147 #ifndef WIP_16BYTE_ALIGN
4148 			*var = asNEWARRAY(asBYTE, size);
4149 #else
4150 			*var = asNEWARRAYALIGNED(asBYTE, size, MAX_TYPE_ALIGNMENT);
4151 #endif
4152 
4153 			// Clear the buffer for the pointers that will be placed in it
4154 			memset(*var, 0, size);
4155 		}
4156 		l_bc += 2;
4157 		break;
4158 
4159 	case asBC_SetListSize:
4160 		{
4161 			// Set the size element in the buffer
4162 			asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc));
4163 			asUINT off  = asBC_DWORDARG(l_bc);
4164 			asUINT size = asBC_DWORDARG(l_bc+1);
4165 
4166 			asASSERT( var );
4167 
4168 			*(asUINT*)(var+off) = size;
4169 		}
4170 		l_bc += 3;
4171 		break;
4172 
4173 	case asBC_PshListElmnt:
4174 		{
4175 			// Push the pointer to the list element on the stack
4176 			// In essence it does the same as PSF, RDSPtr, ADDSi
4177 			asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc));
4178 			asUINT off = asBC_DWORDARG(l_bc);
4179 
4180 			asASSERT( var );
4181 
4182 			l_sp -= AS_PTR_SIZE;
4183 			*(asPWORD*)l_sp = asPWORD(var+off);
4184 		}
4185 		l_bc += 2;
4186 		break;
4187 
4188 	case asBC_SetListType:
4189 		{
4190 			// Set the type id in the buffer
4191 			asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc));
4192 			asUINT off  = asBC_DWORDARG(l_bc);
4193 			asUINT type = asBC_DWORDARG(l_bc+1);
4194 
4195 			asASSERT( var );
4196 
4197 			*(asUINT*)(var+off) = type;
4198 		}
4199 		l_bc += 3;
4200 		break;
4201 
4202 	//------------------------------
4203 	// Exponent operations
4204 	case asBC_POWi:
4205 		{
4206 			bool isOverflow;
4207 			*(int*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powi(*(int*)(l_fp - asBC_SWORDARG1(l_bc)), *(int*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow);
4208 			if( isOverflow )
4209 			{
4210 				// Need to move the values back to the context
4211 				m_regs.programPointer    = l_bc;
4212 				m_regs.stackPointer      = l_sp;
4213 				m_regs.stackFramePointer = l_fp;
4214 
4215 				// Raise exception
4216 				SetInternalException(TXT_POW_OVERFLOW);
4217 				return;
4218 			}
4219 		}
4220 		l_bc += 2;
4221 		break;
4222 
4223 	case asBC_POWu:
4224 		{
4225 			bool isOverflow;
4226 			*(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powu(*(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc)), *(asDWORD*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow);
4227 			if( isOverflow )
4228 			{
4229 				// Need to move the values back to the context
4230 				m_regs.programPointer    = l_bc;
4231 				m_regs.stackPointer      = l_sp;
4232 				m_regs.stackFramePointer = l_fp;
4233 
4234 				// Raise exception
4235 				SetInternalException(TXT_POW_OVERFLOW);
4236 				return;
4237 			}
4238 		}
4239 		l_bc += 2;
4240 		break;
4241 
4242 	case asBC_POWf:
4243 		{
4244 			float r = powf(*(float*)(l_fp - asBC_SWORDARG1(l_bc)), *(float*)(l_fp - asBC_SWORDARG2(l_bc)));
4245 			*(float*)(l_fp - asBC_SWORDARG0(l_bc)) = r;
4246 			if( r == float(HUGE_VAL) )
4247 			{
4248 				// Need to move the values back to the context
4249 				m_regs.programPointer    = l_bc;
4250 				m_regs.stackPointer      = l_sp;
4251 				m_regs.stackFramePointer = l_fp;
4252 
4253 				// Raise exception
4254 				SetInternalException(TXT_POW_OVERFLOW);
4255 				return;
4256 			}
4257 		}
4258 		l_bc += 2;
4259 		break;
4260 
4261 	case asBC_POWd:
4262 		{
4263 			double r = pow(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), *(double*)(l_fp - asBC_SWORDARG2(l_bc)));
4264 			*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = r;
4265 			if( r == HUGE_VAL )
4266 			{
4267 				// Need to move the values back to the context
4268 				m_regs.programPointer    = l_bc;
4269 				m_regs.stackPointer      = l_sp;
4270 				m_regs.stackFramePointer = l_fp;
4271 
4272 				// Raise exception
4273 				SetInternalException(TXT_POW_OVERFLOW);
4274 				return;
4275 			}
4276 		}
4277 		l_bc += 2;
4278 		break;
4279 
4280 	case asBC_POWdi:
4281 		{
4282 			double r = pow(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), *(int*)(l_fp - asBC_SWORDARG2(l_bc)));
4283 			*(double*)(l_fp - asBC_SWORDARG0(l_bc)) = r;
4284 			if( r == HUGE_VAL )
4285 			{
4286 				// Need to move the values back to the context
4287 				m_regs.programPointer    = l_bc;
4288 				m_regs.stackPointer      = l_sp;
4289 				m_regs.stackFramePointer = l_fp;
4290 
4291 				// Raise exception
4292 				SetInternalException(TXT_POW_OVERFLOW);
4293 				return;
4294 			}
4295 			l_bc += 2;
4296 		}
4297 		break;
4298 
4299 	case asBC_POWi64:
4300 		{
4301 			bool isOverflow;
4302 			*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powi64(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)), *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow);
4303 			if( isOverflow )
4304 			{
4305 				// Need to move the values back to the context
4306 				m_regs.programPointer    = l_bc;
4307 				m_regs.stackPointer      = l_sp;
4308 				m_regs.stackFramePointer = l_fp;
4309 
4310 				// Raise exception
4311 				SetInternalException(TXT_POW_OVERFLOW);
4312 				return;
4313 			}
4314 		}
4315 		l_bc += 2;
4316 		break;
4317 
4318 	case asBC_POWu64:
4319 		{
4320 			bool isOverflow;
4321 			*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powu64(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)), *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow);
4322 			if( isOverflow )
4323 			{
4324 				// Need to move the values back to the context
4325 				m_regs.programPointer    = l_bc;
4326 				m_regs.stackPointer      = l_sp;
4327 				m_regs.stackFramePointer = l_fp;
4328 
4329 				// Raise exception
4330 				SetInternalException(TXT_POW_OVERFLOW);
4331 				return;
4332 			}
4333 		}
4334 		l_bc += 2;
4335 		break;
4336 	case asBC_Thiscall1:
4337 		// This instruction is a faster version of asBC_CALLSYS. It is faster because
4338 		// it has much less runtime overhead with determining the calling convention
4339 		// and no dynamic code for loading the parameters. The instruction can only
4340 		// be used to call functions with the following signatures:
4341 		//
4342 		//  type &obj::func(int)
4343 		//  type &obj::func(uint)
4344 		//  void  obj::func(int)
4345 		//  void  obj::func(uint)
4346 		{
4347 			// Get function ID from the argument
4348 			int i = asBC_INTARG(l_bc);
4349 
4350 			// Need to move the values back to the context as the called functions
4351 			// may use the debug interface to inspect the registers
4352 			m_regs.programPointer    = l_bc;
4353 			m_regs.stackPointer      = l_sp;
4354 			m_regs.stackFramePointer = l_fp;
4355 
4356 			// Pop the thispointer from the stack
4357 			void *obj = *(void**)l_sp;
4358 			if (obj == 0)
4359 				SetInternalException(TXT_NULL_POINTER_ACCESS);
4360 			else
4361 			{
4362 				// Only update the stack pointer if all is OK so the
4363 				// exception handler can properly clean up the stack
4364 				l_sp += AS_PTR_SIZE;
4365 
4366 				// Pop the int arg from the stack
4367 				int arg = *(int*)l_sp;
4368 				l_sp++;
4369 
4370 				// Call the method
4371 				m_callingSystemFunction = m_engine->scriptFunctions[i];
4372 				void *ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction);
4373 				m_callingSystemFunction = 0;
4374 				*(asPWORD*)&m_regs.valueRegister = (asPWORD)ptr;
4375 			}
4376 
4377 			// Update the program position after the call so that line number is correct
4378 			l_bc += 2;
4379 
4380 			if( m_regs.doProcessSuspend )
4381 			{
4382 				// Should the execution be suspended?
4383 				if( m_doSuspend )
4384 				{
4385 					m_regs.programPointer    = l_bc;
4386 					m_regs.stackPointer      = l_sp;
4387 					m_regs.stackFramePointer = l_fp;
4388 
4389 					m_status = asEXECUTION_SUSPENDED;
4390 					return;
4391 				}
4392 				// An exception might have been raised
4393 				if( m_status != asEXECUTION_ACTIVE )
4394 				{
4395 					m_regs.programPointer    = l_bc;
4396 					m_regs.stackPointer      = l_sp;
4397 					m_regs.stackFramePointer = l_fp;
4398 
4399 					return;
4400 				}
4401 			}
4402 		}
4403 		break;
4404 
4405 	// Don't let the optimizer optimize for size,
4406 	// since it requires extra conditions and jumps
4407 	case 201: l_bc = (asDWORD*)201; break;
4408 	case 202: l_bc = (asDWORD*)202; break;
4409 	case 203: l_bc = (asDWORD*)203; break;
4410 	case 204: l_bc = (asDWORD*)204; break;
4411 	case 205: l_bc = (asDWORD*)205; break;
4412 	case 206: l_bc = (asDWORD*)206; break;
4413 	case 207: l_bc = (asDWORD*)207; break;
4414 	case 208: l_bc = (asDWORD*)208; break;
4415 	case 209: l_bc = (asDWORD*)209; break;
4416 	case 210: l_bc = (asDWORD*)210; break;
4417 	case 211: l_bc = (asDWORD*)211; break;
4418 	case 212: l_bc = (asDWORD*)212; break;
4419 	case 213: l_bc = (asDWORD*)213; break;
4420 	case 214: l_bc = (asDWORD*)214; break;
4421 	case 215: l_bc = (asDWORD*)215; break;
4422 	case 216: l_bc = (asDWORD*)216; break;
4423 	case 217: l_bc = (asDWORD*)217; break;
4424 	case 218: l_bc = (asDWORD*)218; break;
4425 	case 219: l_bc = (asDWORD*)219; break;
4426 	case 220: l_bc = (asDWORD*)220; break;
4427 	case 221: l_bc = (asDWORD*)221; break;
4428 	case 222: l_bc = (asDWORD*)222; break;
4429 	case 223: l_bc = (asDWORD*)223; break;
4430 	case 224: l_bc = (asDWORD*)224; break;
4431 	case 225: l_bc = (asDWORD*)225; break;
4432 	case 226: l_bc = (asDWORD*)226; break;
4433 	case 227: l_bc = (asDWORD*)227; break;
4434 	case 228: l_bc = (asDWORD*)228; break;
4435 	case 229: l_bc = (asDWORD*)229; break;
4436 	case 230: l_bc = (asDWORD*)230; break;
4437 	case 231: l_bc = (asDWORD*)231; break;
4438 	case 232: l_bc = (asDWORD*)232; break;
4439 	case 233: l_bc = (asDWORD*)233; break;
4440 	case 234: l_bc = (asDWORD*)234; break;
4441 	case 235: l_bc = (asDWORD*)235; break;
4442 	case 236: l_bc = (asDWORD*)236; break;
4443 	case 237: l_bc = (asDWORD*)237; break;
4444 	case 238: l_bc = (asDWORD*)238; break;
4445 	case 239: l_bc = (asDWORD*)239; break;
4446 	case 240: l_bc = (asDWORD*)240; break;
4447 	case 241: l_bc = (asDWORD*)241; break;
4448 	case 242: l_bc = (asDWORD*)242; break;
4449 	case 243: l_bc = (asDWORD*)243; break;
4450 	case 244: l_bc = (asDWORD*)244; break;
4451 	case 245: l_bc = (asDWORD*)245; break;
4452 	case 246: l_bc = (asDWORD*)246; break;
4453 	case 247: l_bc = (asDWORD*)247; break;
4454 	case 248: l_bc = (asDWORD*)248; break;
4455 	case 249: l_bc = (asDWORD*)249; break;
4456 	case 250: l_bc = (asDWORD*)250; break;
4457 	case 251: l_bc = (asDWORD*)251; break;
4458 	case 252: l_bc = (asDWORD*)252; break;
4459 	case 253: l_bc = (asDWORD*)253; break;
4460 	case 254: l_bc = (asDWORD*)254; break;
4461 	case 255: l_bc = (asDWORD*)255; break;
4462 
4463 #ifdef AS_DEBUG
4464 	default:
4465 		asASSERT(false);
4466 		SetInternalException(TXT_UNRECOGNIZED_BYTE_CODE);
4467 #endif
4468 #if defined(_MSC_VER) && !defined(AS_DEBUG)
4469 	default:
4470 		// This Microsoft specific code allows the
4471 		// compiler to optimize the switch case as
4472 		// it will know that the code will never
4473 		// reach this point
4474 		__assume(0);
4475 #endif
4476 	}
4477 
4478 #ifdef AS_DEBUG
4479 		asDWORD instr = *(asBYTE*)old;
4480 		if( instr != asBC_JMP && instr != asBC_JMPP && (instr < asBC_JZ || instr > asBC_JNP) && instr != asBC_JLowZ && instr != asBC_JLowNZ &&
4481 			instr != asBC_CALL && instr != asBC_CALLBND && instr != asBC_CALLINTF && instr != asBC_RET && instr != asBC_ALLOC && instr != asBC_CallPtr &&
4482 			instr != asBC_JitEntry )
4483 		{
4484 			asASSERT( (l_bc - old) == asBCTypeSize[asBCInfo[instr].type] );
4485 		}
4486 #endif
4487 	}
4488 }
4489 
SetException(const char * descr)4490 int asCContext::SetException(const char *descr)
4491 {
4492 	// Only allow this if we're executing a CALL byte code
4493 	if( m_callingSystemFunction == 0 ) return asERROR;
4494 
4495 	SetInternalException(descr);
4496 
4497 	return 0;
4498 }
4499 
SetInternalException(const char * descr)4500 void asCContext::SetInternalException(const char *descr)
4501 {
4502 	if( m_inExceptionHandler )
4503 	{
4504 		asASSERT(false); // Shouldn't happen
4505 		return; // but if it does, at least this will not crash the application
4506 	}
4507 
4508 	m_status                = asEXECUTION_EXCEPTION;
4509 	m_regs.doProcessSuspend = true;
4510 
4511 	m_exceptionString       = descr;
4512 	m_exceptionFunction     = m_currentFunction->id;
4513 
4514 	if( m_currentFunction->scriptData )
4515 	{
4516 		m_exceptionLine    = m_currentFunction->GetLineNumber(int(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf()), &m_exceptionSectionIdx);
4517 		m_exceptionColumn  = m_exceptionLine >> 20;
4518 		m_exceptionLine   &= 0xFFFFF;
4519 	}
4520 	else
4521 	{
4522 		m_exceptionSectionIdx = 0;
4523 		m_exceptionLine       = 0;
4524 		m_exceptionColumn     = 0;
4525 	}
4526 
4527 	if( m_exceptionCallback )
4528 		CallExceptionCallback();
4529 }
4530 
CleanReturnObject()4531 void asCContext::CleanReturnObject()
4532 {
4533 	if( m_initialFunction && m_initialFunction->DoesReturnOnStack() && m_status == asEXECUTION_FINISHED )
4534 	{
4535 		// If function returns on stack we need to call the destructor on the returned object
4536 		if(CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct )
4537 			m_engine->CallObjectMethod(GetReturnObject(), CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct);
4538 
4539 		return;
4540 	}
4541 
4542 	if( m_regs.objectRegister == 0 ) return;
4543 
4544 	asASSERT( m_regs.objectType != 0 );
4545 
4546 	if( m_regs.objectType )
4547 	{
4548 		if (m_regs.objectType->GetFlags() & asOBJ_FUNCDEF)
4549 		{
4550 			// Release the function pointer
4551 			reinterpret_cast<asIScriptFunction*>(m_regs.objectRegister)->Release();
4552 			m_regs.objectRegister = 0;
4553 		}
4554 		else
4555 		{
4556 			// Call the destructor on the object
4557 			asSTypeBehaviour *beh = &(CastToObjectType(reinterpret_cast<asCTypeInfo*>(m_regs.objectType))->beh);
4558 			if (m_regs.objectType->GetFlags() & asOBJ_REF)
4559 			{
4560 				asASSERT(beh->release || (m_regs.objectType->GetFlags() & asOBJ_NOCOUNT));
4561 
4562 				if (beh->release)
4563 					m_engine->CallObjectMethod(m_regs.objectRegister, beh->release);
4564 
4565 				m_regs.objectRegister = 0;
4566 			}
4567 			else
4568 			{
4569 				if (beh->destruct)
4570 					m_engine->CallObjectMethod(m_regs.objectRegister, beh->destruct);
4571 
4572 				// Free the memory
4573 				m_engine->CallFree(m_regs.objectRegister);
4574 				m_regs.objectRegister = 0;
4575 			}
4576 		}
4577 	}
4578 }
4579 
CleanStack()4580 void asCContext::CleanStack()
4581 {
4582 	m_inExceptionHandler = true;
4583 
4584 	// Run the clean up code for each of the functions called
4585 	CleanStackFrame();
4586 
4587 	// Set the status to exception so that the stack unwind is done correctly.
4588 	// This shouldn't be done for the current function, which is why we only
4589 	// do this after the first CleanStackFrame() is done.
4590 	m_status = asEXECUTION_EXCEPTION;
4591 
4592 	while( m_callStack.GetLength() > 0 )
4593 	{
4594 		// Only clean up until the top most marker for a nested call
4595 		asPWORD *s = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE;
4596 		if( s[0] == 0 )
4597 			break;
4598 
4599 		PopCallState();
4600 
4601 		CleanStackFrame();
4602 	}
4603 
4604 	m_inExceptionHandler = false;
4605 }
4606 
4607 // Interface
IsVarInScope(asUINT varIndex,asUINT stackLevel)4608 bool asCContext::IsVarInScope(asUINT varIndex, asUINT stackLevel)
4609 {
4610 	// Don't return anything if there is no bytecode, e.g. before calling Execute()
4611 	if( m_regs.programPointer == 0 ) return false;
4612 
4613 	if( stackLevel >= GetCallstackSize() ) return false;
4614 
4615 	asCScriptFunction *func;
4616 	asUINT pos;
4617 
4618 	if( stackLevel == 0 )
4619 	{
4620 		func = m_currentFunction;
4621 		if( func->scriptData == 0 ) return false;
4622 		pos = asUINT(m_regs.programPointer - func->scriptData->byteCode.AddressOf());
4623 	}
4624 	else
4625 	{
4626 		asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
4627 		func = (asCScriptFunction*)s[1];
4628 		if( func->scriptData == 0 ) return false;
4629 		pos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf());
4630 	}
4631 
4632 	// First determine if the program position is after the variable declaration
4633 	if( func->scriptData->variables.GetLength() <= varIndex ) return false;
4634 	if( func->scriptData->variables[varIndex]->declaredAtProgramPos > pos ) return false;
4635 
4636 	asUINT declaredAt = func->scriptData->variables[varIndex]->declaredAtProgramPos;
4637 
4638 	// If the program position is after the variable declaration it is necessary
4639 	// determine if the program position is still inside the statement block where
4640 	// the variable was delcared.
4641 	for( int n = 0; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ )
4642 	{
4643 		if( func->scriptData->objVariableInfo[n].programPos >= declaredAt )
4644 		{
4645 			// If the current block ends between the declaredAt and current
4646 			// program position, then we know the variable is no longer visible
4647 			int level = 0;
4648 			for( ; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ )
4649 			{
4650 				if( func->scriptData->objVariableInfo[n].programPos > pos )
4651 					break;
4652 
4653 				if( func->scriptData->objVariableInfo[n].option == asBLOCK_BEGIN ) level++;
4654 				if( func->scriptData->objVariableInfo[n].option == asBLOCK_END && --level < 0 )
4655 					return false;
4656 			}
4657 
4658 			break;
4659 		}
4660 	}
4661 
4662 	// Variable is visible
4663 	return true;
4664 }
4665 
4666 // Internal
DetermineLiveObjects(asCArray<int> & liveObjects,asUINT stackLevel)4667 void asCContext::DetermineLiveObjects(asCArray<int> &liveObjects, asUINT stackLevel)
4668 {
4669 	asASSERT( stackLevel < GetCallstackSize() );
4670 
4671 	asCScriptFunction *func;
4672 	asUINT pos;
4673 
4674 	if( stackLevel == 0 )
4675 	{
4676 		func = m_currentFunction;
4677 		if( func->scriptData == 0 )
4678 			return;
4679 
4680 		pos = asUINT(m_regs.programPointer - func->scriptData->byteCode.AddressOf());
4681 
4682 		if( m_status == asEXECUTION_EXCEPTION )
4683 		{
4684 			// Don't consider the last instruction as executed, as it failed with an exception
4685 			// It's not actually necessary to decrease the exact size of the instruction. Just
4686 			// before the current position is enough to disconsider it.
4687 			pos--;
4688 		}
4689 	}
4690 	else
4691 	{
4692 		asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
4693 		func = (asCScriptFunction*)s[1];
4694 		if( func->scriptData == 0 )
4695 			return;
4696 
4697 		pos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf());
4698 
4699 		// Don't consider the last instruction as executed, as the function that was called by it
4700 		// is still being executed. If we consider it as executed already, then a value object
4701 		// returned by value would be considered alive, which it is not.
4702 		pos--;
4703 	}
4704 
4705 	// Determine which object variables that are really live ones
4706 	liveObjects.SetLength(func->scriptData->objVariablePos.GetLength());
4707 	memset(liveObjects.AddressOf(), 0, sizeof(int)*liveObjects.GetLength());
4708 	for( int n = 0; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ )
4709 	{
4710 		// Find the first variable info with a larger position than the current
4711 		// As the variable info are always placed on the instruction right after the
4712 		// one that initialized or freed the object, the current position needs to be
4713 		// considered as valid.
4714 		if( func->scriptData->objVariableInfo[n].programPos > pos )
4715 		{
4716 			// We've determined how far the execution ran, now determine which variables are alive
4717 			for( --n; n >= 0; n-- )
4718 			{
4719 				switch( func->scriptData->objVariableInfo[n].option )
4720 				{
4721 				case asOBJ_UNINIT: // Object was destroyed
4722 					{
4723 						// TODO: optimize: This should have been done by the compiler already
4724 						// Which variable is this?
4725 						asUINT var = 0;
4726 						for( asUINT v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ )
4727 							if( func->scriptData->objVariablePos[v] == func->scriptData->objVariableInfo[n].variableOffset )
4728 							{
4729 								var = v;
4730 								break;
4731 							}
4732 						liveObjects[var] -= 1;
4733 					}
4734 					break;
4735 				case asOBJ_INIT: // Object was created
4736 					{
4737 						// Which variable is this?
4738 						asUINT var = 0;
4739 						for( asUINT v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ )
4740 							if( func->scriptData->objVariablePos[v] == func->scriptData->objVariableInfo[n].variableOffset )
4741 							{
4742 								var = v;
4743 								break;
4744 							}
4745 						liveObjects[var] += 1;
4746 					}
4747 					break;
4748 				case asBLOCK_BEGIN: // Start block
4749 					// We should ignore start blocks, since it just means the
4750 					// program was within the block when the exception ocurred
4751 					break;
4752 				case asBLOCK_END: // End block
4753 					// We need to skip the entire block, as the objects created
4754 					// and destroyed inside this block are already out of scope
4755 					{
4756 						int nested = 1;
4757 						while( nested > 0 )
4758 						{
4759 							int option = func->scriptData->objVariableInfo[--n].option;
4760 							if( option == 3 )
4761 								nested++;
4762 							if( option == 2 )
4763 								nested--;
4764 						}
4765 					}
4766 					break;
4767 				}
4768 			}
4769 
4770 			// We're done with the investigation
4771 			break;
4772 		}
4773 	}
4774 }
4775 
CleanArgsOnStack()4776 void asCContext::CleanArgsOnStack()
4777 {
4778 	if( !m_needToCleanupArgs )
4779 		return;
4780 
4781 	asASSERT( m_currentFunction->scriptData );
4782 
4783 	// Find the instruction just before the current program pointer
4784 	asDWORD *instr = m_currentFunction->scriptData->byteCode.AddressOf();
4785 	asDWORD *prevInstr = 0;
4786 	while( instr < m_regs.programPointer )
4787 	{
4788 		prevInstr = instr;
4789 		instr += asBCTypeSize[asBCInfo[*(asBYTE*)(instr)].type];
4790 	}
4791 
4792 	// Determine what function was being called
4793 	asCScriptFunction *func = 0;
4794 	asBYTE bc = *(asBYTE*)prevInstr;
4795 	if( bc == asBC_CALL || bc == asBC_CALLSYS || bc == asBC_CALLINTF )
4796 	{
4797 		int funcId = asBC_INTARG(prevInstr);
4798 		func = m_engine->scriptFunctions[funcId];
4799 	}
4800 	else if( bc == asBC_CALLBND )
4801 	{
4802 		int funcId = asBC_INTARG(prevInstr);
4803 		func = m_engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature;
4804 	}
4805 	else if( bc == asBC_CallPtr )
4806 	{
4807 		asUINT v;
4808 		int var = asBC_SWORDARG0(prevInstr);
4809 
4810 		// Find the funcdef from the local variable
4811 		for( v = 0; v < m_currentFunction->scriptData->objVariablePos.GetLength(); v++ )
4812 			if( m_currentFunction->scriptData->objVariablePos[v] == var )
4813 			{
4814 				func = CastToFuncdefType(m_currentFunction->scriptData->objVariableTypes[v])->funcdef;
4815 				break;
4816 			}
4817 
4818 		if( func == 0 )
4819 		{
4820 			// Look in parameters
4821 			int paramPos = 0;
4822 			if( m_currentFunction->objectType )
4823 				paramPos -= AS_PTR_SIZE;
4824 			if( m_currentFunction->DoesReturnOnStack() )
4825 				paramPos -= AS_PTR_SIZE;
4826 			for( v = 0; v < m_currentFunction->parameterTypes.GetLength(); v++ )
4827 			{
4828 				if( var == paramPos )
4829 				{
4830 					if (m_currentFunction->parameterTypes[v].IsFuncdef())
4831 						func = CastToFuncdefType(m_currentFunction->parameterTypes[v].GetTypeInfo())->funcdef;
4832 					break;
4833 				}
4834 				paramPos -= m_currentFunction->parameterTypes[v].GetSizeOnStackDWords();
4835 			}
4836 		}
4837 	}
4838 	else
4839 		asASSERT( false );
4840 
4841 	asASSERT( func );
4842 
4843 	// Clean parameters
4844 	int offset = 0;
4845 	if( func->objectType )
4846 		offset += AS_PTR_SIZE;
4847 	if( func->DoesReturnOnStack() )
4848 		offset += AS_PTR_SIZE;
4849 	for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
4850 	{
4851 		if( (func->parameterTypes[n].IsObject() || func->parameterTypes[n].IsFuncdef()) && !func->parameterTypes[n].IsReference() )
4852 		{
4853 			// TODO: cleanup: This logic is repeated twice in CleanStackFrame too. Should create a common function to share the code
4854 			if( *(asPWORD*)&m_regs.stackPointer[offset] )
4855 			{
4856 				// Call the object's destructor
4857 				asSTypeBehaviour *beh = func->parameterTypes[n].GetBehaviour();
4858 				if (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF)
4859 				{
4860 					(*(asCScriptFunction**)&m_regs.stackPointer[offset])->Release();
4861 				}
4862 				else if( func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF )
4863 				{
4864 					asASSERT( (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release );
4865 
4866 					if( beh->release )
4867 						m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->release);
4868 				}
4869 				else
4870 				{
4871 					if( beh->destruct )
4872 						m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->destruct);
4873 
4874 					// Free the memory
4875 					m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackPointer[offset]);
4876 				}
4877 				*(asPWORD*)&m_regs.stackPointer[offset] = 0;
4878 			}
4879 		}
4880 
4881 		offset += func->parameterTypes[n].GetSizeOnStackDWords();
4882 	}
4883 
4884 	m_needToCleanupArgs = false;
4885 }
4886 
CleanStackFrame()4887 void asCContext::CleanStackFrame()
4888 {
4889 	// Clean object variables on the stack
4890 	// If the stack memory is not allocated or the program pointer
4891 	// is not set, then there is nothing to clean up on the stack frame
4892 	if( !m_isStackMemoryNotAllocated && m_regs.programPointer )
4893 	{
4894 		// If the exception occurred while calling a function it is necessary
4895 		// to clean up the arguments that were put on the stack.
4896 		CleanArgsOnStack();
4897 
4898 		// Restore the stack pointer
4899 		asASSERT( m_currentFunction->scriptData );
4900 		m_regs.stackPointer += m_currentFunction->scriptData->variableSpace;
4901 
4902 		// Determine which object variables that are really live ones
4903 		asCArray<int> liveObjects;
4904 		DetermineLiveObjects(liveObjects, 0);
4905 
4906 		for( asUINT n = 0; n < m_currentFunction->scriptData->objVariablePos.GetLength(); n++ )
4907 		{
4908 			int pos = m_currentFunction->scriptData->objVariablePos[n];
4909 			if( n < m_currentFunction->scriptData->objVariablesOnHeap )
4910 			{
4911 				// Check if the pointer is initialized
4912 				if( *(asPWORD*)&m_regs.stackFramePointer[-pos] )
4913 				{
4914 					// Call the object's destructor
4915 					if (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_FUNCDEF)
4916 					{
4917 						(*(asCScriptFunction**)&m_regs.stackFramePointer[-pos])->Release();
4918 					}
4919 					else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_REF )
4920 					{
4921 						asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh;
4922 						asASSERT( (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_NOCOUNT) || beh->release );
4923 						if( beh->release )
4924 							m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->release);
4925 					}
4926 					else
4927 					{
4928 						asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh;
4929 						if( beh->destruct )
4930 							m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct);
4931 						else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_LIST_PATTERN )
4932 							m_engine->DestroyList((asBYTE*)*(asPWORD*)&m_regs.stackFramePointer[-pos], CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n]));
4933 
4934 						// Free the memory
4935 						m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos]);
4936 					}
4937 					*(asPWORD*)&m_regs.stackFramePointer[-pos] = 0;
4938 				}
4939 			}
4940 			else
4941 			{
4942 				asASSERT( m_currentFunction->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE );
4943 
4944 				// Only destroy the object if it is truly alive
4945 				if( liveObjects[n] > 0 )
4946 				{
4947 					asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh;
4948 					if( beh->destruct )
4949 						m_engine->CallObjectMethod((void*)(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct);
4950 				}
4951 			}
4952 		}
4953 	}
4954 	else
4955 		m_isStackMemoryNotAllocated = false;
4956 
4957 	// Functions that do not own the object and parameters shouldn't do any clean up
4958 	if( m_currentFunction->dontCleanUpOnException )
4959 		return;
4960 
4961 	// Clean object and parameters
4962 	int offset = 0;
4963 	if( m_currentFunction->objectType )
4964 		offset += AS_PTR_SIZE;
4965 	if( m_currentFunction->DoesReturnOnStack() )
4966 		offset += AS_PTR_SIZE;
4967 	for( asUINT n = 0; n < m_currentFunction->parameterTypes.GetLength(); n++ )
4968 	{
4969 		if( (m_currentFunction->parameterTypes[n].IsObject() ||m_currentFunction->parameterTypes[n].IsFuncdef()) && !m_currentFunction->parameterTypes[n].IsReference() )
4970 		{
4971 			if( *(asPWORD*)&m_regs.stackFramePointer[offset] )
4972 			{
4973 				// Call the object's destructor
4974 				asSTypeBehaviour *beh = m_currentFunction->parameterTypes[n].GetBehaviour();
4975 				if (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF)
4976 				{
4977 					(*(asCScriptFunction**)&m_regs.stackFramePointer[offset])->Release();
4978 				}
4979 				else if( m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF )
4980 				{
4981 					asASSERT( (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release );
4982 
4983 					if( beh->release )
4984 						m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->release);
4985 				}
4986 				else
4987 				{
4988 					if( beh->destruct )
4989 						m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->destruct);
4990 
4991 					// Free the memory
4992 					m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[offset]);
4993 				}
4994 				*(asPWORD*)&m_regs.stackFramePointer[offset] = 0;
4995 			}
4996 		}
4997 
4998 		offset += m_currentFunction->parameterTypes[n].GetSizeOnStackDWords();
4999 	}
5000 }
5001 
5002 // interface
GetExceptionLineNumber(int * column,const char ** sectionName)5003 int asCContext::GetExceptionLineNumber(int *column, const char **sectionName)
5004 {
5005 	if( GetState() != asEXECUTION_EXCEPTION ) return asERROR;
5006 
5007 	if( column ) *column = m_exceptionColumn;
5008 
5009 	if( sectionName )
5010 	{
5011 		// The section index can be -1 if the exception was raised in a generated function, e.g. $fact for templates
5012 		if( m_exceptionSectionIdx >= 0 )
5013 			*sectionName = m_engine->scriptSectionNames[m_exceptionSectionIdx]->AddressOf();
5014 		else
5015 			*sectionName = 0;
5016 	}
5017 
5018 	return m_exceptionLine;
5019 }
5020 
5021 // interface
GetExceptionFunction()5022 asIScriptFunction *asCContext::GetExceptionFunction()
5023 {
5024 	if( GetState() != asEXECUTION_EXCEPTION ) return 0;
5025 
5026 	return m_engine->scriptFunctions[m_exceptionFunction];
5027 }
5028 
5029 // interface
GetExceptionString()5030 const char *asCContext::GetExceptionString()
5031 {
5032 	if( GetState() != asEXECUTION_EXCEPTION ) return 0;
5033 
5034 	return m_exceptionString.AddressOf();
5035 }
5036 
5037 // interface
GetState() const5038 asEContextState asCContext::GetState() const
5039 {
5040 	return m_status;
5041 }
5042 
5043 // interface
SetLineCallback(asSFuncPtr callback,void * obj,int callConv)5044 int asCContext::SetLineCallback(asSFuncPtr callback, void *obj, int callConv)
5045 {
5046 	// First turn off the line callback to avoid a second thread
5047 	// attempting to call it while the new one is still being set
5048 	m_lineCallback = false;
5049 
5050 	m_lineCallbackObj = obj;
5051 	bool isObj = false;
5052 	if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST )
5053 	{
5054 		m_regs.doProcessSuspend = m_doSuspend;
5055 		return asNOT_SUPPORTED;
5056 	}
5057 	if( (unsigned)callConv >= asCALL_THISCALL )
5058 	{
5059 		isObj = true;
5060 		if( obj == 0 )
5061 		{
5062 			m_regs.doProcessSuspend = m_doSuspend;
5063 			return asINVALID_ARG;
5064 		}
5065 	}
5066 
5067 	int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_lineCallbackFunc);
5068 
5069 	// Turn on the line callback after setting both the function pointer and object pointer
5070 	if( r >= 0 ) m_lineCallback = true;
5071 
5072 	// The BC_SUSPEND instruction should be processed if either line
5073 	// callback is set or if the application has requested a suspension
5074 	m_regs.doProcessSuspend = m_doSuspend || m_lineCallback;
5075 
5076 	return r;
5077 }
5078 
CallLineCallback()5079 void asCContext::CallLineCallback()
5080 {
5081 	if( m_lineCallbackFunc.callConv < ICC_THISCALL )
5082 		m_engine->CallGlobalFunction(this, m_lineCallbackObj, &m_lineCallbackFunc, 0);
5083 	else
5084 		m_engine->CallObjectMethod(m_lineCallbackObj, this, &m_lineCallbackFunc, 0);
5085 }
5086 
5087 // interface
SetExceptionCallback(asSFuncPtr callback,void * obj,int callConv)5088 int asCContext::SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv)
5089 {
5090 	m_exceptionCallback = true;
5091 	m_exceptionCallbackObj = obj;
5092 	bool isObj = false;
5093 	if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST )
5094 		return asNOT_SUPPORTED;
5095 	if( (unsigned)callConv >= asCALL_THISCALL )
5096 	{
5097 		isObj = true;
5098 		if( obj == 0 )
5099 		{
5100 			m_exceptionCallback = false;
5101 			return asINVALID_ARG;
5102 		}
5103 	}
5104 	int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_exceptionCallbackFunc);
5105 	if( r < 0 ) m_exceptionCallback = false;
5106 	return r;
5107 }
5108 
CallExceptionCallback()5109 void asCContext::CallExceptionCallback()
5110 {
5111 	if( m_exceptionCallbackFunc.callConv < ICC_THISCALL )
5112 		m_engine->CallGlobalFunction(this, m_exceptionCallbackObj, &m_exceptionCallbackFunc, 0);
5113 	else
5114 		m_engine->CallObjectMethod(m_exceptionCallbackObj, this, &m_exceptionCallbackFunc, 0);
5115 }
5116 
5117 // interface
ClearLineCallback()5118 void asCContext::ClearLineCallback()
5119 {
5120 	m_lineCallback = false;
5121 	m_regs.doProcessSuspend = m_doSuspend;
5122 }
5123 
5124 // interface
ClearExceptionCallback()5125 void asCContext::ClearExceptionCallback()
5126 {
5127 	m_exceptionCallback = false;
5128 }
5129 
CallGeneric(asCScriptFunction * descr)5130 int asCContext::CallGeneric(asCScriptFunction *descr)
5131 {
5132 	asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
5133 	void (*func)(asIScriptGeneric*) = (void (*)(asIScriptGeneric*))sysFunc->func;
5134 	int popSize = sysFunc->paramSize;
5135 	asDWORD *args = m_regs.stackPointer;
5136 
5137 	// Verify the object pointer if it is a class method
5138 	void *currentObject = 0;
5139 	asASSERT( sysFunc->callConv == ICC_GENERIC_FUNC || sysFunc->callConv == ICC_GENERIC_METHOD );
5140 	if( sysFunc->callConv == ICC_GENERIC_METHOD )
5141 	{
5142 		// The object pointer should be popped from the context stack
5143 		popSize += AS_PTR_SIZE;
5144 
5145 		// Check for null pointer
5146 		currentObject = (void*)*(asPWORD*)(args);
5147 		if( currentObject == 0 )
5148 		{
5149 			SetInternalException(TXT_NULL_POINTER_ACCESS);
5150 			return 0;
5151 		}
5152 
5153 		asASSERT( sysFunc->baseOffset == 0 );
5154 
5155 		// Skip object pointer
5156 		args += AS_PTR_SIZE;
5157 	}
5158 
5159 	if( descr->DoesReturnOnStack() )
5160 	{
5161 		// Skip the address where the return value will be stored
5162 		args += AS_PTR_SIZE;
5163 		popSize += AS_PTR_SIZE;
5164 	}
5165 
5166 	asCGeneric gen(m_engine, descr, currentObject, args);
5167 
5168 	m_callingSystemFunction = descr;
5169 #ifdef AS_NO_EXCEPTIONS
5170 	func(&gen);
5171 #else
5172 	// This try/catch block is to catch potential exception that may
5173 	// be thrown by the registered function.
5174 	try
5175 	{
5176 		func(&gen);
5177 	}
5178 	catch (...)
5179 	{
5180 		// Convert the exception to a script exception so the VM can
5181 		// properly report the error to the application and then clean up
5182 		SetException(TXT_EXCEPTION_CAUGHT);
5183 	}
5184 #endif
5185 	m_callingSystemFunction = 0;
5186 
5187 	m_regs.valueRegister = gen.returnVal;
5188 	m_regs.objectRegister = gen.objectRegister;
5189 	m_regs.objectType = descr->returnType.GetTypeInfo();
5190 
5191 	// Clean up arguments
5192 	const asUINT cleanCount = sysFunc->cleanArgs.GetLength();
5193 	if( cleanCount )
5194 	{
5195 		asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
5196 		for( asUINT n = 0; n < cleanCount; n++, clean++ )
5197 		{
5198 			void **addr = (void**)&args[clean->off];
5199 			if( clean->op == 0 )
5200 			{
5201 				if( *addr != 0 )
5202 				{
5203 					m_engine->CallObjectMethod(*addr, clean->ot->beh.release);
5204 					*addr = 0;
5205 				}
5206 			}
5207 			else
5208 			{
5209 				asASSERT( clean->op == 1 || clean->op == 2 );
5210 				asASSERT( *addr );
5211 
5212 				if( clean->op == 2 )
5213 					m_engine->CallObjectMethod(*addr, clean->ot->beh.destruct);
5214 
5215 				m_engine->CallFree(*addr);
5216 			}
5217 		}
5218 	}
5219 
5220 	// Return how much should be popped from the stack
5221 	return popSize;
5222 }
5223 
5224 // interface
GetVarCount(asUINT stackLevel)5225 int asCContext::GetVarCount(asUINT stackLevel)
5226 {
5227 	asIScriptFunction *func = GetFunction(stackLevel);
5228 	if( func == 0 ) return asINVALID_ARG;
5229 
5230 	return func->GetVarCount();
5231 }
5232 
5233 // interface
GetVarName(asUINT varIndex,asUINT stackLevel)5234 const char *asCContext::GetVarName(asUINT varIndex, asUINT stackLevel)
5235 {
5236 	asIScriptFunction *func = GetFunction(stackLevel);
5237 	if( func == 0 ) return 0;
5238 
5239 	const char *name = 0;
5240 	int r = func->GetVar(varIndex, &name);
5241 	return r >= 0 ? name : 0;
5242 }
5243 
5244 // interface
GetVarDeclaration(asUINT varIndex,asUINT stackLevel,bool includeNamespace)5245 const char *asCContext::GetVarDeclaration(asUINT varIndex, asUINT stackLevel, bool includeNamespace)
5246 {
5247 	asIScriptFunction *func = GetFunction(stackLevel);
5248 	if( func == 0 ) return 0;
5249 
5250 	return func->GetVarDecl(varIndex, includeNamespace);
5251 }
5252 
5253 // interface
GetVarTypeId(asUINT varIndex,asUINT stackLevel)5254 int asCContext::GetVarTypeId(asUINT varIndex, asUINT stackLevel)
5255 {
5256 	asIScriptFunction *func = GetFunction(stackLevel);
5257 	if( func == 0 ) return asINVALID_ARG;
5258 
5259 	int typeId;
5260 	int r = func->GetVar(varIndex, 0, &typeId);
5261 	return r < 0 ? r : typeId;
5262 }
5263 
5264 // interface
GetAddressOfVar(asUINT varIndex,asUINT stackLevel)5265 void *asCContext::GetAddressOfVar(asUINT varIndex, asUINT stackLevel)
5266 {
5267 	// Don't return anything if there is no bytecode, e.g. before calling Execute()
5268 	if( m_regs.programPointer == 0 ) return 0;
5269 
5270 	if( stackLevel >= GetCallstackSize() ) return 0;
5271 
5272 	asCScriptFunction *func;
5273 	asDWORD *sf;
5274 	if( stackLevel == 0 )
5275 	{
5276 		func = m_currentFunction;
5277 		sf = m_regs.stackFramePointer;
5278 	}
5279 	else
5280 	{
5281 		asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
5282 		func = (asCScriptFunction*)s[1];
5283 		sf = (asDWORD*)s[0];
5284 	}
5285 
5286 	if( func == 0 )
5287 		return 0;
5288 
5289 	if( func->scriptData == 0 )
5290 		return 0;
5291 
5292 	if( varIndex >= func->scriptData->variables.GetLength() )
5293 		return 0;
5294 
5295 	// For object variables it's necessary to dereference the pointer to get the address of the value
5296 	// Reference parameters must also be dereferenced to give the address of the value
5297 	int pos = func->scriptData->variables[varIndex]->stackOffset;
5298 	if( (func->scriptData->variables[varIndex]->type.IsObject() && !func->scriptData->variables[varIndex]->type.IsObjectHandle()) || (pos <= 0) )
5299 	{
5300 		// Determine if the object is really on the heap
5301 		bool onHeap = false;
5302 		if( func->scriptData->variables[varIndex]->type.IsObject() &&
5303 			!func->scriptData->variables[varIndex]->type.IsObjectHandle() )
5304 		{
5305 			onHeap = true;
5306 			if( func->scriptData->variables[varIndex]->type.GetTypeInfo()->GetFlags() & asOBJ_VALUE )
5307 			{
5308 				for( asUINT n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ )
5309 				{
5310 					if( func->scriptData->objVariablePos[n] == pos )
5311 					{
5312 						onHeap = n < func->scriptData->objVariablesOnHeap;
5313 
5314 						if( !onHeap )
5315 						{
5316 							// If the object on the stack is not initialized return a null pointer instead
5317 							asCArray<int> liveObjects;
5318 							DetermineLiveObjects(liveObjects, stackLevel);
5319 
5320 							if( liveObjects[n] <= 0 )
5321 								return 0;
5322 						}
5323 
5324 						break;
5325 					}
5326 				}
5327 			}
5328 		}
5329 
5330 		// If it wasn't an object on the heap, then check if it is a reference parameter
5331 		if( !onHeap && pos <= 0 )
5332 		{
5333 			// Determine what function argument this position matches
5334 			int stackPos = 0;
5335 			if( func->objectType )
5336 				stackPos -= AS_PTR_SIZE;
5337 
5338 			if( func->DoesReturnOnStack() )
5339 				stackPos -= AS_PTR_SIZE;
5340 
5341 			for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
5342 			{
5343 				if( stackPos == pos )
5344 				{
5345 					// The right argument was found. Is this a reference parameter?
5346 					if( func->inOutFlags[n] != asTM_NONE )
5347 						onHeap = true;
5348 
5349 					break;
5350 				}
5351 				stackPos -= func->parameterTypes[n].GetSizeOnStackDWords();
5352 			}
5353 		}
5354 
5355 		if( onHeap )
5356 			return *(void**)(sf - func->scriptData->variables[varIndex]->stackOffset);
5357 	}
5358 
5359 	return sf - func->scriptData->variables[varIndex]->stackOffset;
5360 }
5361 
5362 // interface
5363 // returns the typeId of the 'this' object at the given call stack level (-1 for current)
5364 // returns 0 if the function call at the given stack level is not a method
GetThisTypeId(asUINT stackLevel)5365 int asCContext::GetThisTypeId(asUINT stackLevel)
5366 {
5367 	asIScriptFunction *func = GetFunction(stackLevel);
5368 	if( func == 0 ) return asINVALID_ARG;
5369 
5370 	if( func->GetObjectType() == 0 )
5371 		return 0; // not in a method
5372 
5373 	// create a datatype
5374 	asCDataType dt = asCDataType::CreateType((asCObjectType*)func->GetObjectType(), false);
5375 
5376 	// return a typeId from the data type
5377 	return m_engine->GetTypeIdFromDataType(dt);
5378 }
5379 
5380 // interface
5381 // returns the 'this' object pointer at the given call stack level (-1 for current)
5382 // returns 0 if the function call at the given stack level is not a method
GetThisPointer(asUINT stackLevel)5383 void *asCContext::GetThisPointer(asUINT stackLevel)
5384 {
5385 	if( stackLevel >= GetCallstackSize() )
5386 		return 0;
5387 
5388 	asCScriptFunction *func;
5389 	asDWORD *sf;
5390 	if( stackLevel == 0 )
5391 	{
5392 		func = m_currentFunction;
5393 		sf = m_regs.stackFramePointer;
5394 	}
5395 	else
5396 	{
5397 		asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE;
5398 		func = (asCScriptFunction*)s[1];
5399 		sf = (asDWORD*)s[0];
5400 	}
5401 
5402 	if( func == 0 )
5403 		return 0;
5404 
5405 	if( func->objectType == 0 )
5406 		return 0; // not in a method
5407 
5408 	void *thisPointer = (void*)*(asPWORD*)(sf);
5409 	if( thisPointer == 0 )
5410 	{
5411 		return 0;
5412 	}
5413 
5414 	// NOTE: this returns the pointer to the 'this' while the GetVarPointer functions return
5415 	// a pointer to a pointer. I can't imagine someone would want to change the 'this'
5416 	return thisPointer;
5417 }
5418 
5419 
5420 
5421 
5422 
5423 
5424 
5425 // TODO: Move these to as_utils.cpp
5426 
5427 struct POW_INFO
5428 {
5429 	asQWORD MaxBaseu64;
5430 	asDWORD MaxBasei64;
5431 	asWORD  MaxBaseu32;
5432 	asWORD  MaxBasei32;
5433 	char    HighBit;
5434 };
5435 
5436 const POW_INFO pow_info[] =
5437 {
5438 	{          0ULL,          0UL,     0,     0, 0 },  // 0 is a special case
5439 	{          0ULL,          0UL,     0,     0, 1 },  // 1 is a special case
5440     { 3037000499ULL, 2147483647UL, 65535, 46340, 2 },  // 2
5441     {    2097152ULL,    1664510UL,  1625,  1290, 2 },  // 3
5442     {      55108ULL,      46340UL,   255,   215, 3 },  // 4
5443     {       6208ULL,       5404UL,    84,    73, 3 },  // 5
5444     {       1448ULL,       1290UL,    40,    35, 3 },  // 6
5445     {        511ULL,        463UL,    23,    21, 3 },  // 7
5446     {        234ULL,        215UL,    15,    14, 4 },  // 8
5447     {        128ULL,        118UL,    11,    10, 4 },  // 9
5448     {         78ULL,         73UL,     9,     8, 4 },  // 10
5449     {         52ULL,         49UL,     7,     7, 4 },  // 11
5450     {         38ULL,         35UL,     6,     5, 4 },  // 12
5451     {         28ULL,         27UL,     5,     5, 4 },  // 13
5452     {         22ULL,         21UL,     4,     4, 4 },  // 14
5453     {         18ULL,         17UL,     4,     4, 4 },  // 15
5454     {         15ULL,         14UL,     3,     3, 5 },  // 16
5455     {         13ULL,         12UL,     3,     3, 5 },  // 17
5456     {         11ULL,         10UL,     3,     3, 5 },  // 18
5457     {          9ULL,          9UL,     3,     3, 5 },  // 19
5458     {          8ULL,          8UL,     3,     2, 5 },  // 20
5459     {          8ULL,          7UL,     2,     2, 5 },  // 21
5460     {          7ULL,          7UL,     2,     2, 5 },  // 22
5461     {          6ULL,          6UL,     2,     2, 5 },  // 23
5462     {          6ULL,          5UL,     2,     2, 5 },  // 24
5463     {          5ULL,          5UL,     2,     2, 5 },  // 25
5464     {          5ULL,          5UL,     2,     2, 5 },  // 26
5465     {          5ULL,          4UL,     2,     2, 5 },  // 27
5466     {          4ULL,          4UL,     2,     2, 5 },  // 28
5467     {          4ULL,          4UL,     2,     2, 5 },  // 29
5468     {          4ULL,          4UL,     2,     2, 5 },  // 30
5469     {          4ULL,          4UL,     2,     1, 5 },  // 31
5470     {          3ULL,          3UL,     1,     1, 6 },  // 32
5471     {          3ULL,          3UL,     1,     1, 6 },  // 33
5472     {          3ULL,          3UL,     1,     1, 6 },  // 34
5473     {          3ULL,          3UL,     1,     1, 6 },  // 35
5474     {          3ULL,          3UL,     1,     1, 6 },  // 36
5475     {          3ULL,          3UL,     1,     1, 6 },  // 37
5476     {          3ULL,          3UL,     1,     1, 6 },  // 38
5477     {          3ULL,          3UL,     1,     1, 6 },  // 39
5478     {          2ULL,          2UL,     1,     1, 6 },  // 40
5479     {          2ULL,          2UL,     1,     1, 6 },  // 41
5480     {          2ULL,          2UL,     1,     1, 6 },  // 42
5481     {          2ULL,          2UL,     1,     1, 6 },  // 43
5482     {          2ULL,          2UL,     1,     1, 6 },  // 44
5483     {          2ULL,          2UL,     1,     1, 6 },  // 45
5484     {          2ULL,          2UL,     1,     1, 6 },  // 46
5485     {          2ULL,          2UL,     1,     1, 6 },  // 47
5486     {          2ULL,          2UL,     1,     1, 6 },  // 48
5487     {          2ULL,          2UL,     1,     1, 6 },  // 49
5488     {          2ULL,          2UL,     1,     1, 6 },  // 50
5489     {          2ULL,          2UL,     1,     1, 6 },  // 51
5490     {          2ULL,          2UL,     1,     1, 6 },  // 52
5491     {          2ULL,          2UL,     1,     1, 6 },  // 53
5492     {          2ULL,          2UL,     1,     1, 6 },  // 54
5493     {          2ULL,          2UL,     1,     1, 6 },  // 55
5494     {          2ULL,          2UL,     1,     1, 6 },  // 56
5495     {          2ULL,          2UL,     1,     1, 6 },  // 57
5496     {          2ULL,          2UL,     1,     1, 6 },  // 58
5497     {          2ULL,          2UL,     1,     1, 6 },  // 59
5498     {          2ULL,          2UL,     1,     1, 6 },  // 60
5499     {          2ULL,          2UL,     1,     1, 6 },  // 61
5500     {          2ULL,          2UL,     1,     1, 6 },  // 62
5501 	{          2ULL,          1UL,     1,     1, 6 },  // 63
5502 };
5503 
as_powi(int base,int exponent,bool & isOverflow)5504 int as_powi(int base, int exponent, bool& isOverflow)
5505 {
5506 	if( exponent < 0 )
5507 	{
5508 		if( base == 0 )
5509 			// Divide by zero
5510 			isOverflow = true;
5511 		else
5512 			// Result is less than 1, so it truncates to 0
5513 			isOverflow = false;
5514 
5515 		return 0;
5516 	}
5517 	else if( exponent == 0 && base == 0 )
5518 	{
5519 		// Domain error
5520 		isOverflow = true;
5521 		return 0;
5522 	}
5523 	else if( exponent >= 31 )
5524 	{
5525 		switch( base )
5526 		{
5527 		case -1:
5528 			isOverflow = false;
5529 			return exponent & 1 ? -1 : 1;
5530 		case 0:
5531 			isOverflow = false;
5532 			break;
5533 		case 1:
5534 			isOverflow = false;
5535 			return 1;
5536 		default:
5537 			isOverflow = true;
5538 			break;
5539 		}
5540 		return 0;
5541 	}
5542 	else
5543 	{
5544 		const asWORD max_base = pow_info[exponent].MaxBasei32;
5545 		const char high_bit = pow_info[exponent].HighBit;
5546 		if( max_base != 0 && max_base < (base < 0 ? -base : base) )
5547 		{
5548 			isOverflow = true;
5549 			return 0;  // overflow
5550 		}
5551 
5552 		int result = 1;
5553 		switch( high_bit )
5554 		{
5555 		case 5:
5556 			if( exponent & 1 ) result *= base;
5557 			exponent >>= 1;
5558 			base *= base;
5559 		case 4:
5560 			if( exponent & 1 ) result *= base;
5561 			exponent >>= 1;
5562 			base *= base;
5563 		case 3:
5564 			if( exponent & 1 ) result *= base;
5565 			exponent >>= 1;
5566 			base *= base;
5567 		case 2:
5568 			if( exponent & 1 ) result *= base;
5569 			exponent >>= 1;
5570 			base *= base;
5571 		case 1:
5572 			if( exponent ) result *= base;
5573 		default:
5574 			isOverflow = false;
5575 			return result;
5576 		}
5577 	}
5578 }
5579 
as_powu(asDWORD base,asDWORD exponent,bool & isOverflow)5580 asDWORD as_powu(asDWORD base, asDWORD exponent, bool& isOverflow)
5581 {
5582 	if( exponent == 0 && base == 0 )
5583 	{
5584 		// Domain error
5585 		isOverflow = true;
5586 		return 0;
5587 	}
5588 	else if( exponent >= 32 )
5589 	{
5590 		switch( base )
5591 		{
5592 		case 0:
5593 			isOverflow = false;
5594 			break;
5595 		case 1:
5596 			isOverflow = false;
5597 			return 1;
5598 		default:
5599 			isOverflow = true;
5600 			break;
5601 		}
5602 		return 0;
5603 	}
5604 	else
5605 	{
5606 		const asWORD max_base = pow_info[exponent].MaxBaseu32;
5607 		const char high_bit = pow_info[exponent].HighBit;
5608 		if( max_base != 0 && max_base < base )
5609 		{
5610 			isOverflow = true;
5611 			return 0;  // overflow
5612 		}
5613 
5614 		asDWORD result = 1;
5615 		switch( high_bit )
5616 		{
5617 		case 5:
5618 			if( exponent & 1 ) result *= base;
5619 			exponent >>= 1;
5620 			base *= base;
5621 		case 4:
5622 			if( exponent & 1 ) result *= base;
5623 			exponent >>= 1;
5624 			base *= base;
5625 		case 3:
5626 			if( exponent & 1 ) result *= base;
5627 			exponent >>= 1;
5628 			base *= base;
5629 		case 2:
5630 			if( exponent & 1 ) result *= base;
5631 			exponent >>= 1;
5632 			base *= base;
5633 		case 1:
5634 			if( exponent ) result *= base;
5635 		default:
5636 			isOverflow = false;
5637 			return result;
5638 		}
5639 	}
5640 }
5641 
as_powi64(asINT64 base,asINT64 exponent,bool & isOverflow)5642 asINT64 as_powi64(asINT64 base, asINT64 exponent, bool& isOverflow)
5643 {
5644 	if( exponent < 0 )
5645 	{
5646 		if( base == 0 )
5647 			// Divide by zero
5648 			isOverflow = true;
5649 		else
5650 			// Result is less than 1, so it truncates to 0
5651 			isOverflow = false;
5652 
5653 		return 0;
5654 	}
5655 	else if( exponent == 0 && base == 0 )
5656 	{
5657 		// Domain error
5658 		isOverflow = true;
5659 		return 0;
5660 	}
5661 	else if( exponent >= 63 )
5662 	{
5663 		switch( base )
5664 		{
5665 		case -1:
5666 			isOverflow = false;
5667 			return exponent & 1 ? -1 : 1;
5668 		case 0:
5669 			isOverflow = false;
5670 			break;
5671 		case 1:
5672 			isOverflow = false;
5673 			return 1;
5674 		default:
5675 			isOverflow = true;
5676 			break;
5677 		}
5678 		return 0;
5679 	}
5680 	else
5681 	{
5682 		const asDWORD max_base = pow_info[exponent].MaxBasei64;
5683 		const char high_bit = pow_info[exponent].HighBit;
5684 		if( max_base != 0 && max_base < (base < 0 ? -base : base) )
5685 		{
5686 			isOverflow = true;
5687 			return 0;  // overflow
5688 		}
5689 
5690 		asINT64 result = 1;
5691 		switch( high_bit )
5692 		{
5693 		case 6:
5694 			if( exponent & 1 ) result *= base;
5695 			exponent >>= 1;
5696 			base *= base;
5697 		case 5:
5698 			if( exponent & 1 ) result *= base;
5699 			exponent >>= 1;
5700 			base *= base;
5701 		case 4:
5702 			if( exponent & 1 ) result *= base;
5703 			exponent >>= 1;
5704 			base *= base;
5705 		case 3:
5706 			if( exponent & 1 ) result *= base;
5707 			exponent >>= 1;
5708 			base *= base;
5709 		case 2:
5710 			if( exponent & 1 ) result *= base;
5711 			exponent >>= 1;
5712 			base *= base;
5713 		case 1:
5714 			if( exponent ) result *= base;
5715 		default:
5716 			isOverflow = false;
5717 			return result;
5718 		}
5719 	}
5720 }
5721 
as_powu64(asQWORD base,asQWORD exponent,bool & isOverflow)5722 asQWORD as_powu64(asQWORD base, asQWORD exponent, bool& isOverflow)
5723 {
5724 	if( exponent == 0 && base == 0 )
5725 	{
5726 		// Domain error
5727 		isOverflow = true;
5728 		return 0;
5729 	}
5730 	else if( exponent >= 64 )
5731 	{
5732 		switch( base )
5733 		{
5734 		case 0:
5735 			isOverflow = false;
5736 			break;
5737 		case 1:
5738 			isOverflow = false;
5739 			return 1;
5740 		default:
5741 			isOverflow = true;
5742 			break;
5743 		}
5744 		return 0;
5745 	}
5746 	else
5747 	{
5748 		const asQWORD max_base = pow_info[exponent].MaxBaseu64;
5749 		const char high_bit = pow_info[exponent].HighBit;
5750 		if( max_base != 0 && max_base < base )
5751 		{
5752 			isOverflow = true;
5753 			return 0;  // overflow
5754 		}
5755 
5756 		asQWORD result = 1;
5757 		switch( high_bit )
5758 		{
5759 		case 6:
5760 			if( exponent & 1 ) result *= base;
5761 			exponent >>= 1;
5762 			base *= base;
5763 		case 5:
5764 			if( exponent & 1 ) result *= base;
5765 			exponent >>= 1;
5766 			base *= base;
5767 		case 4:
5768 			if( exponent & 1 ) result *= base;
5769 			exponent >>= 1;
5770 			base *= base;
5771 		case 3:
5772 			if( exponent & 1 ) result *= base;
5773 			exponent >>= 1;
5774 			base *= base;
5775 		case 2:
5776 			if( exponent & 1 ) result *= base;
5777 			exponent >>= 1;
5778 			base *= base;
5779 		case 1:
5780 			if( exponent ) result *= base;
5781 		default:
5782 			isOverflow = false;
5783 			return result;
5784 		}
5785 	}
5786 }
5787 
5788 END_AS_NAMESPACE
5789 
5790 
5791 
5792